commit 47273ae3fd48f2aa48ca8d99cc1d0b677b5545aa Author: KodouWZF <3092554823@qq.com> Date: Mon Nov 2 10:59:03 2026 +0800 init: 信创文件安全传输系统内外网本地 Docker 部署 包含 s-file 后端、React 前端、MeshSafe 安全检测对接,以及内外网两套 compose/nginx/配置(仅前端 28180/28280 对外发布,其余端口不暴露)。 说明:deploy/config/application-iw.yml 与 application-ow.yml 按维护者 明确要求原样入库,其中含本机 Docker 用的库口令、RabbitMQ 口令与 JWT 密钥;上生产前需替换。 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fc1d678 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.DS_Store +.swc-cache/ +*.log +.idea/ +.vscode/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..98d4447 --- /dev/null +++ b/README.md @@ -0,0 +1,85 @@ +# senmesh-zc(信创文件安全传输系统 · 合并仓库) + +光闸内外网文件摆渡系统,前后端合并仓库: + +| 目录 | 项目 | 说明 | 技术栈 | +|---|---|---|---| +| `backend/` | s-file(原 alita-bjy-uygur) | 服务端:文件传输/网盘/机构用户管理/MeshSafe 安全检测对接 | Java 8 + Spring Boot 2.4.2 + MyBatis-Plus + PG/DM8 | +| `frontend/` | senmesh-zc-legacy | Web 前端:我的文件/分享/内外网传输/管理端 | React 19 + Vite + TanStack Router/Query + shadcn/ui | + +> 两端保留原仓库完整提交历史(子目录导入),`git log --follow` 可追溯。 + +## 本地启动 + +```bash +# 后端(需 JDK8,本地联调配置见 backend/docker-test/application-local.yml) +cd backend && mvn spring-boot:run + +# 前端(dev 代理 /api -> localhost:8081) +cd frontend && bun install && bun dev +``` + +--- + +## 文件安全检测(MeshSafe 对接配置) + +对接独立检测服务 MeshSafe(`code.senmesh.com/zhaolei/MeshSate`):文件**上传**与跨网传输**接收解包**后自动送检(HMAC-SHA256 签名 + 响应验签),结论回写 `x_file_security` 表并标记在文件上。 + +**核心行为**: + +- 检测不通过的文件**禁止分享与跨网传输**(下载/预览不受限);文件夹内部分文件不通过时,分享/传输弹窗列出清单,用户确认后**仅传输通过的内容**(`onlyPassed=true`) +- 检测中 → 禁止分享/传输;检测失败 → 默认放行(仅标记,可重新检测) +- 管理员可**人工复核**改判(必填说明,留痕并回写 MeshSafe)、**重新检测** +- 列表"安全检测"列展示状态徽章 + 结论摘要,悬停浮窗显示全信息;检测中的文件列表每 2 秒自动轮询刷新 + +### 1. 后端配置(`backend` 的 application.yml) + +```yaml +meshsafe: + enabled: true # 总开关:false 时整体关闭——不送检/不拦截/预检返回空/前端隐藏检测列 + base-url: https://meshsafe.internal # MeshSafe 服务地址 + client-id: s-file # MeshSafe 分配的调用方标识 + secret: "***" # MeshSafe 分配的密钥(勿泄露,建议环境变量注入) + channel: default # 业务通道标识(仅用于 MeshSafe 日志追溯) + timeout-seconds: 120 # 单次请求超时 + fail-open: true # 检测服务异常时降级:true-放行(仅标记检测失败) / false-同样禁止分享传输 + poll-timeout-minutes: 60 # "检测中"超过该时长仍无结论则标记检测失败(防死轮询) + review-sync-to-meshsafe: true # 人工复核是否回写 MeshSafe(失败仅告警,不影响本地生效) + poll: + cron: "0 */30 * * * ?" # 轮询未完成检测任务的定时任务(默认30秒) +``` + +| 配置项 | 说明 | +|---|---| +| `enabled` | **总开关**。关闭场景(无需 MeshSafe 的部署):后端上传/解包不送检、分享传输不拦截、`/file_security/share_check` 预检返回空、复核与重新检测接口报"文件安全检测未开启" | +| `fail-open` | 安全优先的部署建议 `false`(检测服务异常时宁可阻断);可用性优先用 `true` | +| 其余 | 一般保持默认即可 | + +### 2. 数据库 + +执行 `backend/db/upgrade-20261101-meshsafe-file-security.sql`(新增 `x_file_security` 检测记录表,MySQL/DM8 与 PostgreSQL 双节;全新环境直接执行 init 脚本已包含)。同一文件允许多条检测记录(复核/重检均新增),业务取最新一条。 + +### 3. MeshSafe 侧配置 + +- 向管理员申请调用方凭证,并将 `client_id:secret` 加入 MeshSafe 的 `MESHSAFE_API_CLIENTS` 环境变量白名单; +- MeshSafe 策略 `config/policy.yaml` 的 `engine_failure_mode` 生产必须为 `fail_closed`(引擎异常宁可拒绝),注意不要为了"服务没起来也能用"改成 `fail_open` 后带上生产; +- 建议监控 `GET /api/v1/health`(重点 `clamav.available` 与签名库更新时间)。 + +### 4. 前端(无需配置) + +前端通过 `GET /file_security/enabled` 自动感知总开关:开启时展示"安全检测"列与复核/重新检测入口,关闭时相关 UI 完全隐藏,无需前端发版。 + +### 5. 部署检查清单 + +1. 执行数据库升级脚本(`x_file_security`); +2. 后端配置 `meshsafe:` 段并确认 `enabled: true`; +3. MeshSafe 侧将后端凭证加入白名单,确认 `/api/v1/health` 健康; +4. 重启后端,上传一个测试文件验证:列表出现"检测中"→ 数秒内变为"检测通过/不通过"; +5. 用测试样本验证拦截链路(分享/传输被拒、文件夹确认跳过、复核改判后放行)。 + +### 6. 相关文档与代码 + +- 接口文档:`backend/docs/接口文档-文件安全检测.md` +- 客户端实现:`backend/src/main/java/com/senmesh/sfile/client/MeshSafeClient.java`(HKDF 密钥派生、请求签名、multipart 手工构造、响应验签) +- 检测记录表:`x_file_security`(实体 `FileSecurity`,取最新一条生效) +- 送检触发点:网盘上传(`NormalUserFileServiceImpl`)、传输接收解包(`TransferFileMonitorServiceImpl`)、手动重检(`/file_security/rescan`) diff --git a/backend/.gitignore b/backend/.gitignore new file mode 100644 index 0000000..ede0056 --- /dev/null +++ b/backend/.gitignore @@ -0,0 +1,34 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/.DS_Store +.commandcode/ diff --git a/backend/AGENTS.md b/backend/AGENTS.md new file mode 100644 index 0000000..979ac72 --- /dev/null +++ b/backend/AGENTS.md @@ -0,0 +1,74 @@ +# AGENTS.md — s-file(alita-bjy-uygur)编码代理指南 + +信创文件传输/网盘后端服务:内网与外网之间做文件安全传输("内穿外/外传内"),附带个人网盘、分享、机构与用户管理、通知等能力。单 Maven 模块,Spring Boot 可执行 jar,Docker 部署(`src/main/resources/Dockerfile`)。 + +## 技术栈(务必匹配,勿升级) + +- **Java 8** + Spring Boot **2.4.2**(父 POM 管理) +- ORM:**MyBatis-Plus 3.4.0**(注解/BaseMapper)+ 自研 `com.senmesh.tkmybatis` 封装 + PageHelper 1.4.6 + 自定义分页拦截器 +- 数据库:**达梦 DM8**(信创主力,另有 MySQL/PG 驱动),Druid 连接池,SQL 需多库兼容 +- 安全:Spring Security + 自研 JWT(`com.senmesh.security`),Redisson 分布式锁,RabbitMQ +- 文档:springfox swagger2 2.7.0;Lombok + MapStruct 1.2.0 + +## 常用命令 + +```bash +# 编译(需 JDK 8,例如本机 Zulu 1.8) +export JAVA_HOME=/Users/leijiaping/Library/Java/JavaVirtualMachines/azul-1.8.0_452/Contents/Home +mvn compile -DskipTests + +# 测试目录基本为空(仅 PwdTest),项目无自动化测试,验证靠编译 + 自查 +``` + +**已知依赖问题(重要)**:商业依赖 `e-iceblue:spire.pdf:3.7.4` 在阿里云/e-iceblue 官方仓库均不存在(官方仓库只有 9.x+)。本地仓库 `~/.m2/repository/e-iceblue/spire.pdf/3.7.4/` 现已安装一个**手工编译级 stub jar**(仅为 `PdfUtils.java` 引用的类签名生成),使 `mvn package` 可以通过;**代价是运行 PDF 盖章功能(`PdfUtils.pdfStampPerPage`)会失败**。正式发布前需从公司私服获取真实 jar 覆盖。全量快速编译验证可跳过 PdfUtils.java(详见下方命令)。 + +```bash +mvn dependency:build-classpath -Dmdep.outputFile=/tmp/cp.txt # 需联网 +$JAVA_HOME/bin/javac -encoding UTF-8 -cp "$(cat /tmp/cp.txt)" \ + -sourcepath src/main/java -d /tmp/v \ + $(find src/main/java -name "*.java" ! -name "PdfUtils.java") +``` + +## 包结构地图(`com.senmesh`) + +| 包 | 职责 | +|---|---| +| `usercenter` | 用户中心:`user`(用户/机构用户/注销)、`org`、`authority`(角色/权限)、`notice`(通知)、`auth` 等,子模块按「controller/service/impl/dto/entity/dao/mapper(XML)/constant/enums」分目录 | +| `sfile` | 文件业务:`UserFile`(上传/传输/分享记录,核心表 `x_user_file`)、`TransferUserFile`、`ShareUserFile`、`TransferFileMonitorJob`(定时扫描传输目录) | +| `component/file` | 物理文件上传组件(`xs_file_record`、`/file/upload`、`FileProperties`) | +| `common` | `AlitaResult`、`PageQueryDTO`、`BaseEntity`、`UserContextHolder`、异常体系 | +| `security` | JWT 过滤器、登录、`UserInfoDTO` | +| `frame/redis` | Redisson 封装:`RedissonUtils`、`@AutoUnLock`、`LockDTO` | +| `mybatis` / `mybatisplus` / `tkmybatis` | 分页拦截器、`@MapperScan`、`MyMapper` 基类 | +| `mq`、`codesetting`、`config` 等 | 其他支撑模块 | + +**注意**:源码树里有同包覆写的框架类(`org/springframework/...`、`com/senmesh/swagger`),改动前先确认是否为刻意覆写,不要删除。 + +## 新增一个接口的标准动作 + +1. **DTO**:查询 DTO 继承 `PageQueryDTO`(自带 pageNo/pageSize/needPage/pageResult);出参 DTO 继承 `BaseDTO`(用 `@SuperBuilder`);时间字段统一 `Date` + `@DateTimeFormat` + `@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone="GMT+8")`。 +2. **Entity**:继承 `BaseEntity`(带机构的继承 `OrgBaseEntity`),`@TableName` 注解,逻辑删除字段 `deleted`。 +3. **Mapper**:接口继承 `MyMapper`(已有 `saveEntity`/`updateEntitySelective`/`getById`/`deleteEntity`,自动填充 createBy/updateBy),放 `**/dao/`;**自定义 SQL 的 XML 放同名 java 源码目录的 `mapper/` 下**(pom 已配置打包 java 目录下 `**/*.xml`),XML 中参数一律 `@Param("param")` + `param.xxx` 引用。 +4. **Service**:接口 + `impl`。权限校验用命令式断言(项目无 @PreAuthorize): + - 平台超管:`Assert.isTrue(UserContextHolder.isSuperior(), "当前用户无操作权限")`,注意字段拼写就是 `supeiror`(历史笔误,勿"修复") + - 机构管理员:`UserContextHolder.isAdministrator()`;平台机构:`checkPlatformOrg()` +5. **Controller**:返回一律 `AlitaResult`(`AlitaResult.success(data)`);`@Api(tags=...)` + `@ApiOperation`;分页接口返回 `AlitaResult>`,模式:Service 把 queryDTO 传给 mapper 即自动分页,Controller 返回 `queryDTO.getPageResult()`。查询类用 GET + query 参数绑定,操作类用 POST + `@Validated @RequestBody`。 +6. **URL 前缀有语义**:`anon/**` 匿名(清单在配置 `security.anonymous`)、`unac/**` 已登录未激活可用、`authed/**` 已实名;普通前缀 = 登录即可。 + +## 关键业务概念 + +- **用户**(`uc_user`):`status` 1待激活/2已激活/3已注销 + `enabled` 启用开关 + 逻辑删除 `deleted`,三者独立。登录侧实时校验 `enabled=TRUE and status!=3`,禁用/注销后用户下次请求即失效。注销有两套:自助申请流(`UserCancelService`,`uc_user_cancel` 表)与管理员直接注销(`user/admin_cancel`)。同一手机号可对应多个账号(企业+个人)。 +- **机构**:`xs_org`(`parent_id` 树)+ `uc_org_user` 中间表(含 `administrator` 标志,一个用户可在多个机构,登录时选定 orgId)。**用户表没有 org_id**。平台机构固定 `orgId=1`(`CommonConstants.PLATFORM_ORG_ID`)。 +- **文件记录**(`x_user_file`):上传/发送/接收/分享全在这一张表,靠 `root_type` 区分:`1`普通(上传)、`2`内穿外、`3`外传内、`4`我的分享;`file_status`:1正常/2失效/11解析中/12待审核/13传输中/14失败。表里只有 `user_id`,无手机号,按手机号查需 JOIN `uc_user.phone`。 +- **传输方向映射**(`file.transfer.location`:1内网/2外网):发送记录 = 内网端 rootType 2 / 外网端 rootType 3;接收记录取反。手机号只在传输 ZIP 包内 `transferMetadata.json`,接收端解包时靠它反查本地用户。 + +## 陷阱清单 + +- 只能写 **Java 8** 语法(无 `var`/`Set.of`/record/switch 表达式;集合用 guava `Sets.newHashSet` 等也行)。 +- SQL 要兼容 DM8:布尔字面量用 `TRUE/FALSE`(bit 列),时间用 `now()`;避免 MySQL 专属函数;分页依赖拦截器,XML 里不要手写 limit。 +- XML 放错位置不会被打包——必须放 java 源码目录(与现有 `UserMapper.xml`、`UserFileMapper.xml` 同级模式)。 +- 驼峰映射由 MyBatis-Plus 默认开启,XML 直接 `SELECT u.real_name` 即可映射 `realName`;列别名规避同名冲突(如 `u.type AS user_type`)。 +- 注销/禁用等敏感操作要防并发:参考 `userCancel` 的 `RedissonUtils.tryLockAutomatically(LockDTO...)` + `@AutoUnLock` 模式;禁止注销/禁用自己与超管。 +- 数据库初始化脚本在 `db/`(`init-table.sql` MySQL 版、`init-table-postgres-full.sql` PG 版),改表结构需同步两个版本;增量变更另建 `db/upgrade-YYYYMMDD-*.sql`(现有:`upgrade-20260914-upload-config.sql`),历史上有过 DDL 只加脚本、不改 init 的情况,新环境安装依赖 init 脚本,**改表务必 init 与 upgrade 双写**。 +- 给前端的接口变更请同步维护 `docs/` 下的接口文档(现有:`接口文档-用户管理与记录查询.md`、`接口文档-机构上传配置.md`)。 +- `.commandcode/` 为本地工具产物,勿提交。 diff --git a/backend/README.md b/backend/README.md new file mode 100644 index 0000000..45d053e --- /dev/null +++ b/backend/README.md @@ -0,0 +1,2 @@ +# demo + diff --git a/backend/db/init-data.sql b/backend/db/init-data.sql new file mode 100644 index 0000000..7e998c4 --- /dev/null +++ b/backend/db/init-data.sql @@ -0,0 +1,46 @@ +-- 系统uc_platform +INSERT INTO uc_platform +(platform_code, name, full_name, short_name, business, deleted, create_time) +VALUES(1, '文档系统', 's-file', 'file', true, FALSE, now()); + +-- 平台机构/平台机构管理员 +INSERT INTO xs_org +(org_name, org_code, type, address_code, address_name, description, quality, enable, activated, parent_id, credit_code, trade, deleted, create_by, create_time, update_by, update_time, proxy_by, activation_code, phone, query_children, org_logo, registered_address, company_size, business_license, recruit_position_type) +VALUES('senmesh', 'O001', '1', '440232', NULL, NULL, false, TRUE, TRUE, NULL, '', NULL, FALSE, 0, now(), 1, now(), null, NULL, null, NULL, null, '1234', '6', null, '1'); + +INSERT INTO uc_user +(username, password, type, supeiror, security_code, nickname, avatar, phone, phone_binding, real_name, card_no, authenticated, status, email, address, education, init_user_id, enabled, account_non_expired, account_non_locked, credentials_non_expired, deleted, create_by, create_time, update_by, update_time, proxy_by, gender, birthday) +VALUES('admin', '$2a$10$0N3iaxx2sYv0hXvYzS4.6.yriL.DfjRTjED7Y4vkqxzbxi2dNpBou', 1, TRUE, '$2a$10$mGA1jdBzq8micEr02KiJ9OiYQz1fc/PSVG0hN0EYUuxhZp8EI1M2q', '平台管理员', '', '13888888888', TRUE, '平台管理员', NULL, FALSE, 2, null, NULL, NULL, NULL, TRUE, TRUE, TRUE, TRUE, FALSE, 0, now(), 1, NULL, NULL, NULL, NULL); +INSERT INTO uc_org_user +(user_id, org_id, administrator, deleted, create_by, create_time, update_by, update_time, proxy_by) +VALUES(1, 1, TRUE, FALSE, 0, now(), NULL, NULL, NULL); +-- 平台uc_org_relation +INSERT INTO uc_org_relation +(org_id, org_type, parent_id, path, platform_code, platform_name, deleted, create_by, create_time, update_by, update_time, proxy_by) +VALUES(1, 1, 0, '1', 1, NULL, FALSE, NULL, NULL, NULL, NULL, NULL); + +-- ---------------------------- +-- Records of x_file_category +-- ---------------------------- +INSERT INTO x_file_category (file_category, file_suffix, deleted, create_by, create_time) VALUES +('video', 'mp4', FALSE, 0, NOW()), +('video', 'mkv', FALSE, 0, NOW()), +('video', 'avi', FALSE, 0, NOW()), +('video', 'mov', FALSE, 0, NOW()), +('video', 'wmv', FALSE, 0, NOW()), +('video', 'flv', FALSE, 0, NOW()), +('audio', 'mp3', FALSE, 0, NOW()), +('audio', 'wav', FALSE, 0, NOW()), +('audio', 'flac', FALSE, 0, NOW()), +('audio', 'aac', FALSE, 0, NOW()), +('document', 'txt', FALSE, 0, NOW()), +('document', 'docx', FALSE, 0, NOW()), +('document', 'pdf', FALSE, 0, NOW()), +('document', 'epub', FALSE, 0, NOW()), +('other', 'zip', FALSE, 0, NOW()), +('other', 'rar', FALSE, 0, NOW()), +('other', '7z', FALSE, 0, NOW()), +('other', 'jpg', FALSE, 0, NOW()), +('other', 'png', FALSE, 0, NOW()), +('other', 'gif', FALSE, 0, NOW()), +('other', 'tiff', FALSE, 0, NOW()); diff --git a/backend/db/init-table-postgres-full.sql b/backend/db/init-table-postgres-full.sql new file mode 100644 index 0000000..c595562 --- /dev/null +++ b/backend/db/init-table-postgres-full.sql @@ -0,0 +1,2082 @@ +-- PostgreSQL Database Initialization Script +-- Converted from MySQL with Column Comments + +-- ---------------------------- +-- Table structure for async_task_notice +-- ---------------------------- +DROP TABLE IF EXISTS async_task_notice; +CREATE TABLE async_task_notice ( + id BIGSERIAL PRIMARY KEY, + union_type VARCHAR(32) NOT NULL, + union_id BIGINT NOT NULL, + content VARCHAR(255) NOT NULL, + biz_status_str VARCHAR(32) DEFAULT NULL, + biz_param_data VARCHAR(512) DEFAULT NULL, + flow_status SMALLINT DEFAULT 1, + notice_status SMALLINT DEFAULT 1, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +CREATE INDEX idx_create_by ON async_task_notice(create_by); +CREATE INDEX idx_union ON async_task_notice(union_type,union_id); +COMMENT ON TABLE async_task_notice IS '异步任务通知'; +COMMENT ON COLUMN async_task_notice.id IS '主键'; +COMMENT ON COLUMN async_task_notice.union_type IS '关联类型:common_import等'; +COMMENT ON COLUMN async_task_notice.union_id IS '关联id'; +COMMENT ON COLUMN async_task_notice.content IS '内容'; +COMMENT ON COLUMN async_task_notice.biz_status_str IS '业务状态'; +COMMENT ON COLUMN async_task_notice.biz_param_data IS '业务参数'; +COMMENT ON COLUMN async_task_notice.flow_status IS '流程状态:1开启,2结束'; +COMMENT ON COLUMN async_task_notice.notice_status IS '通知状态:1未读,2已读'; +COMMENT ON COLUMN async_task_notice.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN async_task_notice.create_by IS '创建人'; +COMMENT ON COLUMN async_task_notice.create_time IS '创建时间'; +COMMENT ON COLUMN async_task_notice.update_by IS '更新人'; +COMMENT ON COLUMN async_task_notice.update_time IS '更新时间'; +COMMENT ON COLUMN async_task_notice.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for notice_content_template +-- ---------------------------- +DROP TABLE IF EXISTS notice_content_template; +CREATE TABLE notice_content_template ( + id BIGSERIAL PRIMARY KEY, + template_id BIGINT DEFAULT NULL, + channel_type SMALLINT DEFAULT NULL, + title VARCHAR(64) DEFAULT NULL, + content_template TEXT, + enabled BOOLEAN DEFAULT TRUE, + link VARCHAR(128) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE notice_content_template IS '通知消息体模版'; +COMMENT ON COLUMN notice_content_template.id IS '主键'; +COMMENT ON COLUMN notice_content_template.template_id IS '通知模版id'; +COMMENT ON COLUMN notice_content_template.channel_type IS '消息通道类型:1站内信,2短信,3钉钉,4企业微信,5邮件(见notice_channel_type)'; +COMMENT ON COLUMN notice_content_template.title IS '标题'; +COMMENT ON COLUMN notice_content_template.content_template IS '内容模版'; +COMMENT ON COLUMN notice_content_template.enabled IS '是否启用'; +COMMENT ON COLUMN notice_content_template.link IS '链接'; +COMMENT ON COLUMN notice_content_template.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN notice_content_template.create_by IS '创建人'; +COMMENT ON COLUMN notice_content_template.create_time IS '创建时间'; +COMMENT ON COLUMN notice_content_template.update_by IS '更新人'; +COMMENT ON COLUMN notice_content_template.update_time IS '更新时间'; +COMMENT ON COLUMN notice_content_template.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for notice_receiver_setting +-- ---------------------------- +DROP TABLE IF EXISTS notice_receiver_setting; +CREATE TABLE notice_receiver_setting ( + id BIGSERIAL PRIMARY KEY, + template_id BIGINT DEFAULT NULL, + org_id BIGINT DEFAULT NULL, + receiver_union_type SMALLINT DEFAULT NULL, + receiver_union_id BIGINT DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE notice_receiver_setting IS '通知接收人设置'; +COMMENT ON COLUMN notice_receiver_setting.id IS '主键'; +COMMENT ON COLUMN notice_receiver_setting.template_id IS '通知模版id'; +COMMENT ON COLUMN notice_receiver_setting.org_id IS '机构id'; +COMMENT ON COLUMN notice_receiver_setting.receiver_union_type IS '接收人关联类型:1用户id,2角色,3标准角色(见notice_receiver_type)'; +COMMENT ON COLUMN notice_receiver_setting.receiver_union_id IS '接收人关联id:用户id,角色id,标准角色id'; +COMMENT ON COLUMN notice_receiver_setting.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN notice_receiver_setting.create_by IS '创建人'; +COMMENT ON COLUMN notice_receiver_setting.create_time IS '创建时间'; +COMMENT ON COLUMN notice_receiver_setting.update_by IS '更新人'; +COMMENT ON COLUMN notice_receiver_setting.update_time IS '更新时间'; +COMMENT ON COLUMN notice_receiver_setting.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for notice_send_record +-- ---------------------------- +DROP TABLE IF EXISTS notice_send_record; +CREATE TABLE notice_send_record ( + id BIGSERIAL PRIMARY KEY, + template_id BIGINT DEFAULT NULL, + sender_org_id BIGINT DEFAULT NULL, + receiver_org_id BIGINT DEFAULT NULL, + content_template_id BIGINT DEFAULT NULL, + content_param_data VARCHAR(512) DEFAULT NULL, + content TEXT, + appointed BOOLEAN DEFAULT NULL, + link VARCHAR(128) DEFAULT NULL, + content_template TEXT, + title VARCHAR(64) DEFAULT NULL, + channel_type SMALLINT DEFAULT NULL, + status SMALLINT DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE notice_send_record IS '通知发送记录(内容模版级)'; +COMMENT ON COLUMN notice_send_record.id IS '主键'; +COMMENT ON COLUMN notice_send_record.template_id IS '通知模版id'; +COMMENT ON COLUMN notice_send_record.sender_org_id IS '发送方机构id'; +COMMENT ON COLUMN notice_send_record.receiver_org_id IS '接收方机构id'; +COMMENT ON COLUMN notice_send_record.content_template_id IS '消息体模版id'; +COMMENT ON COLUMN notice_send_record.content_param_data IS '消息体参数'; +COMMENT ON COLUMN notice_send_record.content IS '消息体'; +COMMENT ON COLUMN notice_send_record.appointed IS '是否指定接收方(非预先设定)'; +COMMENT ON COLUMN notice_send_record.link IS '链接'; +COMMENT ON COLUMN notice_send_record.content_template IS '内容模版'; +COMMENT ON COLUMN notice_send_record.title IS '标题'; +COMMENT ON COLUMN notice_send_record.channel_type IS '消息通道类型:1站内信,2短信,3钉钉,4企业微信,5邮件(见notice_channel_type)'; +COMMENT ON COLUMN notice_send_record.status IS '状态:1待处理,2已处理 等(见notice_send_status)'; +COMMENT ON COLUMN notice_send_record.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN notice_send_record.create_by IS '创建人'; +COMMENT ON COLUMN notice_send_record.create_time IS '创建时间'; +COMMENT ON COLUMN notice_send_record.update_by IS '更新人'; +COMMENT ON COLUMN notice_send_record.update_time IS '更新时间'; +COMMENT ON COLUMN notice_send_record.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for notice_send_record_detail +-- ---------------------------- +DROP TABLE IF EXISTS notice_send_record_detail; +CREATE TABLE notice_send_record_detail ( + id BIGSERIAL PRIMARY KEY, + record_id BIGINT DEFAULT NULL, + user_id BIGINT DEFAULT NULL, + receiver_account_no VARCHAR(32) DEFAULT NULL, + receiver_status SMALLINT DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE notice_send_record_detail IS '通知发送记录明细(接收人)'; +COMMENT ON COLUMN notice_send_record_detail.id IS '主键'; +COMMENT ON COLUMN notice_send_record_detail.record_id IS '发送记录id'; +COMMENT ON COLUMN notice_send_record_detail.user_id IS '接收人id'; +COMMENT ON COLUMN notice_send_record_detail.receiver_account_no IS '接收方帐号'; +COMMENT ON COLUMN notice_send_record_detail.receiver_status IS '接收状态:1待发送,2已发送,3发送失败,4接收已读(见notice_receiver_status)'; +COMMENT ON COLUMN notice_send_record_detail.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN notice_send_record_detail.create_by IS '创建人'; +COMMENT ON COLUMN notice_send_record_detail.create_time IS '创建时间'; +COMMENT ON COLUMN notice_send_record_detail.update_by IS '更新人'; +COMMENT ON COLUMN notice_send_record_detail.update_time IS '更新时间'; +COMMENT ON COLUMN notice_send_record_detail.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for notice_template +-- ---------------------------- +DROP TABLE IF EXISTS notice_template; +CREATE TABLE notice_template ( + id BIGSERIAL PRIMARY KEY, + template_code VARCHAR(32) DEFAULT NULL, + template_name VARCHAR(64) DEFAULT NULL, + module_type SMALLINT DEFAULT NULL, + biz_type SMALLINT DEFAULT NULL, + level SMALLINT DEFAULT NULL, + enabled BOOLEAN DEFAULT TRUE, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE notice_template IS '通知模版'; +COMMENT ON COLUMN notice_template.id IS '主键'; +COMMENT ON COLUMN notice_template.template_code IS '通知模版code'; +COMMENT ON COLUMN notice_template.template_name IS '通知模版名称'; +COMMENT ON COLUMN notice_template.module_type IS '模块分类:1业务,2监控/预警(见notice_module_type)'; +COMMENT ON COLUMN notice_template.biz_type IS '业务分类:'; +COMMENT ON COLUMN notice_template.level IS '级别:1平台,2机构(见notice_level)'; +COMMENT ON COLUMN notice_template.enabled IS '是否启用'; +COMMENT ON COLUMN notice_template.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN notice_template.create_by IS '创建人'; +COMMENT ON COLUMN notice_template.create_time IS '创建时间'; +COMMENT ON COLUMN notice_template.update_by IS '更新人'; +COMMENT ON COLUMN notice_template.update_time IS '更新时间'; +COMMENT ON COLUMN notice_template.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_action +-- ---------------------------- +DROP TABLE IF EXISTS uc_action; +CREATE TABLE uc_action ( + id BIGSERIAL PRIMARY KEY, + union_type VARCHAR(32) DEFAULT NULL, + union_id BIGINT DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE uc_action IS '操作记录'; +COMMENT ON COLUMN uc_action.id IS '主键'; +COMMENT ON COLUMN uc_action.union_type IS '关联类型'; +COMMENT ON COLUMN uc_action.union_id IS '关联id'; +COMMENT ON COLUMN uc_action.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_action.create_by IS '创建人'; +COMMENT ON COLUMN uc_action.create_time IS '创建时间'; +COMMENT ON COLUMN uc_action.update_by IS '更新人'; +COMMENT ON COLUMN uc_action.update_time IS '更新时间'; +COMMENT ON COLUMN uc_action.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_action_detail +-- ---------------------------- +DROP TABLE IF EXISTS uc_action_detail; +CREATE TABLE uc_action_detail ( + id BIGSERIAL PRIMARY KEY, + action_id BIGINT DEFAULT NULL, + field VARCHAR(32) DEFAULT NULL, + field_alias VARCHAR(32) DEFAULT NULL, + field_dict_code VARCHAR(32) DEFAULT NULL, + old_value VARCHAR(255) DEFAULT NULL, + new_value VARCHAR(255) DEFAULT NULL, + diff TEXT, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE uc_action_detail IS '操作记录明细'; +COMMENT ON COLUMN uc_action_detail.id IS '主键'; +COMMENT ON COLUMN uc_action_detail.action_id IS '操作记录id'; +COMMENT ON COLUMN uc_action_detail.field IS '属性'; +COMMENT ON COLUMN uc_action_detail.field_alias IS '属性别名'; +COMMENT ON COLUMN uc_action_detail.field_dict_code IS '属性字典'; +COMMENT ON COLUMN uc_action_detail.old_value IS '旧值'; +COMMENT ON COLUMN uc_action_detail.new_value IS '新值'; +COMMENT ON COLUMN uc_action_detail.diff IS '差异'; +COMMENT ON COLUMN uc_action_detail.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_action_detail.create_by IS '创建人'; +COMMENT ON COLUMN uc_action_detail.create_time IS '创建时间'; +COMMENT ON COLUMN uc_action_detail.update_by IS '更新人'; +COMMENT ON COLUMN uc_action_detail.update_time IS '更新时间'; +COMMENT ON COLUMN uc_action_detail.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_auth_client +-- ---------------------------- +DROP TABLE IF EXISTS uc_auth_client; +CREATE TABLE uc_auth_client ( + id BIGSERIAL PRIMARY KEY, + auth_type_code SMALLINT DEFAULT NULL, + client_name VARCHAR(32) DEFAULT NULL, + param_data VARCHAR(256) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE uc_auth_client IS '授权客户端'; +COMMENT ON COLUMN uc_auth_client.id IS '主键'; +COMMENT ON COLUMN uc_auth_client.auth_type_code IS '授权类型标识'; +COMMENT ON COLUMN uc_auth_client.client_name IS '授权应用名称'; +COMMENT ON COLUMN uc_auth_client.param_data IS '配置数据'; +COMMENT ON COLUMN uc_auth_client.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_auth_client.create_by IS '创建人'; +COMMENT ON COLUMN uc_auth_client.create_time IS '创建时间'; +COMMENT ON COLUMN uc_auth_client.update_by IS '更新人'; +COMMENT ON COLUMN uc_auth_client.update_time IS '更新时间'; +COMMENT ON COLUMN uc_auth_client.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_auth_detail +-- ---------------------------- +DROP TABLE IF EXISTS uc_auth_detail; +CREATE TABLE uc_auth_detail ( + id BIGSERIAL PRIMARY KEY, + auth_client_id BIGINT DEFAULT NULL, + auth_type_code SMALLINT DEFAULT NULL, + nickname VARCHAR(32) DEFAULT NULL, + avatar VARCHAR(256) DEFAULT NULL, + gender VARCHAR(2) DEFAULT NULL, + country VARCHAR(32) DEFAULT NULL, + province VARCHAR(32) DEFAULT NULL, + city VARCHAR(32) DEFAULT NULL, + open_id VARCHAR(32) DEFAULT NULL, + unique_id VARCHAR(32) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE uc_auth_detail IS '授权明细表'; +COMMENT ON COLUMN uc_auth_detail.id IS '主键'; +COMMENT ON COLUMN uc_auth_detail.auth_client_id IS '授权客户端id'; +COMMENT ON COLUMN uc_auth_detail.auth_type_code IS '授权类型标识'; +COMMENT ON COLUMN uc_auth_detail.nickname IS '昵称'; +COMMENT ON COLUMN uc_auth_detail.avatar IS '头像'; +COMMENT ON COLUMN uc_auth_detail.gender IS '性别'; +COMMENT ON COLUMN uc_auth_detail.country IS '国家'; +COMMENT ON COLUMN uc_auth_detail.province IS '省份'; +COMMENT ON COLUMN uc_auth_detail.city IS '城市'; +COMMENT ON COLUMN uc_auth_detail.open_id IS 'open_id'; +COMMENT ON COLUMN uc_auth_detail.unique_id IS '授权唯一id'; +COMMENT ON COLUMN uc_auth_detail.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_auth_detail.create_by IS '创建人'; +COMMENT ON COLUMN uc_auth_detail.create_time IS '创建时间'; +COMMENT ON COLUMN uc_auth_detail.update_by IS '更新人'; +COMMENT ON COLUMN uc_auth_detail.update_time IS '更新时间'; +COMMENT ON COLUMN uc_auth_detail.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_auth_detail_entrypoint +-- ---------------------------- +DROP TABLE IF EXISTS uc_auth_detail_entrypoint; +CREATE TABLE uc_auth_detail_entrypoint ( + id BIGSERIAL PRIMARY KEY, + auth_detail_id BIGINT DEFAULT NULL, + union_id BIGINT DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +CREATE INDEX idx_union_id ON uc_auth_detail_entrypoint(union_id); +COMMENT ON TABLE uc_auth_detail_entrypoint IS '授权明细入口'; +COMMENT ON COLUMN uc_auth_detail_entrypoint.id IS '主键'; +COMMENT ON COLUMN uc_auth_detail_entrypoint.auth_detail_id IS '授权客户端id'; +COMMENT ON COLUMN uc_auth_detail_entrypoint.union_id IS '关联id(小程序码id)'; +COMMENT ON COLUMN uc_auth_detail_entrypoint.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_auth_detail_entrypoint.create_by IS '创建人'; +COMMENT ON COLUMN uc_auth_detail_entrypoint.create_time IS '创建时间'; +COMMENT ON COLUMN uc_auth_detail_entrypoint.update_by IS '更新人'; +COMMENT ON COLUMN uc_auth_detail_entrypoint.update_time IS '更新时间'; +COMMENT ON COLUMN uc_auth_detail_entrypoint.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_auth_subscribe_detail +-- ---------------------------- +DROP TABLE IF EXISTS uc_auth_subscribe_detail; +CREATE TABLE uc_auth_subscribe_detail ( + id BIGSERIAL PRIMARY KEY, + auth_client_id BIGINT DEFAULT NULL, + open_id VARCHAR(32) DEFAULT NULL, + unique_id VARCHAR(32) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE uc_auth_subscribe_detail IS '授权订阅明细表'; +COMMENT ON COLUMN uc_auth_subscribe_detail.id IS '主键'; +COMMENT ON COLUMN uc_auth_subscribe_detail.auth_client_id IS '授权客户端id'; +COMMENT ON COLUMN uc_auth_subscribe_detail.open_id IS 'open_id'; +COMMENT ON COLUMN uc_auth_subscribe_detail.unique_id IS '授权唯一id'; +COMMENT ON COLUMN uc_auth_subscribe_detail.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_auth_subscribe_detail.create_by IS '创建人'; +COMMENT ON COLUMN uc_auth_subscribe_detail.create_time IS '创建时间'; +COMMENT ON COLUMN uc_auth_subscribe_detail.update_by IS '更新人'; +COMMENT ON COLUMN uc_auth_subscribe_detail.update_time IS '更新时间'; +COMMENT ON COLUMN uc_auth_subscribe_detail.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_auth_type +-- ---------------------------- +DROP TABLE IF EXISTS uc_auth_type; +CREATE TABLE uc_auth_type ( + id BIGSERIAL PRIMARY KEY, + auth_main_type SMALLINT DEFAULT NULL, + auth_type_code SMALLINT DEFAULT NULL, + name VARCHAR(32) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE uc_auth_type IS '授权类型'; +COMMENT ON COLUMN uc_auth_type.id IS '主键'; +COMMENT ON COLUMN uc_auth_type.auth_main_type IS '授权大类:1微信,2支付宝'; +COMMENT ON COLUMN uc_auth_type.auth_type_code IS '授权类型标识'; +COMMENT ON COLUMN uc_auth_type.name IS '名称'; +COMMENT ON COLUMN uc_auth_type.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_auth_type.create_by IS '创建人'; +COMMENT ON COLUMN uc_auth_type.create_time IS '创建时间'; +COMMENT ON COLUMN uc_auth_type.update_by IS '更新人'; +COMMENT ON COLUMN uc_auth_type.update_time IS '更新时间'; +COMMENT ON COLUMN uc_auth_type.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_domain +-- ---------------------------- +DROP TABLE IF EXISTS uc_domain; +CREATE TABLE uc_domain ( + id BIGSERIAL PRIMARY KEY, + platform_code SMALLINT DEFAULT NULL, + domain_name VARCHAR(32) DEFAULT NULL, + ip_port VARCHAR(32) DEFAULT NULL, + publiced BOOLEAN DEFAULT NULL, + org_id BIGINT DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE uc_domain IS '域名表'; +COMMENT ON COLUMN uc_domain.id IS '主键'; +COMMENT ON COLUMN uc_domain.platform_code IS '平台编码'; +COMMENT ON COLUMN uc_domain.domain_name IS '域名'; +COMMENT ON COLUMN uc_domain.ip_port IS 'ip:port'; +COMMENT ON COLUMN uc_domain.publiced IS '是否公共'; +COMMENT ON COLUMN uc_domain.org_id IS '机构id'; +COMMENT ON COLUMN uc_domain.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_domain.create_by IS '创建人'; +COMMENT ON COLUMN uc_domain.create_time IS '创建时间'; +COMMENT ON COLUMN uc_domain.update_by IS '更新人'; +COMMENT ON COLUMN uc_domain.update_time IS '更新时间'; +COMMENT ON COLUMN uc_domain.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_domain_auth +-- ---------------------------- +DROP TABLE IF EXISTS uc_domain_auth; +CREATE TABLE uc_domain_auth ( + id BIGSERIAL PRIMARY KEY, + domain_id BIGINT DEFAULT NULL, + auth_type_code SMALLINT DEFAULT NULL, + auth_client_id BIGINT DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE uc_domain_auth IS '域名授权表'; +COMMENT ON COLUMN uc_domain_auth.id IS '主键'; +COMMENT ON COLUMN uc_domain_auth.domain_id IS '域名id'; +COMMENT ON COLUMN uc_domain_auth.auth_type_code IS '授权类型标识'; +COMMENT ON COLUMN uc_domain_auth.auth_client_id IS '授权客户端id'; +COMMENT ON COLUMN uc_domain_auth.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_domain_auth.create_by IS '创建人'; +COMMENT ON COLUMN uc_domain_auth.create_time IS '创建时间'; +COMMENT ON COLUMN uc_domain_auth.update_by IS '更新人'; +COMMENT ON COLUMN uc_domain_auth.update_time IS '更新时间'; +COMMENT ON COLUMN uc_domain_auth.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_domain_setting +-- ---------------------------- +DROP TABLE IF EXISTS uc_domain_setting; +CREATE TABLE uc_domain_setting ( + id BIGSERIAL PRIMARY KEY, + domain_id BIGINT DEFAULT NULL, + type SMALLINT DEFAULT NULL, + remark VARCHAR(32) DEFAULT '', + data TEXT, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE uc_domain_setting IS '域名配置表'; +COMMENT ON COLUMN uc_domain_setting.id IS '主键'; +COMMENT ON COLUMN uc_domain_setting.domain_id IS '域名id'; +COMMENT ON COLUMN uc_domain_setting.type IS '类型'; +COMMENT ON COLUMN uc_domain_setting.remark IS '配置备注'; +COMMENT ON COLUMN uc_domain_setting.data IS '配置数据'; +COMMENT ON COLUMN uc_domain_setting.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_domain_setting.create_by IS '创建人'; +COMMENT ON COLUMN uc_domain_setting.create_time IS '创建时间'; +COMMENT ON COLUMN uc_domain_setting.update_by IS '更新人'; +COMMENT ON COLUMN uc_domain_setting.update_time IS '更新时间'; +COMMENT ON COLUMN uc_domain_setting.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_dynamic_table +-- ---------------------------- +DROP TABLE IF EXISTS uc_dynamic_table; +CREATE TABLE uc_dynamic_table ( + id BIGSERIAL PRIMARY KEY, + table_type VARCHAR(32) DEFAULT NULL, + user_id BIGINT DEFAULT NULL, + column_data TEXT, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); + +-- ---------------------------- +-- Table structure for uc_faq +-- ---------------------------- +DROP TABLE IF EXISTS uc_faq; +CREATE TABLE uc_faq ( + id BIGSERIAL PRIMARY KEY, + faq_order INTEGER DEFAULT 0, + faq_type VARCHAR(2) DEFAULT NULL, + question VARCHAR(512) DEFAULT NULL, + answer TEXT, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE uc_faq IS '常见问题表'; +COMMENT ON COLUMN uc_faq.id IS '主键'; +COMMENT ON COLUMN uc_faq.faq_order IS '排序'; +COMMENT ON COLUMN uc_faq.faq_type IS '类型'; +COMMENT ON COLUMN uc_faq.question IS '问题'; +COMMENT ON COLUMN uc_faq.answer IS '回答'; +COMMENT ON COLUMN uc_faq.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_faq.create_by IS '创建人'; +COMMENT ON COLUMN uc_faq.create_time IS '创建时间'; +COMMENT ON COLUMN uc_faq.update_by IS '更新人'; +COMMENT ON COLUMN uc_faq.update_time IS '更新时间'; +COMMENT ON COLUMN uc_faq.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_faq_file +-- ---------------------------- +DROP TABLE IF EXISTS uc_faq_file; +CREATE TABLE uc_faq_file ( + id BIGSERIAL PRIMARY KEY, + question_id BIGINT DEFAULT NULL, + file_name VARCHAR(256) DEFAULT NULL, + file_code VARCHAR(32) DEFAULT NULL, + file_suffix VARCHAR(32) DEFAULT NULL, + sort BIGINT DEFAULT NULL, + description VARCHAR(256) DEFAULT NULL, + deleted BOOLEAN NOT NULL DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE uc_faq_file IS '常见问题附件关系表'; +COMMENT ON COLUMN uc_faq_file.id IS '主键'; +COMMENT ON COLUMN uc_faq_file.question_id IS '常见问题ID'; +COMMENT ON COLUMN uc_faq_file.file_name IS '文件名称'; +COMMENT ON COLUMN uc_faq_file.file_code IS '文件编码'; +COMMENT ON COLUMN uc_faq_file.file_suffix IS '文件后缀'; +COMMENT ON COLUMN uc_faq_file.sort IS '排序'; +COMMENT ON COLUMN uc_faq_file.description IS '文件描述'; +COMMENT ON COLUMN uc_faq_file.deleted IS '是否删除'; +COMMENT ON COLUMN uc_faq_file.create_by IS '创建人'; +COMMENT ON COLUMN uc_faq_file.create_time IS '创建时间'; +COMMENT ON COLUMN uc_faq_file.update_by IS '更新人'; +COMMENT ON COLUMN uc_faq_file.update_time IS '更新时间'; +COMMENT ON COLUMN uc_faq_file.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_feedback +-- ---------------------------- +DROP TABLE IF EXISTS uc_feedback; +CREATE TABLE uc_feedback ( + id BIGSERIAL PRIMARY KEY, + type VARCHAR(2) DEFAULT NULL, + user_id BIGINT DEFAULT NULL, + phone VARCHAR(32) DEFAULT NULL, + content VARCHAR(255) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL, + source_type VARCHAR(2) DEFAULT NULL +); +COMMENT ON TABLE uc_feedback IS '反馈表'; +COMMENT ON COLUMN uc_feedback.id IS '主键'; +COMMENT ON COLUMN uc_feedback.type IS '反馈类型'; +COMMENT ON COLUMN uc_feedback.user_id IS '用户id'; +COMMENT ON COLUMN uc_feedback.phone IS '手机号'; +COMMENT ON COLUMN uc_feedback.content IS '反馈内容'; +COMMENT ON COLUMN uc_feedback.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_feedback.create_by IS '创建人'; +COMMENT ON COLUMN uc_feedback.create_time IS '创建时间'; +COMMENT ON COLUMN uc_feedback.update_by IS '更新人'; +COMMENT ON COLUMN uc_feedback.update_time IS '更新时间'; +COMMENT ON COLUMN uc_feedback.proxy_by IS '代理人'; +COMMENT ON COLUMN uc_feedback.source_type IS '来源'; + +-- ---------------------------- +-- Table structure for uc_import_main +-- ---------------------------- +DROP TABLE IF EXISTS uc_import_main; +CREATE TABLE uc_import_main ( + id BIGSERIAL PRIMARY KEY, + import_no VARCHAR(64) DEFAULT NULL, + type VARCHAR(32) DEFAULT NULL, + import_status SMALLINT DEFAULT NULL, + total_num INTEGER DEFAULT NULL, + success_num INTEGER DEFAULT NULL, + fail_msg VARCHAR(255) DEFAULT NULL, + finish_time TIMESTAMP DEFAULT NULL, + execute_type SMALLINT DEFAULT NULL, + extra_id BIGINT DEFAULT NULL, + file_code VARCHAR(32) DEFAULT NULL, + file_name VARCHAR(128) DEFAULT NULL, + org_id BIGINT DEFAULT NULL, + remark VARCHAR(255) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +CREATE INDEX idx_import_no ON uc_import_main(import_no); +COMMENT ON TABLE uc_import_main IS '通用导入批次表'; +COMMENT ON COLUMN uc_import_main.id IS '主键ID'; +COMMENT ON COLUMN uc_import_main.import_no IS '批次号'; +COMMENT ON COLUMN uc_import_main.type IS '导入类型'; +COMMENT ON COLUMN uc_import_main.import_status IS '导入状态:1新建,2解析失败,3校验中,4校验失败,5校验成功,6执行导入'; +COMMENT ON COLUMN uc_import_main.total_num IS '总数'; +COMMENT ON COLUMN uc_import_main.success_num IS '成功数'; +COMMENT ON COLUMN uc_import_main.fail_msg IS '失败原因'; +COMMENT ON COLUMN uc_import_main.finish_time IS '完成时间时间'; +COMMENT ON COLUMN uc_import_main.execute_type IS '执行类型:1.普通,2.指定外部id'; +COMMENT ON COLUMN uc_import_main.extra_id IS '外部生成id'; +COMMENT ON COLUMN uc_import_main.file_code IS '文件CODE'; +COMMENT ON COLUMN uc_import_main.file_name IS '文件名称'; +COMMENT ON COLUMN uc_import_main.org_id IS '机构ID'; +COMMENT ON COLUMN uc_import_main.remark IS '备注'; +COMMENT ON COLUMN uc_import_main.deleted IS '是否删除'; +COMMENT ON COLUMN uc_import_main.create_by IS '创建人'; +COMMENT ON COLUMN uc_import_main.create_time IS '创建时间'; +COMMENT ON COLUMN uc_import_main.update_by IS '修改人'; +COMMENT ON COLUMN uc_import_main.update_time IS '修改时间'; +COMMENT ON COLUMN uc_import_main.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_lite_code +-- ---------------------------- +DROP TABLE IF EXISTS uc_lite_code; +CREATE TABLE uc_lite_code ( + id BIGSERIAL PRIMARY KEY, + lite_code_config_id BIGINT DEFAULT NULL, + unique_code VARCHAR(32) DEFAULT NULL, + param_value VARCHAR(255) DEFAULT NULL, + query_value VARCHAR(255) DEFAULT NULL, + file_code VARCHAR(32) DEFAULT NULL, + url_scheme VARCHAR(64) DEFAULT NULL, + name VARCHAR(32) DEFAULT NULL, + user_id BIGINT DEFAULT NULL, + org_id BIGINT DEFAULT NULL, + platform_code SMALLINT DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE uc_lite_code IS '小程序码'; +COMMENT ON COLUMN uc_lite_code.id IS '主键'; +COMMENT ON COLUMN uc_lite_code.lite_code_config_id IS '小程序码配置id'; +COMMENT ON COLUMN uc_lite_code.unique_code IS '唯一码-uuid'; +COMMENT ON COLUMN uc_lite_code.param_value IS '参数值(按参数键升序排列)(格式:**&**)'; +COMMENT ON COLUMN uc_lite_code.query_value IS 'query参数值(格式:**=**&**=**)'; +COMMENT ON COLUMN uc_lite_code.file_code IS '小程序码文件编码'; +COMMENT ON COLUMN uc_lite_code.url_scheme IS '小程序scheme码'; +COMMENT ON COLUMN uc_lite_code.name IS '名称'; +COMMENT ON COLUMN uc_lite_code.user_id IS '用户id'; +COMMENT ON COLUMN uc_lite_code.org_id IS '机构id'; +COMMENT ON COLUMN uc_lite_code.platform_code IS '平台编码'; +COMMENT ON COLUMN uc_lite_code.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_lite_code.create_by IS '创建人'; +COMMENT ON COLUMN uc_lite_code.create_time IS '创建时间'; +COMMENT ON COLUMN uc_lite_code.update_by IS '更新人'; +COMMENT ON COLUMN uc_lite_code.update_time IS '更新时间'; +COMMENT ON COLUMN uc_lite_code.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_lite_code_config +-- ---------------------------- +DROP TABLE IF EXISTS uc_lite_code_config; +CREATE TABLE uc_lite_code_config ( + id BIGSERIAL PRIMARY KEY, + auth_client_id BIGINT DEFAULT NULL, + biz_type SMALLINT DEFAULT NULL, + path VARCHAR(64) DEFAULT NULL, + param_key VARCHAR(64) DEFAULT NULL, + env_param_key VARCHAR(64) DEFAULT NULL, + platform_code SMALLINT DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE uc_lite_code_config IS '小程序码配置'; +COMMENT ON COLUMN uc_lite_code_config.id IS '主键'; +COMMENT ON COLUMN uc_lite_code_config.auth_client_id IS '授权客户端id'; +COMMENT ON COLUMN uc_lite_code_config.biz_type IS '小程序码业务类型'; +COMMENT ON COLUMN uc_lite_code_config.path IS '路径'; +COMMENT ON COLUMN uc_lite_code_config.param_key IS '参数键-逗号分隔'; +COMMENT ON COLUMN uc_lite_code_config.env_param_key IS '内置环境参数键-逗号分隔'; +COMMENT ON COLUMN uc_lite_code_config.platform_code IS '平台编码'; +COMMENT ON COLUMN uc_lite_code_config.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_lite_code_config.create_by IS '创建人'; +COMMENT ON COLUMN uc_lite_code_config.create_time IS '创建时间'; +COMMENT ON COLUMN uc_lite_code_config.update_by IS '更新人'; +COMMENT ON COLUMN uc_lite_code_config.update_time IS '更新时间'; +COMMENT ON COLUMN uc_lite_code_config.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_org_relation +-- ---------------------------- +DROP TABLE IF EXISTS uc_org_relation; +CREATE TABLE uc_org_relation ( + id BIGSERIAL PRIMARY KEY, + org_id BIGINT DEFAULT NULL, + org_type SMALLINT DEFAULT NULL, + parent_id BIGINT DEFAULT NULL, + path VARCHAR(255) DEFAULT NULL, + platform_code SMALLINT DEFAULT NULL, + platform_name VARCHAR(32) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +CREATE INDEX idx_org_id ON uc_org_relation(org_id); +COMMENT ON TABLE uc_org_relation IS '机构关系表'; +COMMENT ON COLUMN uc_org_relation.id IS '主键'; +COMMENT ON COLUMN uc_org_relation.org_id IS '机构id'; +COMMENT ON COLUMN uc_org_relation.org_type IS '类型'; +COMMENT ON COLUMN uc_org_relation.parent_id IS '上级id'; +COMMENT ON COLUMN uc_org_relation.path IS '路径'; +COMMENT ON COLUMN uc_org_relation.platform_code IS '平台编码'; +COMMENT ON COLUMN uc_org_relation.platform_name IS '平台名称'; +COMMENT ON COLUMN uc_org_relation.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_org_relation.create_by IS '创建人'; +COMMENT ON COLUMN uc_org_relation.create_time IS '创建时间'; +COMMENT ON COLUMN uc_org_relation.update_by IS '更新人'; +COMMENT ON COLUMN uc_org_relation.update_time IS '更新时间'; +COMMENT ON COLUMN uc_org_relation.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_org_user +-- ---------------------------- +DROP TABLE IF EXISTS uc_org_user; +CREATE TABLE uc_org_user ( + id BIGSERIAL PRIMARY KEY, + user_id BIGINT DEFAULT NULL, + org_id BIGINT DEFAULT NULL, + administrator BOOLEAN DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +CREATE INDEX INDEX12378548369700 ON uc_org_user(user_id); +CREATE INDEX INDEX12378670651400 ON uc_org_user(org_id); +COMMENT ON TABLE uc_org_user IS '机构用户表'; +COMMENT ON COLUMN uc_org_user.id IS '主键'; +COMMENT ON COLUMN uc_org_user.user_id IS '用户id'; +COMMENT ON COLUMN uc_org_user.org_id IS '机构id'; +COMMENT ON COLUMN uc_org_user.administrator IS '是否管理员'; +COMMENT ON COLUMN uc_org_user.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_org_user.create_by IS '创建人'; +COMMENT ON COLUMN uc_org_user.create_time IS '创建时间'; +COMMENT ON COLUMN uc_org_user.update_by IS '更新人'; +COMMENT ON COLUMN uc_org_user.update_time IS '更新时间'; +COMMENT ON COLUMN uc_org_user.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_platform +-- ---------------------------- +DROP TABLE IF EXISTS uc_platform; +CREATE TABLE uc_platform ( + id BIGSERIAL PRIMARY KEY, + platform_code SMALLINT DEFAULT NULL, + name VARCHAR(32) DEFAULT NULL, + full_name VARCHAR(32) DEFAULT NULL, + short_name VARCHAR(32) DEFAULT NULL, + business BOOLEAN DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE uc_platform IS '系统应用表'; +COMMENT ON COLUMN uc_platform.id IS '主键'; +COMMENT ON COLUMN uc_platform.platform_code IS '平台编码'; +COMMENT ON COLUMN uc_platform.name IS '名称'; +COMMENT ON COLUMN uc_platform.full_name IS '全称'; +COMMENT ON COLUMN uc_platform.short_name IS '简称'; +COMMENT ON COLUMN uc_platform.business IS '是否业务系统'; +COMMENT ON COLUMN uc_platform.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_platform.create_by IS '创建人'; +COMMENT ON COLUMN uc_platform.create_time IS '创建时间'; +COMMENT ON COLUMN uc_platform.update_by IS '更新人'; +COMMENT ON COLUMN uc_platform.update_time IS '更新时间'; +COMMENT ON COLUMN uc_platform.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_slick_param +-- ---------------------------- +DROP TABLE IF EXISTS uc_slick_param; +CREATE TABLE uc_slick_param ( + id BIGSERIAL PRIMARY KEY, + unique_code VARCHAR(32) DEFAULT NULL, + query_value VARCHAR(255) DEFAULT NULL, + param_data VARCHAR(255) DEFAULT NULL, + hash_code INTEGER DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +CREATE INDEX idx_hash_code ON uc_slick_param(hash_code); +CREATE INDEX idx_unique_code ON uc_slick_param(unique_code); +COMMENT ON TABLE uc_slick_param IS '圆滑的参数'; +COMMENT ON COLUMN uc_slick_param.id IS '主键'; +COMMENT ON COLUMN uc_slick_param.unique_code IS '唯一码-uuid'; +COMMENT ON COLUMN uc_slick_param.query_value IS 'query升序值(格式:**=**&**=**)'; +COMMENT ON COLUMN uc_slick_param.param_data IS 'json'; +COMMENT ON COLUMN uc_slick_param.hash_code IS '哈希值'; +COMMENT ON COLUMN uc_slick_param.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_slick_param.create_by IS '创建人'; +COMMENT ON COLUMN uc_slick_param.create_time IS '创建时间'; +COMMENT ON COLUMN uc_slick_param.update_by IS '更新人'; +COMMENT ON COLUMN uc_slick_param.update_time IS '更新时间'; +COMMENT ON COLUMN uc_slick_param.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_user +-- ---------------------------- +DROP TABLE IF EXISTS uc_user; +CREATE TABLE uc_user ( + id BIGSERIAL PRIMARY KEY, + username VARCHAR(32) DEFAULT NULL, + password VARCHAR(128) DEFAULT NULL, + type SMALLINT DEFAULT NULL, + supeiror BOOLEAN DEFAULT NULL, + security_code VARCHAR(128) DEFAULT NULL, + nickname VARCHAR(32) DEFAULT NULL, + avatar VARCHAR(256) DEFAULT NULL, + phone VARCHAR(32) DEFAULT NULL, + phone_binding BOOLEAN DEFAULT NULL, + real_name VARCHAR(32) DEFAULT NULL, + card_no VARCHAR(18) DEFAULT NULL, + authenticated BOOLEAN DEFAULT NULL, + status SMALLINT DEFAULT NULL, + email VARCHAR(32) DEFAULT NULL, + address VARCHAR(32) DEFAULT NULL, + education SMALLINT DEFAULT NULL, + init_user_id BIGINT DEFAULT NULL, + enabled BOOLEAN DEFAULT NULL, + account_non_expired BOOLEAN DEFAULT NULL, + account_non_locked BOOLEAN DEFAULT NULL, + credentials_non_expired BOOLEAN DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL, + gender SMALLINT DEFAULT NULL, + birthday date DEFAULT NULL +); +CREATE INDEX idx_card_no ON uc_user(card_no); +CREATE INDEX idx_phone ON uc_user(phone); +CREATE INDEX idx_real_name ON uc_user(real_name); +COMMENT ON TABLE uc_user IS '用户表'; +COMMENT ON COLUMN uc_user.id IS '主键'; +COMMENT ON COLUMN uc_user.username IS '账号'; +COMMENT ON COLUMN uc_user.password IS '密码'; +COMMENT ON COLUMN uc_user.type IS '用户类型:1企业用户,2个人用户'; +COMMENT ON COLUMN uc_user.supeiror IS '是否超管'; +COMMENT ON COLUMN uc_user.security_code IS '安全码'; +COMMENT ON COLUMN uc_user.nickname IS '昵称'; +COMMENT ON COLUMN uc_user.avatar IS '头像'; +COMMENT ON COLUMN uc_user.phone IS '手机号码'; +COMMENT ON COLUMN uc_user.phone_binding IS '手机号绑定状态'; +COMMENT ON COLUMN uc_user.real_name IS '真实姓名'; +COMMENT ON COLUMN uc_user.card_no IS '身份证号'; +COMMENT ON COLUMN uc_user.authenticated IS '是否实名'; +COMMENT ON COLUMN uc_user.status IS '状态:1.待激活,2已激活,3已注销'; +COMMENT ON COLUMN uc_user.email IS '邮箱'; +COMMENT ON COLUMN uc_user.address IS '用户所在地'; +COMMENT ON COLUMN uc_user.education IS '1博士、2硕士、3本科、4大专、5高中、6中专/中技、7初中及以下、8不限'; +COMMENT ON COLUMN uc_user.init_user_id IS '初始(推荐)用户id'; +COMMENT ON COLUMN uc_user.enabled IS '是否启用'; +COMMENT ON COLUMN uc_user.account_non_expired IS '账号是否未过期'; +COMMENT ON COLUMN uc_user.account_non_locked IS '是否未锁定'; +COMMENT ON COLUMN uc_user.credentials_non_expired IS '凭据是否未过期'; +COMMENT ON COLUMN uc_user.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_user.create_by IS '创建人'; +COMMENT ON COLUMN uc_user.create_time IS '创建时间'; +COMMENT ON COLUMN uc_user.update_by IS '更新人'; +COMMENT ON COLUMN uc_user.update_time IS '更新时间'; +COMMENT ON COLUMN uc_user.proxy_by IS '代理人'; +COMMENT ON COLUMN uc_user.gender IS '性别:1男2女'; +COMMENT ON COLUMN uc_user.birthday IS '生日'; + +-- ---------------------------- +-- Table structure for uc_user_auth +-- ---------------------------- +DROP TABLE IF EXISTS uc_user_auth; +CREATE TABLE uc_user_auth ( + id BIGSERIAL PRIMARY KEY, + auth_main_type SMALLINT DEFAULT NULL, + unique_id VARCHAR(32) DEFAULT NULL, + user_id BIGINT DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +CREATE INDEX idx_unique_id ON uc_user_auth(unique_id); +COMMENT ON TABLE uc_user_auth IS '用户授权中间表'; +COMMENT ON COLUMN uc_user_auth.id IS '主键'; +COMMENT ON COLUMN uc_user_auth.auth_main_type IS '授权大类'; +COMMENT ON COLUMN uc_user_auth.unique_id IS '授权唯一id'; +COMMENT ON COLUMN uc_user_auth.user_id IS '用户id'; +COMMENT ON COLUMN uc_user_auth.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_user_auth.create_by IS '创建人'; +COMMENT ON COLUMN uc_user_auth.create_time IS '创建时间'; +COMMENT ON COLUMN uc_user_auth.update_by IS '更新人'; +COMMENT ON COLUMN uc_user_auth.update_time IS '更新时间'; +COMMENT ON COLUMN uc_user_auth.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_user_cancel +-- ---------------------------- +DROP TABLE IF EXISTS uc_user_cancel; +CREATE TABLE uc_user_cancel ( + id BIGSERIAL PRIMARY KEY, + user_id BIGINT DEFAULT NULL, + status SMALLINT DEFAULT 1, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL, + cancellation_type VARCHAR(2) DEFAULT NULL, + remark VARCHAR(255) DEFAULT NULL +); +COMMENT ON TABLE uc_user_cancel IS '用户申请注销表'; +COMMENT ON COLUMN uc_user_cancel.id IS '主键'; +COMMENT ON COLUMN uc_user_cancel.user_id IS '用户表ID'; +COMMENT ON COLUMN uc_user_cancel.status IS '申请状态 1:已申请 2:已注销'; +COMMENT ON COLUMN uc_user_cancel.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_user_cancel.create_by IS '创建人'; +COMMENT ON COLUMN uc_user_cancel.create_time IS '创建时间'; +COMMENT ON COLUMN uc_user_cancel.update_by IS '更新人'; +COMMENT ON COLUMN uc_user_cancel.update_time IS '更新时间'; +COMMENT ON COLUMN uc_user_cancel.proxy_by IS '代理人'; +COMMENT ON COLUMN uc_user_cancel.cancellation_type IS '注销原因类型 数据字典'; +COMMENT ON COLUMN uc_user_cancel.remark IS '备注'; + +-- ---------------------------- +-- Table structure for uc_user_config +-- ---------------------------- +DROP TABLE IF EXISTS uc_user_config; +CREATE TABLE uc_user_config ( + id BIGSERIAL PRIMARY KEY, + user_id BIGINT DEFAULT NULL, + config_code VARCHAR(64) DEFAULT NULL, + config_value VARCHAR(1024) DEFAULT NULL, + remark VARCHAR(128) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE uc_user_config IS '用户配置表'; +COMMENT ON COLUMN uc_user_config.id IS '主键'; +COMMENT ON COLUMN uc_user_config.user_id IS '用户id'; +COMMENT ON COLUMN uc_user_config.config_code IS '编码'; +COMMENT ON COLUMN uc_user_config.config_value IS '配置值'; +COMMENT ON COLUMN uc_user_config.remark IS '备注'; +COMMENT ON COLUMN uc_user_config.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_user_config.create_by IS '创建人'; +COMMENT ON COLUMN uc_user_config.create_time IS '创建时间'; +COMMENT ON COLUMN uc_user_config.update_by IS '更新人'; +COMMENT ON COLUMN uc_user_config.update_time IS '更新时间'; +COMMENT ON COLUMN uc_user_config.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_user_extension +-- ---------------------------- +DROP TABLE IF EXISTS uc_user_extension; +CREATE TABLE uc_user_extension ( + id BIGSERIAL PRIMARY KEY, + user_id BIGINT DEFAULT NULL, + technique_tag VARCHAR(256) DEFAULT NULL, + residence_address VARCHAR(128) DEFAULT NULL, + file_code VARCHAR(255) DEFAULT NULL, + file_name VARCHAR(255) DEFAULT NULL, + covid_vaccine SMALLINT DEFAULT NULL, + wechat_qr_code VARCHAR(32) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE uc_user_extension IS '用户扩展表'; +COMMENT ON COLUMN uc_user_extension.id IS '主键'; +COMMENT ON COLUMN uc_user_extension.user_id IS '用户id'; +COMMENT ON COLUMN uc_user_extension.technique_tag IS '技能标签'; +COMMENT ON COLUMN uc_user_extension.residence_address IS '常住地区'; +COMMENT ON COLUMN uc_user_extension.file_code IS '简历附件编码'; +COMMENT ON COLUMN uc_user_extension.file_name IS '简历附件名称'; +COMMENT ON COLUMN uc_user_extension.covid_vaccine IS '新冠疫苗:1.未接种,2.1针,3.2针,4.3针'; +COMMENT ON COLUMN uc_user_extension.wechat_qr_code IS '微信二维码'; +COMMENT ON COLUMN uc_user_extension.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_user_extension.create_by IS '创建人'; +COMMENT ON COLUMN uc_user_extension.create_time IS '创建时间'; +COMMENT ON COLUMN uc_user_extension.update_by IS '更新人'; +COMMENT ON COLUMN uc_user_extension.update_time IS '更新时间'; +COMMENT ON COLUMN uc_user_extension.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_user_face +-- ---------------------------- +DROP TABLE IF EXISTS uc_user_face; +CREATE TABLE uc_user_face ( + id BIGSERIAL PRIMARY KEY, + user_id BIGINT DEFAULT NULL, + type SMALLINT DEFAULT NULL, + file_code VARCHAR(32) DEFAULT NULL, + deleted BOOLEAN NOT NULL DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +CREATE INDEX INDEX12379510213700 ON uc_user_face(user_id); +COMMENT ON TABLE uc_user_face IS '用户活体信息表'; +COMMENT ON COLUMN uc_user_face.id IS 'ID'; +COMMENT ON COLUMN uc_user_face.user_id IS '用户ID'; +COMMENT ON COLUMN uc_user_face.type IS '类型 1:照片 2:视频'; +COMMENT ON COLUMN uc_user_face.file_code IS '文件编码'; +COMMENT ON COLUMN uc_user_face.deleted IS '是否删除'; +COMMENT ON COLUMN uc_user_face.create_by IS '创建人'; +COMMENT ON COLUMN uc_user_face.create_time IS '创建时间'; +COMMENT ON COLUMN uc_user_face.update_by IS '更新人'; +COMMENT ON COLUMN uc_user_face.update_time IS '更新时间'; +COMMENT ON COLUMN uc_user_face.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for uc_user_postal_info +-- ---------------------------- +DROP TABLE IF EXISTS uc_user_postal_info; +CREATE TABLE uc_user_postal_info ( + id BIGSERIAL PRIMARY KEY, + defaulted BOOLEAN DEFAULT NULL, + name VARCHAR(50) DEFAULT NULL, + phone VARCHAR(50) DEFAULT NULL, + address_code VARCHAR(50) DEFAULT NULL, + address_name VARCHAR(50) DEFAULT NULL, + address_detail VARCHAR(100) DEFAULT NULL, + deleted BOOLEAN DEFAULT NULL, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE uc_user_postal_info IS '用户邮寄信息'; +COMMENT ON COLUMN uc_user_postal_info.id IS '主键'; +COMMENT ON COLUMN uc_user_postal_info.defaulted IS '是否默认'; +COMMENT ON COLUMN uc_user_postal_info.name IS '收货人'; +COMMENT ON COLUMN uc_user_postal_info.phone IS '手机号'; +COMMENT ON COLUMN uc_user_postal_info.address_code IS '地区编码'; +COMMENT ON COLUMN uc_user_postal_info.address_name IS '地址名称'; +COMMENT ON COLUMN uc_user_postal_info.address_detail IS '详细地址'; +COMMENT ON COLUMN uc_user_postal_info.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_user_postal_info.create_by IS '创建人'; +COMMENT ON COLUMN uc_user_postal_info.create_time IS '创建时间'; +COMMENT ON COLUMN uc_user_postal_info.update_by IS '更新人'; +COMMENT ON COLUMN uc_user_postal_info.update_time IS '更新时间'; +COMMENT ON COLUMN uc_user_postal_info.proxy_by IS '代理人'; + + +-- ---------------------------- +-- Table structure for uc_user_register +-- ---------------------------- +DROP TABLE IF EXISTS uc_user_register; +CREATE TABLE uc_user_register ( + id BIGSERIAL PRIMARY KEY, + platform_code SMALLINT DEFAULT NULL, + user_id BIGINT DEFAULT NULL, + inviter_id BIGINT DEFAULT NULL, + inviter_type SMALLINT DEFAULT NULL, + inviter_org_id BIGINT DEFAULT NULL, + entrypoint VARCHAR(32) DEFAULT NULL, + union_id BIGINT DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +CREATE INDEX idx_user_id ON uc_user_register(user_id); +COMMENT ON TABLE uc_user_register IS '用户注册表'; +COMMENT ON COLUMN uc_user_register.id IS '主键'; +COMMENT ON COLUMN uc_user_register.platform_code IS '平台编码'; +COMMENT ON COLUMN uc_user_register.user_id IS '用户id'; +COMMENT ON COLUMN uc_user_register.inviter_id IS '邀请人id'; +COMMENT ON COLUMN uc_user_register.inviter_type IS '邀请人用户类型'; +COMMENT ON COLUMN uc_user_register.inviter_org_id IS '邀请人机构id'; +COMMENT ON COLUMN uc_user_register.entrypoint IS '入口点'; +COMMENT ON COLUMN uc_user_register.union_id IS '关联id(小程序码id)'; +COMMENT ON COLUMN uc_user_register.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN uc_user_register.create_by IS '创建人'; +COMMENT ON COLUMN uc_user_register.create_time IS '创建时间'; +COMMENT ON COLUMN uc_user_register.update_by IS '更新人'; +COMMENT ON COLUMN uc_user_register.update_time IS '更新时间'; +COMMENT ON COLUMN uc_user_register.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for xs_chat +-- ---------------------------- +DROP TABLE IF EXISTS xs_chat; +CREATE TABLE xs_chat ( + id BIGSERIAL PRIMARY KEY, + org_id BIGINT DEFAULT NULL, + org_user_id BIGINT DEFAULT NULL, + person_user_id BIGINT DEFAULT NULL, + type VARCHAR(32) DEFAULT NULL, + status SMALLINT DEFAULT NULL, + deleted BOOLEAN NOT NULL DEFAULT FALSE, + create_by BIGINT NOT NULL, + create_time TIMESTAMP NOT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE xs_chat IS '聊天表'; +COMMENT ON COLUMN xs_chat.id IS '主键'; +COMMENT ON COLUMN xs_chat.org_id IS '机构id'; +COMMENT ON COLUMN xs_chat.org_user_id IS '机构用户id'; +COMMENT ON COLUMN xs_chat.person_user_id IS '个人用户id'; +COMMENT ON COLUMN xs_chat.type IS '类型(chat_type)'; +COMMENT ON COLUMN xs_chat.status IS '状态:1有效,2关闭'; +COMMENT ON COLUMN xs_chat.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN xs_chat.create_by IS '创建人'; +COMMENT ON COLUMN xs_chat.create_time IS '创建时间'; +COMMENT ON COLUMN xs_chat.update_by IS '更新人'; +COMMENT ON COLUMN xs_chat.update_time IS '更新时间'; +COMMENT ON COLUMN xs_chat.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for xs_chat_msg +-- ---------------------------- +DROP TABLE IF EXISTS xs_chat_msg; +CREATE TABLE xs_chat_msg ( + id BIGSERIAL PRIMARY KEY, + chat_id BIGINT DEFAULT NULL, + sender_id BIGINT DEFAULT NULL, + msg_type VARCHAR(16) DEFAULT NULL, + content VARCHAR(1024) DEFAULT NULL, + msg_status SMALLINT DEFAULT NULL, + deleted BOOLEAN NOT NULL DEFAULT FALSE, + create_by BIGINT NOT NULL, + create_time TIMESTAMP NOT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE xs_chat_msg IS '聊天消息表'; +COMMENT ON COLUMN xs_chat_msg.id IS '主键'; +COMMENT ON COLUMN xs_chat_msg.chat_id IS '聊天id'; +COMMENT ON COLUMN xs_chat_msg.sender_id IS '发送用户id'; +COMMENT ON COLUMN xs_chat_msg.msg_type IS '消息类型(chat_msg_type):text等'; +COMMENT ON COLUMN xs_chat_msg.content IS '个人用户id'; +COMMENT ON COLUMN xs_chat_msg.msg_status IS '消息状态:1未读,2已读'; +COMMENT ON COLUMN xs_chat_msg.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN xs_chat_msg.create_by IS '创建人'; +COMMENT ON COLUMN xs_chat_msg.create_time IS '创建时间'; +COMMENT ON COLUMN xs_chat_msg.update_by IS '更新人'; +COMMENT ON COLUMN xs_chat_msg.update_time IS '更新时间'; +COMMENT ON COLUMN xs_chat_msg.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for xs_code_setting +-- ---------------------------- +DROP TABLE IF EXISTS xs_code_setting; +CREATE TABLE xs_code_setting ( + id BIGSERIAL PRIMARY KEY, + code VARCHAR(64) DEFAULT NULL, + name VARCHAR(128) DEFAULT NULL, + remark VARCHAR(128) DEFAULT NULL, + type VARCHAR(2) DEFAULT NULL, + data_type VARCHAR(2) DEFAULT NULL, + data_format VARCHAR(128) DEFAULT NULL, + level VARCHAR(20) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE xs_code_setting IS '编码表'; +COMMENT ON COLUMN xs_code_setting.id IS '主键ID'; +COMMENT ON COLUMN xs_code_setting.code IS '编码'; +COMMENT ON COLUMN xs_code_setting.name IS '名称'; +COMMENT ON COLUMN xs_code_setting.remark IS '备注'; +COMMENT ON COLUMN xs_code_setting.type IS '类型 模板编码、配置编码'; +COMMENT ON COLUMN xs_code_setting.data_type IS '数据类型'; +COMMENT ON COLUMN xs_code_setting.data_format IS '数据格式编号'; +COMMENT ON COLUMN xs_code_setting.level IS '级别 平台、渠道、定制机构、普通机构'; +COMMENT ON COLUMN xs_code_setting.deleted IS '是否删除'; +COMMENT ON COLUMN xs_code_setting.create_by IS '创建人'; +COMMENT ON COLUMN xs_code_setting.create_time IS '创建时间'; +COMMENT ON COLUMN xs_code_setting.update_by IS '修改人'; +COMMENT ON COLUMN xs_code_setting.update_time IS '修改时间'; +COMMENT ON COLUMN xs_code_setting.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for xs_company_extend +-- ---------------------------- +DROP TABLE IF EXISTS xs_company_extend; +CREATE TABLE xs_company_extend ( + id BIGSERIAL PRIMARY KEY, + seller_id BIGINT DEFAULT NULL, + org_id BIGINT DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +CREATE INDEX INDEX173651263650200 ON xs_company_extend(org_id); +COMMENT ON TABLE xs_company_extend IS '企业的扩展信息'; +COMMENT ON COLUMN xs_company_extend.id IS '主键ID'; +COMMENT ON COLUMN xs_company_extend.seller_id IS '销售'; +COMMENT ON COLUMN xs_company_extend.org_id IS '所属机构ID'; +COMMENT ON COLUMN xs_company_extend.deleted IS '是否删除'; +COMMENT ON COLUMN xs_company_extend.create_by IS '创建人'; +COMMENT ON COLUMN xs_company_extend.create_time IS '创建时间'; +COMMENT ON COLUMN xs_company_extend.update_by IS '修改人'; +COMMENT ON COLUMN xs_company_extend.update_time IS '修改时间'; +COMMENT ON COLUMN xs_company_extend.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for xs_component +-- ---------------------------- +DROP TABLE IF EXISTS xs_component; +CREATE TABLE xs_component ( + id BIGSERIAL PRIMARY KEY, + url_id BIGINT DEFAULT NULL, + code VARCHAR(32) DEFAULT NULL, + name VARCHAR(64) DEFAULT NULL, + platform_code SMALLINT DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE xs_component IS '组件'; +COMMENT ON COLUMN xs_component.id IS '主键ID'; +COMMENT ON COLUMN xs_component.url_id IS '菜单id'; +COMMENT ON COLUMN xs_component.code IS '组件编码'; +COMMENT ON COLUMN xs_component.name IS '组件名称'; +COMMENT ON COLUMN xs_component.platform_code IS '平台编码'; +COMMENT ON COLUMN xs_component.deleted IS '是否删除'; +COMMENT ON COLUMN xs_component.create_by IS '创建人'; +COMMENT ON COLUMN xs_component.create_time IS '创建时间'; +COMMENT ON COLUMN xs_component.update_by IS '修改人'; +COMMENT ON COLUMN xs_component.update_time IS '修改时间'; +COMMENT ON COLUMN xs_component.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for xs_config +-- ---------------------------- +DROP TABLE IF EXISTS xs_config; +CREATE TABLE xs_config ( + id BIGSERIAL PRIMARY KEY, + config_code VARCHAR(64) DEFAULT NULL, + config_value TEXT, + org_id BIGINT DEFAULT NULL, + remark VARCHAR(128) DEFAULT NULL, + enable BOOLEAN DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE xs_config IS '配置表'; +COMMENT ON COLUMN xs_config.id IS '主键ID'; +COMMENT ON COLUMN xs_config.config_code IS '编码'; +COMMENT ON COLUMN xs_config.config_value IS '配置值'; +COMMENT ON COLUMN xs_config.org_id IS '机构'; +COMMENT ON COLUMN xs_config.remark IS '备注'; +COMMENT ON COLUMN xs_config.enable IS '是否启用'; +COMMENT ON COLUMN xs_config.deleted IS '是否删除'; +COMMENT ON COLUMN xs_config.create_by IS '创建人'; +COMMENT ON COLUMN xs_config.create_time IS '创建时间'; +COMMENT ON COLUMN xs_config.update_by IS '修改人'; +COMMENT ON COLUMN xs_config.update_time IS '修改时间'; +COMMENT ON COLUMN xs_config.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for xs_dict +-- ---------------------------- +DROP TABLE IF EXISTS xs_dict; +CREATE TABLE xs_dict ( + id BIGSERIAL PRIMARY KEY, + dict_code VARCHAR(32) DEFAULT NULL, + dict_name VARCHAR(64) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +CREATE INDEX idx_dict_code ON xs_dict(dict_code); +COMMENT ON TABLE xs_dict IS '数据字典主信息'; +COMMENT ON COLUMN xs_dict.id IS '主键ID'; +COMMENT ON COLUMN xs_dict.dict_code IS '字典编码'; +COMMENT ON COLUMN xs_dict.dict_name IS '字典名称'; +COMMENT ON COLUMN xs_dict.deleted IS '是否删除'; +COMMENT ON COLUMN xs_dict.create_by IS '创建人'; +COMMENT ON COLUMN xs_dict.create_time IS '创建时间'; +COMMENT ON COLUMN xs_dict.update_by IS '修改人'; +COMMENT ON COLUMN xs_dict.update_time IS '修改时间'; +COMMENT ON COLUMN xs_dict.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for xs_dict_detail +-- ---------------------------- +DROP TABLE IF EXISTS xs_dict_detail; +CREATE TABLE xs_dict_detail ( + id BIGSERIAL PRIMARY KEY, + dict_id BIGINT DEFAULT NULL, + dict_detail_code VARCHAR(64) DEFAULT NULL, + dict_detail_name VARCHAR(128) DEFAULT NULL, + dict_order INTEGER DEFAULT NULL, + parent_id BIGINT DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +CREATE INDEX idx_dict_id ON xs_dict_detail(dict_id); +COMMENT ON TABLE xs_dict_detail IS '数据字典明细信息'; +COMMENT ON COLUMN xs_dict_detail.id IS '主键ID'; +COMMENT ON COLUMN xs_dict_detail.dict_id IS '字典ID'; +COMMENT ON COLUMN xs_dict_detail.dict_detail_code IS '子项编码'; +COMMENT ON COLUMN xs_dict_detail.dict_detail_name IS '子项名称'; +COMMENT ON COLUMN xs_dict_detail.dict_order IS '排序'; +COMMENT ON COLUMN xs_dict_detail.parent_id IS '父子项ID'; +COMMENT ON COLUMN xs_dict_detail.deleted IS '是否删除'; +COMMENT ON COLUMN xs_dict_detail.create_by IS '创建人'; +COMMENT ON COLUMN xs_dict_detail.create_time IS '创建时间'; +COMMENT ON COLUMN xs_dict_detail.update_by IS '修改人'; +COMMENT ON COLUMN xs_dict_detail.update_time IS '修改时间'; +COMMENT ON COLUMN xs_dict_detail.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for xs_district +-- ---------------------------- +DROP TABLE IF EXISTS xs_district; +CREATE TABLE xs_district ( + id BIGSERIAL PRIMARY KEY, + name VARCHAR(32) DEFAULT NULL, + parent_id BIGINT DEFAULT NULL, + initial VARCHAR(32) DEFAULT NULL, + initials VARCHAR(32) DEFAULT NULL, + pinyin VARCHAR(32) DEFAULT NULL, + extra VARCHAR(32) DEFAULT NULL, + suffix VARCHAR(32) DEFAULT NULL, + code VARCHAR(32) DEFAULT NULL, + area_code VARCHAR(32) DEFAULT NULL, + district_order INTEGER DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL, + level INTEGER DEFAULT NULL +); +COMMENT ON TABLE xs_district IS '省份城市'; +COMMENT ON COLUMN xs_district.id IS '主键ID'; +COMMENT ON COLUMN xs_district.name IS '城市名称'; +COMMENT ON COLUMN xs_district.parent_id IS '上级城市ID'; +COMMENT ON COLUMN xs_district.initial IS '首字母'; +COMMENT ON COLUMN xs_district.initials IS '简拼'; +COMMENT ON COLUMN xs_district.pinyin IS '全拼'; +COMMENT ON COLUMN xs_district.extra IS '特别行政区'; +COMMENT ON COLUMN xs_district.suffix IS '后缀'; +COMMENT ON COLUMN xs_district.code IS '城市编码'; +COMMENT ON COLUMN xs_district.area_code IS '区域编码'; +COMMENT ON COLUMN xs_district.district_order IS '排序'; +COMMENT ON COLUMN xs_district.deleted IS '是否删除'; +COMMENT ON COLUMN xs_district.create_by IS '创建人'; +COMMENT ON COLUMN xs_district.create_time IS '创建时间'; +COMMENT ON COLUMN xs_district.update_by IS '修改人'; +COMMENT ON COLUMN xs_district.update_time IS '修改时间'; +COMMENT ON COLUMN xs_district.proxy_by IS '代理人'; +COMMENT ON COLUMN xs_district.level IS '层级'; + +-- ---------------------------- +-- Table structure for xs_file_record +-- ---------------------------- +DROP TABLE IF EXISTS xs_file_record; +CREATE TABLE xs_file_record ( + id BIGSERIAL PRIMARY KEY, + file_code VARCHAR(64) DEFAULT NULL, + file_path VARCHAR(512) DEFAULT NULL, + file_name VARCHAR(128) DEFAULT NULL, + file_size INTEGER DEFAULT NULL, + md5_code VARCHAR(64) DEFAULT NULL, + file_suffix VARCHAR(32) DEFAULT NULL, + org_id BIGINT DEFAULT NULL, + storage_type VARCHAR(32) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +CREATE INDEX idx_file_code ON xs_file_record(file_code); +COMMENT ON TABLE xs_file_record IS '附件信息'; +COMMENT ON COLUMN xs_file_record.id IS '主键ID'; +COMMENT ON COLUMN xs_file_record.file_code IS '文件编码'; +COMMENT ON COLUMN xs_file_record.file_path IS '文件路径'; +COMMENT ON COLUMN xs_file_record.file_name IS '文件名'; +COMMENT ON COLUMN xs_file_record.file_size IS '文件大小'; +COMMENT ON COLUMN xs_file_record.md5_code IS '文件MD5'; +COMMENT ON COLUMN xs_file_record.file_suffix IS '文件后缀'; +COMMENT ON COLUMN xs_file_record.org_id IS '所属机构'; +COMMENT ON COLUMN xs_file_record.storage_type IS '储存器类型'; +COMMENT ON COLUMN xs_file_record.deleted IS '是否删除'; +COMMENT ON COLUMN xs_file_record.create_by IS '创建人'; +COMMENT ON COLUMN xs_file_record.create_time IS '创建时间'; +COMMENT ON COLUMN xs_file_record.update_by IS '修改人'; +COMMENT ON COLUMN xs_file_record.update_time IS '修改时间'; +COMMENT ON COLUMN xs_file_record.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for xs_org +-- ---------------------------- +DROP TABLE IF EXISTS xs_org; +CREATE TABLE xs_org ( + id BIGSERIAL PRIMARY KEY, + org_name VARCHAR(32) DEFAULT NULL, + org_code VARCHAR(64) DEFAULT NULL, + type VARCHAR(2) DEFAULT NULL, + address_code VARCHAR(16) DEFAULT NULL, + address_name VARCHAR(128) DEFAULT NULL, + description VARCHAR(1024) DEFAULT NULL, + quality BOOLEAN DEFAULT FALSE, + enable BOOLEAN DEFAULT NULL, + activated BOOLEAN DEFAULT FALSE, + parent_id BIGINT DEFAULT NULL, + credit_code VARCHAR(64) DEFAULT NULL, + trade VARCHAR(2) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL, + activation_code VARCHAR(32) DEFAULT NULL, + phone VARCHAR(32) DEFAULT NULL, + query_children BOOLEAN DEFAULT NULL, + org_logo VARCHAR(64) DEFAULT NULL, + registered_address VARCHAR(128) DEFAULT NULL, + company_size VARCHAR(32) DEFAULT NULL, + business_license VARCHAR(64) DEFAULT NULL, + recruit_position_type VARCHAR(2) NOT NULL DEFAULT 1 +); +COMMENT ON TABLE xs_org IS '机构'; +COMMENT ON COLUMN xs_org.id IS '主键ID'; +COMMENT ON COLUMN xs_org.org_name IS '机构名称'; +COMMENT ON COLUMN xs_org.org_code IS '机构编号'; +COMMENT ON COLUMN xs_org.type IS '机构类型(1.平台 2.渠道代理商 3.普通机构 4.定制机构 5.散户机构 6.产品机构)'; +COMMENT ON COLUMN xs_org.address_code IS '任务地点编码'; +COMMENT ON COLUMN xs_org.address_name IS '任务地点全称'; +COMMENT ON COLUMN xs_org.description IS '机构描述'; +COMMENT ON COLUMN xs_org.quality IS '是否优质企业'; +COMMENT ON COLUMN xs_org.enable IS '是否启用'; +COMMENT ON COLUMN xs_org.activated IS '是否激活'; +COMMENT ON COLUMN xs_org.parent_id IS '父机构ID'; +COMMENT ON COLUMN xs_org.credit_code IS '统一社会信用代码'; +COMMENT ON COLUMN xs_org.trade IS '所属行业'; +COMMENT ON COLUMN xs_org.deleted IS '是否删除'; +COMMENT ON COLUMN xs_org.create_by IS '创建人'; +COMMENT ON COLUMN xs_org.create_time IS '创建时间'; +COMMENT ON COLUMN xs_org.update_by IS '修改人'; +COMMENT ON COLUMN xs_org.update_time IS '修改时间'; +COMMENT ON COLUMN xs_org.proxy_by IS '代理人'; +COMMENT ON COLUMN xs_org.activation_code IS '机构账号激活码'; +COMMENT ON COLUMN xs_org.phone IS '手机号码'; +COMMENT ON COLUMN xs_org.query_children IS '是否能查看下级数据'; +COMMENT ON COLUMN xs_org.org_logo IS '企业logo'; +COMMENT ON COLUMN xs_org.registered_address IS '注册地址'; +COMMENT ON COLUMN xs_org.company_size IS '规模 数据字典'; +COMMENT ON COLUMN xs_org.business_license IS '营业执照'; +COMMENT ON COLUMN xs_org.recruit_position_type IS '招聘岗位类型'; + +-- ---------------------------- +-- Table structure for xs_org_user +-- ---------------------------- +DROP TABLE IF EXISTS xs_org_user; +CREATE TABLE xs_org_user ( + id BIGSERIAL PRIMARY KEY, + org_id BIGINT DEFAULT NULL, + user_id BIGINT DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE xs_org_user IS '机构用户'; +COMMENT ON COLUMN xs_org_user.id IS '主键ID'; +COMMENT ON COLUMN xs_org_user.org_id IS '机构id'; +COMMENT ON COLUMN xs_org_user.user_id IS '用户id'; +COMMENT ON COLUMN xs_org_user.deleted IS '是否删除'; +COMMENT ON COLUMN xs_org_user.create_by IS '创建人'; +COMMENT ON COLUMN xs_org_user.create_time IS '创建时间'; +COMMENT ON COLUMN xs_org_user.update_by IS '修改人'; +COMMENT ON COLUMN xs_org_user.update_time IS '修改时间'; +COMMENT ON COLUMN xs_org_user.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for xs_permission +-- ---------------------------- +DROP TABLE IF EXISTS xs_permission; +CREATE TABLE xs_permission ( + id BIGSERIAL PRIMARY KEY, + role_id BIGINT DEFAULT NULL, + resource_type VARCHAR(2) DEFAULT NULL, + resource_id BIGINT DEFAULT NULL, + attribute VARCHAR(32) DEFAULT NULL, + org_id BIGINT DEFAULT NULL, + platform_code SMALLINT DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE xs_permission IS '权限表'; +COMMENT ON COLUMN xs_permission.id IS '主键ID'; +COMMENT ON COLUMN xs_permission.role_id IS '角色id'; +COMMENT ON COLUMN xs_permission.resource_type IS '资源类型:1菜单 2组件 3接口'; +COMMENT ON COLUMN xs_permission.resource_id IS '资源id'; +COMMENT ON COLUMN xs_permission.attribute IS '权限鉴别属性,默认格式:ROLE_{roleId},可以扩展'; +COMMENT ON COLUMN xs_permission.org_id IS '机构id'; +COMMENT ON COLUMN xs_permission.platform_code IS '平台编码 1.业务系统 2.运营中台 3.用户中心 4.支付系统 5.在线培训 6.转发器 7.风控 8.网关 9.发号器 10.基础框架'; +COMMENT ON COLUMN xs_permission.deleted IS '是否删除'; +COMMENT ON COLUMN xs_permission.create_by IS '创建人'; +COMMENT ON COLUMN xs_permission.create_time IS '创建时间'; +COMMENT ON COLUMN xs_permission.update_by IS '修改人'; +COMMENT ON COLUMN xs_permission.update_time IS '修改时间'; +COMMENT ON COLUMN xs_permission.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for xs_permission_organization +-- ---------------------------- +DROP TABLE IF EXISTS xs_permission_organization; +CREATE TABLE xs_permission_organization ( + id BIGSERIAL PRIMARY KEY, + permission_package_id BIGINT DEFAULT NULL, + allocation_org_id BIGINT DEFAULT NULL, + remark VARCHAR(100) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +CREATE INDEX idx_allocation_org_id ON xs_permission_organization(allocation_org_id); +CREATE INDEX idx_permission_package_id ON xs_permission_organization(permission_package_id); +COMMENT ON TABLE xs_permission_organization IS '权限包-机构关系表'; +COMMENT ON COLUMN xs_permission_organization.id IS '主键id'; +COMMENT ON COLUMN xs_permission_organization.permission_package_id IS '权限包id'; +COMMENT ON COLUMN xs_permission_organization.allocation_org_id IS '分配机构orgid'; +COMMENT ON COLUMN xs_permission_organization.remark IS '备注'; +COMMENT ON COLUMN xs_permission_organization.deleted IS '是否删除'; +COMMENT ON COLUMN xs_permission_organization.create_by IS '创建人'; +COMMENT ON COLUMN xs_permission_organization.create_time IS '创建时间'; +COMMENT ON COLUMN xs_permission_organization.update_by IS '修改人'; +COMMENT ON COLUMN xs_permission_organization.update_time IS '修改时间'; +COMMENT ON COLUMN xs_permission_organization.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for xs_permission_package +-- ---------------------------- +DROP TABLE IF EXISTS xs_permission_package; +CREATE TABLE xs_permission_package ( + id BIGSERIAL PRIMARY KEY, + permission_package_name VARCHAR(64) DEFAULT NULL, + permission_package_type SMALLINT DEFAULT 1, + platform_code SMALLINT DEFAULT NULL, + status SMALLINT DEFAULT 1, + remark VARCHAR(100) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE xs_permission_package IS '标准权限包'; +COMMENT ON COLUMN xs_permission_package.id IS '主键id'; +COMMENT ON COLUMN xs_permission_package.permission_package_name IS '权限包名称'; +COMMENT ON COLUMN xs_permission_package.permission_package_type IS '类型 1.基础包 2.其他类型'; +COMMENT ON COLUMN xs_permission_package.platform_code IS '平台编码 1.业务系统 2.运营中台 3.用户中心 4.支付系统 5.在线培训 6.转发器 7.风控 8.网关 9.发号器 10.基础框架'; +COMMENT ON COLUMN xs_permission_package.status IS '状态 1.有效 2.失效'; +COMMENT ON COLUMN xs_permission_package.remark IS '备注'; +COMMENT ON COLUMN xs_permission_package.deleted IS '是否删除'; +COMMENT ON COLUMN xs_permission_package.create_by IS '创建人'; +COMMENT ON COLUMN xs_permission_package.create_time IS '创建时间'; +COMMENT ON COLUMN xs_permission_package.update_by IS '修改人'; +COMMENT ON COLUMN xs_permission_package.update_time IS '修改时间'; +COMMENT ON COLUMN xs_permission_package.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for xs_permission_resources +-- ---------------------------- +DROP TABLE IF EXISTS xs_permission_resources; +CREATE TABLE xs_permission_resources ( + id BIGSERIAL PRIMARY KEY, + permission_package_id BIGINT DEFAULT NULL, + resource_id BIGINT DEFAULT NULL, + resource_type SMALLINT DEFAULT 1, + remark VARCHAR(100) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +CREATE INDEX idx_resource_id ON xs_permission_resources(resource_id); +CREATE INDEX INDEX12372582404500 ON xs_permission_resources(permission_package_id); +COMMENT ON TABLE xs_permission_resources IS '权限包-资源关系表'; +COMMENT ON COLUMN xs_permission_resources.id IS '主键id'; +COMMENT ON COLUMN xs_permission_resources.permission_package_id IS '权限包id'; +COMMENT ON COLUMN xs_permission_resources.resource_id IS '资源id'; +COMMENT ON COLUMN xs_permission_resources.resource_type IS '类型 1.菜单 2.组件 3.接口'; +COMMENT ON COLUMN xs_permission_resources.remark IS '备注'; +COMMENT ON COLUMN xs_permission_resources.deleted IS '是否删除'; +COMMENT ON COLUMN xs_permission_resources.create_by IS '创建人'; +COMMENT ON COLUMN xs_permission_resources.create_time IS '创建时间'; +COMMENT ON COLUMN xs_permission_resources.update_by IS '修改人'; +COMMENT ON COLUMN xs_permission_resources.update_time IS '修改时间'; +COMMENT ON COLUMN xs_permission_resources.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for xs_real_name_two_verification +-- ---------------------------- +DROP TABLE IF EXISTS xs_real_name_two_verification; +CREATE TABLE xs_real_name_two_verification ( + id BIGSERIAL PRIMARY KEY, + user_id BIGINT DEFAULT NULL, + person_name VARCHAR(64) DEFAULT NULL, + identity_no VARCHAR(32) DEFAULT NULL, + status VARCHAR(2) DEFAULT 0, + authentication_source SMALLINT DEFAULT NULL, + err_msg VARCHAR(64) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); + +-- ---------------------------- +-- Table structure for xs_role +-- ---------------------------- +DROP TABLE IF EXISTS xs_role; +CREATE TABLE xs_role ( + id BIGSERIAL PRIMARY KEY, + org_id BIGINT DEFAULT NULL, + name VARCHAR(128) DEFAULT NULL, + type VARCHAR(2) DEFAULT 0, + enabled BOOLEAN NOT NULL DEFAULT FALSE, + description VARCHAR(128) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL, + standard_type VARCHAR(2) DEFAULT 1, + platform_code SMALLINT DEFAULT NULL +); +COMMENT ON TABLE xs_role IS '角色'; +COMMENT ON COLUMN xs_role.id IS '主键ID'; +COMMENT ON COLUMN xs_role.org_id IS '机构id'; +COMMENT ON COLUMN xs_role.name IS '名称'; +COMMENT ON COLUMN xs_role.type IS '类型:0业务角色、1系统角色-渠道代理商、2系统角色-普通机构'; +COMMENT ON COLUMN xs_role.enabled IS '是否启用'; +COMMENT ON COLUMN xs_role.description IS '描述'; +COMMENT ON COLUMN xs_role.deleted IS '是否删除'; +COMMENT ON COLUMN xs_role.create_by IS '创建人'; +COMMENT ON COLUMN xs_role.create_time IS '创建时间'; +COMMENT ON COLUMN xs_role.update_by IS '修改人'; +COMMENT ON COLUMN xs_role.update_time IS '修改时间'; +COMMENT ON COLUMN xs_role.proxy_by IS '代理人'; +COMMENT ON COLUMN xs_role.standard_type IS '标准角色类型:见role_standard_type'; +COMMENT ON COLUMN xs_role.platform_code IS '平台编码'; + +-- ---------------------------- +-- Table structure for xs_role_allocation +-- ---------------------------- +DROP TABLE IF EXISTS xs_role_allocation; +CREATE TABLE xs_role_allocation ( + id BIGSERIAL PRIMARY KEY, + role_id BIGINT DEFAULT NULL, + allocation_type VARCHAR(2) DEFAULT NULL, + allocation_id BIGINT DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +CREATE INDEX idx_allocation_id ON xs_role_allocation(allocation_id); +COMMENT ON TABLE xs_role_allocation IS '角色分配表'; +COMMENT ON COLUMN xs_role_allocation.id IS '主键ID'; +COMMENT ON COLUMN xs_role_allocation.role_id IS '角色id'; +COMMENT ON COLUMN xs_role_allocation.allocation_type IS '角色分配类型:1个人2部门3组'; +COMMENT ON COLUMN xs_role_allocation.allocation_id IS '角色具体分配类型对应的id'; +COMMENT ON COLUMN xs_role_allocation.deleted IS '是否删除'; +COMMENT ON COLUMN xs_role_allocation.create_by IS '创建人'; +COMMENT ON COLUMN xs_role_allocation.create_time IS '创建时间'; +COMMENT ON COLUMN xs_role_allocation.update_by IS '修改人'; +COMMENT ON COLUMN xs_role_allocation.update_time IS '修改时间'; +COMMENT ON COLUMN xs_role_allocation.proxy_by IS '代理人'; + +-- ---------------------------- +-- Table structure for xs_role_standard_type +-- ---------------------------- +DROP TABLE IF EXISTS xs_role_standard_type; +CREATE TABLE xs_role_standard_type ( + id BIGSERIAL PRIMARY KEY, + role_code VARCHAR(32) DEFAULT NULL, + name VARCHAR(64) DEFAULT NULL, + platform_code VARCHAR(32) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT NULL, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL, + type_order INTEGER DEFAULT NULL +); +COMMENT ON TABLE xs_role_standard_type IS '标准角色类型'; +COMMENT ON COLUMN xs_role_standard_type.id IS '主键'; +COMMENT ON COLUMN xs_role_standard_type.role_code IS '编码'; +COMMENT ON COLUMN xs_role_standard_type.name IS '名称'; +COMMENT ON COLUMN xs_role_standard_type.platform_code IS '平台编码'; +COMMENT ON COLUMN xs_role_standard_type.deleted IS '是否逻辑删除'; +COMMENT ON COLUMN xs_role_standard_type.create_by IS '创建人'; +COMMENT ON COLUMN xs_role_standard_type.create_time IS '创建时间'; +COMMENT ON COLUMN xs_role_standard_type.update_by IS '更新人'; +COMMENT ON COLUMN xs_role_standard_type.update_time IS '更新时间'; +COMMENT ON COLUMN xs_role_standard_type.proxy_by IS '代理人'; +COMMENT ON COLUMN xs_role_standard_type.type_order IS '排序'; + +-- ---------------------------- +-- Table structure for xs_url +-- ---------------------------- +DROP TABLE IF EXISTS xs_url; +CREATE TABLE xs_url ( + id BIGSERIAL PRIMARY KEY, + name VARCHAR(128) DEFAULT NULL, + link VARCHAR(256) DEFAULT NULL, + icon VARCHAR(32) DEFAULT NULL, + parent_id BIGINT DEFAULT NULL, + resource_order INTEGER DEFAULT NULL, + type SMALLINT DEFAULT NULL, + visible BOOLEAN DEFAULT NULL, + description VARCHAR(128) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL, + platform_code SMALLINT DEFAULT NULL +); +COMMENT ON TABLE xs_url IS '菜单地址'; +COMMENT ON COLUMN xs_url.id IS '主键ID'; +COMMENT ON COLUMN xs_url.name IS '名称'; +COMMENT ON COLUMN xs_url.link IS '链接'; +COMMENT ON COLUMN xs_url.icon IS 'icon'; +COMMENT ON COLUMN xs_url.parent_id IS '父级'; +COMMENT ON COLUMN xs_url.resource_order IS '排序'; +COMMENT ON COLUMN xs_url.type IS '资源类型 1:菜单 2:接口'; +COMMENT ON COLUMN xs_url.visible IS '是否可见'; +COMMENT ON COLUMN xs_url.description IS '描述'; +COMMENT ON COLUMN xs_url.deleted IS '是否删除'; +COMMENT ON COLUMN xs_url.create_by IS '创建人'; +COMMENT ON COLUMN xs_url.create_time IS '创建时间'; +COMMENT ON COLUMN xs_url.update_by IS '修改人'; +COMMENT ON COLUMN xs_url.update_time IS '修改时间'; +COMMENT ON COLUMN xs_url.proxy_by IS '代理人'; +COMMENT ON COLUMN xs_url.platform_code IS '平台编码'; + + + + +-- ---------------------------- +-- Table structure for x_file_category +-- ---------------------------- +DROP TABLE IF EXISTS x_file_category; +CREATE TABLE x_file_category ( + id BIGSERIAL PRIMARY KEY, + file_category VARCHAR(32) DEFAULT NULL, + file_suffix VARCHAR(32) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE x_file_category IS '文件种类'; +COMMENT ON COLUMN x_file_category.id IS '主键ID'; +COMMENT ON COLUMN x_file_category.file_category IS '文件种类'; +COMMENT ON COLUMN x_file_category.file_suffix IS '文件后缀'; +COMMENT ON COLUMN x_file_category.deleted IS '是否删除'; +COMMENT ON COLUMN x_file_category.create_by IS '创建人'; +COMMENT ON COLUMN x_file_category.create_time IS '创建时间'; +COMMENT ON COLUMN x_file_category.update_by IS '修改人'; +COMMENT ON COLUMN x_file_category.update_time IS '修改时间'; +COMMENT ON COLUMN x_file_category.proxy_by IS '代理人'; + + +-- ---------------------------- +-- Table structure for x_user_space +-- ---------------------------- +DROP TABLE IF EXISTS x_user_space; +CREATE TABLE x_user_space ( + id BIGSERIAL PRIMARY KEY, + user_id BIGINT DEFAULT NULL, + total_size BIGINT DEFAULT NULL, + used_size BIGINT DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE x_user_space IS '用户空间'; +COMMENT ON COLUMN x_user_space.id IS '主键ID'; +COMMENT ON COLUMN x_user_space.user_id IS '用户id'; +COMMENT ON COLUMN x_user_space.total_size IS '总容量'; +COMMENT ON COLUMN x_user_space.used_size IS '已使用容量'; +COMMENT ON COLUMN x_user_space.deleted IS '是否删除'; +COMMENT ON COLUMN x_user_space.create_by IS '创建人'; +COMMENT ON COLUMN x_user_space.create_time IS '创建时间'; +COMMENT ON COLUMN x_user_space.update_by IS '修改人'; +COMMENT ON COLUMN x_user_space.update_time IS '修改时间'; +COMMENT ON COLUMN x_user_space.proxy_by IS '代理人'; + + +-- ---------------------------- +-- Table structure for x_user_file +-- ---------------------------- +DROP TABLE IF EXISTS x_user_file; +CREATE TABLE x_user_file ( + id BIGSERIAL PRIMARY KEY, + user_id BIGINT DEFAULT NULL, + root_type VARCHAR(2) DEFAULT NULL, + file_type VARCHAR(32) DEFAULT NULL, + file_name VARCHAR(256) DEFAULT NULL, + parent_id BIGINT DEFAULT NULL, + file_code VARCHAR(32) DEFAULT NULL, + file_status VARCHAR(2) DEFAULT NULL, + path VARCHAR(255) DEFAULT NULL, + end_time TIMESTAMP DEFAULT NULL, + access_code VARCHAR(6) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +COMMENT ON TABLE x_user_file IS '用户文件'; +COMMENT ON COLUMN x_user_file.id IS '主键ID'; +COMMENT ON COLUMN x_user_file.user_id IS '用户id'; +COMMENT ON COLUMN x_user_file.root_type IS '根类型:1普通/2内穿外/3外传内/4我的分享'; +COMMENT ON COLUMN x_user_file.file_type IS '文件大类:1文件/2文件夹'; +COMMENT ON COLUMN x_user_file.file_name IS '文件名'; +COMMENT ON COLUMN x_user_file.parent_id IS '父id'; +COMMENT ON COLUMN x_user_file.file_code IS '文件编码'; +COMMENT ON COLUMN x_user_file.file_status IS '文件状态:1正常2失效11解析中12待审核13传输中'; +COMMENT ON COLUMN x_user_file.path IS '路径'; +COMMENT ON COLUMN x_user_file.end_time IS '有效期'; +COMMENT ON COLUMN x_user_file.access_code IS '访问码'; +COMMENT ON COLUMN x_user_file.deleted IS '是否删除'; +COMMENT ON COLUMN x_user_file.create_by IS '创建人'; +COMMENT ON COLUMN x_user_file.create_time IS '创建时间'; +COMMENT ON COLUMN x_user_file.update_by IS '修改人'; +COMMENT ON COLUMN x_user_file.update_time IS '修改时间'; +COMMENT ON COLUMN x_user_file.proxy_by IS '代理人'; + + +-- ---------------------------- +-- Table structure for x_file_risk +-- ---------------------------- +DROP TABLE IF EXISTS x_file_risk; +CREATE TABLE x_file_risk ( + id BIGSERIAL PRIMARY KEY, + file_code VARCHAR(32) DEFAULT NULL, + max_risk_level VARCHAR(2) DEFAULT NULL, + risk_json TEXT DEFAULT NULL, + dify_file_json TEXT DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL, + CONSTRAINT uk_file_code UNIQUE (file_code) +); +COMMENT ON TABLE x_file_risk IS '文件风险'; +COMMENT ON COLUMN x_file_risk.id IS '主键ID'; +COMMENT ON COLUMN x_file_risk.file_code IS '文件编码'; +COMMENT ON COLUMN x_file_risk.max_risk_level IS '最高风险等级:1重度/2中度/3轻度'; +COMMENT ON COLUMN x_file_risk.risk_json IS '风险详情JSON'; +COMMENT ON COLUMN x_file_risk.dify_file_json IS 'Dify文件上传响应JSON'; +COMMENT ON COLUMN x_file_risk.deleted IS '是否删除'; +COMMENT ON COLUMN x_file_risk.create_by IS '创建人'; +COMMENT ON COLUMN x_file_risk.create_time IS '创建时间'; +COMMENT ON COLUMN x_file_risk.update_by IS '修改人'; +COMMENT ON COLUMN x_file_risk.update_time IS '修改时间'; +COMMENT ON COLUMN x_file_risk.proxy_by IS '代理人'; + +CREATE TABLE x_upload_config ( + id BIGSERIAL PRIMARY KEY, + org_id BIGINT DEFAULT NULL, + upload_enabled BOOLEAN DEFAULT TRUE, + allow_all_type BOOLEAN DEFAULT TRUE, + allowed_suffixes VARCHAR(1024) DEFAULT NULL, + max_file_size BIGINT DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL, + CONSTRAINT uk_upload_config_org_id UNIQUE (org_id) +); +COMMENT ON TABLE x_upload_config IS '机构上传配置'; +COMMENT ON COLUMN x_upload_config.id IS '主键ID'; +COMMENT ON COLUMN x_upload_config.org_id IS '机构id'; +COMMENT ON COLUMN x_upload_config.upload_enabled IS '是否允许上传'; +COMMENT ON COLUMN x_upload_config.allow_all_type IS '是否允许全部类型(false时按allowed_suffixes白名单校验)'; +COMMENT ON COLUMN x_upload_config.allowed_suffixes IS '允许的文件后缀(逗号分隔,小写),allow_all_type=false时生效'; +COMMENT ON COLUMN x_upload_config.max_file_size IS '单文件大小上限(MB),空或0不限制'; +COMMENT ON COLUMN x_upload_config.deleted IS '是否删除'; +COMMENT ON COLUMN x_upload_config.create_by IS '创建人'; +COMMENT ON COLUMN x_upload_config.create_time IS '创建时间'; +COMMENT ON COLUMN x_upload_config.update_by IS '修改人'; +COMMENT ON COLUMN x_upload_config.update_time IS '修改时间'; +COMMENT ON COLUMN x_upload_config.proxy_by IS '代理人'; + +CREATE TABLE x_file_security ( + id BIGSERIAL PRIMARY KEY, + file_code VARCHAR(32) DEFAULT NULL, + task_id VARCHAR(64) DEFAULT NULL, + scan_status VARCHAR(2) DEFAULT NULL, + action VARCHAR(32) DEFAULT NULL, + reason VARCHAR(1024) DEFAULT NULL, + result_json TEXT DEFAULT NULL, + review_comment VARCHAR(512) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +CREATE INDEX idx_file_security_file_code ON x_file_security(file_code); +CREATE INDEX idx_file_security_scan_status ON x_file_security(scan_status); +COMMENT ON TABLE x_file_security IS '文件安全检测记录'; +COMMENT ON COLUMN x_file_security.id IS '主键ID'; +COMMENT ON COLUMN x_file_security.file_code IS '文件编码'; +COMMENT ON COLUMN x_file_security.task_id IS 'MeshSafe检测任务ID'; +COMMENT ON COLUMN x_file_security.scan_status IS '检测状态:1检测中/2通过/3不通过/4检测失败'; +COMMENT ON COLUMN x_file_security.action IS 'MeshSafe处置动作:pass/manual_review/reject'; +COMMENT ON COLUMN x_file_security.reason IS '检测结论说明'; +COMMENT ON COLUMN x_file_security.result_json IS '检测完整结果JSON'; +COMMENT ON COLUMN x_file_security.review_comment IS '人工复核说明(人工改判时有值)'; +COMMENT ON COLUMN x_file_security.deleted IS '是否删除'; +COMMENT ON COLUMN x_file_security.create_by IS '创建人'; +COMMENT ON COLUMN x_file_security.create_time IS '创建时间'; +COMMENT ON COLUMN x_file_security.update_by IS '修改人'; +COMMENT ON COLUMN x_file_security.update_time IS '修改时间'; +COMMENT ON COLUMN x_file_security.proxy_by IS '代理人'; diff --git a/backend/db/init-table.sql b/backend/db/init-table.sql new file mode 100644 index 0000000..20023cf --- /dev/null +++ b/backend/db/init-table.sql @@ -0,0 +1,1302 @@ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + + +-- ---------------------------- +-- Table structure for async_task_notice +-- ---------------------------- +DROP TABLE IF EXISTS `async_task_notice`; +CREATE TABLE `async_task_notice` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `union_type` varchar(32) NOT NULL COMMENT '关联类型:common_import等', + `union_id` bigint(20) NOT NULL COMMENT '关联id', + `content` varchar(255) NOT NULL COMMENT '内容', + `biz_status_str` varchar(32) DEFAULT NULL COMMENT '业务状态', + `biz_param_data` varchar(512) DEFAULT NULL COMMENT '业务参数', + `flow_status` tinyint(4) DEFAULT '1' COMMENT '流程状态:1开启,2结束', + `notice_status` tinyint(4) DEFAULT '1' COMMENT '通知状态:1未读,2已读', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`), + KEY `idx_create_by` (`create_by`), + KEY `idx_union` (`union_type`,`union_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='异步任务通知'; + + +-- ---------------------------- +-- Table structure for notice_content_template +-- ---------------------------- +DROP TABLE IF EXISTS `notice_content_template`; +CREATE TABLE `notice_content_template` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `template_id` bigint(20) DEFAULT NULL COMMENT '通知模版id', + `channel_type` tinyint(4) DEFAULT NULL COMMENT '消息通道类型:1站内信,2短信,3钉钉,4企业微信,5邮件(见notice_channel_type)', + `title` varchar(64) DEFAULT NULL COMMENT '标题', + `content_template` text COMMENT '内容模版', + `enabled` bit(1) DEFAULT b'1' COMMENT '是否启用', + `link` varchar(128) DEFAULT NULL COMMENT '链接', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='通知消息体模版'; + +-- ---------------------------- +-- Table structure for notice_receiver_setting +-- ---------------------------- +DROP TABLE IF EXISTS `notice_receiver_setting`; +CREATE TABLE `notice_receiver_setting` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `template_id` bigint(20) DEFAULT NULL COMMENT '通知模版id', + `org_id` bigint(20) DEFAULT NULL COMMENT '机构id', + `receiver_union_type` tinyint(4) DEFAULT NULL COMMENT '接收人关联类型:1用户id,2角色,3标准角色(见notice_receiver_type)', + `receiver_union_id` bigint(20) DEFAULT NULL COMMENT '接收人关联id:用户id,角色id,标准角色id', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='通知接收人设置'; + +-- ---------------------------- +-- Table structure for notice_send_record +-- ---------------------------- +DROP TABLE IF EXISTS `notice_send_record`; +CREATE TABLE `notice_send_record` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `template_id` bigint(20) DEFAULT NULL COMMENT '通知模版id', + `sender_org_id` bigint(20) DEFAULT NULL COMMENT '发送方机构id', + `receiver_org_id` bigint(20) DEFAULT NULL COMMENT '接收方机构id', + `content_template_id` bigint(20) DEFAULT NULL COMMENT '消息体模版id', + `content_param_data` varchar(512) DEFAULT NULL COMMENT '消息体参数', + `content` text COMMENT '消息体', + `appointed` bit(1) DEFAULT NULL COMMENT '是否指定接收方(非预先设定)', + `link` varchar(128) DEFAULT NULL COMMENT '链接', + `content_template` text COMMENT '内容模版', + `title` varchar(64) DEFAULT NULL COMMENT '标题', + `channel_type` tinyint(4) DEFAULT NULL COMMENT '消息通道类型:1站内信,2短信,3钉钉,4企业微信,5邮件(见notice_channel_type)', + `status` tinyint(4) DEFAULT NULL COMMENT '状态:1待处理,2已处理 等(见notice_send_status)', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='通知发送记录(内容模版级)'; + +-- ---------------------------- +-- Table structure for notice_send_record_detail +-- ---------------------------- +DROP TABLE IF EXISTS `notice_send_record_detail`; +CREATE TABLE `notice_send_record_detail` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `record_id` bigint(20) DEFAULT NULL COMMENT '发送记录id', + `user_id` bigint(20) DEFAULT NULL COMMENT '接收人id', + `receiver_account_no` varchar(32) DEFAULT NULL COMMENT '接收方帐号', + `receiver_status` tinyint(4) DEFAULT NULL COMMENT '接收状态:1待发送,2已发送,3发送失败,4接收已读(见notice_receiver_status)', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='通知发送记录明细(接收人)'; + +-- ---------------------------- +-- Table structure for notice_template +-- ---------------------------- +DROP TABLE IF EXISTS `notice_template`; +CREATE TABLE `notice_template` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `template_code` varchar(32) DEFAULT NULL COMMENT '通知模版code', + `template_name` varchar(64) DEFAULT NULL COMMENT '通知模版名称', + `module_type` tinyint(4) DEFAULT NULL COMMENT '模块分类:1业务,2监控/预警(见notice_module_type)', + `biz_type` tinyint(4) DEFAULT NULL COMMENT '业务分类:', + `level` tinyint(4) DEFAULT NULL COMMENT '级别:1平台,2机构(见notice_level)', + `enabled` bit(1) DEFAULT b'1' COMMENT '是否启用', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='通知模版'; + + + +-- ---------------------------- +-- Table structure for uc_action +-- ---------------------------- +DROP TABLE IF EXISTS `uc_action`; +CREATE TABLE `uc_action` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `union_type` varchar(32) DEFAULT NULL COMMENT '关联类型', + `union_id` bigint(20) DEFAULT NULL COMMENT '关联id', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='操作记录'; + +-- ---------------------------- +-- Table structure for uc_action_detail +-- ---------------------------- +DROP TABLE IF EXISTS `uc_action_detail`; +CREATE TABLE `uc_action_detail` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `action_id` bigint(20) DEFAULT NULL COMMENT '操作记录id', + `field` varchar(32) DEFAULT NULL COMMENT '属性', + `field_alias` varchar(32) DEFAULT NULL COMMENT '属性别名', + `field_dict_code` varchar(32) DEFAULT NULL COMMENT '属性字典', + `old_value` varchar(255) DEFAULT NULL COMMENT '旧值', + `new_value` varchar(255) DEFAULT NULL COMMENT '新值', + `diff` text COMMENT '差异', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='操作记录明细'; + +-- ---------------------------- +-- Table structure for uc_auth_client +-- ---------------------------- +DROP TABLE IF EXISTS `uc_auth_client`; +CREATE TABLE `uc_auth_client` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `auth_type_code` tinyint(4) DEFAULT NULL COMMENT '授权类型标识', + `client_name` varchar(32) DEFAULT NULL COMMENT '授权应用名称', + `param_data` varchar(256) DEFAULT NULL COMMENT '配置数据', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='授权客户端'; + +-- ---------------------------- +-- Table structure for uc_auth_detail +-- ---------------------------- +DROP TABLE IF EXISTS `uc_auth_detail`; +CREATE TABLE `uc_auth_detail` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `auth_client_id` bigint(20) DEFAULT NULL COMMENT '授权客户端id', + `auth_type_code` tinyint(4) DEFAULT NULL COMMENT '授权类型标识', + `nickname` varchar(32) DEFAULT NULL COMMENT '昵称', + `avatar` varchar(256) DEFAULT NULL COMMENT '头像', + `gender` varchar(2) DEFAULT NULL COMMENT '性别', + `country` varchar(32) DEFAULT NULL COMMENT '国家', + `province` varchar(32) DEFAULT NULL COMMENT '省份', + `city` varchar(32) DEFAULT NULL COMMENT '城市', + `open_id` varchar(32) DEFAULT NULL COMMENT 'open_id', + `unique_id` varchar(32) DEFAULT NULL COMMENT '授权唯一id', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='授权明细表'; + +-- ---------------------------- +-- Table structure for uc_auth_detail_entrypoint +-- ---------------------------- +DROP TABLE IF EXISTS `uc_auth_detail_entrypoint`; +CREATE TABLE `uc_auth_detail_entrypoint` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `auth_detail_id` bigint(20) DEFAULT NULL COMMENT '授权客户端id', + `union_id` bigint(20) DEFAULT NULL COMMENT '关联id(小程序码id)', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`), + KEY `idx_union_id` (`union_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='授权明细入口'; + +-- ---------------------------- +-- Table structure for uc_auth_subscribe_detail +-- ---------------------------- +DROP TABLE IF EXISTS `uc_auth_subscribe_detail`; +CREATE TABLE `uc_auth_subscribe_detail` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `auth_client_id` bigint(20) DEFAULT NULL COMMENT '授权客户端id', + `open_id` varchar(32) DEFAULT NULL COMMENT 'open_id', + `unique_id` varchar(32) DEFAULT NULL COMMENT '授权唯一id', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='授权订阅明细表'; + +-- ---------------------------- +-- Table structure for uc_auth_type +-- ---------------------------- +DROP TABLE IF EXISTS `uc_auth_type`; +CREATE TABLE `uc_auth_type` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `auth_main_type` tinyint(4) DEFAULT NULL COMMENT '授权大类:1微信,2支付宝', + `auth_type_code` tinyint(4) DEFAULT NULL COMMENT '授权类型标识', + `name` varchar(32) DEFAULT NULL COMMENT '名称', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COMMENT='授权类型'; + + + +-- ---------------------------- +-- Table structure for uc_domain +-- ---------------------------- +DROP TABLE IF EXISTS `uc_domain`; +CREATE TABLE `uc_domain` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `platform_code` tinyint(4) DEFAULT NULL COMMENT '平台编码', + `domain_name` varchar(32) DEFAULT NULL COMMENT '域名', + `ip_port` varchar(32) DEFAULT NULL COMMENT 'ip:port', + `publiced` bit(1) DEFAULT NULL COMMENT '是否公共', + `org_id` bigint(20) DEFAULT NULL COMMENT '机构id', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='域名表'; + +-- ---------------------------- +-- Table structure for uc_domain_auth +-- ---------------------------- +DROP TABLE IF EXISTS `uc_domain_auth`; +CREATE TABLE `uc_domain_auth` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `domain_id` bigint(20) DEFAULT NULL COMMENT '域名id', + `auth_type_code` tinyint(4) DEFAULT NULL COMMENT '授权类型标识', + `auth_client_id` bigint(20) DEFAULT NULL COMMENT '授权客户端id', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='域名授权表'; + +-- ---------------------------- +-- Table structure for uc_domain_setting +-- ---------------------------- +DROP TABLE IF EXISTS `uc_domain_setting`; +CREATE TABLE `uc_domain_setting` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `domain_id` bigint(20) DEFAULT NULL COMMENT '域名id', + `type` tinyint(4) DEFAULT NULL COMMENT '类型', + `remark` varchar(32) DEFAULT '' COMMENT '配置备注', + `data` text COMMENT '配置数据', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='域名配置表'; + +-- ---------------------------- +-- Table structure for uc_dynamic_table +-- ---------------------------- +DROP TABLE IF EXISTS `uc_dynamic_table`; +CREATE TABLE `uc_dynamic_table` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `table_type` varchar(32) DEFAULT NULL, + `user_id` bigint(20) DEFAULT NULL, + `column_data` text, + `deleted` bit(1) DEFAULT b'0', + `create_by` bigint(20) DEFAULT NULL, + `create_time` datetime DEFAULT CURRENT_TIMESTAMP, + `update_by` bigint(20) DEFAULT NULL, + `update_time` datetime DEFAULT NULL, + `proxy_by` bigint(20) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- ---------------------------- +-- Table structure for uc_faq +-- ---------------------------- +DROP TABLE IF EXISTS `uc_faq`; +CREATE TABLE `uc_faq` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `faq_order` int(11) DEFAULT '0' COMMENT '排序', + `faq_type` varchar(2) DEFAULT NULL COMMENT '类型', + `question` varchar(512) DEFAULT NULL COMMENT '问题', + `answer` text COMMENT '回答', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='常见问题表'; + +-- ---------------------------- +-- Table structure for uc_faq_file +-- ---------------------------- +DROP TABLE IF EXISTS `uc_faq_file`; +CREATE TABLE `uc_faq_file` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `question_id` bigint(20) DEFAULT NULL COMMENT '常见问题ID', + `file_name` varchar(256) DEFAULT NULL COMMENT '文件名称', + `file_code` varchar(32) DEFAULT NULL COMMENT '文件编码', + `file_suffix` varchar(32) DEFAULT NULL COMMENT '文件后缀', + `sort` bigint(20) DEFAULT NULL COMMENT '排序', + `description` varchar(256) DEFAULT NULL COMMENT '文件描述', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='常见问题附件关系表'; + +-- ---------------------------- +-- Table structure for uc_feedback +-- ---------------------------- +DROP TABLE IF EXISTS `uc_feedback`; +CREATE TABLE `uc_feedback` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `type` varchar(2) DEFAULT NULL COMMENT '反馈类型', + `user_id` bigint(20) DEFAULT NULL COMMENT '用户id', + `phone` varchar(32) DEFAULT NULL COMMENT '手机号', + `content` varchar(255) DEFAULT NULL COMMENT '反馈内容', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + `source_type` varchar(2) DEFAULT NULL COMMENT '来源', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='反馈表'; + +-- ---------------------------- +-- Table structure for uc_import_main +-- ---------------------------- +DROP TABLE IF EXISTS `uc_import_main`; +CREATE TABLE `uc_import_main` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `import_no` varchar(64) DEFAULT NULL COMMENT '批次号', + `type` varchar(32) DEFAULT NULL COMMENT '导入类型', + `import_status` tinyint(4) DEFAULT NULL COMMENT '导入状态:1新建,2解析失败,3校验中,4校验失败,5校验成功,6执行导入', + `total_num` int(11) DEFAULT NULL COMMENT '总数', + `success_num` int(11) DEFAULT NULL COMMENT '成功数', + `fail_msg` varchar(255) DEFAULT NULL COMMENT '失败原因', + `finish_time` datetime DEFAULT NULL COMMENT '完成时间时间', + `execute_type` tinyint(4) DEFAULT NULL COMMENT '执行类型:1.普通,2.指定外部id', + `extra_id` bigint(20) DEFAULT NULL COMMENT '外部生成id', + `file_code` varchar(32) DEFAULT NULL COMMENT '文件CODE', + `file_name` varchar(128) DEFAULT NULL COMMENT '文件名称', + `org_id` bigint(20) DEFAULT NULL COMMENT '机构ID', + `remark` varchar(255) DEFAULT NULL COMMENT '备注', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`), + KEY `idx_import_no` (`import_no`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='通用导入批次表'; + +-- ---------------------------- +-- Table structure for uc_lite_code +-- ---------------------------- +DROP TABLE IF EXISTS `uc_lite_code`; +CREATE TABLE `uc_lite_code` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `lite_code_config_id` bigint(20) DEFAULT NULL COMMENT '小程序码配置id', + `unique_code` varchar(32) DEFAULT NULL COMMENT '唯一码-uuid', + `param_value` varchar(255) DEFAULT NULL COMMENT '参数值(按参数键升序排列)(格式:**&**)', + `query_value` varchar(255) DEFAULT NULL COMMENT 'query参数值(格式:**=**&**=**)', + `file_code` varchar(32) DEFAULT NULL COMMENT '小程序码文件编码', + `url_scheme` varchar(64) DEFAULT NULL COMMENT '小程序scheme码', + `name` varchar(32) DEFAULT NULL COMMENT '名称', + `user_id` bigint(20) DEFAULT NULL COMMENT '用户id', + `org_id` bigint(20) DEFAULT NULL COMMENT '机构id', + `platform_code` tinyint(4) DEFAULT NULL COMMENT '平台编码', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='小程序码'; + +-- ---------------------------- +-- Table structure for uc_lite_code_config +-- ---------------------------- +DROP TABLE IF EXISTS `uc_lite_code_config`; +CREATE TABLE `uc_lite_code_config` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `auth_client_id` bigint(20) DEFAULT NULL COMMENT '授权客户端id', + `biz_type` tinyint(4) DEFAULT NULL COMMENT '小程序码业务类型', + `path` varchar(64) DEFAULT NULL COMMENT '路径', + `param_key` varchar(64) DEFAULT NULL COMMENT '参数键-逗号分隔', + `env_param_key` varchar(64) DEFAULT NULL COMMENT '内置环境参数键-逗号分隔', + `platform_code` tinyint(4) DEFAULT NULL COMMENT '平台编码', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='小程序码配置'; + + +-- ---------------------------- +-- Table structure for uc_org_relation +-- ---------------------------- +DROP TABLE IF EXISTS `uc_org_relation`; +CREATE TABLE `uc_org_relation` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `org_id` bigint(20) DEFAULT NULL COMMENT '机构id', + `org_type` tinyint(4) DEFAULT NULL COMMENT '类型', + `parent_id` bigint(20) DEFAULT NULL COMMENT '上级id', + `path` varchar(255) DEFAULT NULL COMMENT '路径', + `platform_code` tinyint(4) DEFAULT NULL COMMENT '平台编码', + `platform_name` varchar(32) DEFAULT NULL COMMENT '平台名称', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`), + KEY `idx_org_id` (`org_id`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT='机构关系表'; + +-- ---------------------------- +-- Table structure for uc_org_user +-- ---------------------------- +DROP TABLE IF EXISTS `uc_org_user`; +CREATE TABLE `uc_org_user` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `user_id` bigint(20) DEFAULT NULL COMMENT '用户id', + `org_id` bigint(20) DEFAULT NULL COMMENT '机构id', + `administrator` bit(1) DEFAULT NULL COMMENT '是否管理员', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`), + KEY `INDEX12378548369700` (`user_id`), + KEY `INDEX12378670651400` (`org_id`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT='机构用户表'; + +-- ---------------------------- +-- Table structure for uc_platform +-- ---------------------------- +DROP TABLE IF EXISTS `uc_platform`; +CREATE TABLE `uc_platform` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `platform_code` tinyint(4) DEFAULT NULL COMMENT '平台编码', + `name` varchar(32) DEFAULT NULL COMMENT '名称', + `full_name` varchar(32) DEFAULT NULL COMMENT '全称', + `short_name` varchar(32) DEFAULT NULL COMMENT '简称', + `business` bit(1) DEFAULT NULL COMMENT '是否业务系统', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='系统应用表'; + +-- ---------------------------- +-- Table structure for uc_slick_param +-- ---------------------------- +DROP TABLE IF EXISTS `uc_slick_param`; +CREATE TABLE `uc_slick_param` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `unique_code` varchar(32) DEFAULT NULL COMMENT '唯一码-uuid', + `query_value` varchar(255) DEFAULT NULL COMMENT 'query升序值(格式:**=**&**=**)', + `param_data` varchar(255) DEFAULT NULL COMMENT 'json', + `hash_code` int(11) DEFAULT NULL COMMENT '哈希值', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`), + KEY `idx_hash_code` (`hash_code`), + KEY `idx_unique_code` (`unique_code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='圆滑的参数'; + +-- ---------------------------- +-- Table structure for uc_user +-- ---------------------------- +DROP TABLE IF EXISTS `uc_user`; +CREATE TABLE `uc_user` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `username` varchar(32) DEFAULT NULL COMMENT '账号', + `password` varchar(128) DEFAULT NULL COMMENT '密码', + `type` tinyint(4) DEFAULT NULL COMMENT '用户类型:1企业用户,2个人用户', + `supeiror` bit(1) DEFAULT NULL COMMENT '是否超管', + `security_code` varchar(128) DEFAULT NULL COMMENT '安全码', + `nickname` varchar(32) DEFAULT NULL COMMENT '昵称', + `avatar` varchar(256) DEFAULT NULL COMMENT '头像', + `phone` varchar(32) DEFAULT NULL COMMENT '手机号码', + `phone_binding` bit(1) DEFAULT NULL COMMENT '手机号绑定状态', + `real_name` varchar(32) DEFAULT NULL COMMENT '真实姓名', + `card_no` varchar(18) DEFAULT NULL COMMENT '身份证号', + `authenticated` bit(1) DEFAULT NULL COMMENT '是否实名', + `status` tinyint(4) DEFAULT NULL COMMENT '状态:1.待激活,2已激活,3已注销', + `email` varchar(32) DEFAULT NULL COMMENT '邮箱', + `address` varchar(32) DEFAULT NULL COMMENT '用户所在地', + `education` tinyint(4) DEFAULT NULL COMMENT '1博士、2硕士、3本科、4大专、5高中、6中专/中技、7初中及以下、8不限', + `init_user_id` bigint(20) DEFAULT NULL COMMENT '初始(推荐)用户id', + `enabled` bit(1) DEFAULT NULL COMMENT '是否启用', + `account_non_expired` bit(1) DEFAULT NULL COMMENT '账号是否未过期', + `account_non_locked` bit(1) DEFAULT NULL COMMENT '是否未锁定', + `credentials_non_expired` bit(1) DEFAULT NULL COMMENT '凭据是否未过期', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + `gender` tinyint(4) DEFAULT NULL COMMENT '性别:1男2女', + `birthday` date DEFAULT NULL COMMENT '生日', + PRIMARY KEY (`id`), + KEY `idx_card_no` (`card_no`), + KEY `idx_phone` (`phone`), + KEY `idx_real_name` (`real_name`) +) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; + + + +-- ---------------------------- +-- Table structure for uc_user_auth +-- ---------------------------- +DROP TABLE IF EXISTS `uc_user_auth`; +CREATE TABLE `uc_user_auth` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `auth_main_type` tinyint(4) DEFAULT NULL COMMENT '授权大类', + `unique_id` varchar(32) DEFAULT NULL COMMENT '授权唯一id', + `user_id` bigint(20) DEFAULT NULL COMMENT '用户id', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`), + KEY `idx_unique_id` (`unique_id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='用户授权中间表'; + + + +-- ---------------------------- +-- Table structure for uc_user_cancel +-- ---------------------------- +DROP TABLE IF EXISTS `uc_user_cancel`; +CREATE TABLE `uc_user_cancel` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `user_id` bigint(20) DEFAULT NULL COMMENT '用户表ID', + `status` tinyint(4) DEFAULT '1' COMMENT '申请状态 1:已申请 2:已注销', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + `cancellation_type` varchar(2) DEFAULT NULL COMMENT '注销原因类型 数据字典', + `remark` varchar(255) DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户申请注销表'; + + +-- ---------------------------- +-- Table structure for uc_user_config +-- ---------------------------- +DROP TABLE IF EXISTS `uc_user_config`; +CREATE TABLE `uc_user_config` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `user_id` bigint(20) DEFAULT NULL COMMENT '用户id', + `config_code` varchar(64) DEFAULT NULL COMMENT '编码', + `config_value` varchar(1024) DEFAULT NULL COMMENT '配置值', + `remark` varchar(128) DEFAULT NULL COMMENT '备注', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户配置表'; + +-- ---------------------------- +-- Table structure for uc_user_extension +-- ---------------------------- +DROP TABLE IF EXISTS `uc_user_extension`; +CREATE TABLE `uc_user_extension` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `user_id` bigint(20) DEFAULT NULL COMMENT '用户id', + `technique_tag` varchar(256) DEFAULT NULL COMMENT '技能标签', + `residence_address` varchar(128) DEFAULT NULL COMMENT '常住地区', + `file_code` varchar(255) DEFAULT NULL COMMENT '简历附件编码', + `file_name` varchar(255) DEFAULT NULL COMMENT '简历附件名称', + `covid_vaccine` tinyint(4) DEFAULT NULL COMMENT '新冠疫苗:1.未接种,2.1针,3.2针,4.3针', + `wechat_qr_code` varchar(32) DEFAULT NULL COMMENT '微信二维码', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COMMENT='用户扩展表'; + +-- ---------------------------- +-- Table structure for uc_user_face +-- ---------------------------- +DROP TABLE IF EXISTS `uc_user_face`; +CREATE TABLE `uc_user_face` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `user_id` bigint(20) DEFAULT NULL COMMENT '用户ID', + `type` tinyint(4) DEFAULT NULL COMMENT '类型 1:照片 2:视频', + `file_code` varchar(32) DEFAULT NULL COMMENT '文件编码', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`), + KEY `INDEX12379510213700` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户活体信息表'; + +-- ---------------------------- +-- Table structure for uc_user_postal_info +-- ---------------------------- +DROP TABLE IF EXISTS `uc_user_postal_info`; +CREATE TABLE `uc_user_postal_info` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `defaulted` bit(1) DEFAULT NULL COMMENT '是否默认', + `name` varchar(50) DEFAULT NULL COMMENT '收货人', + `phone` varchar(50) DEFAULT NULL COMMENT '手机号', + `address_code` varchar(50) DEFAULT NULL COMMENT '地区编码', + `address_name` varchar(50) DEFAULT NULL COMMENT '地址名称', + `address_detail` varchar(100) DEFAULT NULL COMMENT '详细地址', + `deleted` bit(1) DEFAULT NULL COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户邮寄信息'; + + +-- ---------------------------- +-- Table structure for uc_user_register +-- ---------------------------- +DROP TABLE IF EXISTS `uc_user_register`; +CREATE TABLE `uc_user_register` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `platform_code` tinyint(4) DEFAULT NULL COMMENT '平台编码', + `user_id` bigint(20) DEFAULT NULL COMMENT '用户id', + `inviter_id` bigint(20) DEFAULT NULL COMMENT '邀请人id', + `inviter_type` tinyint(4) DEFAULT NULL COMMENT '邀请人用户类型', + `inviter_org_id` bigint(20) DEFAULT NULL COMMENT '邀请人机构id', + `entrypoint` varchar(32) DEFAULT NULL COMMENT '入口点', + `union_id` bigint(20) DEFAULT NULL COMMENT '关联id(小程序码id)', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`), + KEY `idx_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COMMENT='用户注册表'; + + + +-- ---------------------------- +-- Table structure for xs_chat +-- ---------------------------- +DROP TABLE IF EXISTS `xs_chat`; +CREATE TABLE `xs_chat` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `org_id` bigint(20) DEFAULT NULL COMMENT '机构id', + `org_user_id` bigint(20) DEFAULT NULL COMMENT '机构用户id', + `person_user_id` bigint(20) DEFAULT NULL COMMENT '个人用户id', + `type` varchar(32) DEFAULT NULL COMMENT '类型(chat_type)', + `status` tinyint(4) DEFAULT NULL COMMENT '状态:1有效,2关闭', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) NOT NULL COMMENT '创建人', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='聊天表'; + +-- ---------------------------- +-- Table structure for xs_chat_msg +-- ---------------------------- +DROP TABLE IF EXISTS `xs_chat_msg`; +CREATE TABLE `xs_chat_msg` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `chat_id` bigint(20) DEFAULT NULL COMMENT '聊天id', + `sender_id` bigint(20) DEFAULT NULL COMMENT '发送用户id', + `msg_type` varchar(16) DEFAULT NULL COMMENT '消息类型(chat_msg_type):text等', + `content` varchar(1024) DEFAULT NULL COMMENT '个人用户id', + `msg_status` tinyint(4) DEFAULT NULL COMMENT '消息状态:1未读,2已读', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) NOT NULL COMMENT '创建人', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='聊天消息表'; + +-- ---------------------------- +-- Table structure for xs_code_setting +-- ---------------------------- +DROP TABLE IF EXISTS `xs_code_setting`; +CREATE TABLE `xs_code_setting` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `code` varchar(64) DEFAULT NULL COMMENT '编码', + `name` varchar(128) DEFAULT NULL COMMENT '名称', + `remark` varchar(128) DEFAULT NULL COMMENT '备注', + `type` varchar(2) DEFAULT NULL COMMENT '类型 模板编码、配置编码', + `data_type` varchar(2) DEFAULT NULL COMMENT '数据类型', + `data_format` varchar(128) DEFAULT NULL COMMENT '数据格式编号', + `level` varchar(20) DEFAULT NULL COMMENT '级别 平台、渠道、定制机构、普通机构', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='编码表'; + +-- ---------------------------- +-- Table structure for xs_company_extend +-- ---------------------------- +DROP TABLE IF EXISTS `xs_company_extend`; +CREATE TABLE `xs_company_extend` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `seller_id` bigint(20) DEFAULT NULL COMMENT '销售', + `org_id` bigint(20) DEFAULT NULL COMMENT '所属机构ID', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`), + KEY `INDEX173651263650200` (`org_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='企业的扩展信息'; + +-- ---------------------------- +-- Table structure for xs_component +-- ---------------------------- +DROP TABLE IF EXISTS `xs_component`; +CREATE TABLE `xs_component` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `url_id` bigint(20) DEFAULT NULL COMMENT '菜单id', + `code` varchar(32) DEFAULT NULL COMMENT '组件编码', + `name` varchar(64) DEFAULT NULL COMMENT '组件名称', + `platform_code` tinyint(4) DEFAULT NULL COMMENT '平台编码', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='组件'; + +-- ---------------------------- +-- Table structure for xs_config +-- ---------------------------- +DROP TABLE IF EXISTS `xs_config`; +CREATE TABLE `xs_config` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `config_code` varchar(64) DEFAULT NULL COMMENT '编码', + `config_value` text COMMENT '配置值', + `org_id` bigint(20) DEFAULT NULL COMMENT '机构', + `remark` varchar(128) DEFAULT NULL COMMENT '备注', + `enable` bit(1) DEFAULT NULL COMMENT '是否启用', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COMMENT='配置表'; + +-- ---------------------------- +-- Table structure for xs_dict +-- ---------------------------- +DROP TABLE IF EXISTS `xs_dict`; +CREATE TABLE `xs_dict` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `dict_code` varchar(32) DEFAULT NULL COMMENT '字典编码', + `dict_name` varchar(64) DEFAULT NULL COMMENT '字典名称', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`), + KEY `idx_dict_code` (`dict_code`) +) ENGINE=InnoDB AUTO_INCREMENT=206 DEFAULT CHARSET=utf8mb4 COMMENT='数据字典主信息'; + +-- ---------------------------- +-- Table structure for xs_dict_detail +-- ---------------------------- +DROP TABLE IF EXISTS `xs_dict_detail`; +CREATE TABLE `xs_dict_detail` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `dict_id` bigint(20) DEFAULT NULL COMMENT '字典ID', + `dict_detail_code` varchar(64) DEFAULT NULL COMMENT '子项编码', + `dict_detail_name` varchar(128) DEFAULT NULL COMMENT '子项名称', + `dict_order` int(11) DEFAULT NULL COMMENT '排序', + `parent_id` bigint(20) DEFAULT NULL COMMENT '父子项ID', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`), + KEY `idx_dict_id` (`dict_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1583 DEFAULT CHARSET=utf8mb4 COMMENT='数据字典明细信息'; + +-- ---------------------------- +-- Table structure for xs_district +-- ---------------------------- +DROP TABLE IF EXISTS `xs_district`; +CREATE TABLE `xs_district` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `name` varchar(32) DEFAULT NULL COMMENT '城市名称', + `parent_id` bigint(20) DEFAULT NULL COMMENT '上级城市ID', + `initial` varchar(32) DEFAULT NULL COMMENT '首字母', + `initials` varchar(32) DEFAULT NULL COMMENT '简拼', + `pinyin` varchar(32) DEFAULT NULL COMMENT '全拼', + `extra` varchar(32) DEFAULT NULL COMMENT '特别行政区', + `suffix` varchar(32) DEFAULT NULL COMMENT '后缀', + `code` varchar(32) DEFAULT NULL COMMENT '城市编码', + `area_code` varchar(32) DEFAULT NULL COMMENT '区域编码', + `district_order` int(11) DEFAULT NULL COMMENT '排序', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + `level` int(11) DEFAULT NULL COMMENT '层级', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='省份城市'; + +-- ---------------------------- +-- Table structure for xs_file_record +-- ---------------------------- +DROP TABLE IF EXISTS `xs_file_record`; +CREATE TABLE `xs_file_record` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `file_code` varchar(64) DEFAULT NULL COMMENT '文件编码', + `file_path` varchar(512) DEFAULT NULL COMMENT '文件路径', + `file_name` varchar(128) DEFAULT NULL COMMENT '文件名', + `file_size` int(11) DEFAULT NULL COMMENT '文件大小', + `md5_code` varchar(64) DEFAULT NULL COMMENT '文件MD5', + `file_suffix` varchar(32) DEFAULT NULL COMMENT '文件后缀', + `org_id` bigint(20) DEFAULT NULL COMMENT '所属机构', + `storage_type` varchar(32) DEFAULT NULL COMMENT '储存器类型', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`), + KEY `idx_file_code` (`file_code`) +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COMMENT='附件信息'; + +-- ---------------------------- +-- Table structure for xs_org +-- ---------------------------- +DROP TABLE IF EXISTS `xs_org`; +CREATE TABLE `xs_org` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `org_name` varchar(32) DEFAULT NULL COMMENT '机构名称', + `org_code` varchar(64) DEFAULT NULL COMMENT '机构编号', + `type` varchar(2) DEFAULT NULL COMMENT '机构类型(1.平台 2.渠道代理商 3.普通机构 4.定制机构 5.散户机构 6.产品机构)', + `address_code` varchar(16) DEFAULT NULL COMMENT '任务地点编码', + `address_name` varchar(128) DEFAULT NULL COMMENT '任务地点全称', + `description` varchar(1024) DEFAULT NULL COMMENT '机构描述', + `quality` bit(1) DEFAULT b'0' COMMENT '是否优质企业', + `enable` bit(1) DEFAULT NULL COMMENT '是否启用', + `activated` bit(1) DEFAULT b'0' COMMENT '是否激活', + `parent_id` bigint(20) DEFAULT NULL COMMENT '父机构ID', + `credit_code` varchar(64) DEFAULT NULL COMMENT '统一社会信用代码', + `trade` varchar(2) DEFAULT NULL COMMENT '所属行业', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + `activation_code` varchar(32) DEFAULT NULL COMMENT '机构账号激活码', + `phone` varchar(32) DEFAULT NULL COMMENT '手机号码', + `query_children` bit(1) DEFAULT NULL COMMENT '是否能查看下级数据', + `org_logo` varchar(64) DEFAULT NULL COMMENT '企业logo', + `registered_address` varchar(128) DEFAULT NULL COMMENT '注册地址', + `company_size` varchar(32) DEFAULT NULL COMMENT '规模 数据字典', + `business_license` varchar(64) DEFAULT NULL COMMENT '营业执照', + `recruit_position_type` varchar(2) NOT NULL DEFAULT '1' COMMENT '招聘岗位类型', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT='机构'; + +-- ---------------------------- +-- Table structure for xs_org_user +-- ---------------------------- +DROP TABLE IF EXISTS `xs_org_user`; +CREATE TABLE `xs_org_user` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `org_id` bigint(20) DEFAULT NULL COMMENT '机构id', + `user_id` bigint(20) DEFAULT NULL COMMENT '用户id', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='机构用户'; + +-- ---------------------------- +-- Table structure for xs_permission +-- ---------------------------- +DROP TABLE IF EXISTS `xs_permission`; +CREATE TABLE `xs_permission` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `role_id` bigint(20) DEFAULT NULL COMMENT '角色id', + `resource_type` varchar(2) DEFAULT NULL COMMENT '资源类型:1菜单 2组件 3接口', + `resource_id` bigint(20) DEFAULT NULL COMMENT '资源id', + `attribute` varchar(32) DEFAULT NULL COMMENT '权限鉴别属性,默认格式:ROLE_{roleId},可以扩展', + `org_id` bigint(20) DEFAULT NULL COMMENT '机构id', + `platform_code` tinyint(4) DEFAULT NULL COMMENT '平台编码 1.业务系统 2.运营中台 3.用户中心 4.支付系统 5.在线培训 6.转发器 7.风控 8.网关 9.发号器 10.基础框架', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限表'; + +-- ---------------------------- +-- Table structure for xs_permission_organization +-- ---------------------------- +DROP TABLE IF EXISTS `xs_permission_organization`; +CREATE TABLE `xs_permission_organization` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', + `permission_package_id` bigint(20) DEFAULT NULL COMMENT '权限包id', + `allocation_org_id` bigint(20) DEFAULT NULL COMMENT '分配机构orgid', + `remark` varchar(100) DEFAULT NULL COMMENT '备注', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`), + KEY `idx_allocation_org_id` (`allocation_org_id`), + KEY `idx_permission_package_id` (`permission_package_id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COMMENT='权限包-机构关系表'; + +-- ---------------------------- +-- Table structure for xs_permission_package +-- ---------------------------- +DROP TABLE IF EXISTS `xs_permission_package`; +CREATE TABLE `xs_permission_package` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', + `permission_package_name` varchar(64) DEFAULT NULL COMMENT '权限包名称', + `permission_package_type` tinyint(4) DEFAULT '1' COMMENT '类型 1.基础包 2.其他类型', + `platform_code` tinyint(4) DEFAULT NULL COMMENT '平台编码 1.业务系统 2.运营中台 3.用户中心 4.支付系统 5.在线培训 6.转发器 7.风控 8.网关 9.发号器 10.基础框架', + `status` tinyint(4) DEFAULT '1' COMMENT '状态 1.有效 2.失效', + `remark` varchar(100) DEFAULT NULL COMMENT '备注', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COMMENT='标准权限包'; + +-- ---------------------------- +-- Table structure for xs_permission_resources +-- ---------------------------- +DROP TABLE IF EXISTS `xs_permission_resources`; +CREATE TABLE `xs_permission_resources` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', + `permission_package_id` bigint(20) DEFAULT NULL COMMENT '权限包id', + `resource_id` bigint(20) DEFAULT NULL COMMENT '资源id', + `resource_type` tinyint(4) DEFAULT '1' COMMENT '类型 1.菜单 2.组件 3.接口', + `remark` varchar(100) DEFAULT NULL COMMENT '备注', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`), + KEY `idx_resource_id` (`resource_id`), + KEY `INDEX12372582404500` (`permission_package_id`) +) ENGINE=InnoDB AUTO_INCREMENT=43 DEFAULT CHARSET=utf8mb4 COMMENT='权限包-资源关系表'; + + +-- ---------------------------- +-- Table structure for xs_role +-- ---------------------------- +DROP TABLE IF EXISTS `xs_role`; +CREATE TABLE `xs_role` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `org_id` bigint(20) DEFAULT NULL COMMENT '机构id', + `name` varchar(128) DEFAULT NULL COMMENT '名称', + `type` varchar(2) DEFAULT '0' COMMENT '类型:0业务角色、1系统角色-渠道代理商、2系统角色-普通机构', + `enabled` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否启用', + `description` varchar(128) DEFAULT NULL COMMENT '描述', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + `standard_type` varchar(2) DEFAULT '1' COMMENT '标准角色类型:见role_standard_type', + `platform_code` tinyint(4) DEFAULT NULL COMMENT '平台编码', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色'; + +-- ---------------------------- +-- Table structure for xs_role_allocation +-- ---------------------------- +DROP TABLE IF EXISTS `xs_role_allocation`; +CREATE TABLE `xs_role_allocation` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `role_id` bigint(20) DEFAULT NULL COMMENT '角色id', + `allocation_type` varchar(2) DEFAULT NULL COMMENT '角色分配类型:1个人2部门3组', + `allocation_id` bigint(20) DEFAULT NULL COMMENT '角色具体分配类型对应的id', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`), + KEY `idx_allocation_id` (`allocation_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色分配表'; + +-- ---------------------------- +-- Table structure for xs_role_standard_type +-- ---------------------------- +DROP TABLE IF EXISTS `xs_role_standard_type`; +CREATE TABLE `xs_role_standard_type` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `role_code` varchar(32) DEFAULT NULL COMMENT '编码', + `name` varchar(64) DEFAULT NULL COMMENT '名称', + `platform_code` varchar(32) DEFAULT NULL COMMENT '平台编码', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否逻辑删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + `type_order` int(11) DEFAULT NULL COMMENT '排序', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COMMENT='标准角色类型'; + +-- ---------------------------- +-- Table structure for xs_url +-- ---------------------------- +DROP TABLE IF EXISTS `xs_url`; +CREATE TABLE `xs_url` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `name` varchar(128) DEFAULT NULL COMMENT '名称', + `link` varchar(256) DEFAULT NULL COMMENT '链接', + `icon` varchar(32) DEFAULT NULL COMMENT 'icon', + `parent_id` bigint(20) DEFAULT NULL COMMENT '父级', + `resource_order` int(11) DEFAULT NULL COMMENT '排序', + `type` tinyint(4) DEFAULT NULL COMMENT '资源类型 1:菜单 2:接口', + `visible` bit(1) DEFAULT NULL COMMENT '是否可见', + `description` varchar(128) DEFAULT NULL COMMENT '描述', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + `platform_code` tinyint(4) DEFAULT NULL COMMENT '平台编码', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8mb4 COMMENT='菜单地址'; + + + + + + +CREATE TABLE `x_file_category` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `file_category` varchar(32) DEFAULT NULL COMMENT '文件种类', + `file_suffix` varchar(32) DEFAULT NULL COMMENT '文件后缀', + + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件种类'; + +CREATE TABLE `x_user_space` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `user_id` bigint(20) DEFAULT NULL COMMENT '用户id', + `total_size` bigint DEFAULT NULL COMMENT '总容量', + `used_size` bigint DEFAULT NULL COMMENT '已使用容量', + + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户空间'; + +CREATE TABLE `x_user_file` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `user_id` bigint(20) DEFAULT NULL COMMENT '用户id', + `root_type` varchar(2) DEFAULT NULL COMMENT '根类型:1普通/2内穿外/3外传内/4我的分享', + `file_type` varchar(32) DEFAULT NULL COMMENT '文件大类:1文件/2文件夹', + `file_name` varchar(256) DEFAULT NULL COMMENT '文件名', + `parent_id` bigint(20) DEFAULT NULL COMMENT '父id', + `file_code` varchar(32) DEFAULT NULL COMMENT '文件编码', + `file_status` varchar(2) DEFAULT NULL COMMENT '文件状态:1正常2失效11解析中12待审核13传输中', + `path` varchar(255) DEFAULT NULL COMMENT '路径', + `end_time` datetime DEFAULT NULL COMMENT '有效期', + `access_code` varchar(6) DEFAULT NULL COMMENT '访问码', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户文件'; + +CREATE TABLE `x_file_risk` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `file_code` varchar(32) DEFAULT NULL COMMENT '文件编码', + `max_risk_level` varchar(2) DEFAULT NULL COMMENT '最高风险等级:1重度/2中度/3轻度', + `risk_json` text DEFAULT NULL COMMENT '风险详情JSON', + `dify_file_json` text DEFAULT NULL COMMENT 'Dify文件上传响应JSON', + + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE KEY `uk_file_code` (`file_code`) USING BTREE COMMENT '文件编码唯一索引' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件风险'; + + + +CREATE TABLE `x_upload_config` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `org_id` bigint(20) DEFAULT NULL COMMENT '机构id', + `upload_enabled` bit(1) DEFAULT b'1' COMMENT '是否允许上传', + `allow_all_type` bit(1) DEFAULT b'1' COMMENT '是否允许全部类型(false时按allowed_suffixes白名单校验)', + `allowed_suffixes` varchar(1024) DEFAULT NULL COMMENT '允许的文件后缀(逗号分隔,小写),allow_all_type=false时生效', + `max_file_size` bigint(20) DEFAULT NULL COMMENT '单文件大小上限(MB),空或0不限制', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE KEY `uk_org_id` (`org_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='机构上传配置'; + + +CREATE TABLE `x_file_security` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `file_code` varchar(32) DEFAULT NULL COMMENT '文件编码', + `task_id` varchar(64) DEFAULT NULL COMMENT 'MeshSafe检测任务ID', + `scan_status` varchar(2) DEFAULT NULL COMMENT '检测状态:1检测中/2通过/3不通过/4检测失败', + `action` varchar(32) DEFAULT NULL COMMENT 'MeshSafe处置动作:pass/manual_review/reject', + `reason` varchar(1024) DEFAULT NULL COMMENT '检测结论说明', + `result_json` text DEFAULT NULL COMMENT '检测完整结果JSON', + `review_comment` varchar(512) DEFAULT NULL COMMENT '人工复核说明(人工改判时有值)', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) USING BTREE, + KEY `idx_file_security_file_code` (`file_code`) USING BTREE, + KEY `idx_file_security_scan_status` (`scan_status`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件安全检测记录'; + +SET FOREIGN_KEY_CHECKS = 1; \ No newline at end of file diff --git a/backend/db/upgrade-20260914-upload-config.sql b/backend/db/upgrade-20260914-upload-config.sql new file mode 100644 index 0000000..35a16dd --- /dev/null +++ b/backend/db/upgrade-20260914-upload-config.sql @@ -0,0 +1,62 @@ +-- ============================================================= +-- 升级脚本:机构上传配置(文件上传类型/大小限制) +-- 日期:2026-09-14 +-- 说明:新增 x_upload_config 表(一行对应一个机构)。 +-- 机构管理员可配置本机构允许上传的文件后缀白名单、 +-- 单文件大小上限、上传总开关;未配置的机构默认允许全部。 +-- 拦截点:网盘上传落库(normal_user_file/create)。 +-- 执行方式:MySQL/达梦(DM8 MySQL兼容模式)执行第 1 节; +-- PostgreSQL 执行第 2 节。 +-- ============================================================= + +-- ------------------------------------------------------------- +-- 1. MySQL / 达梦 DM8 +-- ------------------------------------------------------------- +CREATE TABLE `x_upload_config` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `org_id` bigint(20) DEFAULT NULL COMMENT '机构id', + `upload_enabled` bit(1) DEFAULT b'1' COMMENT '是否允许上传', + `allow_all_type` bit(1) DEFAULT b'1' COMMENT '是否允许全部类型(false时按allowed_suffixes白名单校验)', + `allowed_suffixes` varchar(1024) DEFAULT NULL COMMENT '允许的文件后缀(逗号分隔,小写),allow_all_type=false时生效', + `max_file_size` bigint(20) DEFAULT NULL COMMENT '单文件大小上限(MB),空或0不限制', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE KEY `uk_org_id` (`org_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='机构上传配置'; + +-- ------------------------------------------------------------- +-- 2. PostgreSQL +-- ------------------------------------------------------------- +CREATE TABLE x_upload_config ( + id BIGSERIAL PRIMARY KEY, + org_id BIGINT DEFAULT NULL, + upload_enabled BOOLEAN DEFAULT TRUE, + allow_all_type BOOLEAN DEFAULT TRUE, + allowed_suffixes VARCHAR(1024) DEFAULT NULL, + max_file_size BIGINT DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL, + CONSTRAINT uk_upload_config_org_id UNIQUE (org_id) +); +COMMENT ON TABLE x_upload_config IS '机构上传配置'; +COMMENT ON COLUMN x_upload_config.id IS '主键ID'; +COMMENT ON COLUMN x_upload_config.org_id IS '机构id'; +COMMENT ON COLUMN x_upload_config.upload_enabled IS '是否允许上传'; +COMMENT ON COLUMN x_upload_config.allow_all_type IS '是否允许全部类型(false时按allowed_suffixes白名单校验)'; +COMMENT ON COLUMN x_upload_config.allowed_suffixes IS '允许的文件后缀(逗号分隔,小写),allow_all_type=false时生效'; +COMMENT ON COLUMN x_upload_config.max_file_size IS '单文件大小上限(MB),空或0不限制'; +COMMENT ON COLUMN x_upload_config.deleted IS '是否删除'; +COMMENT ON COLUMN x_upload_config.create_by IS '创建人'; +COMMENT ON COLUMN x_upload_config.create_time IS '创建时间'; +COMMENT ON COLUMN x_upload_config.update_by IS '修改人'; +COMMENT ON COLUMN x_upload_config.update_time IS '修改时间'; +COMMENT ON COLUMN x_upload_config.proxy_by IS '代理人'; diff --git a/backend/db/upgrade-20260915-release.sql b/backend/db/upgrade-20260915-release.sql new file mode 100644 index 0000000..e61f122 --- /dev/null +++ b/backend/db/upgrade-20260915-release.sql @@ -0,0 +1,90 @@ +-- ===================================================================== +-- s-file 上线数据库脚本(2026-09-15 版本) +-- 适用场景:已有生产库升级(老版本 → 当前版本) +-- +-- 本次版本(用户启停/注销、机构账号查询、手机号查记录、机构上传配置) +-- 相对老版本的数据库变更只有一项: +-- 新增表 x_upload_config(机构上传配置) +-- 其余功能(启停/注销/查询)全部复用已有表字段,无需任何变更。 +-- +-- 【执行说明】 +-- * 生产主力库为达梦 DM8(MySQL 兼容模式)→ 只执行【第一部分】 +-- * 若目标库是 PostgreSQL → 只执行【第二部分】 +-- * 执行前建议备份;执行后核对【第三部分】的验证 SQL +-- * 可重复执行(幂等):表已存在时再执行会报"已存在"错误,属正常, +-- 说明该脚本已执行过,无需处理 +-- ===================================================================== + + +-- ===================================================================== +-- 第一部分:达梦 DM8 / MySQL +-- ===================================================================== + +CREATE TABLE x_upload_config ( + id BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID', + org_id BIGINT DEFAULT NULL COMMENT '机构id', + upload_enabled BIT(1) DEFAULT b'1' COMMENT '是否允许上传', + allow_all_type BIT(1) DEFAULT b'1' COMMENT '是否允许全部类型(false时按allowed_suffixes白名单校验)', + allowed_suffixes VARCHAR(1024) DEFAULT NULL COMMENT '允许的文件后缀(逗号分隔,小写),allow_all_type=false时生效', + max_file_size BIGINT DEFAULT NULL COMMENT '单文件大小上限(MB),空或0不限制', + deleted BIT(1) DEFAULT b'0' COMMENT '是否删除', + create_by BIGINT DEFAULT NULL COMMENT '创建人', + create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + update_by BIGINT DEFAULT NULL COMMENT '修改人', + update_time DATETIME DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + proxy_by BIGINT DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (id) USING BTREE, + UNIQUE KEY uk_org_id (org_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='机构上传配置'; + +-- 说明:不需要初始化数据。 +-- 未配置的机构 = 默认策略(允许上传全部类型、不限大小), +-- 由各机构管理员在管理后台"上传配置"页面自行配置后落库。 + + +-- ===================================================================== +-- 第二部分:PostgreSQL +-- ===================================================================== + +-- CREATE TABLE x_upload_config ( +-- id BIGSERIAL PRIMARY KEY, +-- org_id BIGINT DEFAULT NULL, +-- upload_enabled BOOLEAN DEFAULT TRUE, +-- allow_all_type BOOLEAN DEFAULT TRUE, +-- allowed_suffixes VARCHAR(1024) DEFAULT NULL, +-- max_file_size BIGINT DEFAULT NULL, +-- deleted BOOLEAN DEFAULT FALSE, +-- create_by BIGINT DEFAULT NULL, +-- create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, +-- update_by BIGINT DEFAULT NULL, +-- update_time TIMESTAMP DEFAULT NULL, +-- proxy_by BIGINT DEFAULT NULL, +-- CONSTRAINT uk_upload_config_org_id UNIQUE (org_id) +-- ); +-- COMMENT ON TABLE x_upload_config IS '机构上传配置'; +-- COMMENT ON COLUMN x_upload_config.id IS '主键ID'; +-- COMMENT ON COLUMN x_upload_config.org_id IS '机构id'; +-- COMMENT ON COLUMN x_upload_config.upload_enabled IS '是否允许上传'; +-- COMMENT ON COLUMN x_upload_config.allow_all_type IS '是否允许全部类型(false时按allowed_suffixes白名单校验)'; +-- COMMENT ON COLUMN x_upload_config.allowed_suffixes IS '允许的文件后缀(逗号分隔,小写),allow_all_type=false时生效'; +-- COMMENT ON COLUMN x_upload_config.max_file_size IS '单文件大小上限(MB),空或0不限制'; +-- COMMENT ON COLUMN x_upload_config.deleted IS '是否删除'; +-- COMMENT ON COLUMN x_upload_config.create_by IS '创建人'; +-- COMMENT ON COLUMN x_upload_config.create_time IS '创建时间'; +-- COMMENT ON COLUMN x_upload_config.update_by IS '修改人'; +-- COMMENT ON COLUMN x_upload_config.update_time IS '修改时间'; +-- COMMENT ON COLUMN x_upload_config.proxy_by IS '代理人'; + + +-- ===================================================================== +-- 第三部分:执行后验证(达梦/MySQL 语法) +-- ===================================================================== + +-- 1) 表存在且为空(0 行正常) +-- SELECT COUNT(*) FROM x_upload_config; + +-- 2) 唯一约束存在(应返回 uk_org_id) +-- SELECT INDEX_NAME FROM USER_INDEXES WHERE TABLE_NAME = 'X_UPLOAD_CONFIG'; + +-- 3) (可选)回滚脚本 —— 如需回滚上线: +-- DROP TABLE x_upload_config; diff --git a/backend/db/upgrade-20261101-meshsafe-file-security.sql b/backend/db/upgrade-20261101-meshsafe-file-security.sql new file mode 100644 index 0000000..8b0277d --- /dev/null +++ b/backend/db/upgrade-20261101-meshsafe-file-security.sql @@ -0,0 +1,71 @@ +-- ============================================================= +-- 升级脚本:MeshSafe 文件安全检测对接 +-- 日期:2026-11-01 +-- 说明:新增 x_file_security 表(按文件编码维度记录安全检测结果)。 +-- 文件上传/传输接收解包后自动提交 MeshSafe 检测, +-- 检测结论(通过/不通过)回写本表;同一文件允许多条检测 +-- 记录(人工复核、重新检测均新增记录),业务取最新一条生效。 +-- 检测不通过的文件禁止分享与跨网传输(下载预览不受限)。 +-- 执行方式:MySQL/达梦(DM8 MySQL兼容模式)执行第 1 节; +-- PostgreSQL 执行第 2 节。 +-- ============================================================= + +-- ------------------------------------------------------------- +-- 1. MySQL / 达梦 DM8 +-- ------------------------------------------------------------- +CREATE TABLE `x_file_security` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `file_code` varchar(32) DEFAULT NULL COMMENT '文件编码', + `task_id` varchar(64) DEFAULT NULL COMMENT 'MeshSafe检测任务ID', + `scan_status` varchar(2) DEFAULT NULL COMMENT '检测状态:1检测中/2通过/3不通过/4检测失败', + `action` varchar(32) DEFAULT NULL COMMENT 'MeshSafe处置动作:pass/manual_review/reject', + `reason` varchar(1024) DEFAULT NULL COMMENT '检测结论说明', + `result_json` text DEFAULT NULL COMMENT '检测完整结果JSON', + `review_comment` varchar(512) DEFAULT NULL COMMENT '人工复核说明(人工改判时有值)', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人', + PRIMARY KEY (`id`) USING BTREE, + KEY `idx_file_security_file_code` (`file_code`) USING BTREE, + KEY `idx_file_security_scan_status` (`scan_status`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件安全检测记录'; + +-- ------------------------------------------------------------- +-- 2. PostgreSQL +-- ------------------------------------------------------------- +CREATE TABLE x_file_security ( + id BIGSERIAL PRIMARY KEY, + file_code VARCHAR(32) DEFAULT NULL, + task_id VARCHAR(64) DEFAULT NULL, + scan_status VARCHAR(2) DEFAULT NULL, + action VARCHAR(32) DEFAULT NULL, + reason VARCHAR(1024) DEFAULT NULL, + result_json TEXT DEFAULT NULL, + review_comment VARCHAR(512) DEFAULT NULL, + deleted BOOLEAN DEFAULT FALSE, + create_by BIGINT DEFAULT NULL, + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by BIGINT DEFAULT NULL, + update_time TIMESTAMP DEFAULT NULL, + proxy_by BIGINT DEFAULT NULL +); +CREATE INDEX idx_file_security_file_code ON x_file_security(file_code); +CREATE INDEX idx_file_security_scan_status ON x_file_security(scan_status); +COMMENT ON TABLE x_file_security IS '文件安全检测记录'; +COMMENT ON COLUMN x_file_security.id IS '主键ID'; +COMMENT ON COLUMN x_file_security.file_code IS '文件编码'; +COMMENT ON COLUMN x_file_security.task_id IS 'MeshSafe检测任务ID'; +COMMENT ON COLUMN x_file_security.scan_status IS '检测状态:1检测中/2通过/3不通过/4检测失败'; +COMMENT ON COLUMN x_file_security.action IS 'MeshSafe处置动作:pass/manual_review/reject'; +COMMENT ON COLUMN x_file_security.reason IS '检测结论说明'; +COMMENT ON COLUMN x_file_security.result_json IS '检测完整结果JSON'; +COMMENT ON COLUMN x_file_security.review_comment IS '人工复核说明(人工改判时有值)'; +COMMENT ON COLUMN x_file_security.deleted IS '是否删除'; +COMMENT ON COLUMN x_file_security.create_by IS '创建人'; +COMMENT ON COLUMN x_file_security.create_time IS '创建时间'; +COMMENT ON COLUMN x_file_security.update_by IS '修改人'; +COMMENT ON COLUMN x_file_security.update_time IS '修改时间'; +COMMENT ON COLUMN x_file_security.proxy_by IS '代理人'; diff --git a/backend/docker-test/application-local.yml b/backend/docker-test/application-local.yml new file mode 100644 index 0000000..b55be82 --- /dev/null +++ b/backend/docker-test/application-local.yml @@ -0,0 +1,118 @@ +server: + port: 8081 + +spring: + application: + name: s-file + datasource: + url: jdbc:postgresql://127.0.0.1:54330/s_file + driver-class-name: org.postgresql.Driver + username: sfile + password: sfile123 + druid: + initial-size: 2 + min-idle: 2 + max-active: 10 + validation-query: SELECT 1 + redis: + host: 127.0.0.1 + port: 63800 + timeout: 5000 + lettuce: + pool: + max-active: 8 + max-idle: 4 + rabbitmq: + host: 127.0.0.1 + port: 56730 + username: sfile + password: sfile123 + servlet: + multipart: + max-file-size: 500MB + max-request-size: 500MB + main: + allow-bean-definition-overriding: true + +mybatis-plus: + mapper-locations: classpath*:com/senmesh/**/mapper/*.xml + +# 平台编码(init-data 中 uc_platform.platform_code=1) +system: + code: 1 + +# 发号器雪花 workerId(键格式: code.snowflake.workid.<本机IP>,方括号与裸键双写兼容) +"[code.snowflake.workid.192.168.71.85]": 1 +"[code.snowflake.workid.172.27.160.1]": 1 +"[code.snowflake.workid.172.28.16.1]": 1 +"[code.snowflake.workid.127.0.0.1]": 1 +code.snowflake.workid.192.168.71.85: 1 +code.snowflake.workid.172.27.160.1: 1 +code.snowflake.workid.172.28.16.1: 1 +code.snowflake.workid.127.0.0.1: 1 + +security: + jwt: + enable: true + secret: sfile-local-test-secret-key-please-change-0123456789abcdef + expiration: 86400000 + header: Authorization + ignoring: /error,/favicon.ico + login-page: /login + superior-only: false + use-local: true + allow-if-all-abstain-decisions: true + oauth2: + enable: false + not-logs: "" + +# 新用户初始密码 +user: + default: + password: Qaz123567!@# + +file: + upload-dir: D:/zcodedata/sfile/upload + storage: + type: local + transfer: + # 内网侧 + location: "1" + send-dir: D:/zcodedata/sfile/transfer/send + receive-dir: D:/zcodedata/sfile/transfer/receive + unpack-risk-check: false + +dify: + risk: + rule: + api-key: test-rule-key + scan: + api-key: test-scan-key + +# MeshSafe 文件安全检测(对接本地 MeshSafe venv 实例,端口 48443) +# enabled=false 完全关闭检测:不送检/不拦截/预检返回空/前端隐藏检测列 +meshsafe: + enabled: true + base-url: http://127.0.0.1:48443 + client-id: test-client + secret: test-secret + channel: sfile-local + timeout-seconds: 120 + fail-open: true + poll-timeout-minutes: 60 + review-sync-to-meshsafe: true + poll: + cron: "0 */10 * * * ?" + +rabbitmq: + custom: + topic-exchange-name: s-file-local-topic + delayed-exchange-name: s-file-local-delayed + broadcast-id: s-file-local-broadcast + +swagger: + enable: true + +logging: + level: + com.senmesh: info diff --git a/backend/docker-test/application.yml b/backend/docker-test/application.yml new file mode 100644 index 0000000..364fdfc --- /dev/null +++ b/backend/docker-test/application.yml @@ -0,0 +1,108 @@ +server: + port: 8080 + +spring: + application: + name: s-file + datasource: + url: jdbc:postgresql://sfile-pg:5432/s_file + driver-class-name: org.postgresql.Driver + username: postgres + password: sfile123 + druid: + initial-size: 2 + min-idle: 2 + max-active: 10 + validation-query: SELECT 1 + redis: + host: sfile-redis + port: 6379 + timeout: 5000 + lettuce: + pool: + max-active: 8 + max-idle: 4 + rabbitmq: + host: sfile-mq + port: 5672 + username: guest + password: guest + servlet: + multipart: + max-file-size: 500MB + max-request-size: 500MB + main: + allow-bean-definition-overriding: true + +mybatis-plus: + mapper-locations: classpath*:com/senmesh/**/mapper/*.xml + +# 平台编码(init-data 中 uc_platform.platform_code=1) +system: + code: 1 + +# 发号器雪花 workerId(键格式: code.snowflake.workid.<容器IP>) +"[code.snowflake.workid.172.20.0.10]": 1 + +security: + jwt: + enable: true + secret: sfile-functional-test-secret-key-please-change-0123456789abcdef + expiration: 86400000 + header: Authorization + ignoring: /error,/favicon.ico + login-page: /login + superior-only: false + use-local: true + allow-if-all-abstain-decisions: true + oauth2: + enable: false + not-logs: "" + +# 新用户初始密码 +user: + default: + password: Qaz123567!@# + +file: + upload-dir: /data/upload + storage: + type: local + transfer: + # 内网侧 + location: "1" + send-dir: /data/transfer/send + receive-dir: /data/transfer/receive + unpack-risk-check: false + +dify: + risk: + rule: + api-key: test-rule-key + scan: + api-key: test-scan-key + +# MeshSafe 文件安全检测(上传/接收解包后自动送检,不通过禁止分享传输) +meshsafe: + enabled: false + base-url: https://meshsafe.internal + client-id: s-file + secret: change-me + channel: default + timeout-seconds: 120 + fail-open: true + poll-timeout-minutes: 60 + review-sync-to-meshsafe: true + +rabbitmq: + custom: + topic-exchange-name: s-file-test-topic + delayed-exchange-name: s-file-test-delayed + broadcast-id: s-file-test-broadcast + +swagger: + enable: false + +logging: + level: + com.senmesh: info diff --git a/backend/docs/接口文档-文件安全检测.md b/backend/docs/接口文档-文件安全检测.md new file mode 100644 index 0000000..f3bf2f0 --- /dev/null +++ b/backend/docs/接口文档-文件安全检测.md @@ -0,0 +1,171 @@ +# 前端接口文档 —— 文件安全检测(MeshSafe 对接) + +> 版本:v1.0(2026-11-01) +> 适用后端:s-file(alita-bjy-uygur) +> Swagger 分组:「文件安全检测」 + +## 功能说明 + +对接独立文件安全检测服务 **MeshSafe**:文件上传(网盘上传)与跨网传输接收解包后,自动提交 MeshSafe 检测,检测结论回写到本系统并标记在文件上。 + +核心规则: + +- **检测不通过(误报可复核)**:文件**只能查看/下载/预览**,**禁止分享与跨网传输**;管理员可人工复核修改检测结果(需填写复核说明),复核通过后即可正常分享/传输; +- **文件夹部分文件不通过**:分享/传输弹窗内提示未通过的文件清单,用户确认后**仅分享/传输检测通过的内容**(请求带 `onlyPassed=true`,后端排除不通过/检测中的文件);不确认则整体拦截; +- **检测中**:禁止分享与传输(检测通常秒级完成,稍后重试即可); +- **检测失败**:默认不阻断业务(仅标记"检测失败",可重新检测);`meshsafe.fail-open=false` 时检测失败同样禁止分享/传输; +- **未检测**:不阻断(历史文件/开关未开启期间上传的文件); +- 同一文件允许多条检测记录(重新检测、人工复核均新增记录),**列表与校验均取最新一条**; +- 人工复核会尽力回写 MeshSafe 的人工复核接口(失败仅告警,不影响本地生效)。 + +检测状态(`securityStatus`)取值: + +| 值 | 含义 | 能否分享/传输 | +|---|---|---| +| 空 | 未检测 | 能 | +| 1 | 检测中 | 否 | +| 2 | 通过 | 能 | +| 3 | 不通过 | 否 | +| 4 | 检测失败 | 默认能(fail-open=false 时否) | + +## 通用约定 + +与既有接口一致:登录态调用;统一返回 `AlitaResult`(`code="200"` 且 `success=true` 成功;业务失败 `success=false`,`msg` 为提示文案)。 + +**总开关**:`meshsafe.enabled=false` 时检测功能整体关闭——上传/解包不送检、分享/传输不拦截、预检返回空、复核与重新检测接口报"文件安全检测未开启";前端通过 `GET /file_security/enabled` 获取开关状态,关闭时列表隐藏"安全检测"列。 + +## 文件列表新增字段 + +`GET /user_file/page`、`GET /user_file/list`、`GET /user_file/record/page_by_phone` 等返回的文件记录新增以下字段(前端据此展示与禁用操作): + +| 字段 | 类型 | 说明 | +|---|---|---| +| securityStatus | String | 安全检测状态:1检测中/2通过/3不通过/4检测失败,null 为未检测 | +| securityAction | String | MeshSafe 处置动作:pass/manual_review/reject | +| securityReason | String | 检测结论说明(可直接展示给用户,人工复核时为复核说明) | +| securityReviewComment | String | 人工复核说明(人工改判时有值) | + +--- + +## 1. 查询文件最新检测结果 + +- **URL**:`GET /file_security/detail` +- **权限**:所有登录用户 +- **参数**: + +| 参数 | 类型 | 必填 | 说明 | +|---|---|---|---| +| fileCode | String | 是 | 文件编码 | + +- **返回**:`AlitaResult`,无检测记录时 `data` 为 null + +**FileSecurityDTO 字段** + +| 字段 | 类型 | 说明 | +|---|---|---| +| fileCode | String | 文件编码 | +| taskId | String | MeshSafe 检测任务 ID | +| scanStatus | String | 检测状态:1检测中/2通过/3不通过/4检测失败 | +| action | String | MeshSafe 处置动作:pass/manual_review/reject | +| reason | String | 检测结论说明 | +| resultJson | String | 检测完整结果 JSON(原始响应) | +| reviewComment | String | 人工复核说明(人工改判时有值) | +| createTime | String | 记录时间 yyyy-MM-dd HH:mm:ss | + +## 2. 人工复核修改检测结果 + +- **URL**:`POST /file_security/review` +- **权限**:平台超管(全部)/ 机构管理员(仅本机构用户的文件) +- **Content-Type**:`application/json` +- **参数**: + +| 参数 | 类型 | 必填 | 说明 | +|---|---|---|---| +| fileCode | String | 是 | 文件编码 | +| decision | String | 是 | 复核结论:`pass` 通过 / `reject` 不通过 | +| comment | String | 是 | 复核说明(审计要求,必填),例如"经人工查验为误报" | + +- **返回**:`AlitaResult`(本次复核生成的最新检测记录) +- **行为**:新增一条检测记录留痕并立即生效;若该文件此前有 MeshSafe 任务 ID,会尽力回写 MeshSafe 人工复核接口(失败仅告警) + +**错误提示**:无检测记录、复核结论不合法、无操作权限、非本机构文件时返回 `success=false` 并附 `msg`。 + +## 3. 分享/传输预检 + +- **URL**:`GET /file_security/share_check` +- **权限**:所有登录用户(校验本人文件) +- **参数**: + +| 参数 | 类型 | 必填 | 说明 | +|---|---|---|---| +| userFileId | Long | 是 | 用户文件ID(普通文件/文件夹) | + +- **返回**:`AlitaResult` + +**FileSecurityShareCheckDTO 字段** + +| 字段 | 类型 | 说明 | +|---|---|---| +| fileType | String | 1文件/2文件夹 | +| totalFileCount | Integer | 目录内文件总数(不含目录) | +| blockedCount | Integer | 检测不通过数量 | +| scanningCount | Integer | 检测中数量 | +| failedCount | Integer | 检测失败数量 | +| blockedFileNames | List<String> | 检测不通过文件名 | +| scanningFileNames | List<String> | 检测中文件名 | +| failedFileNames | List<String> | 检测失败文件名 | +| excludeFileIds | List<Long> | 确认跳过时需排除的用户文件ID | + +**前端用法**:文件夹分享/传输前调用,`excludeFileIds` 非空时弹窗展示文件清单,用户确认后分享/传输请求带 `onlyPassed=true`。 + +## 4. 分享/传输的 onlyPassed 参数 + +`POST /share_user_file/create`、`POST /transfer_user_file/create` 请求体新增可选字段: + +| 参数 | 类型 | 说明 | +|---|---|---| +| onlyPassed | Boolean | 文件夹内存在检测未通过文件且用户已确认跳过时传 `true`,仅复制/传输检测通过的内容;缺省或 `false` 时维持整体拦截 | + +规则:单文件检测不通过 → 无论该参数一律拦截;文件夹 + `onlyPassed=true` → 排除不通过/检测中文件;文件夹内全部被拦截 → 报错「文件夹内没有检测通过的文件,无法分享/传输」。 + +## 5. 重新提交安全检测 + +- **URL**:`POST /file_security/rescan` +- **权限**:平台超管(全部)/ 机构管理员(仅本机构用户的文件) +- **参数**(query): + +| 参数 | 类型 | 必填 | 说明 | +|---|---|---|---| +| fileCode | String | 是 | 文件编码 | + +- **返回**:`AlitaResult`,受理成功返回 `true`(异步执行,结果通过列表/详情查询获取) +- **行为**:新增一条"检测中"记录并异步提交 MeshSafe;该文件正在检测中时拒绝重复提交 + +--- + +## 后端对接配置(运维) + +```yaml +meshsafe: + enabled: true # 总开关,false 时完全不送检、不校验 + base-url: https://meshsafe.internal + client-id: s-file # MeshSafe 分配的调用方标识 + secret: "***" # MeshSafe 分配的密钥(请勿泄露) + channel: default # 业务通道标识(仅用于 MeshSafe 日志追溯) + timeout-seconds: 120 # 单次请求超时 + fail-open: true # 检测服务异常时是否放行(true仅标记检测失败) + poll-timeout-minutes: 60 # 检测中记录超时时长,超时标记检测失败 + review-sync-to-meshsafe: true # 人工复核是否回写 MeshSafe + poll: + cron: "0 */30 * * * ?" # 轮询未完成检测任务的定时任务(默认30秒) +``` + +数据表:`x_file_security`(见 `db/upgrade-20261101-meshsafe-file-security.sql`)。 + +送检触发点: + +1. **网盘上传**:`POST /normal_user_file/create` 落库后异步送检; +2. **跨网传输接收**:传输解包定时任务创建文件记录后逐个异步送检(保护"外传内"方向); +3. **手动重新检测**:上述 `/file_security/rescan`。 + +分享/传输入口强校验:`POST /share_user_file/create`、`POST /transfer_user_file/create` 均校验文件及子文件的最新检测状态,不通过/检测中直接拒绝,`msg` 会带上具体文件名与原因。 diff --git a/backend/docs/接口文档-机构上传配置.md b/backend/docs/接口文档-机构上传配置.md new file mode 100644 index 0000000..90bb74e --- /dev/null +++ b/backend/docs/接口文档-机构上传配置.md @@ -0,0 +1,181 @@ +# 前端接口文档 —— 机构上传配置(文件上传类型/大小限制) + +> 版本:v1.0(2026-09-14) +> 适用后端:s-file(alita-bjy-uygur) +> Swagger 分组:「机构上传配置」 + +## 功能说明 + +机构管理员可以为本机构配置网盘上传策略: + +- **上传总开关**:关闭后本机构用户不能上传任何文件到网盘; +- **类型白名单**:可限制只允许上传指定后缀的文件(如 `doc、docx、pdf、jpg`); +- **单文件大小上限**:单位 MB,超过即拒绝。 + +规则约定: + +- 配置**按机构隔离**,作用于当前登录机构,管理的是本机构用户的**网盘上传**(`normal_user_file/create` 落库时强制校验); +- **未配置过的机构 = 默认策略**:允许上传、允许全部类型、不限大小(对现有用户完全兼容); +- 个人用户(无登录机构)不受机构配置限制; +- 后缀不区分大小写,配置时可带可不带前导点(`PDF`、`.pdf`、`pdf` 等价),服务端统一转小写存储; +- 文件夹创建不受类型/大小校验影响; +- 文件**传输(发送/接收)与分享不受此配置影响**,该配置只管上传。 + +## 通用约定 + +与既有接口一致:登录态调用;统一返回 `AlitaResult`(`code="200"` 且 `success=true` 成功;业务失败 `success=false`,`msg` 为提示文案);时间格式 `yyyy-MM-dd HH:mm:ss`。 + +--- + +## 1. 查询当前机构的上传配置 + +- **URL**:`GET /upload_config/info` +- **权限**:所有登录用户(前端可在上传前读取并据此过滤可选文件类型) +- **参数**:无(按当前登录机构查询) +- **返回**:`AlitaResult` + +**UploadConfigDTO 字段** + +| 字段 | 类型 | 说明 | +|---|---|---| +| orgId | Long | 机构 id | +| uploadEnabled | Boolean | 是否允许上传 | +| allowAllType | Boolean | 是否允许全部类型 | +| allowedSuffixes | List<String> | 允许的后缀(小写、不含点),`allowAllType=false` 时有值,否则为 null | +| maxFileSize | Long | 单文件大小上限(MB),null 或 0 表示不限制 | +| configured | Boolean | **机构是否已配置过**。`false` 表示当前是默认策略(允许上传全部类型、不限大小),前端此时可不限制文件选择器 | + +**返回示例(已配置)** + +```json +{ + "code": "200", + "success": true, + "data": { + "orgId": 12, + "uploadEnabled": true, + "allowAllType": false, + "allowedSuffixes": ["doc", "docx", "pdf", "jpg", "png"], + "maxFileSize": 200, + "configured": true + } +} +``` + +**返回示例(未配置过)** + +```json +{ + "code": "200", + "success": true, + "data": { + "orgId": 12, + "uploadEnabled": true, + "allowAllType": true, + "allowedSuffixes": null, + "maxFileSize": null, + "configured": false + } +} +``` + +--- + +## 2. 保存机构的上传配置 + +Upsert:该机构无配置则新建,有则更新。 + +- **URL**:`POST /upload_config/modify` +- **权限**:**机构管理员** 或 平台超管(其他用户返回「当前用户无操作权限」) +- **Body**(application/json) + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| uploadEnabled | Boolean | 是 | 是否允许上传 | +| allowAllType | Boolean | 是 | 是否允许全部类型 | +| allowedSuffixes | List<String> | 条件必填 | `allowAllType=false` 时必填且不能为空;后缀可带可不带点,自动小写去重 | +| maxFileSize | Long | 否 | 单文件上限(MB),null 或 0 不限制;传负数报错 | + +**校验失败提示** + +| 场景 | msg | +|---|---| +| 非机构管理员/超管 | 当前用户无操作权限 | +| 白名单为空 | 未允许全部类型时,允许的文件后缀不能为空 | +| maxFileSize ≤ 0 | 单文件大小上限必须大于0 | +| 并发修改 | 上传配置正在修改,请稍后重试 | + +**请求示例(只允许文档和图片,单个最大 200MB)** + +```json +POST /upload_config/modify +{ + "uploadEnabled": true, + "allowAllType": false, + "allowedSuffixes": ["doc", "docx", "xls", "xlsx", "pdf", "jpg", "png"], + "maxFileSize": 200 +} +``` + +**请求示例(禁止本机构上传)** + +```json +POST /upload_config/modify +{ + "uploadEnabled": false, + "allowAllType": true +} +``` + +**返回示例** + +```json +{ "code": "200", "success": true, "data": true } +``` + +--- + +## 3. 上传预检(可选,提升体验) + +按文件名/大小对当前机构配置做一次预检,用于**选择文件后、真正上传前**给出友好提示,避免白传一遍物理文件才被拒绝。 + +- **URL**:`GET /upload_config/check` +- **权限**:所有登录用户 +- **参数**(URL query) + +| 参数 | 类型 | 必填 | 说明 | +|---|---|---|---| +| fileName | String | 是 | 完整文件名(含后缀) | +| fileSize | Long | 否 | 文件大小(字节),不传则跳过大小校验 | + +- **返回**:通过时 `{"code":"200","success":true,"data":true}`;不通过时 `success=false`,`msg` 说明原因(与真实上传被拦截时的文案一致)。 + +**不通过返回示例** + +```json +{ + "code": "700", + "success": false, + "msg": "仅允许上传后缀为 doc、docx、pdf、jpg、png 的文件", + "data": null +} +``` + +--- + +## 4. 上传被拦截时的服务端行为 + +用户上传最终在网盘创建记录接口(`POST /normal_user_file/create`)被强制校验,不通过时接口返回 `success=false`,`msg` 为以下之一: + +| 场景 | msg | +|---|---| +| 机构关闭上传 | 当前机构已禁止上传文件,请联系机构管理员 | +| 后缀不在白名单 | 仅允许上传后缀为 doc、docx、pdf 的文件(动态列出) | +| 机构白名单为空(异常配置) | 当前机构未配置可上传的文件类型,请联系机构管理员 | +| 超过大小上限 | 上传文件过大,单文件最大不得超过200MB(动态数值) | + +**前端建议**: + +1. 上传页加载时调 `GET /upload_config/info`:`uploadEnabled=false` 时直接隐藏/禁用上传入口;`allowAllType=false` 时设置文件选择器的 accept 过滤; +2. 选择文件后可先调 `GET /upload_config/check` 预检(可选); +3. 真实上传两步(`/file/upload` → `/normal_user_file/create`)中第二步失败时直接 toast `msg`。 diff --git a/backend/docs/接口文档-用户管理与记录查询.md b/backend/docs/接口文档-用户管理与记录查询.md new file mode 100644 index 0000000..33b1636 --- /dev/null +++ b/backend/docs/接口文档-用户管理与记录查询.md @@ -0,0 +1,498 @@ +# 前端接口文档 —— 用户管理增强 & 机构账号查询 & 按手机号查询文件记录 + +> 版本:v1.2(2026-10-27,新增 1.4 修改用户姓名、1.5 批量创建机构用户) +> 适用后端:s-file(alita-bjy-uygur) +> Swagger 分组:「用户」「用户文件」 + +--- + +## 0. 通用约定 + +### 0.1 请求与认证 + +- 所有接口均需**登录后调用**,认证 token 按现有方式携带(header 或 cookie,与系统其他接口一致)。 +- 新增接口均要求**平台管理员(超管)身份**(`uc_user.supeiror = true`),非管理员调用统一返回失败,提示「当前用户无操作权限」。 + +### 0.2 统一返回结构 `AlitaResult` + +```json +{ + "requestId": "xxx", + "code": "200", + "success": true, + "msg": null, + "data": { ... } +} +``` + +| 字段 | 说明 | +|---|---| +| code | `"200"` 成功;业务失败时 success=false,msg 为错误提示(如「不能禁用当前登录账号」) | +| success | 是否成功 | +| data | 业务数据,失败时为 null | + +### 0.3 分页请求与返回 + +分页查询接口通过 **URL query 参数** 传递分页信息,返回结构 `Page`: + +``` +pageNo 第几页,默认 1 +pageSize 页宽,默认 20,上限 1000 +needPage 是否分页,默认 true(无需传) +``` + +```json +{ + "pageNo": 1, + "pageSize": 20, + "pageCount": 5, + "totalCount": 88, + "entityList": [ ... ] +} +``` + +### 0.4 通用枚举(前后端共用) + +**用户状态 `status`** + +| 值 | 含义 | +|---|---| +| 1 | 待激活 | +| 2 | 已激活 | +| 3 | 已注销 | + +**是否启用 `enabled`**:`true` 启用,`false` 禁用。 + +**文件状态 `fileStatus`** + +| 值 | 含义 | +|---|---| +| 1 | 正常 | +| 2 | 失效 | +| 11 | 解析中 | +| 12 | 待审核 | +| 13 | 传输中 | +| 14 | 失败 | + +**记录类型 `recordType`**(本文档 3.4 节专用) + +| 值 | 含义 | +|---|---| +| 1 | 上传记录 | +| 2 | 发送记录(本端发起文件传输) | +| 3 | 接收记录(本端接收文件传输) | + +> 发送/接收与部署侧有关,但**前端无需关心**:传入 `recordType` 后,后端按部署配置(内网/外网)自动映射到对应的 `root_type`;返回列表中每条记录也已回填 `recordType` / `recordTypeDesc`。 + +--- + +## 1. 用户管理:启用 / 禁用 / 注销 + +### 1.1 启用用户 + +将被禁用的账号重新启用(幂等:已启用的账号重复调用仍返回成功)。 + +- **URL**:`POST /user/enable` +- **权限**:平台管理员 +- **Body**(application/json) + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| userId | Long | 是 | 目标用户 id | + +- **返回**:`AlitaResult`,data 为 `true` +- **失败场景**:用户不存在;账号已注销(提示「已注销账号不可启用」);非管理员 + +**请求示例** + +```json +POST /user/enable +{ "userId": 10086 } +``` + +**返回示例** + +```json +{ "code": "200", "success": true, "data": true } +``` + +### 1.2 禁用用户 + +禁用账号,禁用后该用户无法登录/使用系统(后端登录态校验会实时读取启用状态,被禁用用户下次请求即被拒绝)。幂等:已禁用的账号重复调用仍返回成功。 + +- **URL**:`POST /user/disable` +- **权限**:平台管理员 +- **Body**(application/json) + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| userId | Long | 是 | 目标用户 id | + +- **返回**:`AlitaResult`,data 为 `true` +- **失败场景**: + - 用户不存在 + - `userId` 为当前登录人(提示「不能禁用当前登录账号」) + - 目标是超级管理员(提示「不能禁用超级管理员账号」) + - 目标已注销(提示「已注销账号无需禁用」) + +**请求示例** + +```json +POST /user/disable +{ "userId": 10086 } +``` + +### 1.3 注销用户(管理员直接注销) + +管理员将账号直接置为**已注销**(status=3)并同步禁用(enabled=false),**不进入注销申请审批流程**。注销后账号不可恢复、不可登录。幂等:已注销账号重复调用返回成功。 + +- **URL**:`POST /user/admin_cancel` +- **权限**:平台管理员 +- **Body**(application/json) + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| userId | Long | 是 | 目标用户 id | + +- **返回**:`AlitaResult`,data 为 null +- **失败场景**: + - 用户不存在 + - `userId` 为当前登录人(提示「不能注销当前登录账号」) + - 目标是超级管理员(提示「不能注销超级管理员账号」) + - 并发重复操作(提示「该用户正在注销,请勿重复操作」) + +**请求示例** + +```json +POST /user/admin_cancel +{ "userId": 10086 } +``` + +> **与既有接口的区别**:既有 `POST /user/cancel` 为机构内注销(限定当前登录机构、且要求目标账号启用中),供原「注销申请/同意」流程使用,保持不变;本接口供系统管理员在用户管理页面跨机构直接注销。 + +### 1.4 修改用户姓名 + +修改用户账号的真实姓名(`real_name`)。平台超管可修改全部用户;机构管理员仅可修改本机构用户(同一账号属于多个机构时,改的是账号本身,各机构下展示同步生效)。 + +- **URL**:`POST /user/modify_real_name` +- **权限**:平台超管(全部用户)/ 机构管理员(限本机构用户) +- **Body**(application/json) + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| userId | Long | 是 | 目标用户 id | +| realName | String | 是 | 新姓名,2-30 位,仅支持中文或英文姓名 | + +- **返回**:`AlitaResult`,data 为 `true` +- **失败场景**: + - 用户不存在 + - 目标已注销(提示「已注销账号不可修改姓名」) + - 姓名格式错误(提示「姓名格式错误!(长度2-30位,仅支持中文或英文姓名)」) + - 与原姓名一致(提示「姓名与原姓名一致,无需修改!」) + - 机构管理员操作非本机构用户(提示「只能操作本机构的用户」) + +**请求示例** + +```json +POST /user/modify_real_name +{ "userId": 10086, "realName": "张三" } +``` + +**返回示例** + +```json +{ "code": "200", "success": true, "data": true } +``` + +> **与既有接口的区别**:既有 `POST /user/modify_org_user_info` 为超管编辑企业用户完整信息(账号名/姓名/启用状态一起校验更新);本接口仅更新姓名,供用户管理页与机构账号页的「修改姓名」入口使用。 + +### 1.5 批量创建机构用户 + +一次性提交多条「手机号 + 姓名」创建机构用户。**单条失败不影响其他条目**(每条独立事务),返回与入参**顺序一一对应**的逐条结果,前端据此展示失败项。 + +- **URL**:`POST /user/batch_create_org_user` +- **权限**:登录用户(机构取当前登录机构,与单条创建 `POST /user/create_org_user` 一致) +- **Body**(application/json,对象数组,单次最多 **500** 条) + +数组元素字段: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| phone | String | 是 | 手机号 | +| realName | String | 否 | 姓名 | + +- **返回**:`AlitaResult>` + +**OrgUserCreateResultDTO 字段** + +| 字段 | 类型 | 说明 | +|---|---|---| +| phone | String | 手机号(回显入参) | +| realName | String | 姓名(回显入参) | +| success | Boolean | 是否创建成功 | +| userId | Long | 用户 id,失败时为 null | +| msg | String | 失败原因,成功时为 null | + +**请求示例** + +```json +POST /user/batch_create_org_user +[ + { "phone": "13800000001", "realName": "张三" }, + { "phone": "13800000002", "realName": "李四" } +] +``` + +**返回示例** + +```json +{ + "code": "200", + "success": true, + "data": [ + { "phone": "13800000001", "realName": "张三", "success": true, "userId": 1001, "msg": null }, + { "phone": "13800000002", "realName": "李四", "success": false, "userId": null, "msg": "手机号已存在,不能重复添加" } + ] +} +``` + +- **失败场景**(整体请求失败):列表为空;超过 500 条(提示「单次批量创建不能超过500条」)。单条业务失败(手机号格式不正确、手机号已存在等)不使请求失败,体现在对应条目的 `success/msg` 中。 + +--- + +## 2. 系统管理员:查看各机构下的账号信息 + +### 2.1 分页查询机构账号 + +按机构维度查看账号信息。一行 = 一个机构下的一个账号(同一账号属于多个机构时会出现多行)。不传 `orgId` 时查询全部机构,传 `orgId` 时查看指定机构。 + +- **URL**:`GET /user/page/org_account` +- **权限**:平台管理员 +- **参数**(URL query) + +| 参数 | 类型 | 必填 | 说明 | +|---|---|---|---| +| orgId | Long | 否 | 机构 id,不传查全部机构 | +| orgNameLike | String | 否 | 机构名称,模糊匹配 | +| usernameLike | String | 否 | 账号,模糊匹配 | +| realNameLike | String | 否 | 真实姓名,模糊匹配 | +| phoneLike | String | 否 | 手机号,模糊匹配 | +| enabled | Boolean | 否 | 是否启用:true/false | +| status | Integer | 否 | 用户状态:1 待激活 / 2 已激活 / 3 已注销 | +| createTimeStart | String | 否 | 创建时间起,格式 `yyyy-MM-dd HH:mm:ss` | +| createTimeEnd | String | 否 | 创建时间止,格式 `yyyy-MM-dd HH:mm:ss` | +| pageNo / pageSize | Integer | 否 | 分页参数,默认 1 / 20 | + +- **返回**:`AlitaResult>` + +**OrgAccountDTO 字段** + +| 字段 | 类型 | 说明 | +|---|---|---| +| orgId | Long | 机构 id | +| orgName | String | 机构名称 | +| administrator | Boolean | 是否该机构的管理员 | +| userId | Long | 用户 id(可传给 1.1/1.2/1.3 接口做启停/注销操作) | +| username | String | 账号 | +| nickname | String | 昵称 | +| realName | String | 真实姓名 | +| phone | String | 手机号 | +| email | String | 邮箱 | +| userType | Integer | 用户类型:1 企业用户 / 2 个人用户 | +| enabled | Boolean | 是否启用 | +| status | Integer | 状态:1 待激活 / 2 已激活 / 3 已注销 | +| createTime | String | 创建时间 `yyyy-MM-dd HH:mm:ss` | + +- **排序规则**:机构 id 升序,机构管理员排前面,同机构内按用户 id 倒序。 + +**请求示例** + +``` +GET /user/page/org_account?orgNameLike=教育&phoneLike=138&enabled=false&pageNo=1&pageSize=20 +``` + +**返回示例** + +```json +{ + "code": "200", + "success": true, + "data": { + "pageNo": 1, + "pageSize": 20, + "pageCount": 1, + "totalCount": 2, + "entityList": [ + { + "orgId": 12, + "orgName": "XX市教育局", + "administrator": true, + "userId": 1001, + "username": "admin_xx", + "nickname": "张三", + "realName": "张三", + "phone": "13800000001", + "email": "zhang@xx.gov.cn", + "userType": 1, + "enabled": false, + "status": 2, + "createTime": "2026-08-01 10:00:00" + }, + { + "orgId": 12, + "orgName": "XX市教育局", + "administrator": false, + "userId": 1002, + "username": "user_xx01", + "nickname": "李四", + "realName": "李四", + "phone": "13800000002", + "email": null, + "userType": 1, + "enabled": true, + "status": 2, + "createTime": "2026-08-03 14:30:00" + } + ] + } +} +``` + +--- + +## 3. 按手机号查询文件记录(上传 / 发送 / 接收) + +### 3.1 分页查询 + +输入手机号,精确匹配该手机号名下(可能是多个账号)的全部文件记录,可按记录类型筛选。 + +- **URL**:`GET /user_file/record/page_by_phone` +- **权限**:平台管理员 +- **参数**(URL query) + +| 参数 | 类型 | 必填 | 说明 | +|---|---|---|---| +| phone | String | **是** | 用户手机号,精确匹配,同一手机号关联的所有账号均会命中 | +| recordType | Integer | 否 | 1 上传记录 / 2 发送记录 / 3 接收记录,**不传查全部三类** | +| fileNameLike | String | 否 | 文件名,模糊匹配 | +| fileType | String | 否 | 文件类型:`1` 文件 / `2` 文件夹 | +| fileStatus | String | 否 | 文件状态:1 正常 / 2 失效 / 11 解析中 / 12 待审核 / 13 传输中 / 14 失败 | +| createTimeBegin | String | 否 | 记录时间起,格式 `yyyy-MM-dd HH:mm:ss` | +| createTimeEnd | String | 否 | 记录时间止,格式 `yyyy-MM-dd HH:mm:ss` | +| pageNo / pageSize | Integer | 否 | 分页参数,默认 1 / 20 | + +- **返回**:`AlitaResult>` + +**UserFileRecordDTO 字段**(继承用户文件全部字段,以下为主要字段) + +| 字段 | 类型 | 说明 | +|---|---|---| +| id | Long | 记录 id | +| phone | String | 归属手机号 | +| username | String | 归属账号 | +| realName | String | 归属真实姓名 | +| userType | Integer | 归属用户类型:1 企业用户 / 2 个人用户 | +| recordType | Integer | 记录类型:1 上传 / 2 发送 / 3 接收 | +| recordTypeDesc | String | 记录类型描述(「上传记录」「发送记录」「接收记录」) | +| userId | Long | 归属用户 id | +| rootType | String | 原始根类型:1 普通 / 2 内穿外 / 3 外传内(调试用,前端一般用 recordType 即可) | +| fileType | String | 文件大类:1 文件 / 2 文件夹 | +| fileName | String | 文件名 | +| fileCode | String | 物理文件编码 | +| fileSize | Long | 文件大小(字节) | +| fileStatus | String | 文件状态:1 正常 / 2 失效 / 11 解析中 / 12 待审核 / 13 传输中 / 14 失败 | +| createTime | String | 记录时间(上传/发送/接收发起时间)`yyyy-MM-dd HH:mm:ss` | +| endTime | String | 有效期(分享类记录使用),可能为 null | +| fileCategory | String | 文件种类(文档/图片/视频等,按后缀归类) | +| maxRiskLevel | String | 最高风险等级:1 重度 / 2 中度 / 3 轻度,可能为 null | + +- **排序**:记录 id 倒序(即时间倒序)。 +- **失败场景**:phone 为空;recordType 非法(提示「记录类型不合法,仅支持1上传/2发送/3接收」);非管理员。 + +**请求示例** + +``` +GET /user_file/record/page_by_phone?phone=13800000001&recordType=2&pageNo=1&pageSize=10 +``` + +**返回示例** + +```json +{ + "code": "200", + "success": true, + "data": { + "pageNo": 1, + "pageSize": 10, + "pageCount": 1, + "totalCount": 2, + "entityList": [ + { + "id": 9001, + "phone": "13800000001", + "username": "user_xx01", + "realName": "李四", + "userType": 1, + "recordType": 2, + "recordTypeDesc": "发送记录", + "userId": 1002, + "rootType": "2", + "fileType": "2", + "fileName": "2026年预算材料_20260912103000", + "fileCode": null, + "fileSize": null, + "fileStatus": "1", + "createTime": "2026-09-12 10:30:00", + "endTime": null, + "fileCategory": null, + "maxRiskLevel": null + }, + { + "id": 8802, + "phone": "13800000001", + "username": "user_xx01", + "realName": "李四", + "userType": 1, + "recordType": 1, + "recordTypeDesc": "上传记录", + "userId": 1002, + "rootType": "1", + "fileType": "1", + "fileName": "工作总结.docx", + "fileCode": "fc_3a7d92", + "fileSize": 1048576, + "fileStatus": "1", + "createTime": "2026-09-10 09:12:00", + "endTime": null, + "fileCategory": "文档", + "maxRiskLevel": null + } + ] + } +} +``` + +> **记录类型口径说明**(便于前端理解,无需处理): +> - 上传记录:用户在网盘中上传的文件/文件夹(rootType=1)。 +> - 发送记录:用户发起的文件传输(文件夹整体外发,传输中状态为 13,完成后变 1,失败为 14)。 +> - 接收记录:对端传来的文件在本端解包后归属到该手机号用户的记录(若开启风险审查,先为 12 待审核,通过后为 1)。 + +--- + +## 4. 错误处理建议 + +前端统一按 `success=false` 判定失败并 toast `msg`;特殊 code 沿用系统既有约定(`401` 未登录等,与现有接口一致)。 + +涉及本批接口的典型业务错误文案: + +| 场景 | msg | +|---|---| +| 非平台管理员操作 | 当前用户无操作权限 | +| 启用已注销账号 | 已注销账号不可启用 | +| 禁用/注销自己 | 不能禁用当前登录账号 / 不能注销当前登录账号 | +| 禁用/注销超管 | 不能禁用超级管理员账号 / 不能注销超级管理员账号 | +| recordType 非法 | 记录类型不合法,仅支持1上传/2发送/3接收 | +| phone 为空 | 手机号不能为空 | +| 修改姓名格式错误 | 姓名格式错误!(长度2-30位,仅支持中文或英文姓名) | +| 修改姓名与原值相同 | 姓名与原姓名一致,无需修改! | +| 机构管理员越机构操作 | 只能操作本机构的用户 | diff --git a/backend/docs/生产部署说明.md b/backend/docs/生产部署说明.md new file mode 100644 index 0000000..74bbbe4 --- /dev/null +++ b/backend/docs/生产部署说明.md @@ -0,0 +1,220 @@ +# s-file 生产部署 / 上线说明 + +> 适用版本:2026-09-14(含用户启停/注销、机构账号查询、手机号查记录、机构上传配置、禁用踢下线黑名单) +> 构建产物:`target/s-file.jar`(Spring Boot 可执行 fat jar,需 JDK 8) + +--- + +## 0. 上线前必须处理(阻断项) + +### 0.1 替换 spire.pdf 占位 jar ⚠️ + +本机构开发机的 `~/.m2/repository/e-iceblue/spire.pdf/3.7.4/` 中目前安装的是**编译级 stub(空实现)jar**——它能保证编译打包通过,但 **PDF 盖章功能(`PdfUtils.pdfStampPerPage`)运行时必然失败**。 + +上线前必须: + +1. 从公司私服获取真实的 `spire.pdf-3.7.4.jar`(阿里云与 e-iceblue 官方仓库均无此版本); +2. 覆盖 `~/.m2/repository/e-iceblue/spire.pdf/3.7.4/spire.pdf-3.7.4.jar`(pom 同步覆盖); +3. 重新 `mvn clean package -DskipTests`; +4. 验证:解包 jar 中 `com/spire/pdf/PdfDocument.class` 应为真实实现(stub 版仅 300~500 字节)。 + +> 若该业务暂时不用 PDF 盖章,可带 stub 上线,但需明确告知团队。 + +### 0.2 提供生产配置文件 + +**仓库内不含任何运行配置**(application.yml 是外置的)。启动时通过 `spring.config.additional-location` 挂载。生产模板如下(按实际环境修改): + +```yaml +server: + port: 8080 + +spring: + application: + name: s-file + datasource: + # 生产为达梦 DM8;驱动 com.dameng.jdbc.driver(pom 已含依赖) + url: jdbc:dm://:5236/S_FILE + driver-class-name: com.dameng.jdbc.driver + username: + password: + druid: + initial-size: 5 + min-idle: 5 + max-active: 20 + validation-query: SELECT 1 + redis: # 必须可用:登录缓存 + 禁用/注销踢下线黑名单依赖 Redis + host: + port: 6379 + timeout: 5000 + rabbitmq: + host: + port: 5672 + username: + password: + servlet: + multipart: + max-file-size: 500MB # 按网盘需求调整 + max-request-size: 500MB + main: + allow-bean-definition-overriding: true + +mybatis-plus: + mapper-locations: classpath*:com/senmesh/**/mapper/*.xml # 必须有,否则自定义 XML 的接口全部报 Invalid bound statement + +system: + code: 1 + +# 发号器雪花 workerId:键格式 code.snowflake.workid.<本机IP> +# 单机部署:直接写死本机 IP 的键;多机部署:每台机器一个键、值必须不同且 0~31 +"[code.snowflake.workid.192.168.1.10]": 1 + +security: + jwt: + enable: true + secret: <上线前必须换成 64 字节以上随机串,勿用文档示例> + expiration: 86400 # token 有效期(秒) + header: Authorization + ignoring: /error,/favicon.ico,/v2/api-docs,/swagger-resources/** + login-page: /login + superior-only: false # true=仅平台机构用户可登录系统;按部署侧实际选择 + use-local: true + allow-if-all-abstain-decisions: true + oauth2: + enable: false + anonymous: "" # 匿名白名单按需追加(逗号分隔,如 /file/upload) + +user: + default: + password: <新用户初始密码> + +file: + upload-dir: /data/upload # 容器/主机上需存在且可写 + storage: + type: local # 阿里云 OSS 则改 ali 并补齐 oss 配置 + transfer: + location: "1" # 内网侧 "1",外网侧 "2" —— 两侧必须相反! + send-dir: /data/transfer/send + receive-dir: /data/transfer/receive + unpack-risk-check: false + +dify: + risk: + rule: + api-key: <真实key或占位> + scan: + api-key: <真实key或占位> # 必填(可为占位),否则启动失败 + +rabbitmq: + custom: + topic-exchange-name: s-file-topic + delayed-exchange-name: s-file-delayed + broadcast-id: s-file-broadcast + +swagger: + enable: false # 生产必须 false +``` + +### 0.3 数据库变更 + +- **已有生产库**:执行 `db/upgrade-20260914-upload-config.sql`(达梦执行「1. MySQL / 达梦 DM8」一节,建 `x_upload_config` 表)。其余本次功能无表结构变更。 +- **全新库**:先执行 `db/init-table.sql`(达梦按 MySQL 兼容模式)+ `db/init-data.sql`(平台、平台机构、admin 账号、文件种类字典)。 +- 执行后验证:`select count(*) from x_upload_config;` 无报错即建表成功(0 行为正常,未配置的机构走默认策略)。 + +### 0.4 目录与权限 + +``` +mkdir -p /data/upload /data/transfer/send /data/transfer/receive +chown -R <运行用户> /data +``` + +外网侧与内网侧通过 `file.transfer.location` 区分,`send-dir`/`receive-dir` 指向各自的摆渡目录(网闸/摆渡盘)。 + +--- + +## 1. 启动方式 + +### 1.1 裸机 / 虚拟机(JDK 8) + +```bash +# 需 JDK 1.8(java -version 确认) +java -Xms1g -Xmx2g \ + -Dspring.config.additional-location=file:/opt/sfile/config/application.yml \ + -jar /opt/sfile/s-file.jar \ + > /opt/sfile/logs/stdout.log 2>&1 & +``` + +多节点时按节点 IP 配置不同的 `code.snowflake.workid.`(可用启动参数 `-DCODE_SNOWFLAKE_WORKID_=` 环境变量方式,`_` 映射 `.`)。 + +### 1.2 Docker + +```bash +# 构建(context 内需 s-file.jar 与 Dockerfile,Dockerfile 在 src/main/resources/) +cp target/s-file.jar / && docker build -t s-file:<版本> + +docker run -d --name sfile-app --restart unless-stopped -p 8080:8080 \ + -v /opt/sfile/config/application.yml:/config/application.yml:ro \ + -v /data/upload:/data/upload \ + -v /data/transfer/send:/data/transfer/send \ + -v /data/transfer/receive:/data/transfer/receive \ + -e SPRING_CONFIG_ADDITIONAL_LOCATION=file:/config/application.yml \ + -e CODE_SNOWFLAKE_WORKID_<容器IP大写下划线>=1 \ + s-file:<版本> +``` + +> 注意:基础镜像 `freshworks/oraclejdk8` 为 amd64,arm64 主机需 `--platform linux/amd64`;workerId 键里的 IP 用容器固定 IP(自定义网络 `--ip`),容器重建 IP 不变。 + +--- + +## 2. 前端发布 + +```bash +cd senmesh-zc-legacy +bun install +bun run build # 产出 dist/(.env.production 已带 VITE_APP_TITLE 引号修复,规避 Bun env 解析 bug) +``` + +- `dist/` 交由 nginx 托管; +- nginx 需将 `/api` 反代到后端并**去掉 `/api` 前缀**(与 vite dev 代理行为一致): + +```nginx +location /api/ { + proxy_pass http://<后端IP>:8080/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + client_max_body_size 500m; # 与后端 multipart 上限匹配 +} +``` + +- `.env.production` 当前值:`VITE_API_URL=`(空,走同域 /api)、`VITE_INIT_PASSWORD`(前端判断初始密码强制改密用)——如有调整需重新 build。 + +--- + +## 3. 本次版本功能与数据依赖清单(验收用) + +| 功能 | 依赖 | 验收方法 | +|---|---|---| +| 用户启用/禁用/注销(管理员) | DB `uc_user.enabled/status`;**Redis**(禁用踢下线黑名单) | 禁用后该用户已登录 token 立即失效(302/401),重新登录被拒 | +| 机构管理员启停本机构用户 | 无额外依赖 | 机构管理员可启停本机构用户;跨机构返回「只能操作本机构的用户」 | +| 机构账号查询(超管) | 新增只读查询 | 管理后台-机构账号页正常出列表与筛选 | +| 按手机号查上传/发送/接收记录 | 无额外依赖 | 输入手机号出记录;发送/接收方向由部署侧 `file.transfer.location` 决定 | +| 机构上传配置 | 新表 `x_upload_config` | 管理后台-上传配置保存后,该机构网盘上传立即按策略拦截 | +| 禁用踢下线 | Redis key `user:disabled:{userId}` | `redis-cli keys 'user:disabled:*'` 可见禁用标记 | + +--- + +## 4. 上线步骤建议 + +1. 生产库执行 0.3 升级 SQL(执行前备份); +2. 替换真实 spire.pdf jar 并重新打包(0.1),核对 jar 时间戳; +3. 准备 application.yml(0.2 模板),**核对 JWT secret 已更换、dify api-key 已填、swagger.enable=false**; +4. 创建 /data 目录,确定内外网 location; +5. 部署后端(1.1 或 1.2),观察启动日志出现 `Started SFileApplication`; +6. 构建并发布前端(2),nginx reload; +7. 验收第 3 节清单(至少:admin 登录、上传一个非白名单文件被拒、禁用一个测试用户并确认其会话失效、记录查询出数据); +8. 观察日志无 `ERROR`,Redis 中 `user:disabled:*` 与登录缓存键正常。 + +## 5. 回滚 + +- 后端:保留上一版 jar/镜像,停新启旧即可(本次无破坏性 DDL/DML,`x_upload_config` 留存不影响旧版本运行); +- 前端:nginx 指回上一版 dist 目录; +- 数据库:无需回滚(仅新增表)。 diff --git a/backend/pom.xml b/backend/pom.xml new file mode 100644 index 0000000..86d56f0 --- /dev/null +++ b/backend/pom.xml @@ -0,0 +1,458 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.4.2 + + + com.senmesh + s-file + 0.0.1 + jar + + + 1.2.0.Final + 8 + 8 + + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-test + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-validation + + + + + org.springframework.boot + spring-boot-starter-aop + + + + org.projectlombok + lombok + + + + com.google.guava + guava + 18.0 + compile + + + + + commons-io + commons-io + 2.6 + + + org.apache.commons + commons-lang3 + + + commons-collections + commons-collections + 3.2.2 + + + org.apache.commons + commons-collections4 + 4.2 + + + + org.mapstruct + mapstruct-jdk8 + ${org.mapstruct.version} + provided + + + org.mapstruct + mapstruct-processor + ${org.mapstruct.version} + provided + + + org.mapstruct + mapstruct + ${org.mapstruct.version} + + + + + org.springframework.data + spring-data-commons + + + + + org.freemarker + freemarker + + + + + io.springfox + springfox-swagger2 + 2.7.0 + + + io.springfox + springfox-swagger-ui + 2.7.0 + + + + com.fasterxml.jackson.core + jackson-core + + + + com.alibaba + easyexcel + 3.1.1 + + + + + org.bouncycastle + bcprov-jdk15on + 1.55 + + + + + com.github.ulisesbocchio + jasypt-spring-boot-starter + 3.0.2 + + + + + + com.dameng + Dm8JdbcDriver18 + 8.1.1.49 + + + + mysql + mysql-connector-java + runtime + + + + org.postgresql + postgresql + runtime + + + + com.alibaba + druid-spring-boot-starter + 1.2.4 + + + + com.baomidou + mybatis-plus-boot-starter + 3.4.0 + + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 2.1.3 + + + + + com.github.pagehelper + pagehelper-spring-boot-starter + 1.4.6 + + + + + org.springframework.boot + spring-boot-starter-amqp + + + + + redis.clients + jedis + + + org.springframework.boot + spring-boot-starter-data-redis + + + + io.netty + netty-all + + + org.redisson + redisson-spring-data-21 + 3.11.0 + + + org.redisson + redisson + 3.11.0 + + + + cn.hutool + hutool-all + 5.8.16 + + + + + org.apache.pdfbox + pdfbox + 2.0.20 + + + org.apache.pdfbox + fontbox + 2.0.20 + + + + com.aliyun.oss + aliyun-sdk-oss + 3.14.0 + + + + + e-iceblue + spire.pdf + 3.7.4 + + + com.itextpdf + itextpdf + 5.5.11 + + + com.itextpdf + itext-asian + 5.2.0 + + + + + org.springframework.boot + spring-boot-starter-security + + + + + org.springframework.boot + spring-boot-starter-oauth2-client + + + + io.jsonwebtoken + jjwt + 0.9.0 + + + + spring-boot-starter-websocket + org.springframework.boot + + + + + + com.aliyun + aliyun-java-sdk-core + 4.1.0 + + + + com.tencentcloudapi + tencentcloud-sdk-java + 3.1.100 + + + + com.aliyun + alibaba-dingtalk-service-sdk + 1.0.1 + + + + com.baidu.aip + java-sdk + 4.15.3 + + + org.slf4j + slf4j-simple + + + + + + + io.github.toolgood + toolgood-words + 3.1.0.0 + + + + com.spatial4j + spatial4j + 0.5 + + + + + com.squareup.okhttp3 + okhttp + 4.10.0 + + + + + com.squareup.okio + okio + 2.10.0 + + + + ws.schild + jave-core + 3.4.0 + + + + + ws.schild + jave-nativebin-linux64 + 3.4.0 + + + + + ws.schild + jave-nativebin-osx64 + 3.4.0 + + + + + ws.schild + jave-nativebin-win64 + 3.4.0 + + + + + cn.xfyun + websdk-java-spark + 2.1.3 + + + + cn.xfyun + websdk-java-speech + 3.0.3 + + + + cn.xfyun + websdk-java-nlp + 2.0.7 + + + + + + + + ${project.artifactId} + + + src/main/resources + + + src/main/java + + + **/*.xml + + + + src/main/resources + true + + application.yml + bootstrap.yml + ${project.artifactId}-${profile.active}.yaml + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + com.spotify + docker-maven-plugin + 1.2.1 + + ${project.build.finalName}:${project.version} + ${project.build.outputDirectory} + + ${project.build.finalName}.jar + + + + ${project.build.directory} + ${project.build.finalName}.jar + + + + ${docker.host} + ${docker.certPath} + + + + + + \ No newline at end of file diff --git a/backend/scripts/sfile-ctl.sh b/backend/scripts/sfile-ctl.sh new file mode 100644 index 0000000..b1188d5 --- /dev/null +++ b/backend/scripts/sfile-ctl.sh @@ -0,0 +1,209 @@ +#!/usr/bin/env bash +# ============================================================================== +# s-file 一键部署/运维脚本(生产环境) +# +# 用法: +# ./sfile-ctl.sh start 启动服务 +# ./sfile-ctl.sh stop 停止服务 +# ./sfile-ctl.sh restart 重启服务 +# ./sfile-ctl.sh status 查看状态 +# ./sfile-ctl.sh deploy 发布新版 jar(自动备份旧版并重启) +# ./sfile-ctl.sh log [行数] 查看启动日志(默认 200 行) +# ./sfile-ctl.sh db-upgrade 在达梦库执行升级 SQL(需配置 disql) +# 上线用: db/upgrade-20260915-release.sql +# +# 部署目录结构(脚本首次 start 时自动创建,配置需手工放置): +# /opt/sfile/ +# ├── s-file.jar 服务 jar +# ├── config/application.yml 生产配置(模板见 docs/生产部署说明.md) +# ├── backup/ 历史版本备份 +# ├── logs/ 日志目录 +# └── data/ 上传/摆渡目录(upload/transfer/send/transfer/receive) +# ============================================================================== +set -euo pipefail + +# ------------------------- 环境变量(按服务器实际修改) ------------------------- +APP_NAME="s-file" +INSTALL_DIR="${SFILE_INSTALL_DIR:-/opt/sfile}" +JAR_FILE="${INSTALL_DIR}/${APP_NAME}.jar" +CONFIG_FILE="${INSTALL_DIR}/config/application.yml" +LOG_DIR="${INSTALL_DIR}/logs" +BACKUP_DIR="${INSTALL_DIR}/backup" +STDOUT_LOG="${LOG_DIR}/stdout.log" +GC_LOG="${LOG_DIR}/gc.log" + +# 运行用户(root 部署时可改为专用低权用户,如 sfile) +RUN_USER="${SFILE_RUN_USER:-$(whoami)}" + +# JVM 参数:按机器内存调整 -Xmx;生产建议 2g 起 +JAVA_OPTS="${SFILE_JAVA_OPTS:--Xms1g -Xmx2g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${LOG_DIR} -Xloggc:${GC_LOG} -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M}" + +# 健康检查地址与超时 +HEALTH_URL="http://127.0.0.1:8080/user/info" +START_TIMEOUT=120 + +# 达梦 disql(db-upgrade 用;达梦容器则为 docker exec -i <容器> /opt/dmdbms/bin/disql ...) +DISQL_CMD="${SFILE_DISQL:-disql /@:5236}" +# ----------------------------------------------------------------------------- + +GREEN='\033[32m'; RED='\033[31m'; YELLOW='\033[33m'; NC='\033[0m' +info() { echo -e "${GREEN}[INFO]${NC} $*"; } +warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } +err() { echo -e "${RED}[ERROR]${NC} $*"; } + +get_pid() { + pgrep -f "java .*${JAR_FILE}" 2>/dev/null || true +} + +require_env() { + [ -f "${JAR_FILE}" ] || { err "jar 不存在: ${JAR_FILE},先用 deploy 发布"; exit 1; } + [ -f "${CONFIG_FILE}" ] || { err "配置不存在: ${CONFIG_FILE}(模板见 docs/生产部署说明.md)"; exit 1; } + # 项目要求 JDK 8 运行(字节码 52.0),防护误用高版本 JDK + if command -v java >/dev/null 2>&1; then + local major + major=$(java -version 2>&1 | head -1 | sed -E 's/.*"([0-9]+)\..*"/\1/') + if [ "${major}" != "1" ] && [ "${major}" != "8" ]; then + err "检测到 java 版本为 ${major},本项目要求 JDK 8(请 export JAVA_HOME 指向 JDK8 并确认 java 命令)" + exit 1 + fi + else + err "未找到 java 命令,请安装 JDK 8 并配置 PATH"; exit 1 + fi +} + +prepare_dirs() { + mkdir -p "${INSTALL_DIR}/config" "${LOG_DIR}" "${BACKUP_DIR}" \ + "${INSTALL_DIR}/data/upload" \ + "${INSTALL_DIR}/data/transfer/send" \ + "${INSTALL_DIR}/data/transfer/receive" +} + +start() { + require_env + local pid + pid=$(get_pid) + if [ -n "${pid}" ]; then + warn "${APP_NAME} 已在运行 (PID ${pid}),如需重启请先 stop" + exit 0 + fi + prepare_dirs + info "启动 ${APP_NAME} ..." + # workerId 说明:多节点部署时每台机器配置不同的 code.snowflake.workid.<本机IP>, + # 最简单的方式是用环境变量(. 映射为 _),如: + # export CODE_SNOWFLAKE_WORKID_192_168_1_10=1 + # shellcheck disable=SC2086 + if [ "${RUN_USER}" = "$(whoami)" ]; then + (cd "${INSTALL_DIR}" && nohup java ${JAVA_OPTS} \ + -Dspring.config.additional-location=file:${CONFIG_FILE} \ + -jar ${JAR_FILE} >> ${STDOUT_LOG} 2>&1 & echo $! > "${INSTALL_DIR}/app.pid") + else + su -s /bin/bash "${RUN_USER}" -c "cd ${INSTALL_DIR} && nohup java ${JAVA_OPTS} \ + -Dspring.config.additional-location=file:${CONFIG_FILE} \ + -jar ${JAR_FILE} >> ${STDOUT_LOG} 2>&1 & echo \$! > ${INSTALL_DIR}/app.pid" + fi + + # 启动健康检查轮询 + info "等待服务就绪(最多 ${START_TIMEOUT}s)..." + local waited=0 + while [ ${waited} -lt ${START_TIMEOUT} ]; do + if curl -sf -o /dev/null --max-time 3 "${HEALTH_URL}"; then + info "启动成功 (PID $(cat "${INSTALL_DIR}/app.pid")),耗时约 ${waited}s" + info "日志: tail -f ${STDOUT_LOG}" + return 0 + fi + # 进程若已退出则立即报错,不干等 + if [ -z "$(get_pid)" ]; then + err "进程已退出,最近日志:" + tail -30 "${STDOUT_LOG}" + exit 1 + fi + sleep 3; waited=$((waited + 3)) + done + err "${START_TIMEOUT}s 内未就绪,请检查日志: tail -100 ${STDOUT_LOG}" + exit 1 +} + +stop() { + local pid + pid=$(get_pid) + if [ -z "${pid}" ]; then + info "${APP_NAME} 未在运行" + return 0 + fi + info "停止 ${APP_NAME} (PID ${pid}) ..." + kill "${pid}" + local waited=0 + while kill -0 "${pid}" 2>/dev/null && [ ${waited} -lt 60 ]; do + sleep 2; waited=$((waited + 2)) + done + if kill -0 "${pid}" 2>/dev/null; then + warn "60s 未退出,强制 kill -9" + kill -9 "${pid}" 2>/dev/null || true + fi + rm -f "${INSTALL_DIR}/app.pid" + info "已停止" +} + +status() { + local pid + pid=$(get_pid) + if [ -z "${pid}" ]; then + info "${APP_NAME}: 未运行" + exit 1 + fi + info "${APP_NAME}: 运行中 (PID ${pid})" + if curl -sf -o /dev/null --max-time 3 "${HEALTH_URL}"; then + info "健康检查: 正常" + else + warn "健康检查: 8080 未响应(可能仍在启动)" + fi + info "内存: $(ps -o rss= -p "${pid}" | awk '{printf "%.0fMB", $1/1024}')" +} + +deploy() { + local new_jar="$1" + [ -f "${new_jar}" ] || { err "找不到 jar: ${new_jar}"; exit 1; } + prepare_dirs + local ts; ts=$(date +%Y%m%d-%H%M%S) + if [ -f "${JAR_FILE}" ]; then + # 运行中先停 + if [ -n "$(get_pid)" ]; then + stop + fi + cp "${JAR_FILE}" "${BACKUP_DIR}/${APP_NAME}-${ts}.jar" + info "旧版本已备份: ${BACKUP_DIR}/${APP_NAME}-${ts}.jar" + fi + cp "${new_jar}" "${JAR_FILE}" + # 保留最近 5 个备份 + ls -1t "${BACKUP_DIR}/${APP_NAME}-"*.jar 2>/dev/null | tail -n +6 | xargs -r rm -f + info "新版本已就位: ${JAR_FILE} ($(du -h "${JAR_FILE}" | cut -f1))" + start +} + +db_upgrade() { + local sql_file="$1" + [ -f "${sql_file}" ] || { err "找不到 SQL: ${sql_file}"; exit 1; } + case "${DISQL_CMD}" in + *""*) err "请先在脚本头部或环境变量 SFILE_DISQL 配置真实 disql 连接串"; exit 1;; + esac + info "执行升级 SQL: ${sql_file}" + # 达梦 disql 执行 SQL 文件语法: disql 用户/密码@host:port \`文件路径\` + ${DISQL_CMD} \`"${sql_file}" + info "执行完成,请核对上方输出无 ERROR 后再继续部署" +} + +log() { + local lines="${1:-200}" + tail -n "${lines}" "${STDOUT_LOG}" 2>/dev/null || warn "暂无日志: ${STDOUT_LOG}" +} + +case "${1:-}" in + start) start ;; + stop) stop ;; + restart) stop; start ;; + status) status ;; + deploy) [ $# -ge 2 ] || { err "用法: $0 deploy "; exit 1; }; deploy "$2" ;; + log) log "${2:-200}" ;; + db-upgrade) [ $# -ge 2 ] || { err "用法: $0 db-upgrade "; exit 1; }; db_upgrade "$2" ;; + *) sed -n '2,20p' "$0"; exit 1 ;; +esac diff --git a/backend/src/main/java/com/senmesh/SFileApplication.java b/backend/src/main/java/com/senmesh/SFileApplication.java new file mode 100644 index 0000000..838ddf6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/SFileApplication.java @@ -0,0 +1,22 @@ +package com.senmesh; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.scheduling.annotation.EnableScheduling; + + +/** + * @author sr on 2020-04-16 + */ +@SpringBootApplication(scanBasePackages = {"com.senmesh"}) +@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true) +@EnableScheduling +public class SFileApplication { + + public static void main(String[] args) { + SpringApplication.run(SFileApplication.class, args); + } + + +} diff --git a/backend/src/main/java/com/senmesh/codegenerator/config/CodeConfiguration.java b/backend/src/main/java/com/senmesh/codegenerator/config/CodeConfiguration.java new file mode 100644 index 0000000..fbd2414 --- /dev/null +++ b/backend/src/main/java/com/senmesh/codegenerator/config/CodeConfiguration.java @@ -0,0 +1,67 @@ +package com.senmesh.codegenerator.config; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.senmesh.codegenerator.service.CodeService; +import com.senmesh.codegenerator.service.SnowflakeIdWorker; +import com.senmesh.codegenerator.service.generator.SnowFlakeCodeGenerator; +import com.senmesh.codegenerator.service.impl.CodeServiceImpl; +import com.senmesh.codegenerator.util.CodeUtils; +import com.senmesh.common.CommonConfiguration; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.common.util.RequestUtils; + +import lombok.extern.slf4j.Slf4j; + +/** + * 发号器配置类 + * @author sr on 2021-03-23 + */ +//@Configuration +@AutoConfigureAfter(CommonConfiguration.class) +@Slf4j +public class CodeConfiguration { + + public static final String PROP_WORID_PREFIX = "code.snowflake.workid"; + + /** + * 默认编号生成器 + * @return + * @author sr on 2021-03-23 + */ + @Bean + public SnowFlakeCodeGenerator snowFlakeCodeGenerator() { + // 机器id + String hostIp = RequestUtils.getHostIp(); + log.info("hostIp:" + hostIp); + String workIdStr = EnvironmentUtils.getProperty( + String.join(CommonConstants.POINT, PROP_WORID_PREFIX, hostIp)); + Long workId = 99l; + try { + if (StringUtils.isNoneBlank(workIdStr)) { + workId = Long.valueOf(workIdStr); + } + } catch (Exception e) { + } + SnowflakeIdWorker idWorker = new SnowflakeIdWorker(workId, 0); + return new SnowFlakeCodeGenerator(idWorker); + } + + /** + * 编号service(根据类型分发不同的生成器) + * @return + * @author sr on 2021-03-23 + */ + @Bean + public CodeService codeService() { + CodeService codeService = new CodeServiceImpl(); + CodeUtils.setCodeService(codeService); + return codeService; + } + + +} diff --git a/backend/src/main/java/com/senmesh/codegenerator/constant/CodeConstants.java b/backend/src/main/java/com/senmesh/codegenerator/constant/CodeConstants.java new file mode 100644 index 0000000..12357fb --- /dev/null +++ b/backend/src/main/java/com/senmesh/codegenerator/constant/CodeConstants.java @@ -0,0 +1,26 @@ +package com.senmesh.codegenerator.constant; + +/** + * 编号常量类 + * @author sr on 2019-09-15 + */ +public class CodeConstants { + + /** 生成器类型:默认(不可用) **/ +// public static final String GENERATOR_TYPE_DEFAULT = "DEFAULT"; + public static final String GENERATOR_TYPE_SNOW_FLAKE = "SnowFlake"; + + /** id默认长度 **/ + public static final int ID_DEFAULT_LENGTH = 5; + + /** id默认补位字符 **/ + public static final char ID_DEFAULT_PAD = '0'; + /** id默认日期格式化 **/ + public static final DateFormatterEnum ID_DEFAULT_FORMATTER = DateFormatterEnum.YEAR; + + /** -----异常信息----- **/ + public static final String CODE_GENERATE_ERROR = "编号生成失败"; + /** -----异常信息----- **/ + + +} diff --git a/backend/src/main/java/com/senmesh/codegenerator/constant/DateFormatterEnum.java b/backend/src/main/java/com/senmesh/codegenerator/constant/DateFormatterEnum.java new file mode 100644 index 0000000..9255ff6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/codegenerator/constant/DateFormatterEnum.java @@ -0,0 +1,32 @@ +package com.senmesh.codegenerator.constant; + +import java.time.format.DateTimeFormatter; + +/** + * 日期formatter枚举 + * @author sr on 2019-12-03 + */ +public enum DateFormatterEnum { + + /** 年:yyyy **/ + YEAR(DateTimeFormatter.ofPattern("yyyy")), + /** 年月:yyyyMM **/ + YM(DateTimeFormatter.ofPattern("yyyyMM")), + /** 年月:yyMM **/ + YM2(DateTimeFormatter.ofPattern("yyMM")), + /** 年月日:yyyyMMdd **/ + YMD(DateTimeFormatter.ofPattern("yyyyMMdd")), + /** 年月日:yyMMdd **/ + YMD2(DateTimeFormatter.ofPattern("yyMMdd")); + + private DateTimeFormatter formatter; + + private DateFormatterEnum(DateTimeFormatter formatter){ + this.formatter = formatter; + } + + public DateTimeFormatter getDateTimeFormatter() { + return this.formatter; + } + +} diff --git a/backend/src/main/java/com/senmesh/codegenerator/exception/CodeGeneratorException.java b/backend/src/main/java/com/senmesh/codegenerator/exception/CodeGeneratorException.java new file mode 100644 index 0000000..ac122b6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/codegenerator/exception/CodeGeneratorException.java @@ -0,0 +1,26 @@ +package com.senmesh.codegenerator.exception; + +/** + * 编号生成器异常 + * @author sr on 2019-12-03 + */ +public class CodeGeneratorException extends RuntimeException{ + + /** **/ + private static final long serialVersionUID = 3558280270933232655L; + + + public CodeGeneratorException() {} + + public CodeGeneratorException(String message) { + super(message); + } + + public CodeGeneratorException(String message, Throwable cause) { + super(message, cause); + } + + public CodeGeneratorException(Throwable cause) { + super(cause); + } +} diff --git a/backend/src/main/java/com/senmesh/codegenerator/pojo/CodeParam.java b/backend/src/main/java/com/senmesh/codegenerator/pojo/CodeParam.java new file mode 100644 index 0000000..64e5818 --- /dev/null +++ b/backend/src/main/java/com/senmesh/codegenerator/pojo/CodeParam.java @@ -0,0 +1,25 @@ +package com.senmesh.codegenerator.pojo; + +import com.senmesh.codegenerator.constant.CodeConstants; + +import lombok.Builder; +import lombok.Data; +import lombok.Builder.Default; + +/** + * 编码生成参数对象 + * @author sr on 2019-12-05 + */ +@Data +@Builder +public class CodeParam { + + /** 生成器类型 **/ + @Default + private String generatorType = CodeConstants.GENERATOR_TYPE_SNOW_FLAKE; + + /** 编码类型 **/ + private String type; + + +} diff --git a/backend/src/main/java/com/senmesh/codegenerator/service/CodeGenerator.java b/backend/src/main/java/com/senmesh/codegenerator/service/CodeGenerator.java new file mode 100644 index 0000000..6deb748 --- /dev/null +++ b/backend/src/main/java/com/senmesh/codegenerator/service/CodeGenerator.java @@ -0,0 +1,42 @@ +package com.senmesh.codegenerator.service; + +import java.util.List; + +import com.senmesh.codegenerator.pojo.CodeParam; + +/** + * 编号生成器 默认一套实现,如需重定义中间时间format和id长度,重写规则 重写规则,注意去发号器对应的数据库表(leaf_alloc)中添加对应type+时间(biz_tag)的记录 + * + * @author sr on 2019-09-15 + */ +public interface CodeGenerator { + + /** + * 自定义特定业务类型,即前缀 + * + * @return + * @author sr on 2019-09-19 + */ + String getType(); + + + /** + * 根据生成规则获取编号 + * + * @param codeParam + * @return + * @author sr on 2020-07-13 + */ + String getCode(T codeParam); + + /** + * 批量根据生成规则获取编号 + * + * @param codeParam + * @return + * @author sr on 2020-07-13 + */ + List batchCode(T codeParam, Integer batchNum); + + +} diff --git a/backend/src/main/java/com/senmesh/codegenerator/service/CodeService.java b/backend/src/main/java/com/senmesh/codegenerator/service/CodeService.java new file mode 100644 index 0000000..9e609b6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/codegenerator/service/CodeService.java @@ -0,0 +1,33 @@ +package com.senmesh.codegenerator.service; + +import java.util.List; + +import com.senmesh.codegenerator.pojo.CodeParam; + +/** + * 编号service(根据类型分发不同的生成器) + * + * @author sr on 2019-09-15 + */ +public interface CodeService { + + /** + * 根据生成规则获取编号 + * + * @param codeParam + * @return + * @author sr on 2020-07-13 + */ + String getCode(CodeParam codeParam); + + /** + * 批量根据生成规则获取编号 + * + * @param codeParam + * @param batchNum 批次数(1-1000) + * @return + * @author sr on 2020-07-13 + */ + List batchCode(CodeParam codeParam, Integer batchNum); + +} diff --git a/backend/src/main/java/com/senmesh/codegenerator/service/SnowflakeIdWorker.java b/backend/src/main/java/com/senmesh/codegenerator/service/SnowflakeIdWorker.java new file mode 100644 index 0000000..387f95f --- /dev/null +++ b/backend/src/main/java/com/senmesh/codegenerator/service/SnowflakeIdWorker.java @@ -0,0 +1,160 @@ +package com.senmesh.codegenerator.service; + +/** + * Twitter_Snowflake
+ * SnowFlake的结构如下(每部分用-分开):
+ * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
+ * 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0
+ * 41位时间戳(毫秒级),注意,41位时间戳不是存储当前时间的时间戳,而是存储时间戳的差值(当前时间戳 - 开始时间戳) 得到的值),这里的的开始时间戳,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。41位的时间戳,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69
+ * 10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId
+ * 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间戳)产生4096个ID序号
+ * 加起来刚好64位,为一个Long型。
+ * SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生26万ID左右。 + */ +public class SnowflakeIdWorker { + + // ==============================Fields=========================================== + /** 开始时间戳 (2015-01-01) */ + private final long twepoch = 1420041600000L; + + /** 能容忍的系统时钟回拨时间(2秒) */ + private final long timeOffset = 2000L; + + /** 机器id所占的位数 */ + private final long workerIdBits = 5L; + + /** 数据标识id所占的位数 */ + private final long datacenterIdBits = 5L; + + /** 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */ + private final long maxWorkerId = -1L ^ (-1L << workerIdBits); + + /** 支持的最大数据标识id,结果是31 */ + private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); + + /** 序列在id中占的位数 */ + private final long sequenceBits = 12L; + + /** 机器ID向左移12位 */ + private final long workerIdShift = sequenceBits; + + /** 数据标识id向左移17位(12+5) */ + private final long datacenterIdShift = sequenceBits + workerIdBits; + + /** 时间戳向左移22位(5+5+12) */ + private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; + + /** 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) */ + private final long sequenceMask = -1L ^ (-1L << sequenceBits); + + /** 工作机器ID(0~31) */ + private long workerId; + + /** 数据中心ID(0~31) */ + private long datacenterId; + + /** 毫秒内序列(0~4095) */ + private long sequence = 0L; + + /** 上次生成ID的时间戳 */ + private long lastTimestamp = -1L; + + // ==============================Constructors===================================== + /** + * 构造函数 + * @param workerId 工作ID (0~31) + * @param datacenterId 数据中心ID (0~31) + */ + public SnowflakeIdWorker(long workerId, long datacenterId) { + if (workerId > maxWorkerId || workerId < 0) { + throw new IllegalArgumentException( + String.format("worker Id can't be greater than %d or less than 0", maxWorkerId)); + } + if (datacenterId > maxDatacenterId || datacenterId < 0) { + throw new IllegalArgumentException( + String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId)); + } + this.workerId = workerId; + this.datacenterId = datacenterId; + } + + // ==============================Methods========================================== + /** + * 获得下一个ID (该方法是线程安全的) + * @return SnowflakeId + */ + public synchronized long nextId() { + long timestamp = timeGen(); + + // 当前时间戳小于上一次ID生成的时间戳 + if (timestamp < lastTimestamp) { + long offset = lastTimestamp - timestamp; + // 系统时钟回退在容忍范围内,例如出现过闰秒 + if (offset < timeOffset) { + timestamp = lastTimestamp; + } + // 系统时钟回退超出容忍范围,抛出异常 + else { + throw new RuntimeException(String + .format("Clock moved backwards. Refusing to generate id for %d milliseconds", offset)); + } + } + + // 如果是同一时间生成的,则进行毫秒内序列 + if (lastTimestamp == timestamp) { + sequence = (sequence + 1) & sequenceMask; + // 毫秒内序列溢出 + if (sequence == 0) { + // 阻塞到下一个毫秒,获得新的时间戳 + timestamp = tilNextMillis(lastTimestamp); + } + } + // 时间戳改变,毫秒内序列重置 + else { + sequence = 0L; + } + + // 上次生成ID的时间戳 + lastTimestamp = timestamp; + + // 移位并通过或运算拼到一起组成64位的ID + return ((timestamp - twepoch) << timestampLeftShift) // + | (datacenterId << datacenterIdShift) // + | (workerId << workerIdShift) // + | sequence; + } + + /** + * 阻塞到下一个毫秒,直到获得新的时间戳 + * @param lastTimestamp 上次生成ID的时间戳 + * @return 当前时间戳 + */ + protected long tilNextMillis(long lastTimestamp) { + long timestamp = timeGen(); + while (timestamp <= lastTimestamp) { + timestamp = timeGen(); + } + return timestamp; + } + + /** + * 返回以毫秒为单位的当前时间 + * @return 当前时间(毫秒) + */ + protected long timeGen() { + return System.currentTimeMillis(); + } + + // ==============================Test============================================= + /** 测试 */ + public static void main(String[] args) { + + System.out.println("1000011111010000000111110011100110011110000000000000000001100".length()); + // SnowflakeIdWorker idWorker = new SnowflakeIdWorker(0, 0); + // for (int i = 0; i < 1000; i++) { + // long id = idWorker.nextId(); + // System.out.println(Long.toBinaryString(id)); + // System.out.println(id); + // } + } +} diff --git a/backend/src/main/java/com/senmesh/codegenerator/service/generator/SnowFlakeCodeGenerator.java b/backend/src/main/java/com/senmesh/codegenerator/service/generator/SnowFlakeCodeGenerator.java new file mode 100644 index 0000000..89c2b63 --- /dev/null +++ b/backend/src/main/java/com/senmesh/codegenerator/service/generator/SnowFlakeCodeGenerator.java @@ -0,0 +1,47 @@ +package com.senmesh.codegenerator.service.generator; + +import java.util.List; + +import com.google.common.collect.Lists; +import com.senmesh.codegenerator.constant.CodeConstants; +import com.senmesh.codegenerator.pojo.CodeParam; +import com.senmesh.codegenerator.service.CodeGenerator; +import com.senmesh.codegenerator.service.SnowflakeIdWorker; + +import lombok.extern.slf4j.Slf4j; + +/** + * 默认编号生成器 + * + * @author sr on 2019-09-15 + */ +@Slf4j +public class SnowFlakeCodeGenerator implements CodeGenerator { + + private SnowflakeIdWorker snowflakeIdWorker; + + public SnowFlakeCodeGenerator(SnowflakeIdWorker snowflakeIdWorker) { + this.snowflakeIdWorker = snowflakeIdWorker; + } + + + @Override + public String getType() { + return CodeConstants.GENERATOR_TYPE_SNOW_FLAKE; + } + + @Override + public String getCode(CodeParam codeParam) { + return codeParam.getType() + snowflakeIdWorker.nextId(); + } + + @Override + public List batchCode(CodeParam codeParam, Integer batchNum) { + List ids = Lists.newArrayListWithCapacity(batchNum); + for (int i = 0; i < batchNum; i++) { + ids.add(this.getCode(codeParam)); + } + return ids; + } + +} diff --git a/backend/src/main/java/com/senmesh/codegenerator/service/impl/CodeServiceImpl.java b/backend/src/main/java/com/senmesh/codegenerator/service/impl/CodeServiceImpl.java new file mode 100644 index 0000000..b7d980f --- /dev/null +++ b/backend/src/main/java/com/senmesh/codegenerator/service/impl/CodeServiceImpl.java @@ -0,0 +1,48 @@ +package com.senmesh.codegenerator.service.impl; + +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.google.common.collect.Maps; +import com.senmesh.codegenerator.constant.CodeConstants; +import com.senmesh.codegenerator.pojo.CodeParam; +import com.senmesh.codegenerator.service.CodeGenerator; +import com.senmesh.codegenerator.service.CodeService; + +/** + * 编号service实现类 + * + * @author sr on 2019-09-15 + */ +public class CodeServiceImpl implements CodeService { + + private Map> codeGenerators = Maps.newHashMap(); + + @SuppressWarnings({"unchecked", "rawtypes"}) + @Autowired + private void codeGenerateResolver(List resolvers) { + resolvers.forEach(resolver -> codeGenerators.put(resolver.getType(), resolver)); + } + + private CodeGenerator getResolver(String type) { + CodeGenerator resolver = codeGenerators.get(type); + if (resolver == null) { + resolver = codeGenerators.get(CodeConstants.GENERATOR_TYPE_SNOW_FLAKE); + } + return resolver; + } + + @Override + public String getCode(CodeParam codeParam) { + return getResolver(codeParam.getGeneratorType()).getCode(codeParam); + } + + @Override + public List batchCode(CodeParam codeParam, Integer batchNum) { + return getResolver(codeParam.getGeneratorType()).batchCode(codeParam, batchNum); + } + + +} diff --git a/backend/src/main/java/com/senmesh/codegenerator/util/CodeUtils.java b/backend/src/main/java/com/senmesh/codegenerator/util/CodeUtils.java new file mode 100644 index 0000000..aee77a7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/codegenerator/util/CodeUtils.java @@ -0,0 +1,48 @@ +package com.senmesh.codegenerator.util; + +import java.util.List; + +import com.senmesh.codegenerator.pojo.CodeParam; +import com.senmesh.codegenerator.service.CodeService; +import com.senmesh.component.constants.CodeTypeEnum; + +/** + * 发号器工具类 + * @author sr on 2021-03-23 + */ +public abstract class CodeUtils { + + private static CodeService codeService; + + public static void setCodeService(CodeService codeService) { + CodeUtils.codeService = codeService; + } + + public static String getCode(CodeTypeEnum codeTypeEnum) { + return codeService.getCode(codeTypeEnum.getCodeParam()); + } + + /** + * 根据生成规则获取编号 + * + * @param codeParam + * @return + * @author sr on 2021-03-23 + */ + public static String getCode(CodeParam codeParam) { + return codeService.getCode(codeParam); + } + + /** + * 批量根据生成规则获取编号 + * + * @param codeParam + * @param batchNum + * @return + * @author sr on 2021-03-23 + */ + public static List batchCode(CodeParam codeParam, Integer batchNum) { + return codeService.batchCode(codeParam, batchNum); + } + +} diff --git a/backend/src/main/java/com/senmesh/codesetting/constant/CodeSettingConstants.java b/backend/src/main/java/com/senmesh/codesetting/constant/CodeSettingConstants.java new file mode 100644 index 0000000..52ab057 --- /dev/null +++ b/backend/src/main/java/com/senmesh/codesetting/constant/CodeSettingConstants.java @@ -0,0 +1,37 @@ +package com.senmesh.codesetting.constant; + +public interface CodeSettingConstants { + /** + * 编码配置数据类型 + */ + public static final String CODE_SETTING_DATA_TYPE = "code_setting_data_type"; + + public class CodeSettingDataType { + + public static final String STRING = "1"; + + public static final String NUMBER = "2"; + + public static final String DATE = "3"; + + public static final String BOOL = "4"; + + public static final String RADIO = "5"; + + public static final String CHECKBOX = "6"; + + public static final String FILE = "7"; + + } + + /** + * 编码配置模块:机构配置 + **/ + public static final String CODE_SETTING_TYPE_CONFIG = "1"; + + /** + * 编码配置默认级别 + **/ + public static final String CODE_SETTING_LEVEL_DEFAULT = "1,2,3,4"; + +} diff --git a/backend/src/main/java/com/senmesh/codesetting/controller/CodeSettingController.java b/backend/src/main/java/com/senmesh/codesetting/controller/CodeSettingController.java new file mode 100644 index 0000000..7978f62 --- /dev/null +++ b/backend/src/main/java/com/senmesh/codesetting/controller/CodeSettingController.java @@ -0,0 +1,67 @@ +package com.senmesh.codesetting.controller; + +import com.senmesh.codesetting.dto.CodeSettingDTO; +import com.senmesh.codesetting.dto.CodeSettingOperatorDTO; +import com.senmesh.codesetting.dto.CodeSettingPageQueryDTO; +import com.senmesh.codesetting.dto.CodeSettingQueryDTO; +import com.senmesh.codesetting.service.CodeSettingService; +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 编码表 + * + * @author chenyun chenyun.home@outlook.com + * @since 1.0.0 2023-01-04 + */ +@Api(tags = "编码表") +@RestController +@RequestMapping("code_setting") +public class CodeSettingController { + + @Autowired + private CodeSettingService codeSettingService; + + @PostMapping + @ApiOperation("编码表-创建") + public AlitaResult create(@RequestBody CodeSettingOperatorDTO operatorDTO) { + return AlitaResult.success(codeSettingService.create(operatorDTO)); + } + + @PutMapping + @ApiOperation("编码表-修改") + public AlitaResult modify(@RequestBody CodeSettingOperatorDTO operatorDTO) { + return AlitaResult.success(codeSettingService.modify(operatorDTO)); + } + + @DeleteMapping("{id}") + @ApiOperation("编码表-删除") + public AlitaResult delete(@PathVariable("id") Long id) { + return AlitaResult.success(codeSettingService.delete(id)); + } + + @GetMapping("{id}") + @ApiOperation("编码表-查询单个") + public AlitaResult findById(@PathVariable("id") Long id) { + return AlitaResult.success(codeSettingService.findById(id)); + } + + @GetMapping("list") + @ApiOperation("编码表-列表查询") + public AlitaResult> list(CodeSettingQueryDTO queryDTO) { + return AlitaResult.success(codeSettingService.list(queryDTO)); + } + + @GetMapping("page") + @ApiOperation("编码表-分页查询") + public AlitaResult> page(CodeSettingPageQueryDTO queryDTO) { + codeSettingService.page(queryDTO); + return AlitaResult.success(queryDTO.getPageResult()); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/codesetting/convert/CodeSettingConvert.java b/backend/src/main/java/com/senmesh/codesetting/convert/CodeSettingConvert.java new file mode 100644 index 0000000..efcba09 --- /dev/null +++ b/backend/src/main/java/com/senmesh/codesetting/convert/CodeSettingConvert.java @@ -0,0 +1,25 @@ +package com.senmesh.codesetting.convert; + +import com.senmesh.codesetting.dto.CodeSettingDTO; +import com.senmesh.codesetting.dto.CodeSettingOperatorDTO; +import com.senmesh.codesetting.entity.CodeSetting; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * 编码表 + * + * @author chenyun chenyun.home@outlook.com + * @since 1.0.0 2023-01-04 + */ +@Mapper +public interface CodeSettingConvert { + CodeSettingConvert INSTANCE = Mappers.getMapper(CodeSettingConvert.class); + + CodeSetting convert(CodeSettingDTO dto); + + CodeSettingDTO convert(CodeSetting entity); + + CodeSetting convert(CodeSettingOperatorDTO dto); + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/codesetting/dao/CodeSettingMapper.java b/backend/src/main/java/com/senmesh/codesetting/dao/CodeSettingMapper.java new file mode 100644 index 0000000..c3b05f5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/codesetting/dao/CodeSettingMapper.java @@ -0,0 +1,35 @@ +package com.senmesh.codesetting.dao; + +import com.senmesh.codesetting.dto.CodeSettingDTO; +import com.senmesh.codesetting.dto.CodeSettingPageQueryDTO; +import com.senmesh.codesetting.dto.CodeSettingQueryDTO; +import com.senmesh.codesetting.entity.CodeSetting; +import com.senmesh.tkmybatis.mybatis.MyMapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + * 编码表 + * + * @author chenyun chenyun.home@outlook.com + * @since 1.0.0 2023-01-04 + */ +@Mapper +public interface CodeSettingMapper extends MyMapper { + + List page(@Param("param") CodeSettingPageQueryDTO queryDTO); + + List list(@Param("param") CodeSettingQueryDTO queryDTO); + + /** + * 根据类型查询 + * + * @param type + * @return + */ + @Select("select * from xs_code_setting where type = #{type} and deleted = 0") + List queryByType(String type); +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/codesetting/dto/CodeSettingDTO.java b/backend/src/main/java/com/senmesh/codesetting/dto/CodeSettingDTO.java new file mode 100644 index 0000000..01ba47e --- /dev/null +++ b/backend/src/main/java/com/senmesh/codesetting/dto/CodeSettingDTO.java @@ -0,0 +1,45 @@ +package com.senmesh.codesetting.dto; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.SuperBuilder; + +/** + * 编码表 + * + * @author chenyun chenyun.home@outlook.com + * @since 1.0.0 2023-01-04 + */ +@ApiModel("编码表") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class CodeSettingDTO extends BaseDTO { + private static final long serialVersionUID = 1L; + + @ApiModelProperty("编码") + private String code; + + @ApiModelProperty("名称") + private String name; + + @ApiModelProperty("备注") + private String remark; + + @ApiModelProperty("类型 模板编码、配置编码") + private String type; + + @ApiModelProperty("数据类型") + private String dataType; + + @ApiModelProperty("级别 平台、渠道、定制机构、普通机构") + private String level; + + @ApiModelProperty("数据值") + private String dataFormat; +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/codesetting/dto/CodeSettingOperatorDTO.java b/backend/src/main/java/com/senmesh/codesetting/dto/CodeSettingOperatorDTO.java new file mode 100644 index 0000000..a6d40e3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/codesetting/dto/CodeSettingOperatorDTO.java @@ -0,0 +1,60 @@ +package com.senmesh.codesetting.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotEmpty; +import java.io.Serializable; + +/** + * 编码表 + * + * @author chenyun chenyun.home@outlook.com + * @since 1.0.0 2023-01-04 + */ +@ApiModel("编码表") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CodeSettingOperatorDTO implements Serializable { + + private static final long serialVersionUID = 8836210011277521607L; + private Long id; + + @ApiModelProperty("编码") + @NotEmpty(message = "配置项编码不能为空") + @Length(min = 1, max = 64, message = "配置项编码长度超限") + private String code; + + @ApiModelProperty("名称") + @NotEmpty(message = "配置项名称不能为空") + @Length(min = 1, max = 128, message = "配置项名称长度超限") + private String name; + + @ApiModelProperty("备注") +// @NotEmpty(message = "备注不能为空") + private String remark; + + @ApiModelProperty("数据值") + private String dataFormat; + + @ApiModelProperty("类型 模板编码、配置编码") + @NotEmpty(message = "配置类型不能为空") + private String type; + + @ApiModelProperty("数据类型") + @NotEmpty(message = "配置参数类型不能为空") + private String dataType; + + @ApiModelProperty("级别 平台、渠道、定制机构、普通机构") + @NotEmpty(message = "配置应用级别不能为空") + private String level; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/codesetting/dto/CodeSettingPageQueryDTO.java b/backend/src/main/java/com/senmesh/codesetting/dto/CodeSettingPageQueryDTO.java new file mode 100644 index 0000000..8bdd0a0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/codesetting/dto/CodeSettingPageQueryDTO.java @@ -0,0 +1,77 @@ +package com.senmesh.codesetting.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.senmesh.common.annotation.trimAndUpper.TrimAndUpper; +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +/** + * 编码表 + * + * @author chenyun chenyun.home@outlook.com + * @since 1.0.0 2023-01-04 + */ + +@ApiModel("编码表") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class CodeSettingPageQueryDTO extends PageQueryDTO { + private static final long serialVersionUID = 1L; + + @ApiModelProperty("主键ID") + private Long id; + + @ApiModelProperty("编码") + private String code; + + @ApiModelProperty("编码 (模糊匹配)") + @TrimAndUpper(TrimAndUpper.ExecuteType.TRIM) + private String codeLike; + + @ApiModelProperty("名称 (模糊匹配)") + @TrimAndUpper(TrimAndUpper.ExecuteType.TRIM) + private String nameLike; + + @ApiModelProperty("备注") + private String remark; + + @ApiModelProperty("类型 模板编码、配置编码") + @TrimAndUpper(TrimAndUpper.ExecuteType.TRIM) + private String type; + + @ApiModelProperty("数据类型") + private String dataType; + + @ApiModelProperty("级别 平台、渠道、定制机构、普通机构") + private String level; + + @ApiModelProperty("创建时间起,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTimeStart; + + @ApiModelProperty("创建时间止,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTimeEnd; + + @ApiModelProperty("修改时间起,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTimeStart; + + @ApiModelProperty("修改时间止,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTimeEnd; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/codesetting/dto/CodeSettingQueryDTO.java b/backend/src/main/java/com/senmesh/codesetting/dto/CodeSettingQueryDTO.java new file mode 100644 index 0000000..cb8d028 --- /dev/null +++ b/backend/src/main/java/com/senmesh/codesetting/dto/CodeSettingQueryDTO.java @@ -0,0 +1,74 @@ +package com.senmesh.codesetting.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serializable; +import java.util.Date; + +/** + * 编码表 + * + * @author chenyun chenyun.home@outlook.com + * @since 1.0.0 2023-01-04 + */ +@ApiModel("编码表") +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class CodeSettingQueryDTO implements Serializable { + private static final long serialVersionUID = 1L; + + @ApiModelProperty("主键ID") + private Long id; + + @ApiModelProperty("编码") + private String code; + + @ApiModelProperty("编码 (模糊匹配)") + private String codeLike; + + @ApiModelProperty("名称 (模糊匹配)") + private String nameLike; + + @ApiModelProperty("备注") + private String remark; + + @ApiModelProperty("类型 模板编码、配置编码") + private String type; + + @ApiModelProperty("数据类型") + private String dataType; + + @ApiModelProperty("级别 平台、渠道、定制机构、普通机构") + private String level; + + @ApiModelProperty("创建时间起,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTimeStart; + + @ApiModelProperty("创建时间止,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTimeEnd; + + @ApiModelProperty("修改时间起,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTimeStart; + + @ApiModelProperty("修改时间止,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTimeEnd; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/codesetting/entity/CodeSetting.java b/backend/src/main/java/com/senmesh/codesetting/entity/CodeSetting.java new file mode 100644 index 0000000..c4a7a88 --- /dev/null +++ b/backend/src/main/java/com/senmesh/codesetting/entity/CodeSetting.java @@ -0,0 +1,56 @@ +package com.senmesh.codesetting.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 编码表 + * + * @author chenyun chenyun.home@outlook.com + * @since 1.0.0 2023-01-04 + */ +@TableName("xs_code_setting") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class CodeSetting extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** + * 编码 + */ + private String code; + /** + * 名称 + */ + private String name; + /** + * 备注 + */ + private String remark; + /** + * 类型 模板编码、配置编码 + */ + private String type; + /** + * 数据类型 + */ + private String dataType; + /** + * 数据格式编号 + */ + private String dataFormat; + /** + * 级别 平台、渠道、定制机构、普通机构 + */ + private String level; +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/codesetting/mapper/CodeSettingMapper.xml b/backend/src/main/java/com/senmesh/codesetting/mapper/CodeSettingMapper.xml new file mode 100644 index 0000000..504d4e5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/codesetting/mapper/CodeSettingMapper.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + FROM + xs_code_setting t + WHERE t.deleted = FALSE + + AND t.id = #{param.id} + + + AND t.code = #{param.code} + + + + AND t.code like #{codeLike} + + + + AND t.name like #{nameLike} + + + AND t.remark = #{param.remark} + + + AND t.type = #{param.type} + + + AND t.data_type = #{param.dataType} + + + AND FIND_IN_SET(CONCAT(#{param.level},""),t.level) + + + AND t.create_time >= #{param.createTimeStart} + + + AND t.create_time <= #{param.createTimeEnd} + + + AND t.update_time >= #{param.updateTimeStart} + + + AND t.update_time <= #{param.updateTimeEnd} + + ORDER BY t.id DESC + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/codesetting/service/CodeSettingService.java b/backend/src/main/java/com/senmesh/codesetting/service/CodeSettingService.java new file mode 100644 index 0000000..ee325f4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/codesetting/service/CodeSettingService.java @@ -0,0 +1,95 @@ +package com.senmesh.codesetting.service; + +import com.senmesh.codesetting.dto.CodeSettingDTO; +import com.senmesh.codesetting.dto.CodeSettingOperatorDTO; +import com.senmesh.codesetting.dto.CodeSettingPageQueryDTO; +import com.senmesh.codesetting.dto.CodeSettingQueryDTO; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.groups.Default; +import java.util.List; + +/** + * 编码表 + * + * @author chenyun chenyun.home@outlook.com + * @since 1.0.0 2023-01-04 + */ +@Validated(Default.class) +public interface CodeSettingService { + + /** + * 编码表 - 创建 + * + * @param operatorDto 操作dto + * @return {@link CodeSettingDTO} + */ + CodeSettingDTO create(@Valid CodeSettingOperatorDTO operatorDto); + + /** + * 校验编码是否存在 + * + * @param code 代码 + * @param codeSettingId 编码ID + * @return boolean true: 存在重复编码 + */ + boolean checkCode(String code, Long codeSettingId); + + /** + * 编码表 - 修改 + * + * @param operatorDto 操作dto + * @return {@link CodeSettingDTO} + */ + CodeSettingDTO modify(@Valid CodeSettingOperatorDTO operatorDto); + + /** + * 编码表 - 删除 + * + * @param id id + * @return {@link CodeSettingDTO} + */ + CodeSettingDTO delete(Long id); + + /** + * 编码表 - 根据ID查询单个 + * + * @param id id + * @return {@link CodeSettingDTO} + */ + CodeSettingDTO findById(Long id); + + /** + * 编码表 - 列表查询 + * + * @param queryDTO 列表查询dto + * @return {@link List}<{@link CodeSettingDTO}> + */ + List list(CodeSettingQueryDTO queryDTO); + + /** + * 编码表 - 分页查询 + * + * @param queryDTO 分页查询dto + * @return {@link CodeSettingDTO} + */ + List page(CodeSettingPageQueryDTO queryDTO); + + /** + * 根据type和code查询 + * + * @param codeSettingType + * @param orgType + * @return + */ + List queryCode(String codeSettingType, String orgType); + + /** + * 根据code查询 + * + * @param code + * @return + */ + CodeSettingDTO getByCode(String code); +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/codesetting/service/impl/CodeSettingServiceImpl.java b/backend/src/main/java/com/senmesh/codesetting/service/impl/CodeSettingServiceImpl.java new file mode 100644 index 0000000..b554198 --- /dev/null +++ b/backend/src/main/java/com/senmesh/codesetting/service/impl/CodeSettingServiceImpl.java @@ -0,0 +1,119 @@ +package com.senmesh.codesetting.service.impl; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import javax.annotation.Resource; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.ArrayUtils; +import org.springframework.stereotype.Service; + +import com.senmesh.codesetting.convert.CodeSettingConvert; +import com.senmesh.codesetting.dao.CodeSettingMapper; +import com.senmesh.codesetting.dto.CodeSettingDTO; +import com.senmesh.codesetting.dto.CodeSettingOperatorDTO; +import com.senmesh.codesetting.dto.CodeSettingPageQueryDTO; +import com.senmesh.codesetting.dto.CodeSettingQueryDTO; +import com.senmesh.codesetting.entity.CodeSetting; +import com.senmesh.codesetting.service.CodeSettingService; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.config.dao.ConfigMapper; + +import lombok.extern.slf4j.Slf4j; + +/** + * 编码表 + * + * @author chenyun chenyun.home@outlook.com + * @since 1.0.0 2023-01-04 + */ +@Slf4j +@Service +public class CodeSettingServiceImpl implements CodeSettingService { + + @Resource + private CodeSettingMapper codeSettingMapper; + + @Resource + private ConfigMapper configMapper; + + @Override + public CodeSettingDTO create(CodeSettingOperatorDTO operatorDto) { + Assert.isTrue(!checkCode(operatorDto.getCode(), null), "配置项编码已存在"); + CodeSetting codeSetting = CodeSettingConvert.INSTANCE.convert(operatorDto); + codeSettingMapper.saveEntity(codeSetting); + return CodeSettingConvert.INSTANCE.convert(codeSetting); + } + + @Override + public boolean checkCode(String code, Long codeSettingId) { + return codeSettingMapper.existsEntity(CodeSetting.builder().code(code).build()); + } + + @Override + public CodeSettingDTO modify(CodeSettingOperatorDTO operatorDto) { + CodeSettingDTO codeSettingDto = this.findById(operatorDto.getId()); + if (Objects.isNull(codeSettingDto)) { + return null; + } + Assert.isTrue(!checkCode(operatorDto.getCode(), operatorDto.getId()), "配置项编码已存在"); + CodeSetting codeSetting = CodeSettingConvert.INSTANCE.convert(operatorDto); + codeSettingMapper.updateEntity(codeSetting); + return this.findById(operatorDto.getId()); + } + + @Override + public CodeSettingDTO delete(Long id) { + CodeSettingDTO codeSettingDto = this.findById(id); + if (Objects.isNull(codeSettingDto)) { + return null; + } + CodeSetting codeSetting = CodeSetting.builder().build(); + codeSetting.setId(id); + codeSettingMapper.deleteEntity(codeSetting, UserContextHolder.getLoginUserId()); + // 删除配置项的时候,同步删除配置项下的配置 + configMapper.batchDelete(codeSettingDto.getCode(), UserContextHolder.getExistLoginUserId()); + return codeSettingDto; + } + + @Override + public CodeSettingDTO findById(Long id) { + CodeSetting codeSetting = codeSettingMapper.getById(id); + if (Objects.isNull(codeSetting)) { + return null; + } + return CodeSettingConvert.INSTANCE.convert(codeSetting); + } + + @Override + public List list(CodeSettingQueryDTO queryDTO) { + return codeSettingMapper.list(queryDTO); + } + + @Override + public List page(CodeSettingPageQueryDTO queryDTO) { + return codeSettingMapper.page(queryDTO); + } + + @Override + public List queryCode(String codeSettingType, String orgType) { + List codeSettings = codeSettingMapper.queryByType(codeSettingType); + return codeSettings.stream() + .filter(codeSetting -> ArrayUtils + .contains(codeSetting.getLevel().split(CommonConstants.COMMA), orgType)) + .map(CodeSettingConvert.INSTANCE::convert).collect(Collectors.toList()); + } + + @Override + public CodeSettingDTO getByCode(String code) { + List list = this.list(CodeSettingQueryDTO.builder().code(code).build()); + if (CollectionUtils.isEmpty(list)) { + return null; + } + return list.get(0); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/common/AlitaResult.java b/backend/src/main/java/com/senmesh/common/AlitaResult.java new file mode 100644 index 0000000..070873a --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/AlitaResult.java @@ -0,0 +1,253 @@ +package com.senmesh.common; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.senmesh.sdk.common.constant.SdkConstants; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 用于 ajax 请求的响应工具类 + * + * @author guhong + * @date 2019/8/19 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class AlitaResult implements Serializable { + + /** */ + private static final long serialVersionUID = 5933105804003541576L; + + /** 未登录 * */ + public static final String UN_LOGIN_CODE = "401"; + /** 无权限 * */ + public static final String NO_AUTHORITY_CODE = "402"; + /** 无查询信息 * */ + public static final String NO_RESULT_CODE = "405"; + /** 登录用户多机构 * */ + public static final String DUPLICATE_ORG_CODE = "600"; + /** 登录用户多用户 * */ + public static final String DUPLICATE_USER_CODE = "601"; + /** 用户未实名 * */ + public static final String UN_AUTH_CODE = "602"; + /** 用户更换token **/ + public static final String CHANGE_TOKEN_CODE = "603"; + /** 用户未绑定手机号 **/ + public static final String UN_BINDING_PHONE = "604"; + /** 登录用户相关异常 **/ + public static final String LOGIN_ERROR_CODE = "666"; + /** 系统异常 * */ + public static final String SYSTEM_ERROR_CODE = "999"; + /** 业务异常 **/ + public static final String BUSINESS_ERROR_CODE = "700"; + /** 校验异常 * */ + public static final String VALIDATION_ERROR_CODE = "555"; + /** 操作成功 * */ + public static final String SUCCESS_CODE = "200"; + + public static final String CHANG_TOKEN_MSG = "token变更"; + + /** 链路id **/ + private String requestId; + /** 响应信息 */ + private String msg; + /** 响应code */ + private String code; + /** 是否成功 */ + private Boolean success; + /** 操作成功,响应数据 */ + private T data; + /** 操作失败结果 **/ + private Object errorData; + + /** 临时json **/ + @JsonIgnore + private String tempJson; + + public AlitaResult(String code, String msg, boolean success, T data) { + this.msg = msg; + this.code = code; + this.success = success; + this.data = data; + } + + public AlitaResult(String code, String msg, Serializable errorData) { + this.msg = msg; + this.code = code; + this.success = false; + this.errorData = errorData; + } + + /** + * 创建一个成功的响应对象 + * + * @return + */ + public static AlitaResult success() { + return success(null); + } + + /** + * 创建一个成功的响应对象 + * + * @param data + * @return + */ + public static AlitaResult success(T data) { + return new AlitaResult(SUCCESS_CODE, "请求成功", true, data); + } + + /** + * 创建一个成功的响应对象 + * + * @param msg + * @return + */ + public static AlitaResult success(String msg, T data) { + return new AlitaResult(SUCCESS_CODE, msg, true, data); + } + + /** + * 创建一个失败的响应对象 + * + * @param msg + * @return + */ + public static AlitaResult error(String msg) { + return new AlitaResult(SYSTEM_ERROR_CODE, msg, false, null); + } + + /** + * 创建一个失败的响应对象 + * + * @param code + * @param msg + * @return + */ + public static AlitaResult error(String code, String msg) { + return new AlitaResult(code, msg, false, null); + } + + /** + * 创建一个失败的响应对象 + * + * @param code + * @param msg + * @return + */ + public static AlitaResult error(String code, String msg, T data) { + return new AlitaResult(code, msg, false, data); + } + + /** + * 创建一个失败的响应对象 + * + * @param msg + * @return + */ + public static AlitaResult error(String msg, T data) { + return new AlitaResult(SYSTEM_ERROR_CODE, msg, false, data); + } + + /** + * 创建业务异常对象 + * + * @param + * @param msg + * @return + * @author sr on 2020-07-02 + */ + public static AlitaResult bizError(String msg) { + return new AlitaResult(BUSINESS_ERROR_CODE, msg, false, null); + } + + /** + * 创建一个未登录响应对象 + * + * @return + */ + public static AlitaResult unLogin() { + return new AlitaResult(UN_LOGIN_CODE, "请先登录", false, null); + } + + /** + * 创建未实名响应对象 + * @param + * @return + * @author sr on 2021-06-30 + */ + public static AlitaResult unAuth() { + return new AlitaResult(UN_AUTH_CODE, "请先实名", false, null); + } + + /** + * 创建未绑定手机号响应对象 + * @param + * @return + * @author sr on 2021-06-30 + */ + public static AlitaResult unBinding() { + return new AlitaResult(UN_BINDING_PHONE, "请先绑定手机号", false, null); + } + + /** + * 创建一个未登录响应对象 + * + * @param loginUrl 登录地址 + * @return + * @author sr on 2019-12-29 + */ + public static AlitaResult unLogin(String loginUrl) { + return new AlitaResult(UN_LOGIN_CODE, "请先登录", false, loginUrl); + } + + /** + * 更换token + * @param + * @param token + * @return + * @author sr on 2021-08-02 + */ + public static AlitaResult changeToken(Serializable token) { + return new AlitaResult(AlitaResult.CHANGE_TOKEN_CODE, CHANG_TOKEN_MSG, token); + } + + /** + * 创建一个未登录响应对象 + * + * @return + * @author sr on 2019-12-29 + */ + public static AlitaResult noResult() { + return new AlitaResult(NO_RESULT_CODE, "无查询信息", false, null); + } + + /** + * 接口调用失败,未能拿到返回对象 + * + * @param + * @param msg + * @return + * @author sr on 2020-04-10 + */ + public static AlitaResult sdkInvokeNotReachError(String msg) { + return new AlitaResult(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, msg, false, null); + } + + @SuppressWarnings({"hiding", "unchecked"}) + public AlitaResult setRequestId(String requestId){ + this.requestId = requestId; + return (AlitaResult) this; + } + + public AlitaResult setTempJson(String tempJson){ + this.tempJson = tempJson; + return (AlitaResult) this; + } + +} diff --git a/backend/src/main/java/com/senmesh/common/CommonConfiguration.java b/backend/src/main/java/com/senmesh/common/CommonConfiguration.java new file mode 100644 index 0000000..b32c203 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/CommonConfiguration.java @@ -0,0 +1,110 @@ +package com.senmesh.common; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.core.env.Environment; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StringDeserializer; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.senmesh.common.cache.DefaultCacheProvider; +import com.senmesh.common.cache.ICacheProvider; +import com.senmesh.common.log.ILogProvider; +import com.senmesh.common.log.provider.Slf4jLogProvider; +import com.senmesh.common.log.util.LogUtils; +import com.senmesh.common.service.IMockProvider; +import com.senmesh.common.service.IMockProvider.DefaultMockProvider; +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.common.util.MockUtils; +import com.senmesh.component.file.service.IFileStorage; +import com.senmesh.component.file.service.storage.LocalFileStorage; +import com.senmesh.component.file.util.FileStorageUtils; + +import lombok.var; + +/** + * @author sr on 2020-07-24 + */ +@Configuration +public class CommonConfiguration { + + @Bean + EnvironmentUtils environmentUtils(Environment environment) { + return new EnvironmentUtils(environment); + } + + @Bean + @ConditionalOnMissingBean(ICacheProvider.class) + @Order(100) + DefaultCacheProvider defauCacheProvider() { + return new DefaultCacheProvider(); + } + + @Bean + @Order(100) + @ConditionalOnMissingBean(ILogProvider.class) + Slf4jLogProvider slf4jLogProvider() { + return new Slf4jLogProvider(); + } + + @Bean + @Order(200) + LogUtils logUtils(ILogProvider iLogProvider) { + LogUtils logUtils = new LogUtils(); + logUtils.setLogProvider(iLogProvider); + return logUtils; + } + + @Bean + @ConditionalOnMissingBean(IFileStorage.class) + public LocalFileStorage localFileStorage() { + return new LocalFileStorage(); + } + + @Bean + public FileStorageUtils fileStorageUtils(IFileStorage fileStorage) { + return new FileStorageUtils(fileStorage); + } + + @Bean + @ConditionalOnMissingBean(IMockProvider.class) + public IMockProvider defaultMockProvider() { + return new DefaultMockProvider(); + } + + @Bean + public MockUtils mockUtils(IMockProvider mockProvider) { + return new MockUtils(mockProvider); + } + + /** + * requestbody string trim + * @return + * @author sr on 2024-04-19 + */ + @Bean + public SimpleModule stringDeserializerModule() { + final var module = new SimpleModule(); + module.addDeserializer(String.class, new StringDeserializer() { + @Override + public String deserialize(JsonParser p, DeserializationContext ctx) throws java.io.IOException { + final var value = super.deserialize(p, ctx); + if (value == null) { + return null; + } + + final var trimmed = value.trim(); + if (trimmed.isEmpty()) { + return null; + } + + return trimmed; + } + }); + return module; + } + +} diff --git a/backend/src/main/java/com/senmesh/common/CoreConfiguration.java b/backend/src/main/java/com/senmesh/common/CoreConfiguration.java new file mode 100644 index 0000000..987eb5b --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/CoreConfiguration.java @@ -0,0 +1,26 @@ +package com.senmesh.common; + +import org.jasypt.encryption.StringEncryptor; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.senmesh.common.trace.DefaultTracer; +import com.senmesh.common.trace.ITracer; +import com.senmesh.common.util.JasyptUtils; + +@Configuration +public class CoreConfiguration { + + @Bean + JasyptUtils jasyptUtils(StringEncryptor stringEncryptor) { + return new JasyptUtils(stringEncryptor); + } + + @Bean + @ConditionalOnMissingBean(value = ITracer.class) + ITracer defaultTracer() { + return new DefaultTracer(); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/actuate/health/dto/HealthDTO.java b/backend/src/main/java/com/senmesh/common/actuate/health/dto/HealthDTO.java new file mode 100644 index 0000000..5964987 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/actuate/health/dto/HealthDTO.java @@ -0,0 +1,24 @@ +package com.senmesh.common.actuate.health.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 监控健康信息 + * + * @author sr on 2020-07-08 + * @param + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class HealthDTO { + + private String status; + + private T details; + +} diff --git a/backend/src/main/java/com/senmesh/common/annotation/AlitaStopWatch.java b/backend/src/main/java/com/senmesh/common/annotation/AlitaStopWatch.java new file mode 100644 index 0000000..3a21d98 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/annotation/AlitaStopWatch.java @@ -0,0 +1,14 @@ +package com.senmesh.common.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface AlitaStopWatch { + +} diff --git a/backend/src/main/java/com/senmesh/common/annotation/CheckAndMock.java b/backend/src/main/java/com/senmesh/common/annotation/CheckAndMock.java new file mode 100644 index 0000000..0a1f4b3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/annotation/CheckAndMock.java @@ -0,0 +1,56 @@ +package com.senmesh.common.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.senmesh.common.constant.ProjectProfileEnum; + +/** + * 校验并mock + * + * @author sr on 2020-05-20 + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface CheckAndMock { + + /** + * 属性前缀 + * + * @return + * @author sr on 2020-05-20 + */ + String propertyPrefix() default ""; + + /** + * 属性配置类 + * + * @return + * @author sr on 2020-05-20 + */ + Class checkAndMockPropertity() default ICheckAndMockPropertity.class; + + /** + * mock实现类(需注入spring上下文,提供与原方法方法名/参数/返回对象一致的方法) + * + * @return + * @author sr on 2020-05-20 + */ + Class mockClass(); + + // String mockBeanId(); + + /** + * 指定环境直接mock + * + * @return + * @author sr on 2020-05-21 + */ + ProjectProfileEnum[] mockIfInProfile() default {}; + + +} diff --git a/backend/src/main/java/com/senmesh/common/annotation/CheckJob.java b/backend/src/main/java/com/senmesh/common/annotation/CheckJob.java new file mode 100644 index 0000000..76ad1b9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/annotation/CheckJob.java @@ -0,0 +1,27 @@ +package com.senmesh.common.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 校验定时任务是否开启 + * + * @author sr on 2020-05-19 + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface CheckJob { + + /** + * 配置文件是否开启的key,明确指定为false时才关闭 + * + * @return + * @author sr on 2020-05-19 + */ + String value(); + +} diff --git a/backend/src/main/java/com/senmesh/common/annotation/ICheckAndMockPropertity.java b/backend/src/main/java/com/senmesh/common/annotation/ICheckAndMockPropertity.java new file mode 100644 index 0000000..f317fab --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/annotation/ICheckAndMockPropertity.java @@ -0,0 +1,34 @@ +package com.senmesh.common.annotation; + +/** + * 需要校验后mock的配置 + * + * @author sr on 2020-05-20 + */ +public interface ICheckAndMockPropertity { + + /** + * 是否开启 + * + * @return + * @author sr on 2020-05-21 + */ + Boolean getEnable(); + + /** + * 次数限制 + * + * @return + * @author sr on 2020-05-21 + */ + Long getNumLimit(); + + /** + * 属性前缀 + * + * @return + * @author sr on 2020-05-21 + */ + String getPropertityPrefix(); + +} diff --git a/backend/src/main/java/com/senmesh/common/annotation/Mask.java b/backend/src/main/java/com/senmesh/common/annotation/Mask.java new file mode 100644 index 0000000..5e01afd --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/annotation/Mask.java @@ -0,0 +1,19 @@ +package com.senmesh.common.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; + +/** + * 掩码 + * @author sr on 2021-11-25 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.METHOD}) +@JacksonAnnotationsInside +public @interface Mask { + +} diff --git a/backend/src/main/java/com/senmesh/common/annotation/MaskAnontationIntrospector.java b/backend/src/main/java/com/senmesh/common/annotation/MaskAnontationIntrospector.java new file mode 100644 index 0000000..07a74e7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/annotation/MaskAnontationIntrospector.java @@ -0,0 +1,32 @@ +package com.senmesh.common.annotation; + +import com.fasterxml.jackson.databind.introspect.Annotated; +import com.fasterxml.jackson.databind.introspect.AnnotatedMember; +import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector; + +/** + * @author sr on 2021-11-25 + */ +public class MaskAnontationIntrospector extends JacksonAnnotationIntrospector { + + private static final long serialVersionUID = 1L; + + @Override + public Object findSerializer(Annotated a) { + Mask mask = a.getAnnotation(Mask.class); + if (mask != null) { + return MaskSerializer.class; + } + return super.findSerializer(a); + } + + @Override + public boolean hasIgnoreMarker(AnnotatedMember m) { + // 直接不打印该字段,则置为true + /*if (m.hasAnnotation(Mask.class)) { + return true; + }*/ + return super.hasIgnoreMarker(m); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/annotation/MaskSerializer.java b/backend/src/main/java/com/senmesh/common/annotation/MaskSerializer.java new file mode 100644 index 0000000..fa00f9d --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/annotation/MaskSerializer.java @@ -0,0 +1,37 @@ +package com.senmesh.common.annotation; + +import java.io.IOException; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; + +/** + * @author sr on 2021-11-25 + */ +public class MaskSerializer extends StdSerializer { + + private static final long serialVersionUID = 1L; + + private String mask = "***"; + + public MaskSerializer() { + super(Object.class); + } + + public MaskSerializer(String mask, int count) { + this(); + } + + public MaskSerializer(MaskSerializer src) { + super(src); + } + + @Override + public void serialize(Object s, JsonGenerator jsonGenerator, + SerializerProvider serializerProvider) throws IOException { + jsonGenerator.writeString(mask); + } + + +} diff --git a/backend/src/main/java/com/senmesh/common/annotation/aspect/AlitaStopWatchAspect.java b/backend/src/main/java/com/senmesh/common/annotation/aspect/AlitaStopWatchAspect.java new file mode 100644 index 0000000..a4e7dbc --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/annotation/aspect/AlitaStopWatchAspect.java @@ -0,0 +1,49 @@ +package com.senmesh.common.annotation.aspect; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.stereotype.Component; +import org.springframework.util.StopWatch; + +import com.senmesh.common.annotation.AlitaStopWatch; +import com.senmesh.common.exception.util.DevopsUtils; +import com.senmesh.common.util.EnvironmentUtils; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Aspect +@Component +public class AlitaStopWatchAspect { + + public static final String DEVOPS_TIME_KEY = "devops.usetime"; + /** 默认十分钟 **/ + public static final Long DEFAULT_DEVOPS_TIME = 10 * 60L; + + + @Around("@annotation(alitaStopWatch)") + public Object around(ProceedingJoinPoint joinPoint, AlitaStopWatch alitaStopWatch) throws Throwable { + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + try { + return joinPoint.proceed(); + } finally { + stopWatch.stop(); + String useTimeStr = EnvironmentUtils.getProperty(DEVOPS_TIME_KEY); + Long maxUseTime = DEFAULT_DEVOPS_TIME; + try { + maxUseTime = Long.parseLong(useTimeStr); + } catch (Exception e) { + } + maxUseTime = 1000 * maxUseTime; + Long actualTime = stopWatch.getTotalTimeMillis(); + String logMsg = joinPoint.getSignature().toShortString() + ",use(ms): " + actualTime; + if (actualTime > maxUseTime) { + DevopsUtils.deal(logMsg); + } + log.info(logMsg); + } + } + +} diff --git a/backend/src/main/java/com/senmesh/common/annotation/aspect/CheckAndMockAspect.java b/backend/src/main/java/com/senmesh/common/annotation/aspect/CheckAndMockAspect.java new file mode 100644 index 0000000..1389299 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/annotation/aspect/CheckAndMockAspect.java @@ -0,0 +1,129 @@ +package com.senmesh.common.annotation.aspect; + +import com.senmesh.common.annotation.CheckAndMock; +import com.senmesh.common.annotation.ICheckAndMockPropertity; +import com.senmesh.common.cache.ICacheProvider; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.constant.ProjectProfileEnum; +import com.senmesh.common.util.SpringContextHolder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; + +/** + * 校验并mock + * + * @author sr on 2020-05-19 + */ +@Aspect +@Component +@Slf4j +@Order(200) +public class CheckAndMockAspect { + + /** 是否开启属性 **/ + public static final String ENABLE_KEY = "enable"; + /** 次数限制属性 **/ + public static final String NUM_LIMIT_KEY = "numLimit"; + /** 默认次数 **/ + public static final Long DEFALUT_NUM_LIMIT = 3L; + + @Autowired + private Environment environment; + + @Autowired + private ICacheProvider iCacheProvider; + + @Around("@annotation(checkAndMock)") + public Object around(ProceedingJoinPoint joinPoint, CheckAndMock checkAndMock) throws Throwable { + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + Method method = signature.getMethod(); + ProjectProfileEnum[] profileEnums = checkAndMock.mockIfInProfile(); + Class mockClass = checkAndMock.mockClass(); + String currentProfile = environment.getProperty(CommonConstants.PROFILE_KEY); + + Object[] args = joinPoint.getArgs(); + // 只要配置环境mock,就不校验开关和次数限制 + if (profileEnums.length > 0) { + for (ProjectProfileEnum profileEnum : profileEnums) { + if (profileEnum.getValue().equals(currentProfile)) { + return mock(mockClass, method, args); + } + } + return joinPoint.proceed(); + } + + // 获取属性配置 + String propertyPrefix = checkAndMock.propertyPrefix(); + boolean enable = true; + Long numLimit = null; + if (StringUtils.isNotBlank(propertyPrefix)) { + enable = BooleanUtils.toBoolean( + environment.getProperty(String.join(CommonConstants.POINT, propertyPrefix, ENABLE_KEY))); + try { + numLimit = enable ? Long.parseLong(environment + .getProperty(String.join(CommonConstants.POINT, propertyPrefix, NUM_LIMIT_KEY))) : 0L; + } catch (NumberFormatException e) { + log.info("{} numLimit not right, use default numLimit", propertyPrefix); + } + } else { + try { + ICheckAndMockPropertity properties = + SpringContextHolder.getBean(checkAndMock.checkAndMockPropertity()); + enable = properties.getEnable(); + numLimit = properties.getNumLimit(); + propertyPrefix = properties.getPropertityPrefix(); + } catch (Exception e) { + log.info("ICheckAndMockPropertity not found..."); + enable = false; + } + } + + // 开关关闭,都走mock + if (!enable) { + return mock(mockClass, method, args); + } + // 开关开启,生产无次数限制,本地测试根据配置/默认次数控制 + boolean isProd = ProjectProfileEnum.PROD.getValue().equals(currentProfile); + if (isProd) { + return joinPoint.proceed(); + } + + numLimit = numLimit == null ? DEFALUT_NUM_LIMIT : numLimit; + String key = String.join(CommonConstants.POINT, propertyPrefix, NUM_LIMIT_KEY); + if (iCacheProvider.outLimit(key, numLimit)) { + // 超限,mock + return mock(mockClass, method, args); + } + // 次数限制 + return joinPoint.proceed(); + } + + + /** + * mock调用 + * + * @param clazz + * @param method + * @param objects + * @return + * @throws Throwable + * @author sr on 2020-05-21 + */ + private Object mock(Class clazz, Method method, Object[] objects) throws Throwable { + Object mockBean = SpringContextHolder.getBean(clazz); + Method mockMethod = mockBean.getClass().getMethod(method.getName(), method.getParameterTypes()); + return mockMethod.invoke(mockBean, objects); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/annotation/aspect/CheckJobAspect.java b/backend/src/main/java/com/senmesh/common/annotation/aspect/CheckJobAspect.java new file mode 100644 index 0000000..b4bd8ff --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/annotation/aspect/CheckJobAspect.java @@ -0,0 +1,46 @@ +package com.senmesh.common.annotation.aspect; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import com.senmesh.common.annotation.CheckJob; +import com.senmesh.common.constant.CommonConstants; + +import lombok.extern.slf4j.Slf4j; + +/** + * 校验定时任务是否开启 + * + * @author sr on 2020-05-19 + */ +@Aspect +@Component +@Slf4j +public class CheckJobAspect { + + /** 配置无效识别符(只有配置false才失效) **/ + private String falseValue = "false"; + + /** 定时任务配置前缀 **/ + public static final String JOB_PROPERTY_PREFIX = "job"; + + @Autowired + private Environment environment; + + @Around("@annotation(checkJob)") + public Object around(ProceedingJoinPoint joinPoint, CheckJob checkJob) throws Throwable { + String propertityKey = checkJob.value(); + boolean disable = falseValue.equals(environment + .getProperty(String.join(CommonConstants.POINT, JOB_PROPERTY_PREFIX, propertityKey))); + if (disable) { + log.info("job:{} not enable...", propertityKey); + return null; + } + return joinPoint.proceed(); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/annotation/trimAndUpper/TrimAndUpper.java b/backend/src/main/java/com/senmesh/common/annotation/trimAndUpper/TrimAndUpper.java new file mode 100644 index 0000000..3e87d65 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/annotation/trimAndUpper/TrimAndUpper.java @@ -0,0 +1,31 @@ +package com.senmesh.common.annotation.trimAndUpper; + +import java.lang.annotation.*; + +/** + * 用于字符串去空格以及大写 + * + * @author Carlye + * @date 2022/02/16 + */ +@Target(value = { ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface TrimAndUpper { + + /** + * 执行类型 + * ALL: (所有类型都包含) + * TRIM: (去两边的空格) + * REPLACE_ALL: (去所有的空格) + * UPPER_CASE: (转大写) + * + * @author Carlye + * @date 2022/02/16 + */ + public static enum ExecuteType { + ALL, TRIM, REPLACE_ALL, UPPER_CASE; + } + + ExecuteType value() default ExecuteType.ALL; +} diff --git a/backend/src/main/java/com/senmesh/common/annotation/trimAndUpper/TrimAndUpperAnontationIntrospector.java b/backend/src/main/java/com/senmesh/common/annotation/trimAndUpper/TrimAndUpperAnontationIntrospector.java new file mode 100644 index 0000000..da7f744 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/annotation/trimAndUpper/TrimAndUpperAnontationIntrospector.java @@ -0,0 +1,27 @@ +package com.senmesh.common.annotation.trimAndUpper; + +import com.fasterxml.jackson.databind.AnnotationIntrospector; +import com.fasterxml.jackson.databind.introspect.Annotated; +import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair; + +/** + * @author sr on 2021-11-25 + */ +public class TrimAndUpperAnontationIntrospector extends AnnotationIntrospectorPair { + + + private static final long serialVersionUID = -1755768596246088917L; + + public TrimAndUpperAnontationIntrospector(AnnotationIntrospector p, + AnnotationIntrospector s) { + super(p, s); + } + @Override + public Object findDeserializer(Annotated a) { + TrimAndUpper trim = a.getAnnotation(TrimAndUpper.class); + if (trim != null) { + return TrimAndUpperDeserializer.class; + } + return super.findDeserializer(a); + } +} diff --git a/backend/src/main/java/com/senmesh/common/annotation/trimAndUpper/TrimAndUpperConfig.java b/backend/src/main/java/com/senmesh/common/annotation/trimAndUpper/TrimAndUpperConfig.java new file mode 100644 index 0000000..ecd4836 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/annotation/trimAndUpper/TrimAndUpperConfig.java @@ -0,0 +1,59 @@ +package com.senmesh.common.annotation.trimAndUpper; + +import com.fasterxml.jackson.databind.AnnotationIntrospector; +import com.fasterxml.jackson.databind.DeserializationConfig; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.cfg.BaseSettings; +import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair; +import java.lang.reflect.Field; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.format.FormatterRegistry; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.util.ReflectionUtils; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; + +@Configuration +public class TrimAndUpperConfig { + + @Autowired + public void addFormatters(FormatterRegistry registry) { + TrimAndUpperFormatterFactory trimAndUpperCaseFormatterFactory = new TrimAndUpperFormatterFactory(); + registry.addFormatterForFieldAnnotation(trimAndUpperCaseFormatterFactory); + } + + @Autowired + public void init(RequestMappingHandlerAdapter handlerAdapter){ + for (HttpMessageConverter messageConverter : handlerAdapter.getMessageConverters()) { + try { + if (messageConverter instanceof MappingJackson2HttpMessageConverter){ + MappingJackson2HttpMessageConverter converter1 = (MappingJackson2HttpMessageConverter)messageConverter; + ObjectMapper objectMapper = converter1.getObjectMapper(); + DeserializationConfig deserializationConfig = objectMapper.getDeserializationConfig(); + + Field _base = ReflectionUtils.findField(DeserializationConfig.class, "_base"); + ReflectionUtils.makeAccessible(_base); + BaseSettings baseSettings = (BaseSettings)ReflectionUtils.getField(_base, deserializationConfig); + + AnnotationIntrospector annotationIntrospector = baseSettings.getAnnotationIntrospector(); + if (annotationIntrospector instanceof AnnotationIntrospectorPair){ + AnnotationIntrospectorPair annotationIntrospectorOld = (AnnotationIntrospectorPair)baseSettings.getAnnotationIntrospector(); + + Field _primary = ReflectionUtils.findField(AnnotationIntrospectorPair.class, "_primary"); + ReflectionUtils.makeAccessible(_primary); + AnnotationIntrospector _primaryObj = (AnnotationIntrospector)ReflectionUtils.getField(_primary, annotationIntrospectorOld); + + Field _secondary = ReflectionUtils.findField(AnnotationIntrospectorPair.class, "_secondary"); + ReflectionUtils.makeAccessible(_secondary); + AnnotationIntrospector _secondaryObj = (AnnotationIntrospector)ReflectionUtils.getField(_secondary, annotationIntrospectorOld); + + converter1.getObjectMapper().setAnnotationIntrospector(new TrimAndUpperAnontationIntrospector(_primaryObj,_secondaryObj)); + } + } + } catch (Exception e) { + //doNothing + } + } + } +} diff --git a/backend/src/main/java/com/senmesh/common/annotation/trimAndUpper/TrimAndUpperDeserializer.java b/backend/src/main/java/com/senmesh/common/annotation/trimAndUpper/TrimAndUpperDeserializer.java new file mode 100644 index 0000000..ead52f5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/annotation/trimAndUpper/TrimAndUpperDeserializer.java @@ -0,0 +1,66 @@ +package com.senmesh.common.annotation.trimAndUpper; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.deser.ContextualDeserializer; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.google.common.collect.Maps; +import com.senmesh.common.annotation.trimAndUpper.TrimAndUpper.ExecuteType; +import java.io.IOException; +import java.util.Map; +import java.util.Objects; +import org.apache.commons.lang3.StringUtils; + +public class TrimAndUpperDeserializer extends StdDeserializer implements ContextualDeserializer { + + private static final Map INSTANCE_MAP = Maps.newHashMap(); + private static final long serialVersionUID = 3463447204376923373L; + + static { + for (ExecuteType value : ExecuteType.values()) { + INSTANCE_MAP.put(value,new TrimAndUpperDeserializer(value)); + } + } + + private ExecuteType executeType; + + public TrimAndUpperDeserializer(){ + super(String.class); + } + + public TrimAndUpperDeserializer(ExecuteType executeType){ + super(String.class); + this.executeType = executeType; + } + + @Override + public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { + String s = jsonParser.getText(); + if (!(StringUtils.isEmpty(s) || Objects.isNull(executeType))) { + if (ExecuteType.ALL == executeType || ExecuteType.TRIM == executeType) { + s = StringUtils.replace(StringUtils.trim(s)," ",""); + } + if (ExecuteType.ALL == executeType || ExecuteType.TRIM == executeType) { + s = StringUtils.upperCase(s); + } + } + return s; + } + + @Override + public JsonDeserializer createContextual(DeserializationContext prov, BeanProperty property) throws JsonMappingException { + ExecuteType executeType = null; + TrimAndUpper ann = null; + if (property != null) { + ann = property.getAnnotation(TrimAndUpper.class); + } + if (ann != null) { + executeType = ann.value(); + } + return INSTANCE_MAP.get(executeType); + } +} diff --git a/backend/src/main/java/com/senmesh/common/annotation/trimAndUpper/TrimAndUpperFormatterFactory.java b/backend/src/main/java/com/senmesh/common/annotation/trimAndUpper/TrimAndUpperFormatterFactory.java new file mode 100644 index 0000000..1a5b719 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/annotation/trimAndUpper/TrimAndUpperFormatterFactory.java @@ -0,0 +1,77 @@ +package com.senmesh.common.annotation.trimAndUpper; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.senmesh.common.annotation.trimAndUpper.TrimAndUpper.ExecuteType; +import org.apache.commons.lang3.StringUtils; +import org.springframework.format.AnnotationFormatterFactory; +import org.springframework.format.Formatter; +import org.springframework.format.Parser; +import org.springframework.format.Printer; + +import java.text.ParseException; +import java.util.*; + +public class TrimAndUpperFormatterFactory implements + AnnotationFormatterFactory { + + private static final Map TRIMMER_FORMATTER_MAP; + + static { + ExecuteType[] values = ExecuteType.values(); + Map map = Maps.newHashMap(); + for (ExecuteType type : values) { + map.put(type, new TrimAndUpperCaseFormatter(type)); + } + TRIMMER_FORMATTER_MAP = Collections.unmodifiableMap(map); + } + + @Override + public Set> getFieldTypes() { + return Sets.newHashSet(String.class); + } + + @Override + public Printer getPrinter(TrimAndUpper trimAndUpper, Class aClass) { + return TRIMMER_FORMATTER_MAP.get(trimAndUpper.value()); + } + + @Override + public Parser getParser(TrimAndUpper trimAndUpper, Class aClass) { + return TRIMMER_FORMATTER_MAP.get(trimAndUpper.value()); + } + + private static class TrimAndUpperCaseFormatter implements Formatter { + + private TrimAndUpper.ExecuteType executeType; + + public TrimAndUpperCaseFormatter(TrimAndUpper.ExecuteType executeType) { + this.executeType = executeType; + } + + @Override + public String parse(String value, Locale locale) throws ParseException { + if (StringUtils.isEmpty(value) || Objects.isNull(executeType)) { + return value; + } + // 去所有空格 + if (ExecuteType.ALL == executeType || ExecuteType.REPLACE_ALL == executeType) { + value = StringUtils.replace(value, " ", ""); + } + // 转大写 + if (ExecuteType.ALL == executeType || ExecuteType.UPPER_CASE == executeType) { + value = StringUtils.upperCase(value); + } + //去两边空格 + if (ExecuteType.ALL == executeType || ExecuteType.TRIM == executeType) { + value = StringUtils.trim(value); + } + return value; + } + + @Override + public String print(String value, Locale locale) { + return value; + } + } +} diff --git a/backend/src/main/java/com/senmesh/common/cache/DefaultCacheProvider.java b/backend/src/main/java/com/senmesh/common/cache/DefaultCacheProvider.java new file mode 100644 index 0000000..88f804c --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/cache/DefaultCacheProvider.java @@ -0,0 +1,31 @@ +package com.senmesh.common.cache; + +import java.util.Map; + +import org.apache.commons.collections.MapUtils; + +import com.google.common.collect.Maps; + +/** + * @author sr on 2020-07-07 + */ +public class DefaultCacheProvider implements ICacheProvider { + + private Map numLimitMap = Maps.newConcurrentMap(); + + @Override + public boolean outLimit(final String key, Long maxNumLimit) { + Long currentNumLimit = null; + final Object lockKey = key.intern(); + synchronized (lockKey) { + currentNumLimit = MapUtils.getLong(numLimitMap, key, 0L); + if (currentNumLimit >= maxNumLimit) { + return true; + } + currentNumLimit++; + numLimitMap.put(key, currentNumLimit); + } + return false; + } + +} diff --git a/backend/src/main/java/com/senmesh/common/cache/ICacheProvider.java b/backend/src/main/java/com/senmesh/common/cache/ICacheProvider.java new file mode 100644 index 0000000..dbd469d --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/cache/ICacheProvider.java @@ -0,0 +1,18 @@ +package com.senmesh.common.cache; + +/** + * @author sr on 2020-07-07 + */ +public interface ICacheProvider { + + /** + * 是否超限 + * + * @param key + * @param maxNumLimit + * @return + * @author sr on 2020-07-07 + */ + boolean outLimit(String key, Long maxNumLimit); + +} diff --git a/backend/src/main/java/com/senmesh/common/cache/RedisCacheProvier.java b/backend/src/main/java/com/senmesh/common/cache/RedisCacheProvier.java new file mode 100644 index 0000000..89bb416 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/cache/RedisCacheProvier.java @@ -0,0 +1,32 @@ +package com.senmesh.common.cache; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.core.annotation.Order; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +/** + * @author sr on 2020-07-07 + */ +@Service +@ConditionalOnClass(RedisTemplate.class) +@Order(1) +public class RedisCacheProvier implements ICacheProvider{ + + @SuppressWarnings("rawtypes") + @Autowired(required = false) + private RedisTemplate redisTemplate; + + @SuppressWarnings("unchecked") + @Override + public boolean outLimit(String key, Long maxNumLimit) { + Long currentNumLimit = redisTemplate.opsForValue().increment(key); + if (currentNumLimit > maxNumLimit) { + redisTemplate.opsForValue().decrement(key); + return true; + } + return false; + } + +} diff --git a/backend/src/main/java/com/senmesh/common/constant/AuthStatusEnum.java b/backend/src/main/java/com/senmesh/common/constant/AuthStatusEnum.java new file mode 100644 index 0000000..9cb50d8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/constant/AuthStatusEnum.java @@ -0,0 +1,48 @@ +package com.senmesh.common.constant; + +/** + * 系统枚举 + * + * @author sr on 2020-06-02 + */ +public enum AuthStatusEnum { + + /** + * 待认证 + **/ + NOT_AUTH(1, "待认证"), + /** + * 认证中 + **/ + AUTHING(2, "认证中"), + /** + * 认证成功 + **/ + AUTH_SUCCESS(3, "认证成功"), + /** + * 认证失败 + **/ + AUTH_FAIL(4, "认证失败"); + + /** + * 状态类型 + */ + private Integer type; + /** + * 状态名称 + */ + private String name; + + AuthStatusEnum(Integer type, String name) { + this.type = type; + this.name = name; + } + + public Integer getType() { + return type; + } + + public String getName() { + return name; + } +} diff --git a/backend/src/main/java/com/senmesh/common/constant/CacheConstants.java b/backend/src/main/java/com/senmesh/common/constant/CacheConstants.java new file mode 100644 index 0000000..b7141f0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/constant/CacheConstants.java @@ -0,0 +1,12 @@ +package com.senmesh.common.constant; + +/** + * 缓存常量 + * + * @author sr on 2020-04-03 + */ +public interface CacheConstants { + + String CACHE_NAME_DICT = "dict"; + +} diff --git a/backend/src/main/java/com/senmesh/common/constant/CommonConstants.java b/backend/src/main/java/com/senmesh/common/constant/CommonConstants.java new file mode 100644 index 0000000..4a2d440 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/constant/CommonConstants.java @@ -0,0 +1,70 @@ +package com.senmesh.common.constant; + +/** + * 公共常量 + * @author sr on 2019-12-03 + */ +public interface CommonConstants { + + /** _(下划线) **/ + String UNDERLINE = "_"; + /** # **/ + String POUND = "#"; + /** & **/ + String AND = "&"; + /** ,(逗号) **/ + String COMMA = ","; + /** :(冒号) **/ + String COLON = ":"; + /** ;(分号) **/ + String SEMICOLON = ";"; + /** . **/ + String POINT = "."; + /** = **/ + String EQUAL = "="; + /** ? **/ + String QUESTION = "?"; + /** -(连字号) **/ + String HYPHEN = "-"; + /** ...(省略号) **/ + String ELLIPSIS = "..."; + + /** 金额精度:两位 **/ + int AMOUNT_SCALE = 2; + + /** 金额小数位 **/ + int AMOUNT_FRACTION = 2; + /** 金额整数位 **/ + int AMOUNT_INTEGER = 14; + + + /** 项目环境配置key **/ + String PROFILE_KEY = "spring.profiles.active"; + /** 项目名称 **/ + String APPLICATION_NAME_KEY = "spring.application.name"; + String SYSTEM_CODE_KEY = "system.code"; + /** security是否使用本地方法 **/ + String USELOCAL_KEY = "security.useLocal"; + + /** + * 表字段去空格 + */ + String TRIM_TABLE_FIELDS_ENBALE_KEY = "trim.table.fields"; + + /** 开关键 **/ + String ENABLE_KEY = "enable"; + + String FALSE_STR = "false"; + + /** 配置值:是 **/ + String CONFIG_TRUE = "1"; + /** 配置值:否 **/ + String CONFIG_FALSE = "0"; + + /** 平台机构id **/ + Long PLATFORM_ORG_ID = 1L; + + /** 用户禁用/注销登录态黑名单key前缀(存Redis,值存在期间该用户已发放的token视为无效) **/ + String USER_DISABLED_KEY = "user:disabled:"; + +} diff --git a/backend/src/main/java/com/senmesh/common/constant/CommonMqConstants.java b/backend/src/main/java/com/senmesh/common/constant/CommonMqConstants.java new file mode 100644 index 0000000..ebc6c1e --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/constant/CommonMqConstants.java @@ -0,0 +1,6 @@ +package com.senmesh.common.constant; + +public interface CommonMqConstants { + + +} diff --git a/backend/src/main/java/com/senmesh/common/constant/CookieConstants.java b/backend/src/main/java/com/senmesh/common/constant/CookieConstants.java new file mode 100644 index 0000000..58d2fb8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/constant/CookieConstants.java @@ -0,0 +1,18 @@ +package com.senmesh.common.constant; + +/** + * @author Jerry.li + * @description Cookie相关常量 + * @date 2020/5/11 + */ +public class CookieConstants { + + /** + * 登录Cookie名称前缀 + */ + public static final String LOGIN_COOKIE_NAME_PREFIX = "xs_ck_"; + + /** 属性配置键:cookie域名 **/ + public static final String PROP_KEY_COOKIE_DOMAIN = "cookie.domain"; + +} diff --git a/backend/src/main/java/com/senmesh/common/constant/ExceptionMsgs.java b/backend/src/main/java/com/senmesh/common/constant/ExceptionMsgs.java new file mode 100644 index 0000000..0bc12a7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/constant/ExceptionMsgs.java @@ -0,0 +1,21 @@ +package com.senmesh.common.constant; + +/** + * 异常错误信息 + * + * @author on 2019-11-05 + */ +public interface ExceptionMsgs { + + String ENTITY_HAS_EXISTS = "数据已存在"; + + String ENTITY_NONE_EXISTS = "数据不存在"; + + String ENTITY_MULTIPLE_EXISTS = "数据存在多条"; + + String UPDATE_DATA_NOT_EXIST = "操作失败,请检查数据"; + + + + +} diff --git a/backend/src/main/java/com/senmesh/common/constant/ExceptionRecordConstants.java b/backend/src/main/java/com/senmesh/common/constant/ExceptionRecordConstants.java new file mode 100644 index 0000000..0862123 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/constant/ExceptionRecordConstants.java @@ -0,0 +1,10 @@ +package com.senmesh.common.constant; + +public interface ExceptionRecordConstants { + + /** + * 接口记录系统类型 + */ + String SOURCE_HYG = "1"; + String SOURCE_XINPAI = "2"; +} diff --git a/backend/src/main/java/com/senmesh/common/constant/GenderEnum.java b/backend/src/main/java/com/senmesh/common/constant/GenderEnum.java new file mode 100644 index 0000000..34a627b --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/constant/GenderEnum.java @@ -0,0 +1,48 @@ +package com.senmesh.common.constant; + +/** + * 性别枚举 + * + */ +public enum GenderEnum { + + MALE(1, "男"), + FEMALE(2, "女"), + OTHER(3, "其它"); + + private final Integer type; + + private final String desc; + + GenderEnum(Integer type, String desc) { + this.type = type; + this.desc = desc; + } + + public Integer getType() { + return type; + } + + public String getDesc() { + return desc; + } + + public static Integer formatFemale(Integer value){ + // 通过sql 身份证号处理性别条件:0女,1男 + if(GenderEnum.FEMALE.getType().equals(value)){ + return 0; + } + return value; + } + + public static String getVal(Integer val){ + if(GenderEnum.MALE.getType().equals(val)){ + return GenderEnum.MALE.desc; + } else if(GenderEnum.FEMALE.getType().equals(val)){ + return GenderEnum.FEMALE.desc; + } + return GenderEnum.OTHER.desc; + } + + +} diff --git a/backend/src/main/java/com/senmesh/common/constant/ProjectProfileEnum.java b/backend/src/main/java/com/senmesh/common/constant/ProjectProfileEnum.java new file mode 100644 index 0000000..f2b6aed --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/constant/ProjectProfileEnum.java @@ -0,0 +1,30 @@ +package com.senmesh.common.constant; + +/** + * 项目环境枚举 + * @author sr on 2020-05-20 + */ +public enum ProjectProfileEnum { + + /** 开发 **/ + DEV("dev"), + /** 测试 **/ + TEST("test"), + /** 测试 * */ + UAT("uat"), + /** 生产 **/ + PROD("prod"), + /** 福安 **/ + FUAN("fuan"); + + private String value; + + ProjectProfileEnum(String value){ + this.value = value; + } + + public String getValue() { + return this.value; + } + +} diff --git a/backend/src/main/java/com/senmesh/common/constant/TradeAccountTypeConstants.java b/backend/src/main/java/com/senmesh/common/constant/TradeAccountTypeConstants.java new file mode 100644 index 0000000..900ff35 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/constant/TradeAccountTypeConstants.java @@ -0,0 +1,69 @@ +package com.senmesh.common.constant; + +import java.util.Arrays; +import java.util.Objects; + +/** + * 交易账户类型常量 + * @author sr on 2020-08-19 + */ +public interface TradeAccountTypeConstants { + + /** 交易账号类型:银行卡 **/ + String TRADE_ACCOUNT_TYPE_BANK = TradeAccountTypeEnum.BANK.getType().toString(); + /** 交易账号类型:子账号 **/ + String TRADE_ACCOUNT_TYPE_SUB_ACCOUNT = TradeAccountTypeEnum.SUB_ACCOUNT.getType().toString(); + /** 交易账号类型:支付宝账号 **/ + String TRADE_ACCOUNT_TYPE_ALIPAY_ACCOUNT = TradeAccountTypeEnum.ALIPAY_ACCOUNT.getType().toString(); + /** 交易账号类型:支付宝用户ID **/ + String TRADE_ACCOUNT_TYPE_ALIPAY_USERID = TradeAccountTypeEnum.ALIPAY_USERID.getType().toString(); + /** 交易账号类型:微信OPENID **/ + String TRADE_ACCOUNT_TYPE_WECHAT_OPENID = TradeAccountTypeEnum.WECHAT_OPENID.getType().toString(); + /** 交易账号类型:平台机构 **/ + String TRADE_ACCOUNT_TYPE_PLATFORM_ORG = TradeAccountTypeEnum.PLATFORM_ORG.getType().toString(); + + /** + * 交易账号类型:其他 + */ + String TRADE_ACCOUNT_TYPE_OTHER = TradeAccountTypeEnum.OTHER.getType().toString(); + + /** + * 帐户类型枚举 + * + * @author Carlye + * @date 2021/08/17 + */ + public enum TradeAccountTypeEnum{ + BANK(1,"银行卡"), + SUB_ACCOUNT(2,"内部子账户"), + ALIPAY_ACCOUNT(3,"支付宝账号"), + ALIPAY_USERID(4,"支付宝用户ID"), + WECHAT_OPENID(5,"微信支付"), + PLATFORM_ORG(6,"平台机构"), + OTHER(99,"其他"); + + private final Integer type; + + private final String desc; + + TradeAccountTypeEnum(Integer type,String desc){ + this.type = type; + this.desc = desc; + } + + public Integer getType() { + return type; + } + + public String getDesc() { + return desc; + } + + public static TradeAccountTypeEnum find(Integer type){ + if (Objects.isNull(type)){ + return null; + } + return Arrays.stream(TradeAccountTypeEnum.values()).filter(e->e.getType().equals(type)).findFirst().orElse(null); + } + } +} diff --git a/backend/src/main/java/com/senmesh/common/controller/TestController.java b/backend/src/main/java/com/senmesh/common/controller/TestController.java new file mode 100644 index 0000000..5969375 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/controller/TestController.java @@ -0,0 +1,41 @@ +package com.senmesh.common.controller; + +import org.springframework.beans.factory.annotation.Autowired; +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.RestController; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.common.util.RequestUtils; +import com.senmesh.commonexport.service.ExportService; +import com.senmesh.usercenter.user.dto.UserDTO; + +@RestController +public class TestController { + + @Autowired + private ExportService exportService; + + @GetMapping("anon/hostIp") + public AlitaResult hostIp() { + return AlitaResult.success(RequestUtils.getHostIp()); + } + + @GetMapping("anon/trim") + public AlitaResult gettrim(UserDTO userDTO) { + return AlitaResult.success(JsonUtils.toJsonString(userDTO)); + } + + + @PostMapping("anon/trim") + public AlitaResult posttrim(@RequestBody UserDTO userDTO) { + return AlitaResult.success(JsonUtils.toJsonString(userDTO)); + } + + + + + +} diff --git a/backend/src/main/java/com/senmesh/common/dto/BaseDTO.java b/backend/src/main/java/com/senmesh/common/dto/BaseDTO.java new file mode 100644 index 0000000..3b86a1f --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/dto/BaseDTO.java @@ -0,0 +1,56 @@ +package com.senmesh.common.dto; + +import java.io.Serializable; +import java.util.Date; + +import javax.validation.constraints.NotNull; + +import org.springframework.format.annotation.DateTimeFormat; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonFormat.Shape; +import com.senmesh.common.validation.Update; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + + +/** + * 基础dto + * + * @author sr on 2019-12-07 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class BaseDTO implements Serializable,IBaseDTO { + + /** **/ + private static final long serialVersionUID = 3305990673475531178L; + + @ApiModelProperty("id") + @NotNull(message = "id不能为空", groups = {Update.class}) + private Long id; + @ApiModelProperty("是否逻辑删除(0否1是)") + private Boolean deleted; + @ApiModelProperty("创建人") + private Long createBy; + @ApiModelProperty("创建时间") + // requestparam + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + // requestbody+serial + @JsonFormat(shape = Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + @ApiModelProperty("修改人") + private Long updateBy; + @ApiModelProperty("修改时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTime; + private Long proxyBy; + +} diff --git a/backend/src/main/java/com/senmesh/common/dto/BaseOperateDTO.java b/backend/src/main/java/com/senmesh/common/dto/BaseOperateDTO.java new file mode 100644 index 0000000..e64732f --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/dto/BaseOperateDTO.java @@ -0,0 +1,41 @@ +package com.senmesh.common.dto; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.senmesh.common.util.UserContextHolder; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 基础操作对象 + * + * @author sr on 2020-08-26 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class BaseOperateDTO implements Serializable, IOperateDTO{ + + /** **/ + private static final long serialVersionUID = -3075506470200622050L; + + /** 操作机构ID **/ + @JsonIgnore + private Long operateOrgId; + + /** 操作用户ID **/ + @JsonIgnore + private Long operateUserId; + + public Long getOperateOrgId() { + return operateOrgId == null ? UserContextHolder.getLoginOrgId() : operateOrgId; + } + + public Long getOperateUserId() { + return operateUserId == null ? UserContextHolder.getLoginUserId() : operateUserId; + } + +} diff --git a/backend/src/main/java/com/senmesh/common/dto/ButtonDTO.java b/backend/src/main/java/com/senmesh/common/dto/ButtonDTO.java new file mode 100644 index 0000000..038cd1d --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/dto/ButtonDTO.java @@ -0,0 +1,13 @@ +package com.senmesh.common.dto; + +import java.io.Serializable; + +/** + * @author sr on 2020-04-22 + */ +public class ButtonDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = -8606784819452806185L; + +} diff --git a/backend/src/main/java/com/senmesh/common/dto/CasTokenDTO.java b/backend/src/main/java/com/senmesh/common/dto/CasTokenDTO.java new file mode 100644 index 0000000..a5e6704 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/dto/CasTokenDTO.java @@ -0,0 +1,27 @@ +package com.senmesh.common.dto; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CasTokenDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = -6818144396647084889L; + + private String token; + + /** 当前token用户id **/ + private Long userId; + + /** 是否新注册 **/ + private Boolean register; + +} diff --git a/backend/src/main/java/com/senmesh/common/dto/ColumnDTO.java b/backend/src/main/java/com/senmesh/common/dto/ColumnDTO.java new file mode 100644 index 0000000..9e24d3c --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/dto/ColumnDTO.java @@ -0,0 +1,37 @@ +package com.senmesh.common.dto; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Builder.Default; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-04-22 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ColumnDTO implements Serializable{ + /** **/ + private static final long serialVersionUID = 1L; + + private static final int DEFAULT_WIDTH = 160; + + /** 标题,如:总条数 **/ + private String title; + /** 下标(同key),如:totalCount **/ + private String dataIndex; + /** 属性,如:totalCount **/ + private String key; + /** 宽度 **/ + @Default + private int width = DEFAULT_WIDTH; + /** 对齐方式 **/ + @Default + private String align = "center"; + +} diff --git a/backend/src/main/java/com/senmesh/common/dto/DisplayedComponentDTO.java b/backend/src/main/java/com/senmesh/common/dto/DisplayedComponentDTO.java new file mode 100644 index 0000000..c7272c4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/dto/DisplayedComponentDTO.java @@ -0,0 +1,32 @@ +package com.senmesh.common.dto; + +import java.io.Serializable; +import java.util.List; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 展示定制的组件 + * + * @author sr on 2020-04-22 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DisplayedComponentDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + /** 消息 **/ + private MessageDTO message; + /** 列配置 **/ + private List columns; + /** 展示数据 **/ + private List data; + /** 按钮 **/ + private List buttons; + +} diff --git a/backend/src/main/java/com/senmesh/common/dto/ExceptionRecordDTO.java b/backend/src/main/java/com/senmesh/common/dto/ExceptionRecordDTO.java new file mode 100644 index 0000000..241826b --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/dto/ExceptionRecordDTO.java @@ -0,0 +1,31 @@ +package com.senmesh.common.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ExceptionRecordDTO implements Serializable { + + /** + * 入参json + */ + private String paramJson; + /** + * 响应json + */ + private String resultJson; + /** + * 调用接口地址 + */ + private String url; + /** + * 系统 1 慧用工、2、3、4待定 + */ + private String sys; +} diff --git a/backend/src/main/java/com/senmesh/common/dto/ExportHeadDetailInfoDTO.java b/backend/src/main/java/com/senmesh/common/dto/ExportHeadDetailInfoDTO.java new file mode 100644 index 0000000..8d471f7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/dto/ExportHeadDetailInfoDTO.java @@ -0,0 +1,27 @@ +package com.senmesh.common.dto; + +import java.io.Serializable; +import java.util.List; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +@NoArgsConstructor +@Data +@Builder +public class ExportHeadDetailInfoDTO implements Serializable { + + private static final long serialVersionUID = 2399902503017038944L; + /** + * 表头 + */ + private String head; + + /** + * 下拉列表 + */ + private List explicitList; +} diff --git a/backend/src/main/java/com/senmesh/common/dto/ExportHeadInfoDTO.java b/backend/src/main/java/com/senmesh/common/dto/ExportHeadInfoDTO.java new file mode 100644 index 0000000..d86a99c --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/dto/ExportHeadInfoDTO.java @@ -0,0 +1,59 @@ +package com.senmesh.common.dto; + +import org.apache.commons.compress.utils.Lists; + +import java.io.Serializable; +import java.util.List; +import java.util.Objects; + +import cn.hutool.core.date.DateUtil; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +@NoArgsConstructor +@Data +@Builder +public class ExportHeadInfoDTO implements Serializable { + + private static final long serialVersionUID = -3123297330700623056L; + + + /** + * 文件名称 + */ + private String fileName; + + /** + * 表头 + */ + private List heads; + + /** + * 数据列 + */ + private List datas; + + public String getFileName() { + if (Objects.isNull(fileName)){ + fileName = DateUtil.today() + "_动态模板"; + } + return fileName; + } + + public List getHeads() { + if (Objects.isNull(heads)){ + heads = Lists.newArrayList(); + } + return heads; + } + + public List getDatas() { + if (Objects.isNull(datas)){ + datas = Lists.newArrayList(); + } + return datas; + } +} diff --git a/backend/src/main/java/com/senmesh/common/dto/IBaseDTO.java b/backend/src/main/java/com/senmesh/common/dto/IBaseDTO.java new file mode 100644 index 0000000..3b74441 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/dto/IBaseDTO.java @@ -0,0 +1,12 @@ +package com.senmesh.common.dto; + +/** + * 基础对象 + * @author sr on 2024-04-18 + */ +public interface IBaseDTO { + + Long getId(); + + +} diff --git a/backend/src/main/java/com/senmesh/common/dto/IDisplayed.java b/backend/src/main/java/com/senmesh/common/dto/IDisplayed.java new file mode 100644 index 0000000..edbfef9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/dto/IDisplayed.java @@ -0,0 +1,23 @@ +package com.senmesh.common.dto; + +/** + * 展示信息 + * + * @author sr on 2020-07-14 + */ +public interface IDisplayed{ + /** + * 是否展示 + * @return + * @author sr on 2020-07-14 + */ + Boolean getDisplayed(); + + /** + * 展示组件 + * @return + * @author sr on 2020-07-14 + */ + DisplayedComponentDTO getDisplayedComponentDto(); + +} diff --git a/backend/src/main/java/com/senmesh/common/dto/IOperateDTO.java b/backend/src/main/java/com/senmesh/common/dto/IOperateDTO.java new file mode 100644 index 0000000..384591c --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/dto/IOperateDTO.java @@ -0,0 +1,26 @@ +package com.senmesh.common.dto; + +/** + * 操作对象 + * + * @author sr on 2020-08-26 + */ +public interface IOperateDTO { + + /** + * 设置操作机构id + * + * @param orgId + * @author sr on 2020-08-31 + */ + void setOperateOrgId(Long orgId); + + /** + * 设置操作用户id + * + * @param userId + * @author sr on 2020-08-31 + */ + void setOperateUserId(Long userId); + +} diff --git a/backend/src/main/java/com/senmesh/common/dto/IPage.java b/backend/src/main/java/com/senmesh/common/dto/IPage.java new file mode 100644 index 0000000..f85b882 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/dto/IPage.java @@ -0,0 +1,43 @@ +package com.senmesh.common.dto; + +import java.util.List; + +/** + * 分页对象 + * + * @author sr on 2020-08-26 + */ +public interface IPage { + + /** + * 第几页 + * + * @return + * @author sr on 2020-08-26 + */ + Integer getPageNo(); + + /** + * 页宽 + * + * @return + * @author sr on 2020-08-26 + */ + Integer getPageSize(); + + + /** + * 获取是否需要分页属性 + * + * @return {@link Boolean} + */ + Boolean getNeedPage(); + + /** + * 设置分页结果 + * + * @author sr on 2020-08-26 + */ + void setPageResult(int totalCount, List results); + +} diff --git a/backend/src/main/java/com/senmesh/common/dto/MessageDTO.java b/backend/src/main/java/com/senmesh/common/dto/MessageDTO.java new file mode 100644 index 0000000..7818a6d --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/dto/MessageDTO.java @@ -0,0 +1,28 @@ +package com.senmesh.common.dto; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.Builder.Default; + +/** + * @author sr on 2020-04-22 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class MessageDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 3623225038987713421L; + /** 类型:success/info/warning/error **/ + @Default + private String type = "info"; + /** 内容 **/ + private String content; + +} diff --git a/backend/src/main/java/com/senmesh/common/dto/OrgBaseDTO.java b/backend/src/main/java/com/senmesh/common/dto/OrgBaseDTO.java new file mode 100644 index 0000000..5422f70 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/dto/OrgBaseDTO.java @@ -0,0 +1,24 @@ +package com.senmesh.common.dto; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 机构基础 + * + * @author sr on 2019-12-22 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@SuperBuilder +public class OrgBaseDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = -2595043832455614748L; + + private Long orgId; + +} diff --git a/backend/src/main/java/com/senmesh/common/dto/PageQueryDTO.java b/backend/src/main/java/com/senmesh/common/dto/PageQueryDTO.java new file mode 100644 index 0000000..4bba060 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/dto/PageQueryDTO.java @@ -0,0 +1,98 @@ +package com.senmesh.common.dto; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.senmesh.tkmybatis.pojo.Page; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; +import java.util.Optional; + +/** + * 分页查询对象 + * + * @author sr on 2020-08-03 + */ +@AllArgsConstructor +@NoArgsConstructor +public class PageQueryDTO extends BaseOperateDTO implements Serializable, IPage { + + /** + * + **/ + private static final long serialVersionUID = -6370476082571087349L; + + /** + * 第几页 + **/ + private Integer pageNo = 1; + /** + * 页宽 + **/ + private Integer pageSize = 20; + /** + * 是否需要分页 + **/ + private Boolean needPage = Boolean.TRUE; + /** + * 分页结果 + **/ + @JsonIgnore + private Page pageResult; + + @Override + public Integer getPageNo() { + return Optional.ofNullable(pageNo).orElse(1); + } + + @Override + public Integer getPageSize() { + return Optional.ofNullable(pageSize).orElse(20); + } + + @Override + public Boolean getNeedPage() { + return Optional.ofNullable(this.needPage).orElse(Boolean.TRUE); + } + + @Override + public void setPageResult(int totalCount, List results) { + pageResult = new Page(getPageNo(), getPageSize()); + pageResult.setPageResult(totalCount, results); + } + + public void setPageNo(Integer pageNo) { + this.pageNo = pageNo; + } + + public void setPageSize(Integer pageSize) { + if (pageSize != null && pageSize >1000) { + this.pageSize = 1000; + } else { + this.pageSize = pageSize; + } + } + + public void setNeedPage(Boolean needPage) { + this.needPage = needPage; + } + + public Page getPageResult() { + return pageResult; + } + + public void setPageResult(Page pageResult) { + this.pageResult = pageResult; + } + + public PageQueryDTO disablePage() { + this.setNeedPage(Boolean.FALSE); + return this; + } + + public Integer getStartPage() { + return (getPageNo() - 1) * getPageSize(); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/easyexcel/DynamicExportTemplateCellWriteHandler.java b/backend/src/main/java/com/senmesh/common/easyexcel/DynamicExportTemplateCellWriteHandler.java new file mode 100644 index 0000000..5e2c63f --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/easyexcel/DynamicExportTemplateCellWriteHandler.java @@ -0,0 +1,156 @@ +package com.senmesh.common.easyexcel; + +import com.google.common.collect.Maps; + + +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.write.handler.AbstractCellWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; +import com.senmesh.common.dto.ExportHeadDetailInfoDTO; +import com.senmesh.common.dto.ExportHeadInfoDTO; + +import org.apache.poi.hssf.util.HSSFColor; +import org.apache.poi.ss.usermodel.BorderStyle; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.DataValidation; +import org.apache.poi.ss.usermodel.DataValidationConstraint; +import org.apache.poi.ss.usermodel.DataValidationHelper; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.usermodel.Name; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.VerticalAlignment; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.util.CellRangeAddressList; +import org.apache.poi.xssf.usermodel.XSSFCellStyle; +import org.apache.poi.xssf.usermodel.XSSFColor; +import org.apache.poi.xssf.usermodel.XSSFDataValidation; + +import java.awt.*; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import cn.hutool.core.collection.CollUtil; + +public class DynamicExportTemplateCellWriteHandler extends AbstractCellWriteHandler { + + private Map exportHeadIndexMap = null; + + private Integer hiddenSheetIndex = 1; + + + + @Override + public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + super.afterCellDispose(writeSheetHolder, writeTableHolder, cellDataList, cell, head, relativeRowIndex, isHead); + int rowIndex = cell.getRowIndex(); + int columnIndex = cell.getColumnIndex(); + Workbook workbook = writeSheetHolder.getParentWriteWorkbookHolder().getWorkbook(); + Sheet sheet = writeSheetHolder.getSheet(); + if (rowIndex == 0) { + Row row = cell.getRow(); + row.setHeight((short) (33 * 20)); + ExportHeadInfoDTO exportInfo = (ExportHeadInfoDTO) ImportDataContext.get("exportInfo"); + + XSSFCellStyle cellStyle = (XSSFCellStyle) workbook.createCellStyle(); + cellStyle.setBorderBottom(BorderStyle.THIN); //下边框 + cellStyle.setBottomBorderColor(IndexedColors.BLACK.index); + cellStyle.setBorderLeft(BorderStyle.THIN);//左边框 + cellStyle.setLeftBorderColor(IndexedColors.BLACK.index); + cellStyle.setBorderTop(BorderStyle.THIN);//上边框 + cellStyle.setTopBorderColor(IndexedColors.BLACK.index); + cellStyle.setBorderRight(BorderStyle.THIN);//右边框 + cellStyle.setRightBorderColor(IndexedColors.BLACK.index); + + cellStyle.setAlignment(HorizontalAlignment.CENTER); + cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); + + Color color = new Color(91, 155, 213); + cellStyle.setFillForegroundColor(new XSSFColor(color,null)); + cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); + + Font font = workbook.createFont(); + cellStyle.setFont(font); + + font.setFontName("Calibri"); + font.setColor(HSSFColor.HSSFColorPredefined.WHITE.getIndex()); + cell.setCellStyle(cellStyle); + if (Objects.isNull(exportHeadIndexMap)) { + List heads = exportInfo.getHeads(); + exportHeadIndexMap = Maps.newHashMap(); + for (int i = 0; i < heads.size(); i++) { + ExportHeadDetailInfoDTO exportHead = heads.get(i); + exportHeadIndexMap.put(i, exportHead); + } + } + + ExportHeadDetailInfoDTO exportHeadDetailInfoDTO = exportHeadIndexMap.get(columnIndex); + String name; + if (Objects.isNull(exportHeadDetailInfoDTO)) { + name = cell.getStringCellValue(); + } else { + name = exportHeadDetailInfoDTO.getHead(); + } + int length = ((name.getBytes(StandardCharsets.UTF_8).length + cell.toString().length()) * 3) / 5 + 5; + sheet.setColumnWidth(columnIndex, length * 290); + + List explicitList = Objects.isNull(exportHeadDetailInfoDTO) ? null : exportHeadDetailInfoDTO.getExplicitList(); + // 设置下拉属性 +// if (CollUtil.isNotEmpty(explicitList)) { +// DataValidationHelper helper = sheet.getDataValidationHelper(); +// DataValidationConstraint constraint = helper.createExplicitListConstraint(explicitList.toArray(new String[]{})); +// //设置生效的起始行、终止行、起始列、终止列 +// CellRangeAddressList cellAddressList = new CellRangeAddressList(1, +// 65535, columnIndex, columnIndex); +// DataValidation validation = helper.createValidation(constraint, cellAddressList); +// //适配xls和xlsx +// if (validation instanceof HSSFDataValidation) { +// validation.setSuppressDropDownArrow(false); +// } else { +// validation.setSuppressDropDownArrow(true); +// validation.setShowErrorBox(true); +// } +// sheet.addValidationData(validation); +// } + + if (CollUtil.isNotEmpty(explicitList)){ + String hiddenName = "hidden" + hiddenSheetIndex; + //1.创建隐藏的sheet页。 起个名字吧!叫"hidden"! + Sheet hiddenSheet = workbook.createSheet(hiddenName); + //2.循环赋值(为了防止下拉框的行数与隐藏域的行数相对应,将隐藏域加到结束行之后) + for (int i = 0; i < explicitList.size(); i++) { + hiddenSheet.createRow(65535 + i).createCell(columnIndex).setCellValue(explicitList.get(i)); + } + Name category1Name = workbook.createName(); + category1Name.setNameName(hiddenName); + //3 A1:A代表隐藏域创建第N列createCell(N)时。以A1列开始A行数据获取下拉数组 + category1Name.setRefersToFormula(hiddenName + "!A1:A" + (explicitList.size() + 65535)); + // + DataValidationHelper helper = sheet.getDataValidationHelper(); + DataValidationConstraint constraint = helper.createFormulaListConstraint(hiddenName); + CellRangeAddressList addressList = new CellRangeAddressList(1, 65535, columnIndex, columnIndex); + DataValidation dataValidation = helper.createValidation(constraint, addressList); + if (dataValidation instanceof XSSFDataValidation) { + // 数据校验 + dataValidation.setSuppressDropDownArrow(true); + dataValidation.setShowErrorBox(true); + } else { + dataValidation.setSuppressDropDownArrow(false); + } + // 作用在目标sheet上 + sheet.addValidationData(dataValidation); + // 设置hiddenSheet隐藏 + workbook.setSheetHidden(hiddenSheetIndex, true); + hiddenSheetIndex++; + } + } + + } +} diff --git a/backend/src/main/java/com/senmesh/common/easyexcel/ExcelUtil.java b/backend/src/main/java/com/senmesh/common/easyexcel/ExcelUtil.java new file mode 100644 index 0000000..3f86999 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/easyexcel/ExcelUtil.java @@ -0,0 +1,77 @@ +package com.senmesh.common.easyexcel; + +import com.google.common.collect.Lists; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.senmesh.common.dto.ExportHeadDetailInfoDTO; +import com.senmesh.common.dto.ExportHeadInfoDTO; + +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import javax.servlet.http.HttpServletResponse; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; + +public class ExcelUtil { + + + private ExcelUtil() { + } + + + /** + * 动态导出excel模板 + * + * @param reqDto 点播dto + */ + public static void dynamicExportTemplate(ExportHeadInfoDTO reqDto) { + if (CollUtil.isEmpty(reqDto.getHeads())) { + return; + } + ImportDataContext.set("exportInfo", reqDto); + + ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + HttpServletResponse response = attr.getResponse(); + if (Objects.isNull(response)) { + return; + } + String fileName = reqDto.getFileName() + ".xlsx"; + + response.setContentType("application/vnd.ms-excel;charset=UTF-8"); + response.setCharacterEncoding("UTF-8"); + String fileNamePrefix = StrUtil.subBefore(fileName, ".", true); + String fileNameSuffix = StrUtil.subAfter(fileName, ".", true); + try { + String fileNamePrefix2 = URLEncoder.encode(fileNamePrefix, "UTF-8").replaceAll("\\+", "%20"); + response.setHeader("Content-Disposition", "attachment;" + fileNamePrefix2 + "." + fileNameSuffix); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + throw new IllegalArgumentException("下载文件异常"); + } + response.addHeader("Param", "no-cache"); + response.addHeader("Cache-Control", "no-cache"); + + try (OutputStream out = response.getOutputStream();) { + ExcelWriter writer = EasyExcel.write(out).registerWriteHandler(new DynamicExportTemplateCellWriteHandler()).build(); + List objects = Lists.newArrayList(); + objects.add(reqDto.getHeads().stream().map(ExportHeadDetailInfoDTO::getHead).collect(Collectors.toList())); + objects.addAll(reqDto.getDatas()); + writer.write(objects, EasyExcel.writerSheet("sheet").build()); + writer.finish(); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/backend/src/main/java/com/senmesh/common/easyexcel/ImportDataContext.java b/backend/src/main/java/com/senmesh/common/easyexcel/ImportDataContext.java new file mode 100644 index 0000000..a9d36fa --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/easyexcel/ImportDataContext.java @@ -0,0 +1,35 @@ +package com.senmesh.common.easyexcel; + +import com.google.common.collect.Maps; + +import java.util.Map; +import java.util.Objects; + +public class ImportDataContext { + public static final ThreadLocal> THREAD_LOCAL_MAP = new ThreadLocal<>(); + + public static Object get(String key) { + Map stringObjectMap = THREAD_LOCAL_MAP.get(); + if (Objects.isNull(stringObjectMap)) { + THREAD_LOCAL_MAP.set(Maps.newHashMap()); + return null; + } + return stringObjectMap.get(key); + } + + public static void set(String key,Object value) { + Map stringObjectMap = THREAD_LOCAL_MAP.get(); + if (Objects.isNull(stringObjectMap)) { + THREAD_LOCAL_MAP.set(Maps.newHashMap()); + } + THREAD_LOCAL_MAP.get().put(key,value); + } + + public static void putAll(Map extraInfoMap){ + Map stringObjectMap = THREAD_LOCAL_MAP.get(); + if (Objects.isNull(stringObjectMap)) { + THREAD_LOCAL_MAP.set(Maps.newHashMap()); + } + THREAD_LOCAL_MAP.get().putAll(extraInfoMap); + } +} diff --git a/backend/src/main/java/com/senmesh/common/entity/BaseEntity.java b/backend/src/main/java/com/senmesh/common/entity/BaseEntity.java new file mode 100644 index 0000000..514aacf --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/entity/BaseEntity.java @@ -0,0 +1,64 @@ +package com.senmesh.common.entity; + +import java.io.Serializable; +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.senmesh.common.dto.IBaseDTO; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public abstract class BaseEntity implements Serializable, Cloneable, IBaseDTO { + + private static final long serialVersionUID = -723338960662087915L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + /** + * 是否逻辑删除(0否1是) + */ + @TableField(value = "deleted", fill = FieldFill.INSERT) + @Builder.Default + private Boolean deleted = Boolean.FALSE; + /** + * 创建人 + */ + @TableField(value = "create_by", fill = FieldFill.INSERT) + private Long createBy; + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @TableField(value = "create_time", fill = FieldFill.INSERT) + private Date createTime; + /** + * 修改人 + */ + @TableField(value = "update_by", fill = FieldFill.UPDATE) + private Long updateBy; + /** + * 修改时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @TableField(value = "update_time", fill = FieldFill.UPDATE) + private Date updateTime; + /** + * 代理人 + */ + private Long proxyBy; +} diff --git a/backend/src/main/java/com/senmesh/common/entity/OrgBaseEntity.java b/backend/src/main/java/com/senmesh/common/entity/OrgBaseEntity.java new file mode 100644 index 0000000..f250c31 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/entity/OrgBaseEntity.java @@ -0,0 +1,27 @@ +package com.senmesh.common.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 机构基础实体 + * @author sr on 2019-10-19 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class OrgBaseEntity extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 2559571969035017003L; + + /** 机构id **/ + private Long orgId; + + +} diff --git a/backend/src/main/java/com/senmesh/common/exception/AlitaException.java b/backend/src/main/java/com/senmesh/common/exception/AlitaException.java new file mode 100644 index 0000000..7d6b75b --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/exception/AlitaException.java @@ -0,0 +1,30 @@ +package com.senmesh.common.exception; + + +/** + * 项目所有自定义异常父类 + * + * @author guhong + */ +public class AlitaException extends RuntimeException { + + /** + * + */ + private static final long serialVersionUID = 3121871576733025786L; + + public AlitaException() {} + + public AlitaException(String message) { + super(message); + } + + public AlitaException(String message, Throwable cause) { + super(message, cause); + } + + public AlitaException(Throwable cause) { + super(cause); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/exception/BusinessException.java b/backend/src/main/java/com/senmesh/common/exception/BusinessException.java new file mode 100644 index 0000000..99d286c --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/exception/BusinessException.java @@ -0,0 +1,30 @@ +package com.senmesh.common.exception; + +/** + * 业务异常 + * + * @author guhong + * @date 2019/8/19 + */ +public class BusinessException extends AlitaException { + + /** + * + */ + private static final long serialVersionUID = -3097174055942519169L; + + public BusinessException() {} + + public BusinessException(String message) { + super(message); + } + + public BusinessException(String message, Throwable cause) { + super(message, cause); + } + + public BusinessException(Throwable cause) { + super(cause); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/exception/ChangeTokenException.java b/backend/src/main/java/com/senmesh/common/exception/ChangeTokenException.java new file mode 100644 index 0000000..837ae5c --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/exception/ChangeTokenException.java @@ -0,0 +1,24 @@ +package com.senmesh.common.exception; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.dto.CasTokenDTO; + +/** + * 更新token + * @author sr on 2021-07-05 + */ +public class ChangeTokenException extends WithResultException{ + + /** **/ + private static final long serialVersionUID = -8897274199463229506L; + + + public ChangeTokenException(CasTokenDTO casTokenDTO) { + super(AlitaResult.changeToken(casTokenDTO)); + } + + public CasTokenDTO getCasTokenDTO(){ + return (CasTokenDTO) getResult().getErrorData(); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/exception/DevopsException.java b/backend/src/main/java/com/senmesh/common/exception/DevopsException.java new file mode 100644 index 0000000..7266039 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/exception/DevopsException.java @@ -0,0 +1,24 @@ +package com.senmesh.common.exception; + +import com.senmesh.common.exception.util.DevopsUtils; + +/** + * 运维业务异常 + * @author sr on 2022-03-01 + */ +public class DevopsException extends BusinessException{ + + /** **/ + private static final long serialVersionUID = 1L; + + public DevopsException(String message) { + super(message); + DevopsUtils.deal(message); + } + + public DevopsException(String message, Throwable cause) { + super(message, cause); + DevopsUtils.deal(message); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/exception/ExistException.java b/backend/src/main/java/com/senmesh/common/exception/ExistException.java new file mode 100644 index 0000000..1483ff8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/exception/ExistException.java @@ -0,0 +1,24 @@ +package com.senmesh.common.exception; + +/** + * 已存在业务异常 + * @author sr on 2022-03-01 + */ +public class ExistException extends BusinessException{ + + /** **/ + private static final long serialVersionUID = 1L; + + public ExistException() { + super(); + } + + public ExistException(String message) { + super(message); + } + + public ExistException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/exception/IDevopsProvider.java b/backend/src/main/java/com/senmesh/common/exception/IDevopsProvider.java new file mode 100644 index 0000000..e8f2cad --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/exception/IDevopsProvider.java @@ -0,0 +1,7 @@ +package com.senmesh.common.exception; + +public interface IDevopsProvider { + + void deal(String msg); + +} diff --git a/backend/src/main/java/com/senmesh/common/exception/NoneLoginException.java b/backend/src/main/java/com/senmesh/common/exception/NoneLoginException.java new file mode 100644 index 0000000..977a62c --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/exception/NoneLoginException.java @@ -0,0 +1,26 @@ +package com.senmesh.common.exception; + +/** + * 用户未登录异常 + * + * @author guhong + * @date 2019/8/19 + */ +public class NoneLoginException extends AlitaException { + + public static final String ERROR_MSG = "用户未登录"; + + /** + * + */ + private static final long serialVersionUID = -7013134475760472324L; + + public NoneLoginException(String msg, Throwable t) { + super(msg, t); + } + + public NoneLoginException() { + super(ERROR_MSG); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/exception/WithResultException.java b/backend/src/main/java/com/senmesh/common/exception/WithResultException.java new file mode 100644 index 0000000..92e7098 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/exception/WithResultException.java @@ -0,0 +1,30 @@ +package com.senmesh.common.exception; + +import com.senmesh.common.AlitaResult; + +/** + * 更新token + * @author sr on 2021-07-05 + */ +public class WithResultException extends AlitaException{ + + /** **/ + private static final long serialVersionUID = -8897274199463229506L; + + private AlitaResult result; + + public WithResultException(AlitaResult result) { + super(result.getMsg()); + this.result = result; + } + + public WithResultException(AlitaResult result, Throwable cause) { + super(result.getMsg(), cause); + this.result = result; + } + + public AlitaResult getResult(){ + return result; + } + +} diff --git a/backend/src/main/java/com/senmesh/common/exception/controller/ExceptionLogController.java b/backend/src/main/java/com/senmesh/common/exception/controller/ExceptionLogController.java new file mode 100644 index 0000000..b014bd6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/exception/controller/ExceptionLogController.java @@ -0,0 +1,33 @@ +package com.senmesh.common.exception.controller; + +import com.senmesh.common.exception.dao.ExceptionLogMapper; +import io.swagger.annotations.Api; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 异常日志查看 + * + * @author on 2019-11-05 + */ +@RestController +@RequestMapping("/anon/exception") +@Api(tags = "异常日志查看") +public class ExceptionLogController { + + @Autowired + private ExceptionLogMapper exceptionLogMapper; + + @GetMapping("/{id}") + public String getExceptionMsg(@PathVariable Long id) { + try { + return exceptionLogMapper.selectById(id).getMsg(); + } catch (Exception e) { + return "未找到对应id错误"; + } + } + +} diff --git a/backend/src/main/java/com/senmesh/common/exception/dao/ExceptionLogMapper.java b/backend/src/main/java/com/senmesh/common/exception/dao/ExceptionLogMapper.java new file mode 100644 index 0000000..affb262 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/exception/dao/ExceptionLogMapper.java @@ -0,0 +1,13 @@ +package com.senmesh.common.exception.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.senmesh.common.exception.entity.ExceptionLog; + +/** + * 异常日志 + * + * @author on 2019-11-05 + */ +public interface ExceptionLogMapper extends BaseMapper { + +} diff --git a/backend/src/main/java/com/senmesh/common/exception/entity/ExceptionLog.java b/backend/src/main/java/com/senmesh/common/exception/entity/ExceptionLog.java new file mode 100644 index 0000000..3505452 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/exception/entity/ExceptionLog.java @@ -0,0 +1,41 @@ +package com.senmesh.common.exception.entity; + +import java.io.Serializable; +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 错误日志 + * @author sr on 2019-10-28 + */ +@TableName("xs_exception_log") +@Data +@NoArgsConstructor +public class ExceptionLog implements Serializable{ + + /** **/ + private static final long serialVersionUID = 3730091070919812549L; + + /** 主键 **/ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + /** 创建时间 **/ + private Date createTime; + + /** 错误信息 **/ + private String msg; + + public ExceptionLog(Date createTime, String msg) { + super(); + this.createTime = createTime; + this.msg = msg; + } + +} diff --git a/backend/src/main/java/com/senmesh/common/exception/handle/GlobalControllerExceptionHandler.java b/backend/src/main/java/com/senmesh/common/exception/handle/GlobalControllerExceptionHandler.java new file mode 100644 index 0000000..98cbd1c --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/exception/handle/GlobalControllerExceptionHandler.java @@ -0,0 +1,188 @@ +package com.senmesh.common.exception.handle; + +import com.senmesh.common.util.EnvironmentUtils; +import java.util.List; +import java.util.Set; +import java.util.StringJoiner; + +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.propertyeditors.StringTrimmerEditor; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.BindException; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; +import org.springframework.validation.ObjectError; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.InitBinder; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.exception.NoneLoginException; +import com.senmesh.common.exception.WithResultException; +import com.senmesh.common.log.dto.ExceptionLogDTO; +import com.senmesh.common.log.util.LogUtils; +import com.senmesh.common.util.SpringContextHolder; +import com.senmesh.common.util.TracerUtils; + +/** + * 全局异常处理 + * + * @author guhong + * @date 2019/8/19 + */ +@RestControllerAdvice +public class GlobalControllerExceptionHandler { + + private static final Logger LOGGER = LoggerFactory + .getLogger(GlobalControllerExceptionHandler.class); + + @Value("${spring.application.name:}") + private String applicationName; + + /** + * 业务异常 + * + * @param ex + */ + @ExceptionHandler(value = {BusinessException.class}) + public AlitaResult handleBusinessException(BusinessException ex) { + String traceId = TracerUtils.getTraceId(); + String msg; + if (StringUtils.isNotBlank(ex.getMessage()) && ex.getMessage().contains(traceId)) { + msg = ex.getMessage(); + }else { + msg = String.format("[%s]操作失败:%s", traceId, ex.getMessage()); + } + + LOGGER.debug(msg, ex); + AlitaResult alitaResult = AlitaResult.error(AlitaResult.BUSINESS_ERROR_CODE, msg); + alitaResult.setRequestId(traceId); + return alitaResult; + } + + /** + * 处理未登录异常 + * + * @param ex + */ + @ExceptionHandler(value = {NoneLoginException.class}) + public AlitaResult handleNoneLoginException(NoneLoginException ex) { + AlitaResult alitaResult = AlitaResult.unLogin(); + alitaResult.setRequestId(TracerUtils.getTraceId()); + return alitaResult; + } + + /** + * 处理更换token + * + * @param ex + */ + @ExceptionHandler(value = {WithResultException.class}) + public AlitaResult handleChangeTokenException(WithResultException ex) { + AlitaResult result = ex.getResult(); + result.setRequestId(TracerUtils.getTraceId()); + return result; + } + + /** + * 处理校验异常 + * + * @param ex + */ + @ExceptionHandler(value = { + MethodArgumentNotValidException.class, + BindException.class}) + public AlitaResult handleValidationException(Exception ex) { + BindingResult result; + if (ex instanceof MethodArgumentNotValidException) { + result = ((MethodArgumentNotValidException) ex).getBindingResult(); + } else { + result = ((BindException) ex).getBindingResult(); + } + if (!result.hasErrors()) { + return AlitaResult.error("操作失败"); + } + + StringJoiner joiner = new StringJoiner(","); + List errors = result.getAllErrors(); + + errors.forEach(error -> { + if (error instanceof FieldError) { + joiner.add(((FieldError) error).getField() + "-" + error.getDefaultMessage()); + } else { + joiner.add(error.getDefaultMessage()); + } + }); + + String msg = String.format("数据异常:%s", joiner.toString()); + LOGGER.error(msg); + AlitaResult alitaResult = AlitaResult.error(AlitaResult.VALIDATION_ERROR_CODE, msg); + alitaResult.setRequestId(TracerUtils.getTraceId()); + return alitaResult; + } + + /** + * 处理未知的错误 + * + * @param ex + */ + @ExceptionHandler(value = {ConstraintViolationException.class}) + @Transactional(rollbackFor = RuntimeException.class) + public AlitaResult handleConstraintViolationException(ConstraintViolationException ex) { + Set> constraintViolations = ex.getConstraintViolations(); + StringJoiner joiner = new StringJoiner(CommonConstants.COMMA); + constraintViolations.stream().forEach(error -> joiner.add(error.getMessage())); + String msg = String.format("数据异常:%s", joiner.toString()); + LOGGER.error(msg); + AlitaResult alitaResult = AlitaResult.error(AlitaResult.VALIDATION_ERROR_CODE, msg); + alitaResult.setRequestId(TracerUtils.getTraceId()); + return alitaResult; + } + + /** + * 处理未知的错误 + * + * @param ex + */ + @ExceptionHandler(value = {Exception.class}) + @Transactional(rollbackFor = RuntimeException.class) + public AlitaResult handleUnknownException(Exception ex) { + String msg = null; + if (ex instanceof HttpRequestMethodNotSupportedException) { + msg = "请求错误:" + ((HttpRequestMethodNotSupportedException) ex).getSupportedMethods()[0] + + SpringContextHolder.getRequest().getRequestURI(); + } else { + LOGGER.error("",ex); + ExceptionLogDTO exceptionLogDTO = ExceptionLogDTO.builder().traceId(TracerUtils.getTraceId()) + .msg(ExceptionUtils.getStackTrace(ex)).build(); + LogUtils.log(exceptionLogDTO); + msg = String.format("系统异常[%s#%s],请稍后重试.", + EnvironmentUtils.getSystemCode(), exceptionLogDTO.getErrNo() + ); + LOGGER.error("系统异常,错误号:{}", exceptionLogDTO.getErrNo()); + } + + AlitaResult alitaResult = AlitaResult.error(msg); + alitaResult.setRequestId(TracerUtils.getTraceId()); + return alitaResult; + } + + @InitBinder + public void initBinder(WebDataBinder binder) { + binder.registerCustomEditor(String.class, new StringTrimmerEditor(" \t\r\n\f", true)); + } + + +} diff --git a/backend/src/main/java/com/senmesh/common/exception/util/Assert.java b/backend/src/main/java/com/senmesh/common/exception/util/Assert.java new file mode 100644 index 0000000..ae7dd6f --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/exception/util/Assert.java @@ -0,0 +1,133 @@ +package com.senmesh.common.exception.util; + +import com.google.common.base.Supplier; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.util.JsonUtils; + +import lombok.extern.slf4j.Slf4j; + +import java.util.Collection; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.lang.Nullable; +import org.springframework.util.CollectionUtils; + +/** + * 断言 + * + * @author sr on 2020-09-02 + */ +@Slf4j +public class Assert { + + private Assert() { + } + + private static void dealLog(String message, Object... logData) { + if (logData.length > 0) { + log.info(new StringBuilder().append(message).append(CommonConstants.COLON) + .append(JsonUtils.toJsonString(logData)).toString()); + } + } + + /** + * true正常,fasle抛BusinessException + * + * @param expression + * @param message + * @author sr on 2020-09-02 + */ + public static void isTrue(boolean expression, String message, Object... logData) { + if (!expression) { + dealLog(message, logData); + throw new BusinessException(message); + } + } + + /** + * true正常,fasle抛BusinessException + * + * @param expression 表达式 + * @param message 消息 + */ + public static void isTrue(boolean expression, Supplier message) { + if (!expression) { + throw new BusinessException(message.get()); + } + } + + + /** + * true正常,fasle抛指定异常 + * @param expression + * @param e + * @author sr on 2021-06-18 + */ + public static void isTrue(boolean expression, RuntimeException e) { + if (!expression) { + throw e; + } + } + + /** + * null正常,notNull抛BusinessException + * + * @param object + * @param message + * @author sr on 2020-09-02 + */ + public static void isNull(@Nullable Object object, String message, Object... logData) { + if (object != null) { + dealLog(message, logData); + throw new BusinessException(message); + } + } + + /** + * notNull正常,null抛BusinessException + * + * @param object + * @param message + * @author sr on 2020-09-02 + */ + public static void notNull(@Nullable Object object, String message, Object... logData) { + if (object == null) { + dealLog(message, logData); + throw new BusinessException(message); + } + } + + /** + * notNull正常,null抛BusinessException + * + * @param object 对象 + * @param message 消息 + */ + public static void notNull(@Nullable Object object, Supplier message) { + if (object == null) { + throw new BusinessException(message.get()); + } + } + + /** + * notBlank正常,blank抛BusinessException + * + * @param str + * @param message + * @author sr on 2021-01-06 + */ + public static void notBlank(String str, String message, Object... logData) { + if (StringUtils.isBlank(str)) { + dealLog(message, logData); + throw new BusinessException(message); + } + } + + public static void notEmpty(@Nullable Collection collection, String message) { + if (CollectionUtils.isEmpty(collection)) { + throw new BusinessException(message); + } +} + +} diff --git a/backend/src/main/java/com/senmesh/common/exception/util/DevopsUtils.java b/backend/src/main/java/com/senmesh/common/exception/util/DevopsUtils.java new file mode 100644 index 0000000..e7374da --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/exception/util/DevopsUtils.java @@ -0,0 +1,33 @@ +package com.senmesh.common.exception.util; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.senmesh.common.exception.IDevopsProvider; + +import lombok.extern.slf4j.Slf4j; + +/** + * 运维工具类 + * @author sr on 2022-03-01 + */ +@Component +@Slf4j +public class DevopsUtils { + + private static IDevopsProvider devopsProvider; + + @Autowired(required = false) + public void setDevopsProvider(IDevopsProvider devopsProvider) { + DevopsUtils.devopsProvider = devopsProvider; + } + + public static void deal(String msg) { + if (devopsProvider == null) { + log.error("no devops provider, error:{}", msg); + return ; + } + devopsProvider.deal(msg); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/exception/util/ExceptionUtils.java b/backend/src/main/java/com/senmesh/common/exception/util/ExceptionUtils.java new file mode 100644 index 0000000..8349a5f --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/exception/util/ExceptionUtils.java @@ -0,0 +1,48 @@ +package com.senmesh.common.exception.util; + +import com.senmesh.common.exception.BusinessException; +import lombok.extern.slf4j.Slf4j; + +/** + * 异常工具类 + * @author sr on 2019-10-14 + */ +@Slf4j +public class ExceptionUtils { + + /** + * @Description 抛异常 + * @Author chenyun.huang + * @Date 2020/3/27 15:06 + **/ + public static void throwBusinessException(String msg) { + ExceptionUtils.throwBusinessException(true,msg); + } + + /** + * 根据判断抛异常 + * @param isThrow + * @param msg 异常信息 + * @author sr on 2019-10-14 + */ + public static void throwBusinessException(boolean isThrow, String msg) { + if (isThrow) { + throw new BusinessException(msg); + } + } + + /** + * 根据判断抛异常 + * @param isThrow + * @param errorMsg 异常信息 + * @param logMsg 日志信息(info级) + * @author sr on 2019-12-18 + */ + public static void throwBusinessException(boolean isThrow, String errorMsg, String logMsg) { + if (isThrow) { + log.info(logMsg); + throw new BusinessException(errorMsg); + } + } + +} diff --git a/backend/src/main/java/com/senmesh/common/exception/util/UUIDUtils.java b/backend/src/main/java/com/senmesh/common/exception/util/UUIDUtils.java new file mode 100644 index 0000000..487dc3b --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/exception/util/UUIDUtils.java @@ -0,0 +1,22 @@ +package com.senmesh.common.exception.util; + +import com.senmesh.common.util.RandomUtils; + +/** + * uuid工具类 + * {@link RandomUtils} + * @author sr on 2019-12-10 + */ +@Deprecated +public class UUIDUtils { + + /** + * 生成uuid,去掉- + * @return + * @author sr on 2019-12-10 + */ + public static String generateUUID() { + return RandomUtils.generateUUID(); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/freemarker/constant/BusinessModelFileEnum.java b/backend/src/main/java/com/senmesh/common/freemarker/constant/BusinessModelFileEnum.java new file mode 100644 index 0000000..4e624f6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/freemarker/constant/BusinessModelFileEnum.java @@ -0,0 +1,60 @@ +package com.senmesh.common.freemarker.constant; + +/** + * @author sr on 2020-04-13 + */ +public enum BusinessModelFileEnum { + + /** 常量 **/ + CONSTANT("Constants.java", "constant", "Constant.ftl"), + /** 控制层 **/ + CONTROLLER_FILE_SUFFIX("Controller.java", "controller", "Controller.ftl"), + /** dao **/ + DAO_FILE_SUFFIX("Mapper.java", "dao", "Dao.ftl"), + /** dto **/ + DTO_FILE_SUFFIX("DTO.java", "dto", "DTO.ftl"), + /** operateDto **/ + OPERATE_DTO_FILE_SUFFIX("OperateDTO.java", "dto", "OperateDTO.ftl"), + /** queryDto **/ + QUERY_DTO_FILE_SUFFIX("QueryDTO.java", "dto", "QueryDTO.ftl"), + /** entity **/ + ENTITY_FILE_SUFFIX(".java", "entity", "entity.ftl"), + /** mapper **/ + MAPPER_FILE_SUFFIX("Mapper.xml", "mapper", "Mapper.ftl"), + /** mapstruct **/ + MAPSTRUCT_FILE_SUFFIX("MapMapper.java", "mapstruct", "MapMapper.ftl"), + /** service **/ + SERVICE_FILE_SUFFIX("Service.java", "service", "Service.ftl"), + /** serviceImpl **/ + SERVICE_IMPL_FILE_SUFFIX("ServiceImpl.java", "service.impl", "ServiceImpl.ftl"), + /** util **/ + UTIL_FILE_SUFFIX("Utils.java", "util", "Util.ftl"); + + + + /** 生成文件后缀 **/ + private String generatefileSuffix; + /** 包名 **/ + private String packageName; + /** 模版文件后缀 **/ + private String ftlFile; + + private BusinessModelFileEnum(String fileSuffix, String packageName, String ftlFile) { + this.generatefileSuffix = fileSuffix; + this.packageName = packageName; + this.ftlFile = ftlFile; + } + + public String getGeneratefileSuffix() { + return generatefileSuffix; + } + + public String getPackageName() { + return packageName; + } + + public String getFtlFile() { + return ftlFile; + } + +} diff --git a/backend/src/main/java/com/senmesh/common/freemarker/constant/FreemarkerConstants.java b/backend/src/main/java/com/senmesh/common/freemarker/constant/FreemarkerConstants.java new file mode 100644 index 0000000..3d57701 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/freemarker/constant/FreemarkerConstants.java @@ -0,0 +1,11 @@ +package com.senmesh.common.freemarker.constant; + +/** + * @author sr on 2020-04-10 + */ +public interface FreemarkerConstants { + + /** 数据库表名前缀 **/ + String TABLE_PREFIX = "xs_"; + +} diff --git a/backend/src/main/java/com/senmesh/common/freemarker/dto/BusinessModelCreateDTO.java b/backend/src/main/java/com/senmesh/common/freemarker/dto/BusinessModelCreateDTO.java new file mode 100644 index 0000000..dd2ba37 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/freemarker/dto/BusinessModelCreateDTO.java @@ -0,0 +1,39 @@ +package com.senmesh.common.freemarker.dto; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-04-10 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class BusinessModelCreateDTO implements Serializable { + + /** **/ + private static final long serialVersionUID = 3962743989033667188L; + + /** + * 文件输出路径-绝对路径,如/work/eclipse/workspace/alita-base/common/src/main/java/com/xxx/common/freemarker/ + **/ + private String exportDir; + /** 包路径,如com.xxx.dict **/ + private String packageName; + /** 是否创建业务路径,默认创建 **/ + private Boolean createBusinessPath; + /** 数据库表名:为空,则默认xs_entityName(snake小写) **/ + private String tableName; + /** 作者名 **/ + private String author; + /** 实体名,如Dict **/ + private String entityName; + /** 实体名描述,如数据字典 **/ + private String entityNameDescription; + +} diff --git a/backend/src/main/java/com/senmesh/common/freemarker/util/CodeGenerateUtils.java b/backend/src/main/java/com/senmesh/common/freemarker/util/CodeGenerateUtils.java new file mode 100644 index 0000000..68194a9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/freemarker/util/CodeGenerateUtils.java @@ -0,0 +1,88 @@ +package com.senmesh.common.freemarker.util; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.freemarker.constant.BusinessModelFileEnum; +import com.senmesh.common.freemarker.constant.FreemarkerConstants; +import com.senmesh.common.freemarker.dto.BusinessModelCreateDTO; +import com.senmesh.common.util.StrUtils; + +import freemarker.template.Template; +import lombok.extern.slf4j.Slf4j; + +/** + * @author sr on 2020-04-13 + */ +@Slf4j +public class CodeGenerateUtils { + + public static void generateModelFile(BusinessModelCreateDTO businessModelCreateDto) { + for (BusinessModelFileEnum businessModelFileEnum : BusinessModelFileEnum.values()) { + generateModelFile(businessModelCreateDto, businessModelFileEnum); + } + } + + public static boolean generateModelFile(BusinessModelCreateDTO businessModelCreateDto, + BusinessModelFileEnum businessModelFileEnum) { + // 文件输出路径/包名路径/实体名+文件后缀 + String entityName = businessModelCreateDto.getEntityName(); + String entityNameLowerCase = StrUtils.toLowerCamel(entityName); + String entityNameSnake = StrUtils.toSnake(entityNameLowerCase); + String packageName = businessModelCreateDto.getPackageName(); + String tableName = businessModelCreateDto.getTableName(); + String path = String.join(StringUtils.EMPTY, + packageNameToPath(businessModelFileEnum.getPackageName()), File.separator, + entityName, businessModelFileEnum.getGeneratefileSuffix()); + if (!Boolean.FALSE.equals(businessModelCreateDto.getCreateBusinessPath())) { + path = String.join(StringUtils.EMPTY, entityName.toLowerCase(), File.separator, path); + packageName = String.join(CommonConstants.POINT, packageName, entityName.toLowerCase()); + } + final String templateName = businessModelFileEnum.getFtlFile(); + File file = new File(businessModelCreateDto.getExportDir(), path); + if (!file.getParentFile().exists()) { + file.getParentFile().mkdirs(); + } + Map dataMap = new HashMap<>(); + try { + dataMap.put("packageName", packageName); + dataMap.put("author", businessModelCreateDto.getAuthor()); + dataMap.put("entityName", entityName); + dataMap.put("entityNameLowerCamel", entityNameLowerCase); + dataMap.put("entityNameSnake", entityNameSnake); + dataMap.put("entityNameDescription", businessModelCreateDto.getEntityNameDescription()); + dataMap.put("tableName", + StringUtils.isBlank(tableName) ? FreemarkerConstants.TABLE_PREFIX + entityNameSnake + : tableName); + + generateFileByTemplate(templateName, file, dataMap); + } catch (Exception e) { + e.printStackTrace(); + log.info("generateFile fail:{}", e.getMessage()); + return false; + } + log.info("generateFile suc:{}", file.getPath()); + return true; + } + + public static void generateFileByTemplate(final String templateName, File file, + Map dataMap) throws Exception { + Template template = FreeMarkerTemplateUtils.getTemplate(templateName); + FileOutputStream fos = new FileOutputStream(file); + Writer out = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"), 10240); + template.process(dataMap, out); + } + + public static String packageNameToPath(String packageName) { + return packageName.replace('.', File.separatorChar); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/freemarker/util/FreeMarkerTemplateUtils.java b/backend/src/main/java/com/senmesh/common/freemarker/util/FreeMarkerTemplateUtils.java new file mode 100644 index 0000000..2d98537 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/freemarker/util/FreeMarkerTemplateUtils.java @@ -0,0 +1,67 @@ +package com.senmesh.common.freemarker.util; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.Map; + +import freemarker.cache.ClassTemplateLoader; +import freemarker.cache.NullCacheStorage; +import freemarker.template.Configuration; +import freemarker.template.Template; +import freemarker.template.TemplateException; +import freemarker.template.TemplateExceptionHandler; +import lombok.extern.slf4j.Slf4j; + +/** + * @author sr on 2020-04-13 + */ +@Slf4j +public class FreeMarkerTemplateUtils { + + private FreeMarkerTemplateUtils() {} + + private static final Configuration CONFIGURATION = new Configuration(Configuration.VERSION_2_3_22); + + static { + //这里比较重要,用来指定加载模板所在的路径 + CONFIGURATION + .setTemplateLoader(new ClassTemplateLoader(FreeMarkerTemplateUtils.class, "/ftls")); + CONFIGURATION.setDefaultEncoding("UTF-8"); + CONFIGURATION.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); + CONFIGURATION.setCacheStorage(NullCacheStorage.INSTANCE); + CONFIGURATION.setClassicCompatible(true); + } + + public static Template getTemplate(String templateName) throws IOException { + try { + return CONFIGURATION.getTemplate(templateName); + } catch (IOException e) { + throw e; + } + } + + /** + * 字符串模版占位符替换 + * @param templateStr + * @param params + * @return + * @author sr on 2020-12-21 + */ + public static String formatString(String templateStr, Map params) { + try { + Template template = new Template("formatString", templateStr, FreeMarkerTemplateUtils.CONFIGURATION); + StringWriter result = new StringWriter(); + template.process(params, result); + return result.toString(); + } catch (IOException | TemplateException e) { + log.error("内容占位符替换失败:{}", e.getMessage()); + } + return null; + } + + + public static void clearCache() { + CONFIGURATION.clearTemplateCache(); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/function/TransactionAfterCommit.java b/backend/src/main/java/com/senmesh/common/function/TransactionAfterCommit.java new file mode 100644 index 0000000..deb6237 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/function/TransactionAfterCommit.java @@ -0,0 +1,38 @@ +package com.senmesh.common.function; + +import org.springframework.transaction.support.TransactionSynchronizationAdapter; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +@FunctionalInterface +public interface TransactionAfterCommit { + + void afterCommit(); + + /** + * 事务提交后的回调操作 + * + * @param transactionAfterCommit 事务提交后 + */ + static void doSomeThingAfterCommit(TransactionAfterCommit transactionAfterCommit) { + TransactionSynchronizationManager + .registerSynchronization(new TransactionSynchronizationAdapter() { + @Override + public void afterCommit() { + transactionAfterCommit.afterCommit(); + } + }); + } + + static void doSomeThingAfterCompletion(TransactionAfterCommit transactionAfterCommit) { + TransactionSynchronizationManager + .registerSynchronization(new TransactionSynchronizationAdapter() { + @Override + public void afterCompletion(int status) { + transactionAfterCommit.afterCommit(); + } + }); + } + + + +} diff --git a/backend/src/main/java/com/senmesh/common/functions/SFunction.java b/backend/src/main/java/com/senmesh/common/functions/SFunction.java new file mode 100644 index 0000000..0a48a34 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/functions/SFunction.java @@ -0,0 +1,31 @@ +package com.senmesh.common.functions; + +import java.io.Serializable; +import java.lang.invoke.SerializedLambda; +import java.lang.reflect.Method; +import java.util.function.Function; + +/** + * @author chenyun + * @description 序列化的Function + * @date 2020/9/16 13:38 + */ +@FunctionalInterface +public interface SFunction extends Function, Serializable { + + /** + * 解析function为SerializedLambda + * + * @return + */ + default SerializedLambda serialized() { + try { + Method replaceMethod = getClass().getDeclaredMethod("writeReplace"); + replaceMethod.setAccessible(true); + return (SerializedLambda) replaceMethod.invoke(this); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/backend/src/main/java/com/senmesh/common/log/ILogProvider.java b/backend/src/main/java/com/senmesh/common/log/ILogProvider.java new file mode 100644 index 0000000..d87c6e8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/log/ILogProvider.java @@ -0,0 +1,12 @@ +package com.senmesh.common.log; + +/** + * 日志提供者 + * + * @author sr on 2020-10-29 + */ +public interface ILogProvider { + + void log(Object object); + +} diff --git a/backend/src/main/java/com/senmesh/common/log/aspect/ControllerLogAspect.java b/backend/src/main/java/com/senmesh/common/log/aspect/ControllerLogAspect.java new file mode 100644 index 0000000..950608a --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/log/aspect/ControllerLogAspect.java @@ -0,0 +1,177 @@ +package com.senmesh.common.log.aspect; + +import com.google.common.collect.Lists; +import com.senmesh.common.AlitaResult; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.dto.IOperateDTO; +import com.senmesh.common.log.dto.OperationLogDTO; +import com.senmesh.common.log.util.LogUtils; +import com.senmesh.common.util.*; +import com.senmesh.security.config.SecurityProperties; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.dto.IUserDetail; +import lombok.extern.slf4j.Slf4j; + +import org.apache.commons.lang3.StringUtils; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.StopWatch; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import java.io.PrintWriter; +import java.io.Serializable; +import java.io.StringWriter; +import java.util.Date; +import java.util.List; +import java.util.Objects; + + +/** + * controller日志 + * + * @author sr on 2020-07-30 + */ +@Component +@Aspect +@Slf4j +public class ControllerLogAspect { + + private static final String ANON_LOGIN_URI = "/anon/user/find_user_detail_dto"; + + + + @Autowired + private SecurityProperties securityProperties; + + + @Around("@within(org.springframework.web.bind.annotation.RestController)") + public Object around(ProceedingJoinPoint joinPoint) throws Throwable { + Object result = null; + Throwable currentThrowable = null; + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + // 记录mongo日志 + IUserDetail userDto = UserContextHolder.getLoginUser(); + OperationLogDTO operationLog = new OperationLogDTO(); + HttpServletRequest request = SpringContextHolder.getRequest(); + String requestUri = request.getRequestURL().toString(); + String traceId = TracerUtils.getTraceId(); + operationLog.setTraceId(traceId); + operationLog.setSpanId(TracerUtils.getSpanId()); + operationLog.setParentId(TracerUtils.getParentId()); + operationLog.setLoginUser(userDto); + operationLog.setIp(RequestUtils.getIpAddress(request)); + operationLog.setSystemName(EnvironmentUtils.getApplicationName()); + operationLog.setRequestMethod(request.getMethod()); + operationLog.setRequestTime(new Date()); + operationLog.setRequestUri(requestUri); + List argList = Lists.newArrayList(); + for (Object object : joinPoint.getArgs()) { + // 移除参数分页对象,结果会返回,会记录 + if (object instanceof Page) { + continue; + } + // 文件对象 + if (object instanceof MultipartFile) { + long fileDes = ((MultipartFile) object).getSize(); + argList.add("multipartFile size:" + fileDes); + continue; + } + + if (!(object instanceof Serializable)) { + continue; + } + + //封装参数 + if (Objects.nonNull(userDto) && Objects.nonNull(object) && object instanceof IOperateDTO) { + //前置请求封装数据 + ((IOperateDTO) object).setOperateOrgId(userDto.getOrgId()); + ((IOperateDTO) object).setOperateUserId(userDto.getId()); + } + argList.add(object); + } + operationLog.setRequestBody(parseString(argList)); + try { + result = joinPoint.proceed(); + if (result instanceof AlitaResult) { + ((AlitaResult) result).setRequestId(traceId); + } + return result; + } catch (Throwable t) { + currentThrowable = t; + throw t; + } finally { + stopWatch.stop(); + try { + boolean canLog = canLog(requestUri); + if (canLog && !requestUri.contains(ANON_LOGIN_URI)) { + operationLog.setUseTime(stopWatch.getTotalTimeMillis()); + if (currentThrowable != null) { + operationLog.setResult("调用异常,异常信息:" + currentThrowable); + } else { + if (result != null && result.getClass().equals(byte[].class)) { + operationLog.setResult("byte数组。。。"); + } else if (result instanceof AlitaResult){ + if (((AlitaResult) result).getData() instanceof Page){ + operationLog.setResult("分页结果。。。"); + } else if (((AlitaResult) result).getData() instanceof List){ + operationLog.setResult("List结果。。。"); + } else { + operationLog.setResult(parseString(result)); + } + } else { + operationLog.setResult(parseString(result)); + } + } + LogUtils.log(operationLog); + } + } catch (Exception e) { + log.info("controller log:{}, error:{}", operationLog, e.getMessage()); + } + + } + } + + private String parseString(Object object) { + try { + return JsonUtils.toJsonString(object, false); + } catch (Exception e) { + return getStackTrace(e); + } + } + + /** + * 获取异常的堆栈信息 + * + * @param t + * @return + */ + public static String getStackTrace(Throwable t) { + StringWriter sw = new StringWriter(); + + try (PrintWriter pw = new PrintWriter(sw)) { + t.printStackTrace(pw); + return sw.toString(); + } catch (Exception e) { + return t.getMessage(); + } + } + + public boolean canLog(String requestUri) { + String notLogs = securityProperties.getNotLogs(); + if (StringUtils.isBlank(notLogs)) { + return true; + } + for (String notlog : notLogs.split(CommonConstants.COMMA)) { + if (requestUri.contains(notlog)) { + return false; + } + } + return true; + } + +} diff --git a/backend/src/main/java/com/senmesh/common/log/dto/ExceptionLogDTO.java b/backend/src/main/java/com/senmesh/common/log/dto/ExceptionLogDTO.java new file mode 100644 index 0000000..1909fbd --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/log/dto/ExceptionLogDTO.java @@ -0,0 +1,68 @@ +package com.senmesh.common.log.dto; + +import java.io.Serializable; +import java.util.Date; + +import org.apache.commons.lang3.StringUtils; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonFormat.Shape; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 异常日志 + * + * @author sr on 2020-12-09 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ExceptionLogDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = -3544344864494146694L; + + private String id; + + /** 错误号 **/ + private String errNo; + + /** 年月 **/ + private String ym; + + /** 序号 **/ + private Long seqId; + + /** 链路id **/ + private String traceId; + + /** 创建时间 **/ + @JsonFormat(shape = Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + + /** 错误信息 **/ + private String msg; + + /** + * ym + seqId(5位补零) + * @return + * @author sr on 2020-12-09 + */ + public String getErrNo() { + if (errNo == null) { + if (seqId != null) { + this.errNo = ym + StringUtils.leftPad(String.valueOf(this.seqId), 5, "0"); + } else if (traceId != null) { + this.errNo = traceId; + } + + } + return errNo; + } + +} diff --git a/backend/src/main/java/com/senmesh/common/log/dto/OperationLogDTO.java b/backend/src/main/java/com/senmesh/common/log/dto/OperationLogDTO.java new file mode 100644 index 0000000..6e9d2e9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/log/dto/OperationLogDTO.java @@ -0,0 +1,59 @@ +package com.senmesh.common.log.dto; + +import java.io.Serializable; +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonFormat; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 操作日志 + * @author sr on 2020-10-26 + */ +@Data +@NoArgsConstructor +public class OperationLogDTO implements Serializable { + + /** **/ + private static final long serialVersionUID = -6817430348970835175L; + + /** 链路id **/ + private String traceId; + + /** spanid **/ + private String spanId; + + /** 上一级链路id **/ + private String parentId; + + /** 系统名称 **/ + private String systemName; + + /** ip **/ + private String ip; + + /** 请求地址 **/ + private String requestUri; + + /** 请求类型 **/ + private String requestMethod; + + /** 请求参数 **/ + private Object requestBody; + + /** 请求时间 **/ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date requestTime; + + /** 请求耗时(ms) **/ + private Long useTime; + + /** 请求结果 **/ + private Object result; + + /** 当前登录用户信息:属性见上下文用户对象 **/ + private Object loginUser; + +} diff --git a/backend/src/main/java/com/senmesh/common/log/provider/Slf4jLogProvider.java b/backend/src/main/java/com/senmesh/common/log/provider/Slf4jLogProvider.java new file mode 100644 index 0000000..1900e51 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/log/provider/Slf4jLogProvider.java @@ -0,0 +1,23 @@ +package com.senmesh.common.log.provider; + +import com.senmesh.common.log.ILogProvider; +import com.senmesh.common.util.JsonUtils; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author sr on 2021-01-21 + */ +@Slf4j +public class Slf4jLogProvider implements ILogProvider { + + @Override + public void log(Object object) { + try { + log.info("class:{}, obj:{}", object.getClass(), JsonUtils.toJsonString(object)); + } catch (Exception e) { + log.error("cant log:{}", e.getMessage()); + } + } + +} diff --git a/backend/src/main/java/com/senmesh/common/log/util/LogUtils.java b/backend/src/main/java/com/senmesh/common/log/util/LogUtils.java new file mode 100644 index 0000000..a1e31c6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/log/util/LogUtils.java @@ -0,0 +1,27 @@ +package com.senmesh.common.log.util; + +import com.senmesh.common.log.ILogProvider; +import com.senmesh.common.log.provider.Slf4jLogProvider; + +/** + * @author sr on 2020-10-29 + */ +public class LogUtils { + + private static ILogProvider logProvider = new Slf4jLogProvider(); + + public void setLogProvider(ILogProvider logProvider) { + LogUtils.logProvider = logProvider; + } + + /** + * 记录日志 + * + * @param object + * @author sr on 2020-10-29 + */ + public static void log(Object object) { + logProvider.log(object); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/sensitive/SensitiveInfoUtils.java b/backend/src/main/java/com/senmesh/common/sensitive/SensitiveInfoUtils.java new file mode 100644 index 0000000..2d281d4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/sensitive/SensitiveInfoUtils.java @@ -0,0 +1,213 @@ +package com.senmesh.common.sensitive; + +import org.apache.commons.lang3.StringUtils; + + +/** + * 脱敏基本工具类 + * + * @author qpc + */ +public class SensitiveInfoUtils { + + /** + * [中文姓名] 只显示第一个汉字,其他隐藏为2个星号<例子:李**> + */ + public static String chineseName(final String fullName) { + if (StringUtils.isBlank(fullName)) { + return ""; + } + final String name = StringUtils.left(fullName, 1); + return StringUtils.rightPad(name, StringUtils.length(fullName), "*"); + } + + /** + * [中文姓名] 只显示第一个汉字,其他隐藏为2个星号<例子:李**> + */ + public static String chineseName(final String familyName, final String givenName) { + if (StringUtils.isBlank(familyName) || StringUtils.isBlank(givenName)) { + return ""; + } + return chineseName(familyName + givenName); + } + + /** + * [身份证号] 显示最后四位,其他隐藏。共计18位或者15位。<例子:*************5762> + */ + public static String idCardNum(final String id) { + if (StringUtils.isBlank(id)) { + return ""; + } + return StringUtils.left(id, 3).concat(StringUtils + .removeStart(StringUtils.leftPad(StringUtils.right(id, 3), StringUtils.length(id), "*"), + "***")); + } + + /** + * 将字符串中某一段替换成* + *

+ * 比如 呵呵哈哈哈或或 , start:0 end:1 则变成 *呵哈哈哈或或 + * + * @param start + * @param end + * @return + */ + public static String exchangeHashKey(String origin, int start, int end) { + if (org.apache.commons.lang3.StringUtils.isBlank(origin)) { + return null; + } + char[] chars = origin.toCharArray(); + int startIndex = start - 1; + for (int i = 0; i < chars.length; i++) { + if (i >= startIndex && i < end) { + chars[i] = '*'; + } + } + return new String(chars); + } + + /** + * 【身份证号】前三位 和后三位 + * + * @param front + * @param end + */ + public static String idCardNum(String idCardNum, int front, int end) { + //身份证不能为空 + if (StringUtils.isEmpty(idCardNum)) { + return ""; + } + //需要截取的长度不能大于身份证号长度 + if ((front + end) > idCardNum.length()) { + return ""; + } + //需要截取的不能小于0 + if (front < 0 || end < 0) { + return ""; + } + //计算*的数量 + int asteriskCount = idCardNum.length() - (front + end); + StringBuffer asteriskStr = new StringBuffer(); + for (int i = 0; i < asteriskCount; i++) { + asteriskStr.append("*"); + } + String regex = "(\\w{" + front + "})(\\w+)(\\w{" + end + "})"; + return idCardNum.replaceAll(regex, "$1" + asteriskStr + "$3"); + } + + /** + * 【固定电话 前四位,后两位 + * + * @param num + * @return + */ + public static String fixedPhone(String num) { + if (StringUtils.isBlank(num)) { + return ""; + } + return StringUtils.left(num, 4).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(num, 2), StringUtils.length(num), "*"), "****")); + } + + /** + * [手机号码] 前三位,后四位,其他隐藏<例子:138******1234> + */ + public static String mobilePhone2(final String num) { + if (StringUtils.isBlank(num)) { + return ""; + } + return StringUtils.left(num, 3).concat(StringUtils + .removeStart(StringUtils.leftPad(StringUtils.right(num, 4), StringUtils.length(num), "*"), + "***")); + + } + + /** + * 【手机号码】前三位,后两位,其他隐藏,比如135******10 + * + * @param num + * @return + */ + public static String mobilePhone(String num) { + if (StringUtils.isBlank(num)) { + return ""; + } + return StringUtils.left(num, 3).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(num, 2), StringUtils.length(num), "*"), "***")); + } + + /** + * [地址] 只显示到地区,不显示详细地址;我们要对个人信息增强保护<例子:北京市海淀区****> + * + * @param sensitiveSize 敏感信息长度 + */ + public static String address(final String address, final int sensitiveSize) { + if (StringUtils.isBlank(address)) { + return ""; + } + if (address.length() <= sensitiveSize) { + return address; + } + final int length = StringUtils.length(address); + return StringUtils.rightPad(StringUtils.left(address, length - sensitiveSize), length, "*"); + } + + /** + * [电子邮箱] 邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示<例子:g**@163.com> + */ + public static String email(final String email) { + if (StringUtils.isBlank(email)) { + return ""; + } + final int index = StringUtils.indexOf(email, "@"); + if (index <= 1) { + return email; + } else { + return StringUtils.rightPad(StringUtils.left(email, 1), index, "*") + .concat(StringUtils.mid(email, index, StringUtils.length(email))); + } + } + + /** + * [银行卡号] 前六位,后四位,其他用星号隐藏每位1个星号<例子:6222600**********1234> + */ + public static String bankCard(final String cardNum) { + if (StringUtils.isBlank(cardNum)) { + return ""; + } + + return StringUtils.left(cardNum, 6).concat(StringUtils + .removeStart(StringUtils.leftPad(StringUtils.right(cardNum, 4), StringUtils.length(cardNum), "*"), + "***")); + + } + + /** + * [公司开户银行联号] 公司开户银行联行号,显示前两位,其他用星号隐藏,每位1个星号<例子:12********> + */ + public static String shopsCode(final String code) { + if (StringUtils.isBlank(code)) { + return ""; + } + return StringUtils.rightPad(StringUtils.left(code, 2), StringUtils.length(code), "*"); + } + + /** + * 【密码】密码的全部字符都用*代替,比如:****** + * + * @param password + * @return + */ + public static String password(String password) { + if (StringUtils.isBlank(password)) { + return ""; + } + String pwd = StringUtils.left(password, 0); + return StringUtils.rightPad(pwd, StringUtils.length(password), "*"); + } + + + public static void main(String[] args) { + String bankCard = "6214851215669289"; + System.out.println(bankCard(bankCard)); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/sensitive/SensitiveType.java b/backend/src/main/java/com/senmesh/common/sensitive/SensitiveType.java new file mode 100644 index 0000000..2915507 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/sensitive/SensitiveType.java @@ -0,0 +1,64 @@ +package com.senmesh.common.sensitive; + + +/** + * 脱敏类型枚举 + * + * @author qpc + */ +public enum SensitiveType { + /** + * 中文名 + */ + CHINESE_NAME, + /** + * 身份证号 + */ + ID_CARD, + /** + * 座机号 + */ + FIXED_PHONE, + /** + * 手机号 + */ + MOBILE_PHONE, + /** + * 密码 + */ + PASSWORD, + /** + * 地址 + */ + ADDRESS, + /** + * 电子邮件 + */ + EMAIL, + /** + * 银行卡 + */ + BANK_CARD, + /** + * 公司开户银行联号 + */ + SHOPS_CODE, + /** + * 自定义正则过滤 + */ + RGE_EXP, + + /** + * 空值 + */ + NULL, + /** + * 自定义处理 + */ + SELF, + + /** + * 公司名称 + */ + COMPANY_NAME +} diff --git a/backend/src/main/java/com/senmesh/common/sensitive/jackson/SensitiveInfo.java b/backend/src/main/java/com/senmesh/common/sensitive/jackson/SensitiveInfo.java new file mode 100644 index 0000000..a255017 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/sensitive/jackson/SensitiveInfo.java @@ -0,0 +1,48 @@ +package com.senmesh.common.sensitive.jackson; + +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.senmesh.common.sensitive.SensitiveType; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * 脱敏AOP注解 + */ +@Retention(RetentionPolicy.RUNTIME) +@JacksonAnnotationsInside +@JsonSerialize(using = SensitiveInfoSerialize.class) +public @interface SensitiveInfo { + SensitiveType value() default SensitiveType.RGE_EXP; + + /** + * 前缀(保留多少位) + * + * @return int + */ + int prefix() default -1; + + + /** + * 后缀(保留多少位) + * + * @return int + */ + int suffix() default -1; + + /** + * 自定义正则匹配规则 + */ + String regExp() default ""; + + /** + * 正则替换字符 + */ + String regStr() default "*"; + + /** + * 自定义处理标识 + */ + String tag() default "self"; +} diff --git a/backend/src/main/java/com/senmesh/common/sensitive/jackson/SensitiveInfoObjectSerialize.java b/backend/src/main/java/com/senmesh/common/sensitive/jackson/SensitiveInfoObjectSerialize.java new file mode 100644 index 0000000..53676f2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/sensitive/jackson/SensitiveInfoObjectSerialize.java @@ -0,0 +1,84 @@ +package com.senmesh.common.sensitive.jackson; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.ContextualSerializer; +import com.senmesh.common.sensitive.SensitiveType; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.util.Objects; + + +/** + * jackson的脱敏实现 + * + * @author doobo + */ +@Slf4j +public class SensitiveInfoObjectSerialize extends JsonSerializer implements ContextualSerializer { + + private SensitiveType type; + + public SensitiveInfoObjectSerialize() { + } + + public SensitiveInfoObjectSerialize(final SensitiveInfo sensitiveInfo) { + this.type = sensitiveInfo.value(); + } + + @Override + public void serialize(final Object s, final JsonGenerator jsonGenerator, + final SerializerProvider serializerProvider) throws IOException, JsonProcessingException { + try { + if (this.type == SensitiveType.NULL && !isBaseType(s.getClass())) { + jsonGenerator.writeObject(null); + return; + } + jsonGenerator.writeObject(s); + } catch (Exception e) { + log.error("脱敏数据处理异常", e); + jsonGenerator.writeObject(s); + } + } + + @Override + public JsonSerializer createContextual(final SerializerProvider serializerProvider, + final BeanProperty beanProperty) throws JsonMappingException { + // 为空直接跳过 + if (beanProperty != null) { + // 非 String 类直接跳过 + if (Objects.equals(beanProperty.getType().getRawClass(), Object.class)) { + SensitiveInfo sensitiveInfo = beanProperty.getAnnotation(SensitiveInfo.class); + if (sensitiveInfo == null) { + sensitiveInfo = beanProperty.getContextAnnotation(SensitiveInfo.class); + } + if (sensitiveInfo != null && sensitiveInfo.value() == SensitiveType.NULL) { + return new SensitiveInfoObjectSerialize(sensitiveInfo); + } + } + return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty); + } + return serializerProvider.findNullValueSerializer(null); + } + + /** + * 判断object是否为基本类型 + * + * @param cls + */ + public boolean isBaseType(Class cls) { + return cls.equals(int.class) || + cls.equals(byte.class) || + cls.equals(long.class) || + cls.equals(double.class) || + cls.equals(float.class) || + cls.equals(char.class) || + cls.equals(short.class) || + cls.equals(boolean.class); + } +} diff --git a/backend/src/main/java/com/senmesh/common/sensitive/jackson/SensitiveInfoSerialize.java b/backend/src/main/java/com/senmesh/common/sensitive/jackson/SensitiveInfoSerialize.java new file mode 100644 index 0000000..7ae1753 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/sensitive/jackson/SensitiveInfoSerialize.java @@ -0,0 +1,125 @@ +package com.senmesh.common.sensitive.jackson; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.ContextualSerializer; +import com.senmesh.common.sensitive.SensitiveInfoUtils; +import com.senmesh.common.sensitive.SensitiveType; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.io.IOException; +import java.util.Objects; + +/** + * jackson的脱敏实现 + * + * @author doobo + */ +@Slf4j +public class SensitiveInfoSerialize extends JsonSerializer implements ContextualSerializer { + + private SensitiveType type; + + private SensitiveInfo sensitiveInfo; + + public SensitiveInfoSerialize() { + } + + public SensitiveInfoSerialize(final SensitiveInfo sensitiveInfo) { + this.type = sensitiveInfo.value(); + this.sensitiveInfo = sensitiveInfo; + } + + private int getOrDefault(int value, int defaultValue) { + return value < 0 ? defaultValue : value; + } + + @Override + public void serialize(final String s, final JsonGenerator jsonGenerator, + final SerializerProvider serializerProvider) throws IOException, JsonProcessingException { + try { + //有正则优先使用正则 + if (StringUtils.isNotBlank(sensitiveInfo.regExp())) { + jsonGenerator.writeString(s.replaceAll(sensitiveInfo.regExp(), sensitiveInfo.regStr())); + return; + } + switch (this.type) { + case CHINESE_NAME: { + jsonGenerator.writeString(SensitiveInfoUtils.chineseName(s)); + break; + } + case ID_CARD: + case MOBILE_PHONE: { + jsonGenerator.writeString(SensitiveInfoUtils.idCardNum(s + , getOrDefault(sensitiveInfo.prefix(), 3), getOrDefault(sensitiveInfo.suffix(), 4))); + break; + } + case FIXED_PHONE: { + jsonGenerator.writeString(SensitiveInfoUtils.fixedPhone(s)); + break; + } + case PASSWORD: { + jsonGenerator.writeString(SensitiveInfoUtils.password(s)); + break; + } + case ADDRESS: { + jsonGenerator.writeString(SensitiveInfoUtils.address(s, getOrDefault(sensitiveInfo.prefix(), 8))); + break; + } + case EMAIL: { + jsonGenerator.writeString(SensitiveInfoUtils.email(s)); + break; + } + case BANK_CARD: { + jsonGenerator.writeString(SensitiveInfoUtils.bankCard(s)); + break; + } + case SHOPS_CODE: { + jsonGenerator.writeString(SensitiveInfoUtils.shopsCode(s)); + break; + } + case NULL: { + jsonGenerator.writeString((String) null); + break; + } + case COMPANY_NAME: { + jsonGenerator.writeString(SensitiveInfoUtils.exchangeHashKey(s + , getOrDefault(sensitiveInfo.prefix(), 0), getOrDefault(sensitiveInfo.suffix(), 3))); + break; + } + default: { + jsonGenerator.writeString(s); + } + } + } catch (Exception e) { + log.error("脱敏数据处理异常", e); + jsonGenerator.writeString(s); + } + } + + @Override + public JsonSerializer createContextual(final SerializerProvider serializerProvider, + final BeanProperty beanProperty) throws JsonMappingException { + // 为空直接跳过 + if (beanProperty != null) { + SensitiveInfo sensitiveInfo = beanProperty.getAnnotation(SensitiveInfo.class); + // 非 String 类直接跳过 + if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) { + if (sensitiveInfo != null) { + // 如果能得到注解,就将注解的 value 传入 SensitiveInfoSerialize + return new SensitiveInfoSerialize(sensitiveInfo); + } + } + if (sensitiveInfo != null && sensitiveInfo.value() == SensitiveType.NULL) { + return new SensitiveInfoObjectSerialize(sensitiveInfo); + } + return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty); + } + return serializerProvider.findNullValueSerializer(null); + } +} diff --git a/backend/src/main/java/com/senmesh/common/sensitive/service/AbstractSensitiveService.java b/backend/src/main/java/com/senmesh/common/sensitive/service/AbstractSensitiveService.java new file mode 100644 index 0000000..0a38589 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/sensitive/service/AbstractSensitiveService.java @@ -0,0 +1,69 @@ +package com.senmesh.common.sensitive.service; + +import com.senmesh.common.sensitive.SensitiveInfoUtils; + +/** + * 默认脱敏工具抽象类 + * 使用时,可继承并重写(覆盖)相关方法 + */ +public abstract class AbstractSensitiveService implements SensitiveService { + @Override + public String chineseName(String fullName) { + return SensitiveInfoUtils.chineseName(fullName); + } + + @Override + public String chineseName(String familyName, String givenName) { + return SensitiveInfoUtils.chineseName(familyName, givenName); + } + + @Override + public String idCardNum(String id) { + return SensitiveInfoUtils.idCardNum(id); + } + + @Override + public String idCardNum(String idCardNum, int front, int end) { + return SensitiveInfoUtils.idCardNum(idCardNum, front, end); + } + + @Override + public String fixedPhone(String num) { + return SensitiveInfoUtils.fixedPhone(num); + } + + @Override + public String mobilePhone2(String num) { + return SensitiveInfoUtils.mobilePhone2(num); + } + + @Override + public String mobilePhone(String num) { + return SensitiveInfoUtils.mobilePhone(num); + } + + @Override + public String address(String address, int sensitiveSize) { + return SensitiveInfoUtils.address(address, sensitiveSize); + } + + @Override + public String email(String email) { + return SensitiveInfoUtils.email(email); + } + + @Override + public String bankCard(String cardNum) { + return SensitiveInfoUtils.bankCard(cardNum); + } + + @Override + public String shopsCode(String code) { + return SensitiveInfoUtils.shopsCode(code); + } + + @Override + public String password(String password) { + return SensitiveInfoUtils.password(password); + } +} diff --git a/backend/src/main/java/com/senmesh/common/sensitive/service/SensitiveService.java b/backend/src/main/java/com/senmesh/common/sensitive/service/SensitiveService.java new file mode 100644 index 0000000..33396fa --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/sensitive/service/SensitiveService.java @@ -0,0 +1,69 @@ +package com.senmesh.common.sensitive.service; + +/** + * 脱敏服务 + */ +public interface SensitiveService { + + /** + * [中文姓名] 只显示第一个汉字,其他隐藏为2个星号<例子:李**> + */ + String chineseName(final String fullName); + + /** + * [中文姓名] 只显示第一个汉字,其他隐藏为2个星号<例子:李**> + */ + String chineseName(final String familyName, final String givenName); + + /** + * [身份证号] 显示最后四位,其他隐藏。共计18位或者15位。<例子:*************5762> + */ + String idCardNum(final String id); + + /** + * 【身份证号】前三位 和后三位 + */ + String idCardNum(String idCardNum, int front, int end); + + /** + * 【固定电话 前四位,后两位 + */ + String fixedPhone(String num); + + /** + * [手机号码] 前三位,后四位,其他隐藏<例子:138******1234> + */ + String mobilePhone2(final String num); + + /** + * 【手机号码】前三位,后两位,其他隐藏,比如135******10 + */ + String mobilePhone(String num); + + /** + * [地址] 只显示到地区,不显示详细地址;我们要对个人信息增强保护<例子:北京市海淀区****> + * + * @param sensitiveSize 敏感信息长度 + */ + String address(final String address, final int sensitiveSize); + + /** + * [电子邮箱] 邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示<例子:g**@163.com> + */ + String email(final String email); + + /** + * [银行卡号] 前六位,后四位,其他用星号隐藏每位1个星号<例子:6222600**********1234> + */ + String bankCard(final String cardNum); + + /** + * [公司开户银行联号] 公司开户银行联行号,显示前两位,其他用星号隐藏,每位1个星号<例子:12********> + */ + String shopsCode(final String code); + + /** + * 【密码】密码的全部字符都用*代替,比如:****** + */ + String password(String password); +} diff --git a/backend/src/main/java/com/senmesh/common/sensitive/service/SensitiveServiceUtils.java b/backend/src/main/java/com/senmesh/common/sensitive/service/SensitiveServiceUtils.java new file mode 100644 index 0000000..f9a847c --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/sensitive/service/SensitiveServiceUtils.java @@ -0,0 +1,32 @@ +package com.senmesh.common.sensitive.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * 脱敏服务工具类 + */ +@Component +public class SensitiveServiceUtils { + + /** + * 脱敏工具 + */ + private static SensitiveService sensitiveService; + + @Autowired(required = false) + public void setSensitiveService(SensitiveService sensitiveService) { + SensitiveServiceUtils.sensitiveService = sensitiveService; + } + + /** + * 获取脱敏工具类 + */ + public static SensitiveService getSensitiveService() { + if (SensitiveServiceUtils.sensitiveService == null) { + SensitiveServiceUtils.sensitiveService = new AbstractSensitiveService() { + }; + } + return SensitiveServiceUtils.sensitiveService; + } +} diff --git a/backend/src/main/java/com/senmesh/common/service/IMockProvider.java b/backend/src/main/java/com/senmesh/common/service/IMockProvider.java new file mode 100644 index 0000000..5d61cff --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/service/IMockProvider.java @@ -0,0 +1,36 @@ +package com.senmesh.common.service; + + +public interface IMockProvider{ + + void mockPlatUser() ; + + void mockUser(Long userId, Long orgId); + + void clearUser(); + + + + + public class DefaultMockProvider implements IMockProvider{ + + @Override + public void mockPlatUser() { + // TODO Auto-generated method stub + } + + @Override + public void mockUser(Long userId, Long orgId) { + // TODO Auto-generated method stub + + } + + @Override + public void clearUser() { + // TODO Auto-generated method stub + + } + + } +} + diff --git a/backend/src/main/java/com/senmesh/common/trace/DefaultTracer.java b/backend/src/main/java/com/senmesh/common/trace/DefaultTracer.java new file mode 100644 index 0000000..c286f98 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/trace/DefaultTracer.java @@ -0,0 +1,12 @@ +package com.senmesh.common.trace; + +import com.senmesh.common.util.RandomUtils; + +public class DefaultTracer implements ITracer{ + + @Override + public String getTraceId() { + return RandomUtils.generateUUID(); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/trace/ITracer.java b/backend/src/main/java/com/senmesh/common/trace/ITracer.java new file mode 100644 index 0000000..48856b0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/trace/ITracer.java @@ -0,0 +1,15 @@ +package com.senmesh.common.trace; + +public interface ITracer { + + String getTraceId(); + + default String getSpanId() { + return null; + } + + default String getParentId() { + return null; + } + +} diff --git a/backend/src/main/java/com/senmesh/common/util/AESUtils.java b/backend/src/main/java/com/senmesh/common/util/AESUtils.java new file mode 100644 index 0000000..f450716 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/AESUtils.java @@ -0,0 +1,50 @@ +package com.senmesh.common.util; + +import java.nio.charset.StandardCharsets; +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import org.springframework.util.Base64Utils; + + +/** + * @author sr on 2024-02-22 + */ +public class AESUtils { + + public static final String TRANSFORM_ECB_5 = "AES/ECB/PKCS5Padding"; + public static final String TRANSFORM_ECB_7 = "AES/ECB/PKCS7Padding"; + public static final String TRANSFORM_ECB = "AES/ECB/NoPadding"; + + static { + Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); + } + + public static Cipher getCipher(String transform) throws Exception { + if (TRANSFORM_ECB_7.equals(transform)) { + return Cipher.getInstance(transform, "BC"); + } else { + return Cipher.getInstance(transform); + } + } + + public static String encrypt(String input, String key, String transform) throws Exception { + Cipher cipher = getCipher(transform); + SecretKey keySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES"); + cipher.init(Cipher.ENCRYPT_MODE, keySpec); + return Base64Utils.encodeToString(cipher.doFinal(input.getBytes(StandardCharsets.UTF_8))); + } + + public static String decrypt(String input, String key, String transform) + throws Exception { + Cipher cipher = getCipher(transform); + SecretKey keySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES"); + cipher.init(Cipher.DECRYPT_MODE, keySpec); + return new String(cipher.doFinal(Base64Utils.decode(input.getBytes(StandardCharsets.UTF_8))), + StandardCharsets.UTF_8); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/util/BaseDtoUtils.java b/backend/src/main/java/com/senmesh/common/util/BaseDtoUtils.java new file mode 100644 index 0000000..29f16f4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/BaseDtoUtils.java @@ -0,0 +1,36 @@ +package com.senmesh.common.util; + +import com.senmesh.common.dto.BaseDTO; +import com.senmesh.common.entity.BaseEntity; + +/** + * 基础dto工具类 + * @author sr on 2019-12-07 + */ +public class BaseDtoUtils { + + /** + * 创建回写dto数据 + * @param entity + * @param dto + * @author sr on 2019-12-07 + */ + public static void createCopy(BaseEntity entity, BaseDTO dto) { + dto.setId(entity.getId()); + dto.setDeleted(entity.getDeleted()); + dto.setCreateTime(entity.getCreateTime()); + dto.setCreateBy(entity.getCreateBy()); + } + + /** + * 修改回写dto数据 + * @param entity + * @param dto + * @author sr on 2019-12-07 + */ + public static void updateCopy(BaseEntity entity, BaseDTO dto) { + dto.setUpdateTime(entity.getUpdateTime()); + dto.setUpdateBy(entity.getUpdateBy()); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/util/BigDecimalUtils.java b/backend/src/main/java/com/senmesh/common/util/BigDecimalUtils.java new file mode 100644 index 0000000..bfd30f0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/BigDecimalUtils.java @@ -0,0 +1,72 @@ +package com.senmesh.common.util; + +import com.senmesh.common.exception.util.Assert; +import java.math.BigDecimal; +import java.math.RoundingMode; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +/** + * @author sr on 2020-08-14 + */ +@Slf4j +public class BigDecimalUtils { + + /** + * 保留两位小数 + * + * @return + */ + public static BigDecimal keepTwo(BigDecimal amount) { + if (amount == null) { + return BigDecimal.ZERO; + } + return amount.setScale(2, RoundingMode.DOWN); + } + + /** + * 转BigDecimal(转换失败,默认值null) + * @param amountStr + * @return + * @author sr on 2020-08-14 + */ + public static BigDecimal parse(String amountStr) { + return parse(amountStr, null); + } + + /** + * 转BigDecimal + * + * @param amountStr + * @param defaultValue 转换失败默认值 + * @return + * @author sr on 2020-08-14 + */ + public static BigDecimal parse(String amountStr, BigDecimal defaultValue) { + if (StringUtils.isBlank(amountStr)) { + return defaultValue; + } + try { + return new BigDecimal(amountStr); + } catch (NumberFormatException e) { + log.info("bigDecimal parse error", e); + return defaultValue; + } + } + + /** + * 见N+1进N 例如见厘进分 + * 0.0321->0.04 + * 0.0310->0.04 + * 0.0301->0.03 + * -0.991->-0.990 + * @param decimal + * @return + */ + public static BigDecimal rounding(BigDecimal decimal, int n){ + Assert.isTrue(n > 0, "小数位必须大于0"); + Assert.notNull(decimal, "金额不能为空"); + return decimal.setScale(n + 1, RoundingMode.DOWN).setScale(n, RoundingMode.UP); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/util/CookieUtils.java b/backend/src/main/java/com/senmesh/common/util/CookieUtils.java new file mode 100644 index 0000000..f5910d4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/CookieUtils.java @@ -0,0 +1,112 @@ +package com.senmesh.common.util; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import com.google.common.base.Strings; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.constant.CookieConstants; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * @author Jerry.li + * @description Cookie工具类 + * @date 2020/4/2 + */ +@Slf4j +public class CookieUtils { + + /** + * 获取登录token存储cookie的key + * + * @return + * @author sr on 2020-06-11 + */ + public static String getLoginTokenCookieKey() { + String profile = EnvironmentUtils.getProperty(CommonConstants.PROFILE_KEY); + return CookieConstants.LOGIN_COOKIE_NAME_PREFIX + + (Strings.isNullOrEmpty(profile) ? null : profile.substring(0, 1)); + } + + /** + * 获取指定key的值 + * + * @param key + * @param cookies + * @return + */ + public static String getCookieValue(String key, Cookie[] cookies) { + String value = null; + if (null != cookies && !StringUtils.isEmpty(key)) { + for (Cookie cookie : cookies) { + String cookieName = cookie.getName(); + if (key.equals(cookieName)) { + value = cookie.getValue(); + break; + } + } + } + return value; + } + + /** + * 创建Cookie + * + * @param name + * @param value + * @param domain + * @param path + * @param maxAge 单位:秒 -1: 代表关闭浏览器时就清除cookie 0:创建完cookie,使用后马上就删除 + * @return + */ + public static Cookie createCookie(String name, String value, String domain, String path, + int maxAge) { + Cookie cookie = new Cookie(name, value); + try { + if (StringUtils.isNotEmpty(domain)) { + cookie.setDomain(domain); + } + path = StringUtils.isEmpty(path) ? "/" : path; + cookie.setPath(path); + cookie.setHttpOnly(false); + cookie.setMaxAge(maxAge); + cookie.setSecure(true); + return cookie; + } catch (Exception e) { + log.error("------创建Cookie时,系统异常:{0}", e); + return null; + } + } + + /** + * 移除Cookie + * + * @param name 需要移除的cookie名称 + * @param domain 指定某个域名,不指定就是清空当前tomcat应用下的所有cookie + * @param request + * @param response + */ + public static void removeCookie(String name, String domain, HttpServletRequest request, + HttpServletResponse response) { + Cookie[] cookies = request.getCookies(); + if (!StringUtils.isEmpty(name) && null != cookies) { + for (Cookie cookie : cookies) { + if (name.equals(cookie.getName())) { + Cookie tempCookie = new Cookie(name, ""); + tempCookie.setMaxAge(0); + tempCookie.setPath("/"); + tempCookie.setSecure(true); + if (!StringUtils.isEmpty(domain)) { + tempCookie.setDomain(domain); + } + response.addCookie(tempCookie); + break; + } + } + } + } + +} diff --git a/backend/src/main/java/com/senmesh/common/util/DateUtils.java b/backend/src/main/java/com/senmesh/common/util/DateUtils.java new file mode 100644 index 0000000..dabc8d6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/DateUtils.java @@ -0,0 +1,335 @@ +package com.senmesh.common.util; + +import lombok.extern.slf4j.Slf4j; +import net.bytebuddy.dynamic.scaffold.MethodGraph.Linked; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.time.FastDateFormat; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.*; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +/** + * 日期工具类 + * @author sr on 2020-08-14 + */ +@Slf4j +public class DateUtils { + + public static final String YYYY_MM_DD = "yyyy-MM-dd"; + public static final String YYYY_MM = "yyyy-MM"; + + public static final String YYYY = "yyyy"; + public static final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; + public static final FastDateFormat YMDHMS_FORMAT = + FastDateFormat.getInstance(DATETIME_PATTERN); + + public static final String DATETIME_PATTERN_NO_SS = "yyyy-MM-dd HH:mm"; + public static final FastDateFormat YMDHM_FORMAT = + FastDateFormat.getInstance(DATETIME_PATTERN_NO_SS); + + /** yyyy-MM-dd **/ + public static final FastDateFormat YMD_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd"); + /** yyMMdd **/ + public static final FastDateFormat YMD_FORMAT2 = FastDateFormat.getInstance("yyyyMMdd"); + + /** yyMM **/ + public static final DateTimeFormatter YM_FORMAT = DateTimeFormatter.ofPattern("yyMM"); + /** yyyyMM **/ + public static final DateTimeFormatter YM_FORMAT2 = DateTimeFormatter.ofPattern("yyyyMM"); + /** yyyy-MM-dd HH:mm:ss **/ + public static final DateTimeFormatter DATETIME_FORMAT = + DateTimeFormatter.ofPattern(DATETIME_PATTERN); + + /** + * @param date + * @return yyyy-MM-dd HH:mm:ss + * @author sr on 2020-08-14 + */ + public static String format(Date date) { + return YMDHMS_FORMAT.format(date); + } + + /** + * @param date + * @return yyyy-MM-dd HH:mm + * @author sr on 2020-08-14 + */ + public static String formatSplitSecond(Date date) { + return YMDHM_FORMAT.format(date); + } + + /** + * @param dateStr yyyy-MM-dd HH:mm:ss + * @return + * @author sr on 2020-08-14 + */ + public static Date parse(String dateStr) { + if (StringUtils.isBlank(dateStr)) { + return null; + } + try { + return YMDHMS_FORMAT.parse(dateStr); + } catch (ParseException e) { + log.error("parse date error", e); + return null; + } + } + + /** + * @param date + * @return yyyy-MM-dd + * @author sr on 2020-08-14 + */ + public static String formatToDay(Date date) { + return YMD_FORMAT.format(date); + } + + /** + * @param dateStr yyyy-MM-dd + * @return + * @author sr on 2020-08-14 + */ + public static Date parseToDay(String dateStr) { + if (StringUtils.isBlank(dateStr)) { + return null; + } + try { + return YMD_FORMAT.parse(dateStr); + } catch (ParseException e) { + log.error("parse date error", e); + return null; + } + } + + /** + * @param date + * @return yyMMdd + * @author sr on 2022-09-22 + */ + public static String formatToDay2(Date date) { + return YMD_FORMAT2.format(date); + } + + /** + * @param dateStr yyMMdd + * @return + * @author sr on 2022-09-22 + */ + public static Date parseToDay2(String dateStr) { + if (StringUtils.isBlank(dateStr)) { + return null; + } + try { + return YMD_FORMAT2.parse(dateStr); + } catch (ParseException e) { + log.error("parse date error", e); + return null; + } + } + + + /** + * 获取当前年月(yyMM) + * @return + * @author sr on 2020-12-09 + */ + public static String getCurrentYm() { + LocalDate localDate = LocalDate.now(); + return localDate.format(DateUtils.YM_FORMAT); + } + + /** + * 获取当前年月日(yyyy-MM-dd) + * @return yyyy-MM-dd + * @author sr on 2023-12-07 + */ + public static String getCurrentYmd() { + return formatToDay(new Date()); + } + + public static LocalDate getLocalDate(Date date) { + if (date == null) { + return LocalDate.now(); + } else { + return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + } + } + + public static LocalDateTime getLocalDateTime(Date date) { + if (date == null) { + return LocalDateTime.now(); + } else { + return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); + } + } + + public static Date toDate(LocalDateTime date) { + ZonedDateTime startZdt = date.atZone(ZoneId.systemDefault()); + return Date.from(startZdt.toInstant()); + } + + /** + * 获取指定日期开始时间字符串(yyyy-MM-dd 00:00:00) + * @param date 为空取当前时间 + * @return + * @author sr on 2021-04-19 + */ + public static String getStartDateTimeStr(Date date) { + LocalDateTime localDateTime = LocalDateTime.of(getLocalDate(date), LocalTime.MIN); + return DATETIME_FORMAT.format(localDateTime); + } + + /** + * 获取当前日期开始时间 + * @return + * @author sr on 2021-04-19 + */ + public static Date getCurrentStartDateTime() { + return getStartDateTime(null); + } + + /** + * 获取指定日期开始时间 + * @param date 为空取当前时间 + * @return + * @author sr on 2021-04-19 + */ + public static Date getStartDateTime(Date date) { + return toDate(LocalDateTime.of(getLocalDate(date), LocalTime.MIN)); + } + + /** + * 获取指定日期开始时间字符串(yyyy-MM-dd 23:59:59) + * @param date 为空取当前时间 + * @return + * @author sr on 2021-04-19 + */ + public static String getEndDateTimeStr(Date date) { + LocalDateTime localDateTime = LocalDateTime.of(getLocalDate(date), LocalTime.MAX); + return DATETIME_FORMAT.format(localDateTime); + } + + + /** + * 获取当前日期结束时间 + * @return + * @author sr on 2021-04-19 + */ + public static Date getCurrentEndDateTime() { + return getEndDateTime(null); + } + + /** + * 获取指定日期结束时间 + * @param date 为空取当前时间 + * @return + * @author sr on 2021-04-19 + */ + public static Date getEndDateTime(Date date) { + return toDate(LocalDateTime.of(getLocalDate(date), LocalTime.MAX)); + } + + /** + * 两个日期间相差的天数 这里不包含起始日期,如果想要结果包含起始日期,则需要再结果上+1 + * @return + */ + public static int getDifferenceDayCount(Date date1, Date date2) { + + LocalDate startDate = DateUtils.getLocalDate(date1); + LocalDate endDate = DateUtils.getLocalDate(date2); + //取正数 + return Math.abs((int) (endDate.toEpochDay() - startDate.toEpochDay())); + } + + /** + * 日期添加月 + * @param date + * @param month + * @return + * @author sr on 2023-03-02 + */ + public static Date addMonth(Date date, int month) { + Calendar c = Calendar.getInstance(); + c.setTime(date); + c.add(Calendar.MONTH, month); + return c.getTime(); + } + + /** + * 添加天 + * @param date + * @param amount + * @return + * @author sr on 2023-12-22 + */ + public static Date addDays(Date date, int amount) { + return add(date, Calendar.DAY_OF_MONTH, amount); + } + + /** + * 日期变化 + * @param date + * @param calendarField {@link Linked Calendar} + * @param amount + * @return + * @author sr on 2023-12-22 + */ + public static Date add(Date date, int calendarField, int amount) { + if (date == null) { + throw new IllegalArgumentException("The date must not be null"); + } + Calendar c = Calendar.getInstance(); + c.setTime(date); + c.add(calendarField, amount); + return c.getTime(); + } + + /** + * 根据日期格式不同计算两个时间内的日期、月份、年 + * @param beginTime 开始时间 + * @param endTime 结束时间 + * @param dateFormat 日期格式 + * @return + */ + public static List getDateBetween(Date beginTime, Date endTime,String dateFormat) { + List result = new ArrayList<>(); + try { + //格式化日期 + SimpleDateFormat sdf = new SimpleDateFormat(dateFormat); + Calendar min = Calendar.getInstance(); + min.setTime(beginTime); + + Calendar max = Calendar.getInstance(); + max.setTime(endTime); + + if(YYYY_MM_DD.equals(dateFormat)){ + while (min.before(max) || min.equals(max)) { + result.add(sdf.format(min.getTime())); + min.add(Calendar.DATE, 1); + } + }else if(YYYY_MM.equals(dateFormat)){ + while (min.before(max) || min.equals(max)) { + result.add(sdf.format(min.getTime())); + min.add(Calendar.MONTH, 1); + } + }else { + while (min.before(max) || min.equals(max)) { + result.add(String.valueOf(min.get(Calendar.YEAR))); + min.add(Calendar.YEAR, 1); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return result; + } + + +} diff --git a/backend/src/main/java/com/senmesh/common/util/DisplayedComponentUtils.java b/backend/src/main/java/com/senmesh/common/util/DisplayedComponentUtils.java new file mode 100644 index 0000000..9c472d3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/DisplayedComponentUtils.java @@ -0,0 +1,57 @@ +package com.senmesh.common.util; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import com.senmesh.common.dto.ColumnDTO; +import com.senmesh.common.dto.DisplayedComponentDTO; +import com.senmesh.common.dto.MessageDTO; + +/** + * @author sr on 2020-04-22 + */ +public class DisplayedComponentUtils { + + /** + * 数组转列配置(index 0标题,1属性key) + * + * @param columnArray + * @return + * @author sr on 2020-04-22 + */ + public static ColumnDTO toColumnDTO(String[] columnArray) { + return ColumnDTO.builder().title(columnArray[0]).key(columnArray[1]).dataIndex(columnArray[1]).build(); + } + + /** + * 批量数组转列配置(index 0标题,1属性key) + * + * @param columnArrays + * @return + * @author sr on 2020-04-22 + */ + public static List toColumnDtos(List columnArrays) { + return columnArrays.stream().map(DisplayedComponentUtils::toColumnDTO) + .collect(Collectors.toList()); + } + + /** + * 创建展示对象 + * + * @param + * @param msg + * @param columnArrays (index 0标题,1属性key) + * @param data + * @return + * @author sr on 2020-04-22 + */ + public static DisplayedComponentDTO create(String msg, List columnArrays, + List data) { + MessageDTO messageDto = MessageDTO.builder().content(msg).build(); + return new DisplayedComponentDTO(messageDto, toColumnDtos(columnArrays), data, + Collections.emptyList()); + } + + +} diff --git a/backend/src/main/java/com/senmesh/common/util/EnumUtil.java b/backend/src/main/java/com/senmesh/common/util/EnumUtil.java new file mode 100644 index 0000000..a6c88aa --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/EnumUtil.java @@ -0,0 +1,42 @@ +package com.senmesh.common.util; + +import com.senmesh.common.functions.SFunction; + +import java.lang.invoke.SerializedLambda; +import java.util.Arrays; + +/** + * @author chenyun + * @description 枚举工具类 + * @date 2020/9/16 13:36 + */ +public class EnumUtil { + + private EnumUtil() { + } + + /** + * @param function 转换函数 + * @param r 转换的值 + * @param + * @param + * @return + */ + public static , R> E resolve(SFunction function, R r) { + SerializedLambda serialized = function.serialized(); + try { + Class aClass = (Class) Class.forName(serialized.getImplClass().replace("/", ".")); + return (E) Arrays.stream(aClass.getEnumConstants()) + .filter(e -> { + R apply = function.apply(e); + return apply != null && apply.equals(r); + }) + .findFirst() + .orElse(null); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + return null; + } + +} diff --git a/backend/src/main/java/com/senmesh/common/util/EnvironmentUtils.java b/backend/src/main/java/com/senmesh/common/util/EnvironmentUtils.java new file mode 100644 index 0000000..d55b734 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/EnvironmentUtils.java @@ -0,0 +1,73 @@ +package com.senmesh.common.util; + +import org.springframework.core.env.Environment; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.util.Assert; + +/** + * 环境变量工具类 + * + * @author sr on 2020-06-11 + */ +public class EnvironmentUtils{ + + private static Environment ENVIRONMENT; + + public EnvironmentUtils(Environment environment) { + EnvironmentUtils.ENVIRONMENT = environment; + getSystemCode(); + } + + private static Integer systemCode; + private static String applicationName; + + /** + * 获取环境变量 + * + * @param key + * @return + * @author sr on 2020-06-17 + */ + public static String getProperty(String key) { + return ENVIRONMENT.getProperty(key); + } + + /** + * 获取项目名 + * + * @return + * @author sr on 2020-06-17 + */ + public static String getApplicationName() { + if (applicationName == null) { + applicationName = ENVIRONMENT.getProperty(CommonConstants.APPLICATION_NAME_KEY); + } + return applicationName; + } + + /** + * 获取系统编码 + * + * @return + * @author sr on 2020-06-17 + */ + public static Integer getSystemCode() { + if (systemCode == null) { + systemCode = Integer.valueOf(ENVIRONMENT.getProperty(CommonConstants.SYSTEM_CODE_KEY)); + } + Assert.notNull(systemCode, "系统标识不能为空"); + return systemCode; + } + + /** + * 获取环境 + * + * @return + * @author sr on 2020-07-22 + */ + public static String getProfile() { + return EnvironmentUtils.getProperty(CommonConstants.PROFILE_KEY); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/util/IdcardUtils.java b/backend/src/main/java/com/senmesh/common/util/IdcardUtils.java new file mode 100644 index 0000000..dc43ff1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/IdcardUtils.java @@ -0,0 +1,159 @@ +package com.senmesh.common.util; + +import org.apache.commons.lang3.StringUtils; + +import lombok.extern.slf4j.Slf4j; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author : yzq + * create at: 2020/10/28 14:39 + * @description: 身份证工具类 + */ + +@Slf4j +public class IdcardUtils { + + // 非法的年龄,用于处理异常。 + private static final int invalidAge = -1; + + //身份证提取正则 + private static Pattern idCardPattern = Pattern.compile("\\d{17}[\\d|x|X]|\\d{15}"); + + /** + * 根据身份证号码计算年龄 + * + * @param idNumber 考虑到了15位身份证,但不一定存在 + */ + public static int getAgeByIDNumber(String idNumber) { + String dateStr; + if (idNumber.length() == 15) { + dateStr = "19" + idNumber.substring(6, 12); + } else if (idNumber.length() == 18) { + dateStr = idNumber.substring(6, 14); + } else {//默认是合法身份证号,但不排除有意外发生 + return invalidAge; + } + + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd"); + try { + Date birthday = simpleDateFormat.parse(dateStr); + return getAgeByDate(birthday); + } catch (ParseException e) { + return invalidAge; + } + + } + + /** + * 根据出生日期获取年龄 + * + * @param birthday + * @return + */ + public static int getAgeByDate(Date birthday) { + Calendar calendar = Calendar.getInstance(); + if (calendar.getTimeInMillis() - birthday.getTime() < 0L) { + return invalidAge; + } + + int yearNow = calendar.get(Calendar.YEAR); + int monthNow = calendar.get(Calendar.MONTH); + int dayOfMonthNow = calendar.get(Calendar.DAY_OF_MONTH); + + calendar.setTime(birthday); + + int yearBirthday = calendar.get(Calendar.YEAR); + int monthBirthday = calendar.get(Calendar.MONTH); + int dayOfMonthBirthday = calendar.get(Calendar.DAY_OF_MONTH); + + int age = yearNow - yearBirthday; + + if (monthNow <= monthBirthday) { + if (monthNow == monthBirthday) { + if (dayOfMonthNow < dayOfMonthBirthday) { + age--; + } + } else { + age--; + } + } + + return age; + } + + /** + * 根据身份证号判断性别 + * + * @param idNumber + * @return + */ + public static String judgeGender(String idNumber) { + + if (idNumber.length() != 18 && idNumber.length() != 15) { + return ""; + } + int gender = 0; + if (idNumber.length() == 18) { + //如果身份证号18位,取身份证号倒数第二位 + char c = idNumber.charAt(idNumber.length() - 2); + gender = Integer.parseInt(String.valueOf(c)); + } else { + //如果身份证号15位,取身份证号最后一位 + char c = idNumber.charAt(idNumber.length() - 1); + gender = Integer.parseInt(String.valueOf(c)); + } + + if (gender % 2 == 1) { + return "男"; + } else { + return "女"; + } + } + + public static Integer getGender(String idNumber) { + if (idNumber.length() != 18 && idNumber.length() != 15) { + return null; + } + int gender = 0; + if (idNumber.length() == 18) { + //如果身份证号18位,取身份证号倒数第二位 + char c = idNumber.charAt(idNumber.length() - 2); + gender = Integer.parseInt(String.valueOf(c)); + } else { + //如果身份证号15位,取身份证号最后一位 + char c = idNumber.charAt(idNumber.length() - 1); + gender = Integer.parseInt(String.valueOf(c)); + } + + if (gender % 2 == 1) { + return 1; + } else { + return 2; + } + } + + + + /** + * @description: 提取身份证号 + * @return: 身份证号 + */ + public static String extractCardNo(String str){ + if (StringUtils.isBlank(str)) { + return null; + } + Matcher matcher = idCardPattern.matcher(str); + if (matcher.find()) { + return matcher.group(); + } + return null; + } + +} diff --git a/backend/src/main/java/com/senmesh/common/util/JasyptUtils.java b/backend/src/main/java/com/senmesh/common/util/JasyptUtils.java new file mode 100644 index 0000000..3491bbb --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/JasyptUtils.java @@ -0,0 +1,54 @@ +package com.senmesh.common.util; + +import org.jasypt.encryption.StringEncryptor; + +import com.senmesh.common.exception.util.Assert; + +import lombok.extern.slf4j.Slf4j; + +/** + * 配置信息加解密工具 + * @author sr on 2021-11-11 + */ +@Slf4j +public class JasyptUtils { + + private static StringEncryptor stringEncryptor; + + public JasyptUtils(StringEncryptor stringEncryptor) { + Assert.isNull(JasyptUtils.stringEncryptor, "已存在加密对象"); + JasyptUtils.stringEncryptor = stringEncryptor; + } + + /** + * 加密 + * @param str + * @return + * @author sr on 2021-11-11 + */ + public static String encrypt(String str) { + try { + return stringEncryptor.encrypt(str); + } catch (Exception e) { + log.info("加密失败:", e); + return null; + } + + } + + /** + * 解密 + * @param encodedStr + * @return + * @author sr on 2021-11-11 + */ + public static String decrypt(String encodedStr) { + try { + return stringEncryptor.decrypt(encodedStr); + } catch (Exception e) { + log.info("解密失败:", e); + return null; + } + } + +} diff --git a/backend/src/main/java/com/senmesh/common/util/JsonUtils.java b/backend/src/main/java/com/senmesh/common/util/JsonUtils.java new file mode 100644 index 0000000..cb92a1a --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/JsonUtils.java @@ -0,0 +1,177 @@ +package com.senmesh.common.util; + +import java.text.SimpleDateFormat; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.senmesh.common.annotation.MaskAnontationIntrospector; + +/** + * json 工具类 + * + * @author on 2019-11-05 + * + */ +public class JsonUtils { + + /** 序列化所有(带mask) **/ + private static ObjectMapper simpleDateMapper; + /** 序列化不为null(带mask) **/ + private static ObjectMapper simpleDateNoEmptyMapper; + + /** 默认(不带mask) **/ + private static ObjectMapper defaultMapper; + + static { + simpleDateMapper = buildObjectMapper(); + simpleDateMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); + simpleDateMapper.setAnnotationIntrospector(new MaskAnontationIntrospector()); + simpleDateNoEmptyMapper = buildObjectMapper(); + simpleDateNoEmptyMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); + // 配置mapper忽略空属性 默认不忽略 + simpleDateNoEmptyMapper.setSerializationInclusion(Include.NON_EMPTY); + simpleDateNoEmptyMapper.setAnnotationIntrospector(new MaskAnontationIntrospector()); + defaultMapper = buildObjectMapper(); + + } + + /** + * (mask)对象转json字符串(null也序列化) + * @param object + * @return + * @author sr on 2020-08-14 + */ + public static String toJsonString(Object object) { + return toJsonString(simpleDateMapper, object); + } + + /** + * (mask)对象转json字符串(null不序列化) + * @param object + * @return + * @author sr on 2021-10-21 + */ + public static String toNoEmptyJson(Object object) { + return toJsonString(simpleDateNoEmptyMapper, object); + } + + /** + * (mask)对象转json字符串 + * @param object + * @param nullable null是否序列化 + * + */ + public static String toJsonString(Object object, boolean nullable) { + ObjectMapper objectMapper; + if (nullable) { + objectMapper = simpleDateMapper; + } else { + objectMapper = simpleDateNoEmptyMapper; + } + return toJsonString(objectMapper, object); + } + + /** + * 对象转json字符串 + * @param objectMapper + * @param object + * @return + * @author sr on 2021-10-21 + */ + public static String toJsonString(ObjectMapper objectMapper, Object object) { + // 为了使JSON视觉上的可读性,增加一行如下代码,注意,在生产中不需要这样,因为这样会增大Json的内容 + // mapper.configure(SerializationFeature.INDENT_OUTPUT, true); + String jsonString = null; + try { + jsonString = objectMapper.writeValueAsString(object); + } catch (Exception e) { + throw new RuntimeException(e); + } + return jsonString; + } + + /** + * 对象转json字符串(默认) + * @param object + * @return + * @author sr on 2024-04-09 + */ + public static String toDefaultJsonString(Object object) { + return toJsonString(defaultMapper, object); + } + + /** + * json字符串转指定对象 + */ + public static T toObject(String json, Class clazz) { + ObjectMapper mapper = defaultMapper; + try { + return mapper.readValue(json, clazz); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static T toObject(String json, TypeReference valueTypeRef) { + ObjectMapper mapper = defaultMapper; + try { + return mapper.readValue(json, valueTypeRef); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * json字符串转指定对象 + */ + @SuppressWarnings("unchecked") + public static Map toMap(String json) { + ObjectMapper mapper = defaultMapper; + try { + JavaType javaType = mapper.getTypeFactory().constructParametricType(LinkedHashMap.class, + new Class[] {String.class, Object.class}); + return (Map) mapper.readValue(json, javaType); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @SuppressWarnings("unchecked") + public static List toList(String json, Class clazz) { + ObjectMapper mapper = defaultMapper; + try { + JavaType javaType = mapper.getTypeFactory().constructCollectionType(List.class, clazz); + return (List) mapper.readValue(json, javaType); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static ObjectMapper buildObjectMapper() { + ObjectMapper mapper = new ObjectMapper(); + // 当反序列化json时,未知属性会引起的反序列化被打断,这里我们禁用未知属性打断反序列化功能, + // 因为,例如json里有10个属性,而我们的bean中只定义了2个属性,其它8个属性将被忽略 + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + return mapper; + } + + /** + * object转指定类型对象 + * + * @param + * @param object + * @param clazz + * @return + * @author sr on 2020-05-25 + */ + public static T objToClassObj(Object object, Class clazz) { + return defaultMapper.convertValue(object, clazz); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/util/ListUtil.java b/backend/src/main/java/com/senmesh/common/util/ListUtil.java new file mode 100644 index 0000000..6072b5d --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/ListUtil.java @@ -0,0 +1,56 @@ +package com.senmesh.common.util; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import org.apache.commons.collections.CollectionUtils; + +public class ListUtil { + + private ListUtil() {} + + /** + * Collection 转 Map + * + * @param collection 集合对象 + * @param func 处理函数 + * @param 原始类型 + * @param 目标类型 + * @return + */ + public static Map> toMap(Collection collection, Function func) { + Map> resMap; + if (CollectionUtils.isEmpty(collection)) { + return Maps.newHashMap(); + } + int size = collection.size(); + resMap = Maps.newHashMapWithExpectedSize(size); + for (T obj : collection) { + R apply = func.apply(obj); + List ts = resMap.get(apply); + if (ts == null) { + ts = Lists.newArrayList(); + } + ts.add(obj); + resMap.put(apply, ts); + } + return resMap; + } + + + /** + * 获取首个记录 + * @param + * @param list + * @return 可为null + * @author sr on 2021-08-10 + */ + public static T first(List list) { + return CollectionUtils.isEmpty(list) ? null : list.get(0); + } +} diff --git a/backend/src/main/java/com/senmesh/common/util/MockUtils.java b/backend/src/main/java/com/senmesh/common/util/MockUtils.java new file mode 100644 index 0000000..de703f2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/MockUtils.java @@ -0,0 +1,25 @@ +package com.senmesh.common.util; + +import com.senmesh.common.service.IMockProvider; + +public class MockUtils { + +public static IMockProvider mockProvider; + + public MockUtils(IMockProvider mockProvider) { + MockUtils.mockProvider = mockProvider; + } + + public static void mockPlatUser() { + mockProvider.mockPlatUser(); + } + + public static void mockUser(Long userId, Long orgId) { + mockProvider.mockUser(userId, orgId); + } + + public static void clearUser() { + mockProvider.clearUser(); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/util/ParameterizedTypeImpl.java b/backend/src/main/java/com/senmesh/common/util/ParameterizedTypeImpl.java new file mode 100644 index 0000000..e25c4fd --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/ParameterizedTypeImpl.java @@ -0,0 +1,62 @@ +package com.senmesh.common.util; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Arrays; + +/** + * copy fastjson + * + * @author sr on 2020-09-02 + */ +public class ParameterizedTypeImpl implements ParameterizedType { + + private final Type[] actualTypeArguments; + private final Type ownerType; + private final Type rawType; + + public ParameterizedTypeImpl(Type[] actualTypeArguments, Type ownerType, Type rawType) { + this.actualTypeArguments = actualTypeArguments; + this.ownerType = ownerType; + this.rawType = rawType; + } + + public Type[] getActualTypeArguments() { + return actualTypeArguments; + } + + public Type getOwnerType() { + return ownerType; + } + + public Type getRawType() { + return rawType; + } + + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + ParameterizedTypeImpl that = (ParameterizedTypeImpl) o; + + // Probably incorrect - comparing Object[] arrays with Arrays.equals + if (!Arrays.equals(actualTypeArguments, that.actualTypeArguments)) + return false; + if (ownerType != null ? ownerType != that.ownerType : that.ownerType != null) + return false; + return rawType != null ? rawType != that.rawType : that.rawType == null; + + } + + @Override + public int hashCode() { + int result = actualTypeArguments != null ? Arrays.hashCode(actualTypeArguments) : 0; + result = 31 * result + (ownerType != null ? ownerType.hashCode() : 0); + result = 31 * result + (rawType != null ? rawType.hashCode() : 0); + return result; + } +} diff --git a/backend/src/main/java/com/senmesh/common/util/ProductConfig.java b/backend/src/main/java/com/senmesh/common/util/ProductConfig.java new file mode 100644 index 0000000..4ef663e --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/ProductConfig.java @@ -0,0 +1,35 @@ +package com.senmesh.common.util; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.math.BigDecimal; + +@NoArgsConstructor +@AllArgsConstructor +@Data +@ApiModel("限额") +public class ProductConfig implements Serializable { + + private static final long serialVersionUID = 3619751184797118876L; + + @ApiModelProperty("产品id") + private Long productId; + + @ApiModelProperty("年龄上限") + private Integer maxAge; + + @ApiModelProperty("年龄下限") + private Integer minAge; + + @ApiModelProperty("限制额度-月") + private BigDecimal limitAmountMonth; + + @ApiModelProperty("限制额度-年") + private BigDecimal limitAmountYear; + +} diff --git a/backend/src/main/java/com/senmesh/common/util/RandomUtils.java b/backend/src/main/java/com/senmesh/common/util/RandomUtils.java new file mode 100644 index 0000000..c0d25d3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/RandomUtils.java @@ -0,0 +1,50 @@ +package com.senmesh.common.util; + +import java.util.UUID; + +import org.apache.commons.lang3.RandomStringUtils; + +/** + * 随机工具类型 + * @author sr on 2020-01-02 + */ +public class RandomUtils { + + /** + * 随机六位数 + * @return + * @author sr on 2020-01-02 + */ + public static int nextSixInt() { + return org.apache.commons.lang3.RandomUtils.nextInt(100000, 1000000); + } + + /** + * 随机六位验证码 + * @return + * @author sr on 2020-01-02 + */ + public static String nextSixVerificationCode() { + return Integer.toString(RandomUtils.nextSixInt()); + } + + /** + * 生成指定长度的随机字符串 + * @param len 指定长度 + * @return + */ + public static String getRandomString(int len) { + return RandomStringUtils.randomAlphabetic(len); + } + + /** + * 生成uuid,去掉- + * @return + * @author sr on 2019-12-10 + */ + public static String generateUUID() { + String uuid = UUID.randomUUID().toString(); + return uuid.replace("-", ""); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/util/ReflectionUtils.java b/backend/src/main/java/com/senmesh/common/util/ReflectionUtils.java new file mode 100644 index 0000000..22c91c3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/ReflectionUtils.java @@ -0,0 +1,53 @@ +package com.senmesh.common.util; + +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import org.apache.commons.lang3.StringUtils; + +/** + * @author Jerry.li + * @description 反射工具类 + * @date 2020/4/21 + */ +@Slf4j +public class ReflectionUtils { + + /** + * 获取对象属性字段数组 + * @param object 对象 + * @return fieldNames + */ + public static String[] getFiledNames(Object object) { + Field[] fields = object.getClass().getDeclaredFields(); + String[] fieldNames = new String[fields.length]; + for (int i = 0; i < fields.length; i++) { + fieldNames[i] = fields[i].getName(); + } + return fieldNames; + } + + /*** + * 根据属性名称获取对象属性值 + * @param fieldName 字段名称 + * @param object 对象 + * @return Object + */ + public static Object getValueByFieldName(String fieldName, Object object) { + try { + // 序列化字段返回null + if (StringUtils.equalsIgnoreCase(fieldName,"serialVersionUID")){ + return null; + } + String firstLetter = fieldName.substring(0, 1).toUpperCase(); + String getter = "get" + firstLetter + fieldName.substring(1); + Method method = object.getClass().getMethod(getter); + return method.invoke(object); + } catch (Exception e) { + log.error("------ReflectionUtils getValueByFieldName error: {0}", e); + return null; + } + } + +} diff --git a/backend/src/main/java/com/senmesh/common/util/RequestUtils.java b/backend/src/main/java/com/senmesh/common/util/RequestUtils.java new file mode 100644 index 0000000..7126708 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/RequestUtils.java @@ -0,0 +1,194 @@ +package com.senmesh.common.util; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.UnknownHostException; + +import java.util.Enumeration; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang3.StringUtils; + +import com.google.common.base.Strings; +import com.google.common.net.InternetDomainName; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author Jerry.li + * @description 网络请求工具类 + * @date 2020/4/16 + */ +@Slf4j +public class RequestUtils { + + /** ajax请求key **/ + public static final String AJAX_REQUEST_HEADER_KEY = "x-requested-with"; + /** ajax请求value **/ + public static final String AJAX_REQUEST_HEADER_VALUE = "XMLHttpRequest"; + /** feign请求key **/ + public static final String FEIGN_REQUEST_HEADER_KEY = "feign-requested"; + /** feign请求value **/ + public static final String FEIGN_REQUEST_HEADER_VALUE = "feignHttpRequest"; + /** 域名分割符 **/ + public static final String DOMAIN_SEPARATOR = "://"; + /** 路径分割符 **/ + public static final String PATH_SEPARATOR = "/"; + + /** origin_host **/ + public static final String ORIGIN_HOST_HEADER_KEY = "origin_host"; + + /** + * 判断是否是ajax请求 + */ + public static boolean isAjaxRequest(HttpServletRequest request) { + String xReq = request.getHeader(AJAX_REQUEST_HEADER_KEY); + return !Strings.isNullOrEmpty(xReq) && AJAX_REQUEST_HEADER_VALUE.equalsIgnoreCase(xReq); + } + + /** + * 判断是否是feign请求 + */ + public static boolean isFeignRequest(HttpServletRequest request) { + String xReq = request.getHeader(FEIGN_REQUEST_HEADER_KEY); + return !Strings.isNullOrEmpty(xReq) && FEIGN_REQUEST_HEADER_VALUE.equalsIgnoreCase(xReq); + } + + /** + * 获取请求域名(不带协议) + * + * @param request + * @return + * @author sr on 2020-03-10 + */ + public static String getDomain(HttpServletRequest request) { + String hostHeader = request.getHeader(RequestUtils.ORIGIN_HOST_HEADER_KEY); + StringBuffer url = request.getRequestURL(); + log.debug("request url:{}", url); + if (StringUtils.isNoneBlank(hostHeader)) { + log.debug("get request head origin_host:{}", hostHeader); + return hostHeader; + } + int start = url.length() - request.getRequestURI().length(); + int subStart = + url.indexOf(RequestUtils.DOMAIN_SEPARATOR) + RequestUtils.DOMAIN_SEPARATOR.length(); + return url.delete(start, url.length()).substring(subStart); + } + + /** + * 获取请求根域名 + * + * @param request + * @return + * @author sr on 2020-06-10 + */ + public static String getRootDomain(HttpServletRequest request) { + String domainStr = getDomain(request); + try { + String rootDomain = InternetDomainName.from(domainStr).topPrivateDomain().toString(); + return rootDomain; + } catch (IllegalArgumentException e) { + log.debug("{}-rootDomain error:{}", domainStr, e.getMessage()); + return null; + } + } + + + /** + * 获取带协议的域名地址 + * + * @param request + * @return + * @author sr on 2020-03-15 + */ + public static String getHttpDomain(HttpServletRequest request) { + StringBuffer url = request.getRequestURL(); + int start = url.length() - request.getRequestURI().length(); + return url.delete(start, url.length()).toString(); + } + + /** + * 替换域名 + * + * @param urlString + * @param domain + * @author sr on 2020-03-10 + */ + public static String replaceDomain(String urlString, String domain) { + StringBuilder urlBuilder = new StringBuilder(urlString); + int start = urlBuilder.indexOf(DOMAIN_SEPARATOR) + DOMAIN_SEPARATOR.length(); + int endIndex = urlBuilder.indexOf(PATH_SEPARATOR, + urlBuilder.indexOf(DOMAIN_SEPARATOR) + DOMAIN_SEPARATOR.length()); + if (endIndex <= 0) { + endIndex = urlString.length(); + } + return urlBuilder.replace(start, endIndex, domain).toString(); + } + + /** + * 获取请求用户IP地址 + * + * @param request + * @return + */ + public static String getIpAddress(HttpServletRequest request) { + String ipAddress = request.getHeader("x-forwarded-for"); + String unknown = "unknown"; + if (ipAddress == null || ipAddress.length() == 0 || unknown.equalsIgnoreCase(ipAddress)) { + ipAddress = request.getHeader("Proxy-Client-IP"); + } + if (ipAddress == null || ipAddress.length() == 0 || unknown.equalsIgnoreCase(ipAddress)) { + ipAddress = request.getHeader("WL-Proxy-Client-IP"); + } + if (ipAddress == null || ipAddress.length() == 0 || unknown.equalsIgnoreCase(ipAddress)) { + ipAddress = request.getRemoteAddr(); + String localhost = "127.0.0.1"; + if (localhost.equals(ipAddress) || "0:0:0:0:0:0:0:1".equals(ipAddress)) { + //根据网卡获取本机配置的IP地址 + InetAddress inetAddress; + try { + inetAddress = InetAddress.getLocalHost(); + ipAddress = inetAddress.getHostAddress(); + } catch (UnknownHostException e) { + log.error("------获取请求用户IP地址时,异常: {0}", e); + } + } + } + + //对于通过多个代理的情况,第一个IP为客户端真实的IP地址,多个IP按照','分割 + if (null != ipAddress && ipAddress.length() > 15) { + //"***.***.***.***".length() = 15 + if (ipAddress.indexOf(',') != -1) { + ipAddress = ipAddress.substring(0, ipAddress.indexOf(',')); + } + } + return ipAddress; + } + + public static String getHostIp() { + try { + String hostname = System.getenv("HOSTNAME"); + String hostIp = InetAddress.getByName(hostname).getHostAddress(); + if ("127.0.0.1".equals(hostIp) || "0:0:0:0:0:0:0:1".equals(hostIp)) { + Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + while (interfaces.hasMoreElements()) { + NetworkInterface iface = interfaces.nextElement(); + if (iface.isUp() && !iface.isLoopback()) { + Enumeration addresses = iface.getInetAddresses(); + while (addresses.hasMoreElements()) { + InetAddress addr = addresses.nextElement(); + if (addr instanceof Inet4Address) { + return addr.getHostAddress(); + } + } + } + } + } + return hostIp; + } catch (Exception e) { + return "127.0.0.1"; + } + } + +} diff --git a/backend/src/main/java/com/senmesh/common/util/ResponseUtils.java b/backend/src/main/java/com/senmesh/common/util/ResponseUtils.java new file mode 100644 index 0000000..1aed807 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/ResponseUtils.java @@ -0,0 +1,27 @@ +package com.senmesh.common.util; + +import java.io.IOException; +import java.io.PrintWriter; + +import javax.servlet.http.HttpServletResponse; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author Jerry.li + * @description 响应工具类 + * @date 2020/4/16 + */ +@Slf4j +public class ResponseUtils { + + public static void printJson(HttpServletResponse response, Object data) { + response.setContentType("application/json;charset=utf-8"); + try (PrintWriter out = response.getWriter();) { + out.print(JsonUtils.toJsonString(data)); + out.flush(); + } catch (IOException ex) { + log.error("------响应异常", ex); + } + } +} diff --git a/backend/src/main/java/com/senmesh/common/util/SensitiveWordUtils.java b/backend/src/main/java/com/senmesh/common/util/SensitiveWordUtils.java new file mode 100644 index 0000000..8cdbc58 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/SensitiveWordUtils.java @@ -0,0 +1,72 @@ +package com.senmesh.common.util; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.ClassPathResource; + +import com.senmesh.common.constant.CommonConstants; + +import toolgood.words.IllegalWordsSearch; +import toolgood.words.IllegalWordsSearchResult; + +@Slf4j +public class SensitiveWordUtils { + + static IllegalWordsSearch search; + + static { + List list = new ArrayList<>(); + try (BufferedReader bufferedReader = new BufferedReader( + new InputStreamReader(new ClassPathResource("config" + File.separator + "sensi_words.txt").getInputStream()))) { + for (String line = bufferedReader.readLine(); line != null; line = + bufferedReader.readLine()) { + list.add(line); + } + } catch (IOException e) { + log.error("sensi_words.txt加载失败"); + } + search = new IllegalWordsSearch(); + search.SetKeywords(list); + } + + /** + * 校验字符串敏感词是否通过 + * + * @param str + * @return + * @author sr on 2024-06-28 + */ + public static boolean check(String str) { + //todo 先全通过 + return true; +// if (StringUtils.isBlank(str)) { +// return true; +// } +// return !search.ContainsAny(str); + } + + public static String findFirst(String str) { + IllegalWordsSearchResult result = search.FindFirst(str); + if (result != null) { + return result.Keyword; + } + return null; + } + + public static String findAll(String str) { + List results = search.FindAll(str); + if (results != null) { + return results.stream().map(r -> r.Keyword).collect(Collectors.joining(CommonConstants.COMMA)); + } + return null; + } + + +} diff --git a/backend/src/main/java/com/senmesh/common/util/SpringContextHolder.java b/backend/src/main/java/com/senmesh/common/util/SpringContextHolder.java new file mode 100644 index 0000000..4ee8181 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/SpringContextHolder.java @@ -0,0 +1,101 @@ +package com.senmesh.common.util; + +import java.io.Serializable; +import java.util.Optional; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +/** + * spring上下文工具类 + * + * @author sr on 2020-05-20 + */ +@Component +public class SpringContextHolder implements ApplicationContextAware { + + private static ApplicationContext applicationContext; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + SpringContextHolder.applicationContext = applicationContext; + } + + public static ApplicationContext getApplicationContext() { + return applicationContext; + } + + /** + * 获取bean + * + * @param + * @param beanId + * @return + * @author sr on 2020-05-20 + */ + @SuppressWarnings("unchecked") + public static T getBean(String beanId) { + return (T) applicationContext.getBean(beanId); + } + + public static T getBean(Class clazz) { + return applicationContext.getBean(clazz); + } + + public static Optional getRequestAttributes() { + return Optional + .ofNullable((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()); + } + + /** + * 获取当前线程的request + */ + public static HttpServletRequest getRequest() { + return getRequestAttributes().map(ServletRequestAttributes :: getRequest).orElse(null); + } + + /** + * 获取当前线程的response + */ + public static HttpServletResponse getResponse() { + return getRequestAttributes().map(ServletRequestAttributes :: getResponse).orElse(null); + } + + /** + * 获取HttpSession + */ + public static HttpSession getHttpSession() { + return getRequest().getSession(); + } + + /** + * 把值放入session + */ + public static void setSessionAttribute(String key, Serializable entity) { + getHttpSession().setAttribute(key, entity); + } + + public static Object getSessionAttribute(String key) { + return getHttpSession().getAttribute(key); + } + + /** + * 把值放入当前request + */ + public static void setRequestAttribute(String key, Object entity) { + getRequest().setAttribute(key, entity); + } + + public static Object getRequestAttribute(String key) { + return getRequest().getAttribute(key); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/util/StrUtils.java b/backend/src/main/java/com/senmesh/common/util/StrUtils.java new file mode 100644 index 0000000..612f6ca --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/StrUtils.java @@ -0,0 +1,152 @@ +package com.senmesh.common.util; + +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.lang3.StringUtils; + +import java.util.TreeMap; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.BusinessException; + +/** + * @author sr on 2021-02-03 + */ +public class StrUtils { + + /** + * 大驼峰转小驼峰(AaBb -> aaBb) + * + * @param upperCamel + * @return + * @author sr on 2021-02-03 + */ + public static String toLowerCamel(String upperCamel) { + StringBuilder sb = + new StringBuilder(Character.toString(Character.toLowerCase(upperCamel.charAt(0)))); + return sb.append(upperCamel.substring(1)).toString(); + } + + /** + * 驼峰转蛇形(AaBb -> aa_bb) + * + * @param upperCamel + * @return + * @author sr on 2021-02-03 + */ + public static String toSnake(String camel) { + StringBuilder stringBuilder = new StringBuilder(); + boolean first = true; + for (char c : camel.toCharArray()) { + char nc = Character.toLowerCase(c); + if (Character.isUpperCase(c) && !first) { + stringBuilder.append('_').append(nc); + } else { + stringBuilder.append(nc); + first = false; + } + } + return stringBuilder.toString(); + } + + /** + * 构建升序参数字符串(xx=**&xx=**) + * @param paramData + * @return + * @author sr on 2022-02-10 + */ + public static String buildAscQueryValue(Object paramData) { + return buildAscQueryValue(paramData, true, null); + } + + /** + * @param paramData 参数 + * @param normal 是否正常(p1=v1&p2=v2) + * @param split 特殊分隔符(v1分隔符v2) + * @return + * @author sr on 2024-11-18 + */ + public static String buildAscQueryValue(Object paramData, boolean normal, String split) { + Map paramDataMap = null; + if (paramData instanceof Map) { + paramDataMap = paramDataMap; + } else { + try { + paramDataMap = JsonUtils.objToClassObj(paramData, Map.class); + } catch (Exception e) { + throw new BusinessException("参数对象格式错误"); + } + } + if (paramDataMap == null || paramDataMap.isEmpty()) { + return null; + } + Map parameters = new TreeMap(); + for (Entry entry : paramDataMap.entrySet()) { + Object value = entry.getValue(); + if (value != null) { + parameters.put(entry.getKey(), value); + } + } + if (parameters.isEmpty()) { + return null; + } + StringBuilder paramstr = new StringBuilder(); + for (Entry entry : parameters.entrySet()) { + if (normal) { + paramstr.append(entry.getKey()).append(CommonConstants.EQUAL) + .append(entry.getValue()).append(CommonConstants.AND); + } else { + paramstr.append(entry.getValue()).append(split); + } + } + + return paramstr.substring(0, paramstr.length() - 1); + } + + + /** + * 构建参数字符串(xx=**&xx=**) + * @param paramData + * @return + * @author sr on 2024-11-18 + */ + public static String buildQueryValue(Object paramData) { + Map paramDataMap = null; + if (paramData instanceof Map) { + paramDataMap = paramDataMap; + } else { + try { + paramDataMap = JsonUtils.objToClassObj(paramData, Map.class); + } catch (Exception e) { + throw new BusinessException("参数对象格式错误"); + } + } + if (paramDataMap == null || paramDataMap.isEmpty()) { + return null; + } + StringBuilder paramstr = new StringBuilder(); + for (Entry entry : paramDataMap.entrySet()) { + Object value = entry.getValue(); + if (value != null) { + paramstr.append(entry.getKey()).append(CommonConstants.EQUAL) + .append(entry.getValue()).append(CommonConstants.AND); + } + } + if (paramstr.length() == 0) { + return null; + } + return paramstr.substring(0, paramstr.length() - 1); + } + + /** + * 不为空/空字符串/"null"字符串 + * @param str + * @return + * @author sr on 2022-02-10 + */ + public static boolean isNotNull(String str) { + return StringUtils.isNotBlank(str) && !"null".equals(str); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/util/TracerUtils.java b/backend/src/main/java/com/senmesh/common/util/TracerUtils.java new file mode 100644 index 0000000..1369ae8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/TracerUtils.java @@ -0,0 +1,38 @@ +package com.senmesh.common.util; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.senmesh.common.trace.ITracer; + +import lombok.extern.slf4j.Slf4j; + +/** + * 链路工具类 + * + * @author sr on 2020-10-29 + */ +@Component +@Slf4j +public class TracerUtils { + + private static ITracer tracer; + + @Autowired + public void setTracer(ITracer tracer) { + TracerUtils.tracer = tracer; + } + + public static String getTraceId() { + return tracer.getTraceId(); + } + + public static String getSpanId() { + return tracer.getSpanId(); + } + + public static String getParentId() { + return tracer.getParentId(); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/util/TreeHelper.java b/backend/src/main/java/com/senmesh/common/util/TreeHelper.java new file mode 100644 index 0000000..5788962 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/TreeHelper.java @@ -0,0 +1,73 @@ +package com.senmesh.common.util; + +import com.google.common.base.Objects; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 树型结构工具类 + * + * @author sr on 2019-12-11 + */ +public class TreeHelper { + + private TreeHelper() { + } + + + /** + * 构建树型数据 + * + * @param parentId 父id + * @param nodeList 节点列表 + * @return {@link List} + */ + public static > List buildTree(I parentId, List nodeList) { + // 根节点列表 + List list = Lists.newArrayList(); + Map treeMap = nodeList.stream() + .collect(Collectors.toMap(TreeNode::getId, treeNode -> treeNode)); + + nodeList.forEach(node -> { + if (Objects.equal(parentId, node.getParentId())) { + list.add(node); + } + // 父节点 + TreeNode parentNode = treeMap.get(node.getParentId()); + if (parentNode != null) { + parentNode.addChildren(node); + } + }); + return list; + } + + + /** + * 返回子节点Ids + * + * @param parentId 父id + * @param nodeList 节点列表 + * @return {@link Set} + */ + public static > Set childrenNodeIds(Long parentId, List nodeList) { + // 根节点列表 + Set set = Sets.newHashSet(parentId); + + nodeList.sort((a, b) -> a.getParentId().compareTo(b.getParentId())); + + nodeList.forEach(node -> { + if (set.contains(node.getParentId())) { + set.add(node.getId()); + } + }); + set.remove(parentId); + return set; + } + +} diff --git a/backend/src/main/java/com/senmesh/common/util/TreeNode.java b/backend/src/main/java/com/senmesh/common/util/TreeNode.java new file mode 100644 index 0000000..97fe256 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/TreeNode.java @@ -0,0 +1,37 @@ +package com.senmesh.common.util; + +import java.io.Serializable; + +/** + * 树型结构 + * + * @param + * @author sr on 2019-12-11 + */ +public interface TreeNode { + + /** + * id + * + * @return + * @author sr on 2019-12-11 + */ + I getId(); + + /** + * 父id + * + * @return + * @author sr on 2019-12-11 + */ + I getParentId(); + + /** + * 添加子节点 + * + * @param node + * @author sr on 2019-12-11 + */ + void addChildren(T node); + +} diff --git a/backend/src/main/java/com/senmesh/common/util/UserContextHolder.java b/backend/src/main/java/com/senmesh/common/util/UserContextHolder.java new file mode 100644 index 0000000..9c101ac --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/util/UserContextHolder.java @@ -0,0 +1,206 @@ +package com.senmesh.common.util; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.NoneLoginException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.usercenter.dto.IUserDetail; +import com.senmesh.usercenter.user.constant.UserTypeEnum; + +import lombok.extern.slf4j.Slf4j; + +/** + * 项目上下文 + * + * @author on 2019-11-05 + */ +@Slf4j +public class UserContextHolder { + + private static final ThreadLocal contextHolder = new ThreadLocal(); + + /** + * 清除 + * + * @author sr on 2020-07-30 + */ + public static void clearContext() { + contextHolder.remove(); + } + + /** + * 设置 + * + * @param context + * @author sr on 2020-07-30 + */ + public static void setContext(IUserDetail context) { + contextHolder.set(context); + } + + /** + * 获取当前登录用户 + * + * @param auth + * @return + * @author sr on 2020-06-16 + */ + public static IUserDetail getLoginUser() { + return contextHolder.get(); + } + + /** + * 获取当前登录用户ID + */ + public static Long getLoginUserId() { + IUserDetail userDTO = getLoginUser(); + return userDTO == null ? null : userDTO.getId(); + } + + /** + * 获取当前登录机构ID + */ + public static Long getLoginOrgId() { + IUserDetail userDTO = getLoginUser(); + return userDTO == null ? null : userDTO.getOrgId(); + } + + /** + * 获取登录用户(未登录抛异常) + * + * @return + * @author sr on 2019-10-11 + */ + public static IUserDetail getExistLoginUser() { + IUserDetail userDTO = getLoginUser(); + if (userDTO == null) { + throw new NoneLoginException(); + } + return userDTO; + } + + /** + * 获取登录用户id(未登录抛异常) + * + * @return + * @author sr on 2019-10-11 + */ + public static Long getExistLoginUserId() { + return getExistLoginUser().getId(); + } + + /** + * 获取登录机构id(未登录抛异常) + * + * @return + * @author sr on 2019-10-11 + */ + public static Long getExistLoginOrgId() { + return getExistLoginUser().getOrgId(); + } + + /** + * 获取机构类型 + * + * @return + * @author sr on 2019-10-22 + */ + public static String getOrgType() { + IUserDetail userDTO = getLoginUser(); + return userDTO == null ? null : userDTO.getOrgType(); + } + + /** + * 获取用户类型 + * + * @return + * @author sr on 2020-06-17 + */ + public static Integer getUserType() { + IUserDetail userDTO = getLoginUser(); + return userDTO == null ? null : userDTO.getType(); + } + + /** + * 获取用户类型(未登录抛异常) + * + * @return + * @author sr on 2020-06-17 + */ + public static Integer getExistUserType() { + return getExistLoginUser().getType(); + } + + /** + * 获取登录超管用户id(超管未登录抛异常) + * + * @return + * @author sr on 2019-10-17 + */ + public static Long getExistLoginSuperiorId() { + IUserDetail userDTO = getExistLoginUser(); + Assert.isTrue(userDTO.getSupeiror(), "只有平台管理员能访问"); + return userDTO.getId(); + } + + /** + * 是否超管用户 + * + * @return + * @author sr on 2020-03-12 + */ + public static boolean isSuperior() { + IUserDetail userDTO = getLoginUser(); + return userDTO != null && Boolean.TRUE.equals(userDTO.getSupeiror()); + } + + /** + * 是否企业管理员 + * @return + * @author sr on 2021-06-22 + */ + public static boolean isAdministrator() { + return isAdministrator(getLoginUser()); + } + + /** + * 是否企业管理员 + * @param userDTO + * @return + * @author sr on 2021-06-29 + */ + public static boolean isAdministrator(IUserDetail userDTO) { + return userDTO != null && UserTypeEnum.ORG.getType().equals(userDTO.getType()) + && userDTO.getAdministrator(); + } + + /** + * + * 校验平台机构访问 + * + * @author sr on 2020-12-28 + */ + public static void checkPlatformOrg() { + Assert.isTrue(CommonConstants.PLATFORM_ORG_ID.equals(getLoginOrgId()), "只有平台机构能访问"); + } + + /** + * 获取除超管以外的机构ID + * + * @return + */ + public static Long getOrgIdNotSupper() { + IUserDetail userDTO = getExistLoginUser(); + return userDTO.getSupeiror() ? null : userDTO.getOrgId(); + } + + /** + * 获取用户状态 + * @return + * @author sr on 2021-06-30 + */ + public static Integer getStatus() { + IUserDetail userDTO = getLoginUser(); + return userDTO == null ? null : userDTO.getStatus(); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/validate/EnumValidator.java b/backend/src/main/java/com/senmesh/common/validate/EnumValidator.java new file mode 100644 index 0000000..040edae --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/validate/EnumValidator.java @@ -0,0 +1,30 @@ +package com.senmesh.common.validate; + +import com.senmesh.mybatis.handle.BaseEnum; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * enum验证器 + * + * @author Carlye + * @date 2021/01/14 + */ +@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = EnumValidatorAdapter.class) +public @interface EnumValidator { + + Class> value(); + + String message(); + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/backend/src/main/java/com/senmesh/common/validate/EnumValidatorAdapter.java b/backend/src/main/java/com/senmesh/common/validate/EnumValidatorAdapter.java new file mode 100644 index 0000000..0ee9210 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/validate/EnumValidatorAdapter.java @@ -0,0 +1,30 @@ +package com.senmesh.common.validate; + + +import com.senmesh.mybatis.handle.BaseEnum; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.util.Arrays; +import java.util.Objects; + +/** + * enum验证器适配器 + * + * @author Carlye + * @date 2021/01/14 + */ +public class EnumValidatorAdapter implements ConstraintValidator { + private BaseEnum[] enumConstants; + + @Override + public void initialize(EnumValidator constraintAnnotation) { + Class> clazz = constraintAnnotation.value(); + enumConstants = clazz.getEnumConstants(); + } + + @Override + public boolean isValid(Object s, ConstraintValidatorContext constraintValidatorContext) { + return Objects.nonNull(enumConstants) && Objects.nonNull(s) && Arrays.stream(enumConstants).anyMatch(e -> s.equals(e.getValue())); + } +} diff --git a/backend/src/main/java/com/senmesh/common/validation/Check.java b/backend/src/main/java/com/senmesh/common/validation/Check.java new file mode 100644 index 0000000..aeef3fc --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/validation/Check.java @@ -0,0 +1,9 @@ +package com.senmesh.common.validation; + +/** + * 校验 + * + * @author on 2019-11-05 + */ +public interface Check { +} diff --git a/backend/src/main/java/com/senmesh/common/validation/Create.java b/backend/src/main/java/com/senmesh/common/validation/Create.java new file mode 100644 index 0000000..e45b79c --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/validation/Create.java @@ -0,0 +1,10 @@ +package com.senmesh.common.validation; + +/** + * 新增校验 + * + * @author on 2019-11-05 + */ +public interface Create { + +} diff --git a/backend/src/main/java/com/senmesh/common/validation/Delete.java b/backend/src/main/java/com/senmesh/common/validation/Delete.java new file mode 100644 index 0000000..96331ea --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/validation/Delete.java @@ -0,0 +1,10 @@ +package com.senmesh.common.validation; + +/** + * 删除校验 + * + * @author on 2019-11-05 + */ +public interface Delete { + +} diff --git a/backend/src/main/java/com/senmesh/common/validation/Send.java b/backend/src/main/java/com/senmesh/common/validation/Send.java new file mode 100644 index 0000000..3f90f5c --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/validation/Send.java @@ -0,0 +1,7 @@ +package com.senmesh.common.validation; + +/** + * @author on 2019-11-05 + */ +public interface Send { +} diff --git a/backend/src/main/java/com/senmesh/common/validation/Update.java b/backend/src/main/java/com/senmesh/common/validation/Update.java new file mode 100644 index 0000000..d3523d0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/validation/Update.java @@ -0,0 +1,10 @@ +package com.senmesh.common.validation; + +/** + * 更新校验 + * + * @author on 2019-11-05 + */ +public interface Update { + +} diff --git a/backend/src/main/java/com/senmesh/common/validation/annotation/BigDecimalRange.java b/backend/src/main/java/com/senmesh/common/validation/annotation/BigDecimalRange.java new file mode 100644 index 0000000..0e37d32 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/validation/annotation/BigDecimalRange.java @@ -0,0 +1,52 @@ +package com.senmesh.common.validation.annotation; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.*; + +@Target({TYPE, ANNOTATION_TYPE,FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = {BigDecimalRangeValidator.class}) +public @interface BigDecimalRange { + + String message() default ""; + + /** + * 提示信息前缀 + * @return 错误提示 + */ + String messagePrefix() default "金额数值"; + + /** + * 最小值 (包含) + * @return 最小值 + */ + String minValue() default ""; + + /** + * 最大值 (包含) + * @return 最大值 + */ + String maxValue() default ""; + + /** + * 校验长度 + * + * @return int 长度 -1:不校验 + */ + int length() default -1; + + /** + * 校验小数点位数 + * @return int 小数点位数校验 -1:不校验 + */ + int scala() default -1; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/backend/src/main/java/com/senmesh/common/validation/annotation/BigDecimalRangeValidator.java b/backend/src/main/java/com/senmesh/common/validation/annotation/BigDecimalRangeValidator.java new file mode 100644 index 0000000..3c97822 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/validation/annotation/BigDecimalRangeValidator.java @@ -0,0 +1,124 @@ +package com.senmesh.common.validation.annotation; + +import lombok.Data; +import org.apache.commons.lang3.StringUtils; +import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorContextImpl; +import org.springframework.validation.annotation.Validated; + +import javax.validation.*; +import java.math.BigDecimal; +import java.util.Objects; +import java.util.Set; + +/** + * 金额数字范围验证器 + * + * @author Carlye + * @date 2021/03/16 + */ +public class BigDecimalRangeValidator implements ConstraintValidator { + + private BigDecimal minValue; + private BigDecimal maxValue; + private int scala; + private int length; + private String messagePrefix; + + @Override + public void initialize(BigDecimalRange constraintAnnotation) { + try { + minValue = new BigDecimal(constraintAnnotation.minValue()); + } catch (Exception e) { + //doNothing + minValue = null; + } + + try { + maxValue = new BigDecimal(constraintAnnotation.maxValue()); + } catch (Exception e) { + //doNothing + maxValue = null; + } + scala = constraintAnnotation.scala(); + length = constraintAnnotation.length(); + messagePrefix = constraintAnnotation.messagePrefix(); + } + + @Override + public boolean isValid(BigDecimal checkValue, + ConstraintValidatorContext context) { + String messageSuffix = "超出范围"; + boolean checkResult = true; + if (Objects.isNull(checkValue)) { + messageSuffix = "不能为空"; + checkResult = false; + } else if (scala >= 0) { //需要对位数进行校验 + //原值输出BigDecimal + String checkValueStr = checkValue.toPlainString(); + if (StringUtils.substringAfter(checkValueStr, ".").length() != scala) { + messageSuffix = "需要保留" + scala + "位小数"; + checkResult = false; + } + } else if (length >= 0) { + //原值输出BigDecimal + String checkValueStr = checkValue.toPlainString(); + if (checkValueStr.length() > length) { + messageSuffix = "超过最大位数限制(" + length + ")"; + checkResult = false; + } + } else if (Objects.nonNull(minValue) && minValue.compareTo(checkValue) > 0) { + messageSuffix = String.join("", "最小值为", minValue.stripTrailingZeros().toPlainString()); + checkResult = false; + } else if (Objects.nonNull(maxValue) && maxValue.compareTo(checkValue) < 0) { + messageSuffix = String.join("", "最大值为", maxValue.stripTrailingZeros().toPlainString()); + checkResult = false; + } + if (!checkResult) { + //改变默认提示信息 + if (ConstraintValidatorContextImpl.class.isAssignableFrom(context.getClass())) { + //禁用默认提示信息 + context.disableDefaultConstraintViolation(); + //设置提示语(在message前面加上key) + context.buildConstraintViolationWithTemplate(String.join("", messagePrefix, messageSuffix)).addConstraintViolation(); + } + } + return checkResult; + } + + public static void main(String[] args) { + BigDecimal bigDecimal = BigDecimal.valueOf(0.90988); + System.out.println(bigDecimal.toPlainString()); + System.out.println(StringUtils.substringAfter(bigDecimal.toPlainString(), ".")); + } + + + @Data + private static class ValidTest { + + @BigDecimalRange(messagePrefix = "火红的萨", maxValue = "0.999", minValue = "0.001") + private BigDecimal checkV; + + + @Validated + public static void test(@Valid ValidTest validTest) { + System.out.println(validTest); + } + + public static void main(String[] args) { + BigDecimal bigDecimal = BigDecimal.valueOf(0.0001); + System.out.println(String.valueOf(bigDecimal)); + Validator validator = Validation.buildDefaultValidatorFactory() + .getValidator(); + ValidTest validTest = new ValidTest(); + validTest.setCheckV(BigDecimal.valueOf(-1)); + Set> validate = validator.validate(validTest); + StringBuilder validateError = new StringBuilder(); + for (ConstraintViolation constraintViolation : validate) { + validateError.append(constraintViolation.getMessage()).append(";"); + } + + System.out.println(validateError); + } + + } +} diff --git a/backend/src/main/java/com/senmesh/common/validation/annotation/Expression.java b/backend/src/main/java/com/senmesh/common/validation/annotation/Expression.java new file mode 100644 index 0000000..802120f --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/validation/annotation/Expression.java @@ -0,0 +1,50 @@ +package com.senmesh.common.validation.annotation; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.TYPE_USE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +import com.senmesh.common.validation.constants.ValidProviderEnum; + +/** + * 表达式校验器注解 + * @author sr on 2021-05-25 + */ +@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE}) +@Retention(RUNTIME) +@Documented +@Constraint(validatedBy = {ExpressionValidator.class}) +public @interface Expression { + + String message() default "{javax.validation.constraints.Expression.message}"; + + /** + * springEl表达式,内置参数value(待校验值),返回值类型boolean + * @return + * @author sr on 2021-05-25 + */ + String expressionStr() default ""; + + /** + * {@link ValidProviderEnum} + * @return + * @author sr on 2021-07-07 + */ + ValidProviderEnum type() default ValidProviderEnum.NONE; + + Class[] groups() default {}; + + Class[] payload() default {}; + +} diff --git a/backend/src/main/java/com/senmesh/common/validation/annotation/ExpressionValidator.java b/backend/src/main/java/com/senmesh/common/validation/annotation/ExpressionValidator.java new file mode 100644 index 0000000..7d46cc1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/validation/annotation/ExpressionValidator.java @@ -0,0 +1,42 @@ +package com.senmesh.common.validation.annotation; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; + +import com.senmesh.common.validation.constants.ValidProviderEnum; + +public class ExpressionValidator implements ConstraintValidator{ + + //SPEL解析 + private static ExpressionParser parser = new SpelExpressionParser(); + + private org.springframework.expression.Expression spelExpression ; + private ValidProviderEnum validProviderEnum; + + @Override + public void initialize(Expression expression) { + String expressionStr = expression.expressionStr(); + if (StringUtils.isNotBlank(expressionStr)) { + spelExpression = parser.parseExpression(expressionStr); + } + validProviderEnum = expression.type(); + } + + + @Override + public boolean isValid(Object value, ConstraintValidatorContext context) { + if (spelExpression != null) { + StandardEvaluationContext spelContext = new StandardEvaluationContext(); + spelContext.setVariable("value", value); + return spelExpression.getValue(spelContext, Boolean.class); + } + return validProviderEnum.getFunction().apply(value); + } + + +} diff --git a/backend/src/main/java/com/senmesh/common/validation/annotation/IdCard.java b/backend/src/main/java/com/senmesh/common/validation/annotation/IdCard.java new file mode 100644 index 0000000..239923e --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/validation/annotation/IdCard.java @@ -0,0 +1,52 @@ +package com.senmesh.common.validation.annotation; + + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.TYPE_USE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; +import javax.validation.constraints.Pattern.Flag; + +/** + * 身份证号 + * + * @author on 2019-11-05 + */ +@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE}) +@Retention(RUNTIME) +@Documented +@Constraint(validatedBy = {IdCardValidator.class}) +@Inherited +public @interface IdCard { + + /** + * @return the error message template + */ + String message() default "身份证号码格式错误"; + + /** + * @return the groups the constraint belongs to + */ + Class[] groups() default {}; + + /** + * @return array of {@code Flag}s considered when resolving the regular expression + */ + Flag[] flags() default {}; + + /** + * @return the payload associated to the constraint + */ + Class[] payload() default {}; +} diff --git a/backend/src/main/java/com/senmesh/common/validation/annotation/IdCardValidator.java b/backend/src/main/java/com/senmesh/common/validation/annotation/IdCardValidator.java new file mode 100644 index 0000000..63e37c5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/validation/annotation/IdCardValidator.java @@ -0,0 +1,29 @@ +package com.senmesh.common.validation.annotation; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +import org.apache.commons.lang3.StringUtils; + +import com.senmesh.common.validation.util.ValidateUtils; + +/** + * 身份证号校验器 + * + * @author on 2019-11-05 + */ +public class IdCardValidator implements ConstraintValidator { + + @Override + public void initialize(IdCard constraintAnnotation) { + + } + + @Override + public boolean isValid(String value, ConstraintValidatorContext context) { + if (StringUtils.isBlank(value)) { + return true; + } + return ValidateUtils.isIdCard(value); + } +} diff --git a/backend/src/main/java/com/senmesh/common/validation/annotation/Phone.java b/backend/src/main/java/com/senmesh/common/validation/annotation/Phone.java new file mode 100644 index 0000000..20900c1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/validation/annotation/Phone.java @@ -0,0 +1,59 @@ +package com.senmesh.common.validation.annotation; + + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.TYPE_USE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; +import javax.validation.constraints.Pattern.Flag; + + +/** + * 电话号码 + * + * @author on 2019-11-05 + */ +@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE}) +@Retention(RUNTIME) +@Documented +@Constraint(validatedBy = {PhoneValidator.class}) +@Inherited +// @Pattern(regexp=ValidateUtil.mobileReg, message = MaterialConstant.PHONE_FORMAT_ERROR) +public @interface Phone { + + /** + * @return the error message template + */ + // @AliasFor(annotation = Pattern.class, attribute = "message") + String message() default "电话号码格式错误"; + + /** + * @return the groups the constraint belongs to + */ + // @AliasFor(annotation = Pattern.class, attribute = "groups") + Class[] groups() default {}; + + /** + * @return array of {@code Flag}s considered when resolving the regular expression + */ + // @AliasFor(annotation = Pattern.class, attribute = "flags") + Flag[] flags() default {}; + + /** + * @return the payload associated to the constraint + */ + // @AliasFor(annotation = Pattern.class, attribute = "payload") + Class[] payload() default {}; +} + diff --git a/backend/src/main/java/com/senmesh/common/validation/annotation/PhoneValidator.java b/backend/src/main/java/com/senmesh/common/validation/annotation/PhoneValidator.java new file mode 100644 index 0000000..af87cd6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/validation/annotation/PhoneValidator.java @@ -0,0 +1,28 @@ +package com.senmesh.common.validation.annotation; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +import org.apache.commons.lang3.StringUtils; + +import com.senmesh.common.validation.util.ValidateUtils; + +/** + * 电话号码校验器 + * + * @author on 2019-11-05 + */ +public class PhoneValidator implements ConstraintValidator { + + @Override + public void initialize(Phone constraintAnnotation) {} + + @Override + public boolean isValid(String value, ConstraintValidatorContext context) { + if (StringUtils.isBlank(value)) { + return true; + } + return ValidateUtils.isPhone(value) || ValidateUtils.isFixedTelephone(value); + } + +} diff --git a/backend/src/main/java/com/senmesh/common/validation/annotation/TableColumn.java b/backend/src/main/java/com/senmesh/common/validation/annotation/TableColumn.java new file mode 100644 index 0000000..1d07939 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/validation/annotation/TableColumn.java @@ -0,0 +1,23 @@ +package com.senmesh.common.validation.annotation; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * @author on 2019-11-05 + */ +@Target(FIELD) +@Retention(RUNTIME) +@Documented +@Inherited +public @interface TableColumn { + + String name(); + + int sort(); +} diff --git a/backend/src/main/java/com/senmesh/common/validation/constants/ValidProviderEnum.java b/backend/src/main/java/com/senmesh/common/validation/constants/ValidProviderEnum.java new file mode 100644 index 0000000..e8b7a24 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/validation/constants/ValidProviderEnum.java @@ -0,0 +1,47 @@ +package com.senmesh.common.validation.constants; + +import java.util.Map; +import java.util.function.Function; + +import com.google.common.collect.Maps; +import com.senmesh.common.validation.util.ValidateUtils; + + +public enum ValidProviderEnum { + + NONE("none", (v) -> false), + CARD_NO("cardNo", (v) -> ValidateUtils.isIdCard((String) v)), + PHONE("phone", (v) -> ValidateUtils.isPhone((String) v)), + USERNAME("username", (v) -> ValidateUtils.matchUsername((String) v)), + PASSWORD("password", (v) -> ValidateUtils.matchPassword((String) v)), + REAL_NAME("realName", (v) -> ValidateUtils.checkRealName((String) v)), + CREDIT_CODE("creditCode", (v) -> ValidateUtils.isCreditCode((String) v)), + ; + + private static Map validMap ; + private String type; + private Function function; + + ValidProviderEnum(String type, Function function) { + this.type = type; + this.function = function; + } + + static { + ValidProviderEnum[] enums = ValidProviderEnum.values(); + validMap = Maps.newHashMapWithExpectedSize(enums.length); + for (ValidProviderEnum providerEnum : enums) { + validMap.put(providerEnum.getType(), providerEnum); + } + } + + public String getType() { + return this.type; + } + + public Function getFunction() { + return this.function; + } + + +} diff --git a/backend/src/main/java/com/senmesh/common/validation/util/ValidateUtils.java b/backend/src/main/java/com/senmesh/common/validation/util/ValidateUtils.java new file mode 100644 index 0000000..2abbcf0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/common/validation/util/ValidateUtils.java @@ -0,0 +1,262 @@ +package com.senmesh.common.validation.util; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.util.Assert; +import java.util.Locale; +import org.apache.commons.lang3.StringUtils; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import java.util.Set; +import java.util.regex.Pattern; + +/** + * @author on 2019-11-05 + */ +public class ValidateUtils { + + + /** + * 用户安全码校验正则 + */ + public static final String SECURITY_CODE_PATTERN = "^[A-Za-z\\d!@#$%^&*]{6,32}$"; + + public static Pattern numberPattern = Pattern.compile("^[-\\+]?[\\d]*$"); + + public static Pattern mobilePattern = Pattern.compile("^[1][0-9]{10}$"); + + public static Pattern fixedTelephone = Pattern.compile("^[0]\\d{2,3}\\d{7,8}"); + + public static final Pattern USERNAME_PATTERN = Pattern.compile("^[a-zA-Z0-9]{4,32}$"); + public static final Pattern PASSWORD_PATTERN = Pattern.compile("[A-Za-z\\d!@#$%^&*]{6,32}$"); + /** + * 正则 邮箱 + */ + private static Pattern EMAIL_REG = Pattern.compile("^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$"); + /** + * 昵称校验 + */ + private static Pattern NICK_NAME_REG = Pattern.compile("^[\\u4e00-\\u9fffa-zA-Z0-9]{2,32}$"); + + /** 姓名 **/ + private static final Pattern REAL_NAME_REG = Pattern.compile( + "^(([a-zA-Z+\\.?\\·?a-zA-Z+]{2,30}$)|([\\u4e00-\\u9fff+\\·?\\u4e00-\\u9fff+]{2,30}$))"); + + public static Validator validator = Validation.buildDefaultValidatorFactory() + .getValidator(); + + /** + * 身份证号权重因子、对应验证码 + */ + // 前十七位加权因子 + public static final int[] idCardWi = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}; + // 这是除以11后,可能产生的11位余数对应的验证码 + public static final String[] idCardY = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"}; + + // 定义判别用户身份证号的正则表达式(15位或者18位,最后一位可以为字母) + // 假设18位身份证号码:41000119910101123X 410001 19910101 123X + // ^开头 + // [1-9] 第一位1-9中的一个 4 + // \\d{5} 五位数字 10001(前六位省市县地区) + // (18|19|20) 19(现阶段可能取值范围18xx-20xx年) + // \\d{2} 91(年份) + // ((0[1-9])|(10|11|12)) 01(月份) + // (([0-2][1-9])|10|20|30|31)01(日期) + // \\d{3} 三位数字 123(第十七位奇数代表男,偶数代表女) + // [0-9Xx] 0123456789Xx其中的一个 X(第十八位为校验值) + // $结尾 + + // 假设15位身份证号码:410001910101123 410001 910101 123 + // ^开头 + // [1-9] 第一位1-9中的一个 4 + // \\d{5} 五位数字 10001(前六位省市县地区) + // \\d{2} 91(年份) + // ((0[1-9])|(10|11|12)) 01(月份) + // (([0-2][1-9])|10|20|30|31)01(日期) + // \\d{3} 三位数字 123(第十五位奇数代表男,偶数代表女),15位身份证不含X + // $结尾 + private static Pattern idCardPattern = Pattern.compile( + "(^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$)|" + + "(^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}$)"); + + /** + * 手机号码校验 + * + * @param mobile + * @return + */ + public static boolean isPhone(String mobile) { + if (StringUtils.isBlank(mobile)) { + return false; + } + return mobilePattern.matcher(mobile).matches(); + } + + /** + * 固定电话校验 + * + * @param phone + * @return + */ + public static boolean isFixedTelephone(String phone) { + if (StringUtils.isBlank(phone)) { + return false; + } + phone = phone.replace("-", ""); + return fixedTelephone.matcher(phone).matches(); + } + + /** + * 身份证校验 + * + * @param idCard + * @return + */ + public static boolean isIdCard(String idCard) { + if (StringUtils.isBlank(idCard)) { + return false; + } + boolean matches = idCardPattern.matcher(idCard).matches(); + // 判断第18位校验值 + if (matches) { + if (idCard.length() == 18) { + try { + char[] charArray = idCard.toCharArray(); + int sum = 0; + for (int i = 0; i < idCardWi.length; i++) { + int current = Integer.parseInt(String.valueOf(charArray[i])); + int count = current * idCardWi[i]; + sum += count; + } + char idCardLast = charArray[17]; + int idCardMod = sum % 11; + if (idCardY[idCardMod].toUpperCase(Locale.ROOT).equals(String.valueOf(idCardLast).toUpperCase(Locale.ROOT))) { + return true; + } else { + return false; + } + + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + } + return matches; + } + + /** + * 校验对象,校验未通过返回异常信息 + * @param object + * @param groups + * @return null 校验通过;否则 返回异常信息 + * @author sr on 2021-05-25 + */ + public static String validate(Object object, Class... groups) { + Set> constraintViolations = validator.validate(object, groups); + if (constraintViolations.isEmpty()) { + return null; + } + StringBuilder errMsg = new StringBuilder(); + constraintViolations.forEach(constraintViolation -> errMsg + .append(constraintViolation.getMessage()).append(CommonConstants.COMMA)); + return errMsg.toString(); + } + + /** + * 校验对象,校验未通过抛BusinessException + * @param object + * @param groups + * @author sr on 2021-05-25 + */ + public static void validateBiz(Object object, Class... groups) { + String errMsg = validate(object, groups); + Assert.isNull(errMsg, errMsg); + } + + /** + * 校验对象,校验未通过抛BusinessException + * @param object + * @param errMsg 自定义异常信息 + * @param groups + * @author sr on 2021-06-10 + */ + public static void validateBiz(Object object, String errMsg, Class... groups) { + String originErrMsg = validate(object, groups); + Assert.isNull(originErrMsg, errMsg); + } + + /** + * 账号是否合规 + * @param userName + * @return + * @author sr on 2021-07-07 + */ + public static boolean matchUsername(String userName) { + if (StringUtils.isBlank(userName)) { + return false; + } + return USERNAME_PATTERN.matcher(userName).matches(); + } + + /** + * 密码是否合规 + * @param password + * @return + * @author sr on 2021-07-07 + */ + public static boolean matchPassword(String password) { + if (StringUtils.isBlank(password)) { + return false; + } + return PASSWORD_PATTERN.matcher(password).matches(); + } + + /** + * 邮箱是否合规 + * @param email + * @return + * @author sr on 2021-07-07 + */ + public static boolean checkEmail(String email) { + if (StringUtils.isBlank(email)) { + return false; + } + return EMAIL_REG.matcher(email).matches(); + } + + public static boolean checkNickName(String nickname) { + if (StringUtils.isBlank(nickname)) { + return false; + } + return NICK_NAME_REG.matcher(nickname).matches(); + } + + /** + * 检查中文姓名 + * + * @param realname 中文名 + * @return boolean + */ + public static boolean checkRealName(String realname) { + if (StringUtils.isBlank(realname)) { + return false; + } + return REAL_NAME_REG.matcher(realname).matches(); + } + + /** + * 校验统一社会信用代码 + * + * @param creditCode 统一社会信用代码 + * @return boolean + */ + public static boolean isCreditCode(String creditCode) { + if (StringUtils.isBlank(creditCode)) { + return false; + } + return cn.hutool.core.lang.Validator.isCreditCode(creditCode); + } +} diff --git a/backend/src/main/java/com/senmesh/commonexport/dto/CommonExportDynamicDTO.java b/backend/src/main/java/com/senmesh/commonexport/dto/CommonExportDynamicDTO.java new file mode 100644 index 0000000..c5b4607 --- /dev/null +++ b/backend/src/main/java/com/senmesh/commonexport/dto/CommonExportDynamicDTO.java @@ -0,0 +1,34 @@ +package com.senmesh.commonexport.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CommonExportDynamicDTO implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 文件名 + */ + private String fileName; + + /** + * 表头列表 + */ + private List head; + + /** + * List : 数据 + */ + private List> datas; + + +} diff --git a/backend/src/main/java/com/senmesh/commonexport/dto/CommonExportMapDTO.java b/backend/src/main/java/com/senmesh/commonexport/dto/CommonExportMapDTO.java new file mode 100644 index 0000000..38d4665 --- /dev/null +++ b/backend/src/main/java/com/senmesh/commonexport/dto/CommonExportMapDTO.java @@ -0,0 +1,64 @@ +package com.senmesh.commonexport.dto; + +import com.alibaba.excel.write.style.column.AbstractHeadColumnWidthStyleStrategy; +import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +/** + * 导出多个sheet实体类 + * + * @param + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CommonExportMapDTO implements Serializable { + private static final long serialVersionUID = -8482074133630026236L; + + private static final String FILE_SUFFIX = ".xlsx"; + + /** + * 文件名 + */ + private String fileName; + + /** + * 文件后缀 + */ + private String fileSuffix; + + /** + * 列宽度策略 + */ + private AbstractHeadColumnWidthStyleStrategy columnWidthStyleStrategy; + + /** + * key : sheetName + * List : 数据 + */ + private Map> datas; + + public String getFileSuffix() { + if (StringUtils.isEmpty(fileSuffix)) { + this.fileSuffix = FILE_SUFFIX; + } + return this.fileSuffix; + } + + public AbstractHeadColumnWidthStyleStrategy getColumnWidthStyleStrategy() { + if (this.columnWidthStyleStrategy == null) { + this.columnWidthStyleStrategy = new SimpleColumnWidthStyleStrategy(20); + } + return this.columnWidthStyleStrategy; + } + +} diff --git a/backend/src/main/java/com/senmesh/commonexport/dto/CommonExportPropertiesDTO.java b/backend/src/main/java/com/senmesh/commonexport/dto/CommonExportPropertiesDTO.java new file mode 100644 index 0000000..b13c9c2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/commonexport/dto/CommonExportPropertiesDTO.java @@ -0,0 +1,67 @@ +package com.senmesh.commonexport.dto; + +import com.alibaba.excel.write.style.column.AbstractHeadColumnWidthStyleStrategy; +import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; + +import java.io.Serializable; +import java.util.List; + +/** + * @author chenyun + * @description 公共导出DTO + * @date 2020/10/21 14:03 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CommonExportPropertiesDTO implements Serializable { + private static final long serialVersionUID = -8482074133630026236L; + + private static final String FILE_SUFFIX = ".xlsx"; + + /** + * 文件名 + */ + private String fileName; + + /** + * 文件后缀 + */ + private String fileSuffix; + + /** + * 列宽度策略 + */ + private AbstractHeadColumnWidthStyleStrategy columnWidthStyleStrategy; + + /** + * sheet 名称 + */ + private String sheetName; + + /** + * 导出头 + */ + private List datas; + + public String getFileSuffix() { + if (StringUtils.isEmpty(fileSuffix)) { + this.fileSuffix = FILE_SUFFIX; + } + return this.fileSuffix; + } + + public AbstractHeadColumnWidthStyleStrategy getColumnWidthStyleStrategy() { + if (this.columnWidthStyleStrategy == null) { + this.columnWidthStyleStrategy = new SimpleColumnWidthStyleStrategy(20); + } + return this.columnWidthStyleStrategy; + } + +} diff --git a/backend/src/main/java/com/senmesh/commonexport/service/ExportService.java b/backend/src/main/java/com/senmesh/commonexport/service/ExportService.java new file mode 100644 index 0000000..f21bd2d --- /dev/null +++ b/backend/src/main/java/com/senmesh/commonexport/service/ExportService.java @@ -0,0 +1,20 @@ +package com.senmesh.commonexport.service; + +import com.senmesh.commonexport.dto.CommonExportMapDTO; +import com.senmesh.commonexport.dto.CommonExportPropertiesDTO; +import com.senmesh.component.file.entity.FileRecord; + +public interface ExportService { + + /** + * 公共导出方法 + * + * @param commonExportPropertiesDTO 导出实体 + * @return FileRecord + */ + FileRecord export(CommonExportPropertiesDTO commonExportPropertiesDTO); + + + FileRecord export(CommonExportMapDTO commonExportMapDTO); + +} diff --git a/backend/src/main/java/com/senmesh/commonexport/service/impl/ExportByDtoServiceImpl.java b/backend/src/main/java/com/senmesh/commonexport/service/impl/ExportByDtoServiceImpl.java new file mode 100644 index 0000000..7d49e62 --- /dev/null +++ b/backend/src/main/java/com/senmesh/commonexport/service/impl/ExportByDtoServiceImpl.java @@ -0,0 +1,81 @@ +package com.senmesh.commonexport.service.impl; + +import java.io.ByteArrayOutputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.apache.poi.ss.formula.functions.T; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.senmesh.common.exception.BusinessException; +import com.senmesh.commonexport.dto.CommonExportMapDTO; +import com.senmesh.commonexport.dto.CommonExportPropertiesDTO; +import com.senmesh.commonexport.service.ExportService; +import com.senmesh.component.file.config.FileProperties; +import com.senmesh.component.file.entity.FileRecord; +import com.senmesh.component.file.service.FileService; + +import cn.hutool.core.collection.CollUtil; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class ExportByDtoServiceImpl implements ExportService { + + @Autowired + private FileProperties fileProperties; + + @Autowired + private FileService fileService; + + public FileRecord export(CommonExportPropertiesDTO commonExportPropertiesDTO) { + CommonExportMapDTO objectCommonExportMapDTO = new CommonExportMapDTO<>(); + objectCommonExportMapDTO.setFileName(commonExportPropertiesDTO.getFileName()); + objectCommonExportMapDTO.setColumnWidthStyleStrategy( + commonExportPropertiesDTO.getColumnWidthStyleStrategy()); + objectCommonExportMapDTO.setFileSuffix(commonExportPropertiesDTO.getFileSuffix()); + objectCommonExportMapDTO.setDatas(new HashMap>() { + { + put(commonExportPropertiesDTO.getSheetName(), commonExportPropertiesDTO.getDatas()); + } + }); + return this.export(objectCommonExportMapDTO); + } + + @Override + public FileRecord export(CommonExportMapDTO commonExportMapDTO) { + Map datas = commonExportMapDTO.getDatas(); + if (CollUtil.isEmpty(datas)) { + return null; + } + Optional first = datas.values().stream().findFirst(); + if (!first.isPresent() || CollUtil.isEmpty(first.get())) { + return null; + } + Class aClass = first.get().get(0).getClass(); + // 临时文件名 + String targetFileName = commonExportMapDTO.getFileName() + commonExportMapDTO.getFileSuffix(); + //3.调用excelUtil 生成临时文件 + try { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + ExcelWriter writer = EasyExcel.write(os, aClass) + .registerWriteHandler(commonExportMapDTO.getColumnWidthStyleStrategy()).build(); + + datas.forEach((key, value) -> writer.write(value, EasyExcel.writerSheet(key).build())); + writer.finish(); + byte[] excelByte = os.toByteArray(); + return fileService.uploadTemp(targetFileName, excelByte); + } catch ( + Exception e) { + log.info("导出文件异常", e); + throw new BusinessException("导出文件异常"); + } + } + + +} diff --git a/backend/src/main/java/com/senmesh/component/action/annotation/ActionField.java b/backend/src/main/java/com/senmesh/component/action/annotation/ActionField.java new file mode 100644 index 0000000..aabb1c6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/annotation/ActionField.java @@ -0,0 +1,19 @@ +package com.senmesh.component.action.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 操作记录 + * @author sr on 2022-02-18 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +public @interface ActionField { + + String alias() default ""; + String dictCode() default ""; + +} diff --git a/backend/src/main/java/com/senmesh/component/action/annotation/ActionModel.java b/backend/src/main/java/com/senmesh/component/action/annotation/ActionModel.java new file mode 100644 index 0000000..5906468 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/annotation/ActionModel.java @@ -0,0 +1,17 @@ +package com.senmesh.component.action.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 操作记录对象 + * @author sr on 2022-02-18 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface ActionModel { + + String type(); +} diff --git a/backend/src/main/java/com/senmesh/component/action/constant/ActionConstants.java b/backend/src/main/java/com/senmesh/component/action/constant/ActionConstants.java new file mode 100644 index 0000000..6d084f0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/constant/ActionConstants.java @@ -0,0 +1,9 @@ +package com.senmesh.component.action.constant; + +/** + * @author sr on 2022-02-18 + */ +public interface ActionConstants { + + +} diff --git a/backend/src/main/java/com/senmesh/component/action/constant/ActionTypeEnum.java b/backend/src/main/java/com/senmesh/component/action/constant/ActionTypeEnum.java new file mode 100644 index 0000000..dfaeca5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/constant/ActionTypeEnum.java @@ -0,0 +1,20 @@ +package com.senmesh.component.action.constant; + +/** + * 操作类型枚举 + * @author sr on 2022-02-21 + */ +public enum ActionTypeEnum { + ; + + ActionTypeEnum(String type) { + this.type = type; + } + + private String type; + + public String getType() { + return type; + } + +} diff --git a/backend/src/main/java/com/senmesh/component/action/controller/ActionController.java b/backend/src/main/java/com/senmesh/component/action/controller/ActionController.java new file mode 100644 index 0000000..fe28f74 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/controller/ActionController.java @@ -0,0 +1,43 @@ +package com.senmesh.component.action.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.senmesh.common.AlitaResult; +import com.senmesh.component.action.dto.ActionDTO; +import com.senmesh.component.action.dto.ActionQueryDTO; +import com.senmesh.component.action.service.ActionService; +import com.senmesh.tkmybatis.pojo.Page; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +import java.util.List; + +/** + * @author sr on 2022-02-18 + */ +@RestController +@RequestMapping("action") +@Api(tags = "操作记录") +public class ActionController { + + @Autowired + private ActionService actionService; + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(ActionQueryDTO actionQueryDTO){ + actionService.page(actionQueryDTO); + return AlitaResult.success(actionQueryDTO.getPageResult()); + } + + @GetMapping("/list") + @ApiOperation("分页查询") + public AlitaResult> list(ActionQueryDTO actionQueryDTO){ + return AlitaResult.success(actionService.list(actionQueryDTO)); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/action/controller/ActionDetailController.java b/backend/src/main/java/com/senmesh/component/action/controller/ActionDetailController.java new file mode 100644 index 0000000..735a2c0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/controller/ActionDetailController.java @@ -0,0 +1,42 @@ +package com.senmesh.component.action.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.component.action.dto.ActionDetailDTO; +import com.senmesh.component.action.dto.ActionDetailQueryDTO; +import com.senmesh.component.action.service.ActionDetailService; +import com.senmesh.tkmybatis.pojo.Page; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * @author sr on 2022-02-18 + */ +@RestController +@RequestMapping("action_detail") +@Api(tags = "操作记录明细") +public class ActionDetailController { + + @Autowired + private ActionDetailService actionDetailService; + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(ActionDetailQueryDTO actionDetailQueryDTO){ + actionDetailService.page(actionDetailQueryDTO); + return AlitaResult.success(actionDetailQueryDTO.getPageResult()); + } + + + @GetMapping("/list") + @ApiOperation("根据关联业务id查询日志") + public AlitaResult> list(ActionDetailQueryDTO actionDetailQueryDTO){ + return AlitaResult.success(actionDetailService.list(actionDetailQueryDTO)); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/action/dao/ActionDetailMapper.java b/backend/src/main/java/com/senmesh/component/action/dao/ActionDetailMapper.java new file mode 100644 index 0000000..719ec9d --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/dao/ActionDetailMapper.java @@ -0,0 +1,28 @@ +package com.senmesh.component.action.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.component.action.dto.ActionDetailDTO; +import com.senmesh.component.action.dto.ActionDetailQueryDTO; +import com.senmesh.component.action.entity.ActionDetail; +import com.senmesh.tkmybatis.mybatis.MyMapper; + +/** + * 操作记录明细 + * + * @author sr on 2022-02-18 + */ +public interface ActionDetailMapper extends MyMapper { + + /** + * 查询 + * + * @param actionDetailQueryDTO + * @return + * @author sr on 2022-02-18 + */ + List listActionDetailDTO(@Param("param") ActionDetailQueryDTO actionDetailQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/component/action/dao/ActionMapper.java b/backend/src/main/java/com/senmesh/component/action/dao/ActionMapper.java new file mode 100644 index 0000000..5782d8d --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/dao/ActionMapper.java @@ -0,0 +1,28 @@ +package com.senmesh.component.action.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.component.action.dto.ActionDTO; +import com.senmesh.component.action.dto.ActionQueryDTO; +import com.senmesh.component.action.entity.Action; +import com.senmesh.tkmybatis.mybatis.MyMapper; + +/** + * 操作记录 + * + * @author sr on 2022-02-18 + */ +public interface ActionMapper extends MyMapper { + + /** + * 查询 + * + * @param actionQueryDTO + * @return + * @author sr on 2022-02-18 + */ + List listActionDTO(@Param("param") ActionQueryDTO actionQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/component/action/dto/ActionCreateDTO.java b/backend/src/main/java/com/senmesh/component/action/dto/ActionCreateDTO.java new file mode 100644 index 0000000..9b82edf --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/dto/ActionCreateDTO.java @@ -0,0 +1,42 @@ +package com.senmesh.component.action.dto; + +import java.io.Serializable; +import java.util.List; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2022-02-18 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "操作记录创建") +public class ActionCreateDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("关联类型") + @NotBlank(message = "关联类型不能为空") + private String unionType; + @ApiModelProperty("关联id") + @NotNull(message = "关联id不能为空") + private Long unionId; + @ApiModelProperty("明细") + @Valid + private List detailDtos; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/action/dto/ActionDTO.java b/backend/src/main/java/com/senmesh/component/action/dto/ActionDTO.java new file mode 100644 index 0000000..bb08fab --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/dto/ActionDTO.java @@ -0,0 +1,36 @@ +package com.senmesh.component.action.dto; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +import java.util.List; + +/** + * @author sr on 2022-02-18 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "操作记录") +public class ActionDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + @ApiModelProperty("关联类型") + private String unionType; + @ApiModelProperty("关联id") + private Long unionId; + @ApiModelProperty("处理人") + private String createName; + @ApiModelProperty("子节点") + private List childNode; +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/action/dto/ActionDetailCreateDTO.java b/backend/src/main/java/com/senmesh/component/action/dto/ActionDetailCreateDTO.java new file mode 100644 index 0000000..9f171c7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/dto/ActionDetailCreateDTO.java @@ -0,0 +1,44 @@ +package com.senmesh.component.action.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; + +import javax.validation.constraints.NotBlank; + +import com.senmesh.common.dto.BaseOperateDTO; + +/** + * @author sr on 2022-02-18 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "操作记录明细创建") +public class ActionDetailCreateDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("属性") + @NotBlank(message = "属性不能为空") + private String field; + @ApiModelProperty("属性别名") + private String fieldAlias; + @ApiModelProperty("属性字典编码") + private String fieldDictCode; + @ApiModelProperty("旧值") + private String oldValue; + @ApiModelProperty("新值") + private String newValue; + @ApiModelProperty("差异") + private String diff; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/action/dto/ActionDetailDTO.java b/backend/src/main/java/com/senmesh/component/action/dto/ActionDetailDTO.java new file mode 100644 index 0000000..f26a46f --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/dto/ActionDetailDTO.java @@ -0,0 +1,42 @@ +package com.senmesh.component.action.dto; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2022-02-18 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "操作记录明细") +public class ActionDetailDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("操作记录id") + private Long actionId; + @ApiModelProperty("属性") + private String field; + @ApiModelProperty("属性别名") + private String fieldAlias; + @ApiModelProperty("属性字典编码") + private String fieldDictCode; + @ApiModelProperty("旧值") + private String oldValue; + @ApiModelProperty("新值") + private String newValue; + @ApiModelProperty("差异") + private String diff; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/action/dto/ActionDetailQueryDTO.java b/backend/src/main/java/com/senmesh/component/action/dto/ActionDetailQueryDTO.java new file mode 100644 index 0000000..d664cb7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/dto/ActionDetailQueryDTO.java @@ -0,0 +1,33 @@ +package com.senmesh.component.action.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; + +import com.senmesh.common.dto.PageQueryDTO; + +/** + * @author sr on 2022-02-18 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "操作记录明细查询条件") +public class ActionDetailQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + + @ApiModelProperty("操作记录id") + private Long actionId; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/action/dto/ActionQueryDTO.java b/backend/src/main/java/com/senmesh/component/action/dto/ActionQueryDTO.java new file mode 100644 index 0000000..f20fb1b --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/dto/ActionQueryDTO.java @@ -0,0 +1,33 @@ +package com.senmesh.component.action.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; + +import com.senmesh.common.dto.PageQueryDTO; + +/** + * @author sr on 2022-02-18 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "操作记录查询条件") +public class ActionQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + + @ApiModelProperty("关联业务id") + private Long unionId; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/action/entity/Action.java b/backend/src/main/java/com/senmesh/component/action/entity/Action.java new file mode 100644 index 0000000..62e325b --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/entity/Action.java @@ -0,0 +1,32 @@ +package com.senmesh.component.action.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 操作记录 + * + * @author sr on 2022-02-18 + */ +@TableName("uc_action") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class Action extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + /** 关联类型 **/ + private String unionType; + /** 关联id **/ + private Long unionId; + +} diff --git a/backend/src/main/java/com/senmesh/component/action/entity/ActionDetail.java b/backend/src/main/java/com/senmesh/component/action/entity/ActionDetail.java new file mode 100644 index 0000000..14516df --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/entity/ActionDetail.java @@ -0,0 +1,41 @@ +package com.senmesh.component.action.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 操作记录明细 + * + * @author sr on 2022-02-18 + */ +@TableName("uc_action_detail") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class ActionDetail extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + /** 操作记录id **/ + private Long actionId; + /** 属性 **/ + private String field; + /** 属性别名 **/ + private String fieldAlias; + /** 属性字典编码 **/ + private String fieldDictCode; + /** 旧值 **/ + private String oldValue; + /** 新值 **/ + private String newValue; + /** 差异 **/ + private String diff; +} diff --git a/backend/src/main/java/com/senmesh/component/action/mapper/ActionDetailMapper.xml b/backend/src/main/java/com/senmesh/component/action/mapper/ActionDetailMapper.xml new file mode 100644 index 0000000..c7f48ea --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/mapper/ActionDetailMapper.xml @@ -0,0 +1,20 @@ + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/action/mapper/ActionMapper.xml b/backend/src/main/java/com/senmesh/component/action/mapper/ActionMapper.xml new file mode 100644 index 0000000..91a08ca --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/mapper/ActionMapper.xml @@ -0,0 +1,19 @@ + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/action/mapstruct/ActionDetailMapMapper.java b/backend/src/main/java/com/senmesh/component/action/mapstruct/ActionDetailMapMapper.java new file mode 100644 index 0000000..c05a391 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/mapstruct/ActionDetailMapMapper.java @@ -0,0 +1,37 @@ +package com.senmesh.component.action.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.component.action.dto.ActionDetailCreateDTO; +import com.senmesh.component.action.dto.ActionDetailDTO; +import com.senmesh.component.action.entity.ActionDetail; + +/** + * @author sr on 2022-02-18 + */ +@Mapper +public interface ActionDetailMapMapper { + + ActionDetailMapMapper INSTANCE = + Mappers.getMapper(ActionDetailMapMapper.class); + + /** + * dto to entity + * + * @param actionDetailDto + * @return + * @author sr on 2022-02-18 + */ + ActionDetail toEntity( + ActionDetailDTO actionDetailDto); + + + /** + * @param ActionDetailCreateDTO + * @return + * @author sr on 2022-02-18 + */ + ActionDetail toEntity(ActionDetailCreateDTO ActionDetailCreateDTO); + +} diff --git a/backend/src/main/java/com/senmesh/component/action/mapstruct/ActionMapMapper.java b/backend/src/main/java/com/senmesh/component/action/mapstruct/ActionMapMapper.java new file mode 100644 index 0000000..a2ac885 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/mapstruct/ActionMapMapper.java @@ -0,0 +1,37 @@ +package com.senmesh.component.action.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.component.action.dto.ActionCreateDTO; +import com.senmesh.component.action.dto.ActionDTO; +import com.senmesh.component.action.entity.Action; + +/** + * @author sr on 2022-02-18 + */ +@Mapper +public interface ActionMapMapper { + + ActionMapMapper INSTANCE = + Mappers.getMapper(ActionMapMapper.class); + + /** + * dto to entity + * + * @param actionDto + * @return + * @author sr on 2022-02-18 + */ + Action toEntity( + ActionDTO actionDto); + + + /** + * @param actionCreateDTO + * @return + * @author sr on 2022-02-18 + */ + Action toEntity(ActionCreateDTO actionCreateDTO); + +} diff --git a/backend/src/main/java/com/senmesh/component/action/service/ActionDetailService.java b/backend/src/main/java/com/senmesh/component/action/service/ActionDetailService.java new file mode 100644 index 0000000..b81b8ce --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/service/ActionDetailService.java @@ -0,0 +1,42 @@ +package com.senmesh.component.action.service; + +import java.util.List; + +import com.senmesh.component.action.dto.ActionDetailDTO; +import com.senmesh.component.action.dto.ActionDetailQueryDTO; + +/** + * 操作记录明细 + * + * @author sr on 2022-02-18 + */ +public interface ActionDetailService { + + /** + * 查询 + * + * @param actionDetailQueryDTO + * @return + * @author sr on 2022-02-18 + */ + List list(ActionDetailQueryDTO actionDetailQueryDTO); + + /** + * 分页查询 + * + * @param actionDetailQueryDTO + * @return + * @author sr on 2022-02-18 + */ + void page(ActionDetailQueryDTO actionDetailQueryDTO); + + /** + * 单个查询 + * + * @param actionDetailQueryDTO + * @return + * @author sr on 2022-02-18 + */ + ActionDetailDTO find(ActionDetailQueryDTO actionDetailQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/component/action/service/ActionService.java b/backend/src/main/java/com/senmesh/component/action/service/ActionService.java new file mode 100644 index 0000000..24b1ed6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/service/ActionService.java @@ -0,0 +1,55 @@ +package com.senmesh.component.action.service; + +import java.util.List; + +import org.springframework.validation.annotation.Validated; + +import com.senmesh.component.action.dto.ActionCreateDTO; +import com.senmesh.component.action.dto.ActionDTO; +import com.senmesh.component.action.dto.ActionQueryDTO; + +/** + * 操作记录 + * + * @author sr on 2022-02-18 + */ +public interface ActionService { + + /** + * 新增 + * + * @param actionOperateDTO + * @return + * @author sr on 2022-02-18 + */ + Long create(@Validated ActionCreateDTO actionOperateDTO); + + + /** + * 查询 + * + * @param actionQueryDTO + * @return + * @author sr on 2022-02-18 + */ + List list(ActionQueryDTO actionQueryDTO); + + /** + * 分页查询 + * + * @param actionQueryDTO + * @return + * @author sr on 2022-02-18 + */ + void page(ActionQueryDTO actionQueryDTO); + + /** + * 单个查询 + * + * @param actionQueryDTO + * @return + * @author sr on 2022-02-18 + */ + ActionDTO find(ActionQueryDTO actionQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/component/action/service/impl/ActionDetailServiceImpl.java b/backend/src/main/java/com/senmesh/component/action/service/impl/ActionDetailServiceImpl.java new file mode 100644 index 0000000..4050421 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/service/impl/ActionDetailServiceImpl.java @@ -0,0 +1,40 @@ +package com.senmesh.component.action.service.impl; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.senmesh.common.util.ListUtil; +import com.senmesh.component.action.dao.ActionDetailMapper; +import com.senmesh.component.action.dto.ActionDetailDTO; +import com.senmesh.component.action.dto.ActionDetailQueryDTO; +import com.senmesh.component.action.service.ActionDetailService; + +/** + * @author sr on 2022-02-18 + */ +@Service +public class ActionDetailServiceImpl implements ActionDetailService { + + @Autowired + private ActionDetailMapper actionDetailMapper; + + @Override + public List list(ActionDetailQueryDTO actionDetailQueryDTO) { + actionDetailQueryDTO.disablePage(); + return actionDetailMapper.listActionDetailDTO(actionDetailQueryDTO); + } + + @Override + public void page(ActionDetailQueryDTO actionDetailQueryDTO) { + actionDetailMapper.listActionDetailDTO(actionDetailQueryDTO); + } + + @Override + public ActionDetailDTO find(ActionDetailQueryDTO actionDetailQueryDTO) { + List actionDetailDTOs = this.list(actionDetailQueryDTO); + return actionDetailDTOs.isEmpty() ? null : ListUtil.first(actionDetailDTOs); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/action/service/impl/ActionServiceImpl.java b/backend/src/main/java/com/senmesh/component/action/service/impl/ActionServiceImpl.java new file mode 100644 index 0000000..1202e77 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/service/impl/ActionServiceImpl.java @@ -0,0 +1,101 @@ +package com.senmesh.component.action.service.impl; + +import com.senmesh.component.action.util.ActionUtils; +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.aop.framework.AopContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.common.util.ListUtil; +import com.senmesh.common.util.MockUtils; +import com.senmesh.component.action.dao.ActionDetailMapper; +import com.senmesh.component.action.dao.ActionMapper; +import com.senmesh.component.action.dto.ActionCreateDTO; +import com.senmesh.component.action.dto.ActionDTO; +import com.senmesh.component.action.dto.ActionDetailCreateDTO; +import com.senmesh.component.action.dto.ActionDetailQueryDTO; +import com.senmesh.component.action.dto.ActionQueryDTO; +import com.senmesh.component.action.entity.Action; +import com.senmesh.component.action.entity.ActionDetail; +import com.senmesh.component.action.mapstruct.ActionDetailMapMapper; +import com.senmesh.component.action.mapstruct.ActionMapMapper; +import com.senmesh.component.action.service.ActionService; +import com.senmesh.mq.consumer.handler.ITopicMqHandler; +import com.senmesh.mq.dto.TopicMqMessage; + +/** + * @author sr on 2022-02-18 + */ +@Service +public class ActionServiceImpl implements ActionService , ITopicMqHandler{ + + @Autowired + private ActionMapper actionMapper; + + @Autowired + private ActionDetailMapper actionDetailMapper; + + @Override + @Transactional + public Long create(ActionCreateDTO actionCreateDTO) { + Action action = ActionMapMapper.INSTANCE.toEntity(actionCreateDTO); + actionMapper.saveEntity(action); + Long actionId = action.getId(); + List detailCreateDtos = actionCreateDTO.getDetailDtos(); + if (CollectionUtils.isEmpty(detailCreateDtos)) { + return actionId; + } + List details = detailCreateDtos.stream().map(dto -> { + ActionDetail actionDetail = ActionDetailMapMapper.INSTANCE.toEntity(dto); + actionDetail.setActionId(actionId); + return actionDetail; + }).collect(Collectors.toList()); + actionDetailMapper.saveEntites(details); + return actionId; + } + + + @Override + public List list(ActionQueryDTO actionQueryDTO) { + actionQueryDTO.disablePage(); + List dtoList = actionMapper.listActionDTO(actionQueryDTO); + dtoList.forEach(f ->{ + f.setChildNode(actionDetailMapper.listActionDetailDTO(ActionDetailQueryDTO.builder().actionId(f.getId()).build())); + }); + return dtoList; + } + + @Override + public void page(ActionQueryDTO actionQueryDTO) { + actionMapper.listActionDTO(actionQueryDTO); + } + + @Override + public ActionDTO find(ActionQueryDTO actionQueryDTO) { + List actionDTOs = this.list(actionQueryDTO); + return actionDTOs.isEmpty() ? null : ListUtil.first(actionDTOs); + } + + + @Override + public String getRoutingKey() { + return ActionUtils.ACTION_LOG; + } + + + @Override + public void onMessage(TopicMqMessage message) { + Long userId = message.getOperateUserId(); + if (userId != null) { + MockUtils.mockUser(userId, message.getOperateOrgId()); + } else { + MockUtils.mockPlatUser(); + } + ((ActionService) AopContext.currentProxy()).create(message.getData()); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/action/util/ActionUtils.java b/backend/src/main/java/com/senmesh/component/action/util/ActionUtils.java new file mode 100644 index 0000000..2e52864 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/action/util/ActionUtils.java @@ -0,0 +1,113 @@ +package com.senmesh.component.action.util; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import com.google.common.collect.Lists; +import com.senmesh.common.util.StrUtils; +import com.senmesh.component.action.annotation.ActionField; +import com.senmesh.component.action.annotation.ActionModel; +import com.senmesh.component.action.dto.ActionCreateDTO; +import com.senmesh.component.action.dto.ActionDetailCreateDTO; +import com.senmesh.component.dict.util.DictUtils; +import com.senmesh.mq.util.MqSendUtils; +import com.senmesh.mybatisplus.util.MybatisPlusUtils; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author sr on 2022-02-18 + */ +@Slf4j +public class ActionUtils { + + /** 操作记录 **/ + public static final String ACTION_LOG = "action_log"; + + + public static void diff(Long objId, Object oldObj, Object newObj) { + if (oldObj == null || newObj == null) { + log.info("记录对象不能为空"); + return; + } + Class objClass = oldObj.getClass(); + if (objClass != newObj.getClass()) { + log.info("记录对象类型需一致"); + return; + } + if (objId == null) { + log.info("记录id不能为空"); + return; + } + try { + Field[] fields = objClass.getDeclaredFields(); + List detailCreateDTOs = Lists.newArrayList(); + for (Field field : fields) { + ActionField actionLog = field.getAnnotation(ActionField.class); + if (actionLog == null) { + continue; + } + field.setAccessible(true); + String fieldAlias = actionLog.alias(); + String fieldName = field.getName(); + try { + Object oldValue = MybatisPlusUtils.dealEnumField(field.get(oldObj)); + Object newValue = MybatisPlusUtils.dealEnumField(field.get(newObj)); + String oldValueStr = oldValue == null ? null : oldValue.toString(); + String newValueStr = newValue == null ? null : newValue.toString(); + + if(StringUtils.isBlank(oldValueStr) && StringUtils.isBlank(newValueStr)){ + continue; + } + String dictCode = actionLog.dictCode(); + String diff = null; + if (StringUtils.isNotBlank(dictCode)) { + Map dictNameMap = DictUtils.getCodeNameMap(dictCode); + diff = formatDiff(fieldAlias, MapUtils.getString(dictNameMap, oldValueStr, oldValueStr), + MapUtils.getString(dictNameMap, newValueStr, newValueStr)); + } else { + dictCode = null; + diff = formatDiff(fieldAlias, oldValueStr, newValueStr); + } + ActionDetailCreateDTO detailCreateDTO = ActionDetailCreateDTO.builder() + .field(fieldName) + .fieldAlias(fieldAlias) + .fieldDictCode(dictCode) + .oldValue(oldValueStr) + .newValue(newValueStr) + .diff(diff) + .build(); + detailCreateDTOs.add(detailCreateDTO); + } catch (IllegalArgumentException | IllegalAccessException e) { + log.info("获取记录对象属性失败", e); + return; + } + } + ActionModel actionModel = objClass.getAnnotation(ActionModel.class); + String unionType = null; + if (actionModel != null) { + unionType = actionModel.type(); + } + unionType = + Optional.ofNullable(unionType) + .orElseGet(() -> StrUtils.toSnake(objClass.getSimpleName())); + ActionCreateDTO actionCreateDTO = + ActionCreateDTO.builder().unionType(unionType).unionId(objId).detailDtos(detailCreateDTOs) + .build(); + MqSendUtils.send(ACTION_LOG, actionCreateDTO); + } catch (Exception e) { + log.info("记录操作失败", e); + } + } + + private static String formatDiff(String fieldAlias, String oldValueStr, String newValueStr) { + return String.join("", fieldAlias, ",旧值为\"", oldValueStr, "\",新值为\"", newValueStr, "\""); + } + + +} diff --git a/backend/src/main/java/com/senmesh/component/asyntasknotice/constant/AsyncTaskFlowStatusEnum.java b/backend/src/main/java/com/senmesh/component/asyntasknotice/constant/AsyncTaskFlowStatusEnum.java new file mode 100644 index 0000000..4c650df --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/asyntasknotice/constant/AsyncTaskFlowStatusEnum.java @@ -0,0 +1,29 @@ +package com.senmesh.component.asyntasknotice.constant; + + +/** + * 异步任务流程状态 + * + * @author sr on 2024-02-06 + */ +public enum AsyncTaskFlowStatusEnum { + + /** 开启 **/ + START(1), + /** 结束 **/ + END(2), + ; + + + private Integer status; + + AsyncTaskFlowStatusEnum(Integer status) { + this.status = status; + } + + public Integer getStatus() { + return status; + } + + +} diff --git a/backend/src/main/java/com/senmesh/component/asyntasknotice/constant/AsyncTaskNoticeStatusEnum.java b/backend/src/main/java/com/senmesh/component/asyntasknotice/constant/AsyncTaskNoticeStatusEnum.java new file mode 100644 index 0000000..96e1b69 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/asyntasknotice/constant/AsyncTaskNoticeStatusEnum.java @@ -0,0 +1,30 @@ +package com.senmesh.component.asyntasknotice.constant; + + +/** + * 异步任务通知状态 + * @author sr on 2024-02-06 + */ +public enum AsyncTaskNoticeStatusEnum { + + /** 未读 **/ + INIT(1), + /** 已读 **/ + READ(2), + ; + + + + + private Integer status; + + AsyncTaskNoticeStatusEnum(Integer status) { + this.status = status; + } + + public Integer getStatus() { + return status; + } + + +} diff --git a/backend/src/main/java/com/senmesh/component/asyntasknotice/constant/AsyncTaskTypeEnum.java b/backend/src/main/java/com/senmesh/component/asyntasknotice/constant/AsyncTaskTypeEnum.java new file mode 100644 index 0000000..32dcd4b --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/asyntasknotice/constant/AsyncTaskTypeEnum.java @@ -0,0 +1,21 @@ +package com.senmesh.component.asyntasknotice.constant; + +/** + * 异步任务类型 + * @author sr on 2024-02-06 + */ +public enum AsyncTaskTypeEnum { + + COMMON_IMPORT("common_import") + ; + + private String type; + + AsyncTaskTypeEnum(String type) { + this.type = type; + } + + public String getType() { + return type; + } +} diff --git a/backend/src/main/java/com/senmesh/component/asyntasknotice/controller/AsyncTaskNoticeController.java b/backend/src/main/java/com/senmesh/component/asyntasknotice/controller/AsyncTaskNoticeController.java new file mode 100644 index 0000000..34b7ba9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/asyntasknotice/controller/AsyncTaskNoticeController.java @@ -0,0 +1,45 @@ +package com.senmesh.component.asyntasknotice.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeDTO; +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeQueryDTO; +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeReadDTO; +import com.senmesh.component.asyntasknotice.service.AsyncTaskNoticeService; +import com.senmesh.tkmybatis.pojo.Page; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2024-02-06 + */ +@RestController +@RequestMapping("async_task_notice") +@Api(tags = "异步任务通知") +public class AsyncTaskNoticeController { + + @Autowired + private AsyncTaskNoticeService asyncTaskNoticeService; + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(AsyncTaskNoticeQueryDTO asyncTaskNoticeQueryDTO){ + asyncTaskNoticeQueryDTO.setCreateBy(UserContextHolder.getExistLoginUserId()); + asyncTaskNoticeService.page(asyncTaskNoticeQueryDTO); + return AlitaResult.success(asyncTaskNoticeQueryDTO.getPageResult()); + } + + + @PostMapping("/read") + @ApiOperation("创建") + public AlitaResult read(AsyncTaskNoticeReadDTO readDTO){ + return AlitaResult.success(asyncTaskNoticeService.read(readDTO)); + } +} diff --git a/backend/src/main/java/com/senmesh/component/asyntasknotice/dao/AsyncTaskNoticeMapper.java b/backend/src/main/java/com/senmesh/component/asyntasknotice/dao/AsyncTaskNoticeMapper.java new file mode 100644 index 0000000..5353ae9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/asyntasknotice/dao/AsyncTaskNoticeMapper.java @@ -0,0 +1,33 @@ +package com.senmesh.component.asyntasknotice.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeDTO; +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeFinishDTO; +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeQueryDTO; +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeReadDTO; +import com.senmesh.component.asyntasknotice.entity.AsyncTaskNotice; +import com.senmesh.tkmybatis.mybatis.MyMapper; + +/** + * 异步任务通知 + * + * @author sr on 2024-02-06 + */ +public interface AsyncTaskNoticeMapper extends MyMapper { + + /** + * 查询 + * + * @param asyncTaskNoticeQueryDTO + * @return + * @author sr on 2024-02-06 + */ + List listAsyncTaskNoticeDTO(@Param("param") AsyncTaskNoticeQueryDTO asyncTaskNoticeQueryDTO); + + int finish(@Param("param") AsyncTaskNoticeFinishDTO finishDTO); + + int read(@Param("param") AsyncTaskNoticeReadDTO readDTO); +} diff --git a/backend/src/main/java/com/senmesh/component/asyntasknotice/dto/AsyncTaskNoticeCreateDTO.java b/backend/src/main/java/com/senmesh/component/asyntasknotice/dto/AsyncTaskNoticeCreateDTO.java new file mode 100644 index 0000000..8833557 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/asyntasknotice/dto/AsyncTaskNoticeCreateDTO.java @@ -0,0 +1,41 @@ +package com.senmesh.component.asyntasknotice.dto; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2024-02-06 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "异步任务通知创建") +public class AsyncTaskNoticeCreateDTO extends BaseOperateDTO{ + + /** **/ + private static final long serialVersionUID = 1L; + + /** 关联类型:common_import等**/ + @NotBlank(message = "关联类型不能为空") + private String unionType; + /** 关联id**/ + @NotNull(message = "关联id不能为空") + private Long unionId; + /** 内容**/ + @NotBlank(message = "内容不能为空") + private String content; + /** 业务状态**/ + private String bizStatusStr; + /** 业务参数**/ + private String bizParamData; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/asyntasknotice/dto/AsyncTaskNoticeDTO.java b/backend/src/main/java/com/senmesh/component/asyntasknotice/dto/AsyncTaskNoticeDTO.java new file mode 100644 index 0000000..1acf267 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/asyntasknotice/dto/AsyncTaskNoticeDTO.java @@ -0,0 +1,41 @@ +package com.senmesh.component.asyntasknotice.dto; + +import com.senmesh.common.dto.BaseDTO; + +import com.senmesh.component.asyntasknotice.constant.AsyncTaskTypeEnum; +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2024-02-06 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "异步任务通知") +public class AsyncTaskNoticeDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + /** @see AsyncTaskTypeEnum 关联类型:common_import等**/ + private String unionType; + /** 关联id**/ + private Long unionId; + /** 内容**/ + private String content; + /** 业务状态**/ + private String bizStatusStr; + /** 业务参数**/ + private String bizParamData; + /** 流程状态:1开启,2结束**/ + private Integer flowStatus; + /** 通知状态:1未读,2已读**/ + private Integer noticeStatus; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/asyntasknotice/dto/AsyncTaskNoticeFinishDTO.java b/backend/src/main/java/com/senmesh/component/asyntasknotice/dto/AsyncTaskNoticeFinishDTO.java new file mode 100644 index 0000000..c43991f --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/asyntasknotice/dto/AsyncTaskNoticeFinishDTO.java @@ -0,0 +1,36 @@ +package com.senmesh.component.asyntasknotice.dto; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2024-02-06 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "异步任务通知结束") +public class AsyncTaskNoticeFinishDTO extends BaseOperateDTO{ + + /** **/ + private static final long serialVersionUID = 1L; + + /** 关联类型:common_import等**/ + @NotBlank(message = "关联类型不能为空") + private String unionType; + /** 关联id**/ + @NotNull(message = "关联id不能为空") + private Long unionId; + /** 业务状态**/ + private String bizStatusStr; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/asyntasknotice/dto/AsyncTaskNoticeQueryDTO.java b/backend/src/main/java/com/senmesh/component/asyntasknotice/dto/AsyncTaskNoticeQueryDTO.java new file mode 100644 index 0000000..fe97f80 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/asyntasknotice/dto/AsyncTaskNoticeQueryDTO.java @@ -0,0 +1,37 @@ +package com.senmesh.component.asyntasknotice.dto; + + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; + +import com.senmesh.common.dto.PageQueryDTO; + +/** + * @author sr on 2024-02-06 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "异步任务通知查询条件") +public class AsyncTaskNoticeQueryDTO extends PageQueryDTO{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + + @ApiModelProperty("创建人") + private Long createBy; + + /** 关联类型:common_import等**/ + private String unionType; + /** 关联id**/ + private Long unionId; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/asyntasknotice/dto/AsyncTaskNoticeReadDTO.java b/backend/src/main/java/com/senmesh/component/asyntasknotice/dto/AsyncTaskNoticeReadDTO.java new file mode 100644 index 0000000..231a1ad --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/asyntasknotice/dto/AsyncTaskNoticeReadDTO.java @@ -0,0 +1,32 @@ +package com.senmesh.component.asyntasknotice.dto; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2024-02-06 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "异步任务通知-读取") +public class AsyncTaskNoticeReadDTO extends BaseOperateDTO{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + /** 关联类型:common_import等**/ + private String unionType; + /** 关联id**/ + private Long unionId; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/asyntasknotice/entity/AsyncTaskNotice.java b/backend/src/main/java/com/senmesh/component/asyntasknotice/entity/AsyncTaskNotice.java new file mode 100644 index 0000000..8d01bcf --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/asyntasknotice/entity/AsyncTaskNotice.java @@ -0,0 +1,43 @@ +package com.senmesh.component.asyntasknotice.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 异步任务通知 + * + * @author sr on 2024-02-06 + */ +@TableName("async_task_notice") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class AsyncTaskNotice extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 关联类型:common_import等**/ + private String unionType; + /** 关联id**/ + private Long unionId; + /** 内容**/ + private String content; + /** 业务状态**/ + private String bizStatusStr; + /** 业务参数**/ + private String bizParamData; + /** 流程状态:1开启,2结束**/ + private Integer flowStatus; + /** 通知状态:1未读,2已读**/ + private Integer noticeStatus; + +} diff --git a/backend/src/main/java/com/senmesh/component/asyntasknotice/mapper/AsyncTaskNoticeMapper.xml b/backend/src/main/java/com/senmesh/component/asyntasknotice/mapper/AsyncTaskNoticeMapper.xml new file mode 100644 index 0000000..274f39d --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/asyntasknotice/mapper/AsyncTaskNoticeMapper.xml @@ -0,0 +1,57 @@ + + + + + + + update async_task_notice + set flow_status = 2,update_time = now(), update_by = #{param.operateUserId} + + ,biz_status_str = #{param.bizStatusStr} + + where + deleted = FALSE + and union_type = #{param.unionType} + and union_id = #{param.unionId} + and flow_status = 1 + + + + update async_task_notice + set notice_status = 2,update_time = now(), update_by = #{param.operateUserId} + where + deleted = FALSE + and create_by = #{param.operateUserId} + and notice_status = 1 + + and id = #{param.id} + + + and union_type = #{param.unionType} + + + and union_id = #{param.unionId} + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/asyntasknotice/mapstruct/AsyncTaskNoticeMapMapper.java b/backend/src/main/java/com/senmesh/component/asyntasknotice/mapstruct/AsyncTaskNoticeMapMapper.java new file mode 100644 index 0000000..3fed446 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/asyntasknotice/mapstruct/AsyncTaskNoticeMapMapper.java @@ -0,0 +1,36 @@ +package com.senmesh.component.asyntasknotice.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeCreateDTO; +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeDTO; +import com.senmesh.component.asyntasknotice.entity.AsyncTaskNotice; + +/** + * @author sr on 2024-02-06 + */ +@Mapper +public interface AsyncTaskNoticeMapMapper { + + AsyncTaskNoticeMapMapper INSTANCE = + Mappers.getMapper(AsyncTaskNoticeMapMapper.class); + + /** + * dto to entity + * + * @param asyncTaskNoticeDto + * @return + * @author sr on 2024-02-06 + */ + AsyncTaskNotice toEntity( + AsyncTaskNoticeDTO asyncTaskNoticeDto); + + + /** + * @return + * @author sr on 2024-02-06 + */ + AsyncTaskNotice toEntity(AsyncTaskNoticeCreateDTO createDTO); + +} diff --git a/backend/src/main/java/com/senmesh/component/asyntasknotice/service/AsyncTaskNoticeService.java b/backend/src/main/java/com/senmesh/component/asyntasknotice/service/AsyncTaskNoticeService.java new file mode 100644 index 0000000..526db55 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/asyntasknotice/service/AsyncTaskNoticeService.java @@ -0,0 +1,87 @@ +package com.senmesh.component.asyntasknotice.service; + +import java.util.List; + +import javax.validation.Valid; + +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeCreateDTO; +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeDTO; +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeFinishDTO; +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeQueryDTO; +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeReadDTO; + +/** + * 异步任务通知 + * + * @author sr on 2024-02-06 + */ +public interface AsyncTaskNoticeService { + + /** + * 创建 + * + * @param createDTO + * @return + * @author sr on 2024-02-06 + */ + Long create(@Valid AsyncTaskNoticeCreateDTO createDTO); + + /** + * 结束 + * @param finishDTO + * @author sr on 2024-02-06 + */ + void finish(@Valid AsyncTaskNoticeFinishDTO finishDTO); + + /** + * 读取 + * @param readDTO + * @return + * @author sr on 2024-02-06 + */ + Integer read(AsyncTaskNoticeReadDTO readDTO); + + + + /** + * 删除 + * + * @param id + * @author sr on 2024-02-06 + */ + void remove(Long id); + + + + /** + * 查询 + * + * @param asyncTaskNoticeQueryDTO + * @return + * @author sr on 2024-02-06 + */ + List list(AsyncTaskNoticeQueryDTO asyncTaskNoticeQueryDTO); + + /** + * 分页查询 + * + * @param asyncTaskNoticeQueryDTO + * @return + * @author sr on 2024-02-06 + */ + void page(AsyncTaskNoticeQueryDTO asyncTaskNoticeQueryDTO); + + /** + * 单个查询 + * + * @param asyncTaskNoticeQueryDTO + * @return + * @author sr on 2024-02-06 + */ + AsyncTaskNoticeDTO find(AsyncTaskNoticeQueryDTO asyncTaskNoticeQueryDTO); + + + + + +} diff --git a/backend/src/main/java/com/senmesh/component/asyntasknotice/service/impl/AsyncTaskNoticeServiceImpl.java b/backend/src/main/java/com/senmesh/component/asyntasknotice/service/impl/AsyncTaskNoticeServiceImpl.java new file mode 100644 index 0000000..9958662 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/asyntasknotice/service/impl/AsyncTaskNoticeServiceImpl.java @@ -0,0 +1,115 @@ +package com.senmesh.component.asyntasknotice.service.impl; + +import com.senmesh.component.notice.constant.NoticeFirstTypeEnum; +import com.senmesh.component.notice.dto.NoticeMsgDTO; +import com.senmesh.component.notice.util.NoticeUtils; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.ListUtil; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.component.asyntasknotice.constant.AsyncTaskFlowStatusEnum; +import com.senmesh.component.asyntasknotice.constant.AsyncTaskNoticeStatusEnum; +import com.senmesh.component.asyntasknotice.dao.AsyncTaskNoticeMapper; +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeCreateDTO; +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeDTO; +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeFinishDTO; +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeQueryDTO; +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeReadDTO; +import com.senmesh.component.asyntasknotice.entity.AsyncTaskNotice; +import com.senmesh.component.asyntasknotice.mapstruct.AsyncTaskNoticeMapMapper; +import com.senmesh.component.asyntasknotice.service.AsyncTaskNoticeService; +import com.senmesh.frame.redis.aop.annotation.AutoUnLock; +import com.senmesh.frame.redis.dto.LockDTO; +import com.senmesh.frame.redis.redisson.RedissonUtils; + +/** + * @author sr on 2024-02-06 + */ +@Service +public class AsyncTaskNoticeServiceImpl implements AsyncTaskNoticeService { + + private static final String LOCK_NAME = "asynctasknotice"; + + @Autowired + private AsyncTaskNoticeMapper asyncTaskNoticeMapper; + + + public static LockDTO getLockDTO(String unionType, Long unionId) { + Assert.notBlank(unionType, "关联类型不能为空"); + Assert.notNull(unionId, "关联id不能为空"); + return LockDTO.builder().methodName(LOCK_NAME).tryLockWaitTime(0L) + .arg(unionType) + .arg(unionId.toString()) + .build(); + } + + @Override + @AutoUnLock + @Transactional + public Long create(AsyncTaskNoticeCreateDTO createDTO) { + String unionType = createDTO.getUnionType(); + Long unionId = createDTO.getUnionId(); + AsyncTaskNotice existNotice = AsyncTaskNotice.builder().unionId(unionId).unionId(unionId).build(); + boolean exist = asyncTaskNoticeMapper.existsEntity(existNotice); + Assert.isTrue(!exist, "已存在相同关联类型数据"); + LockDTO lockDTO = getLockDTO(unionType, unionId); + Assert.isTrue(RedissonUtils.tryLockAutomatically(lockDTO), "关联类型数据正在被操作"); + exist = asyncTaskNoticeMapper.existsEntity(existNotice); + Assert.isTrue(!exist, "已存在相同关联类型数据"); + AsyncTaskNotice notice = AsyncTaskNoticeMapMapper.INSTANCE.toEntity(createDTO); + notice.setFlowStatus(AsyncTaskFlowStatusEnum.START.getStatus()); + notice.setNoticeStatus(AsyncTaskNoticeStatusEnum.INIT.getStatus()); + asyncTaskNoticeMapper.saveEntity(notice); + return notice.getId(); + } + + @Override + @Transactional + public void finish(AsyncTaskNoticeFinishDTO finishDTO) { + AsyncTaskNoticeDTO noticeDTO = find(AsyncTaskNoticeQueryDTO.builder() + .unionType(finishDTO.getUnionType()).unionId(finishDTO.getUnionId()).build()); + Assert.notNull(noticeDTO, "未找到对应的异步任务"); + Assert.isTrue(AsyncTaskFlowStatusEnum.START.getStatus().equals(noticeDTO.getFlowStatus()), "异步任务已结束"); + noticeDTO.setFlowStatus(AsyncTaskFlowStatusEnum.END.getStatus()); + noticeDTO.setBizStatusStr(finishDTO.getBizStatusStr()); + asyncTaskNoticeMapper.updateEntitySelective(AsyncTaskNoticeMapMapper.INSTANCE.toEntity(noticeDTO)); + // 发通知 + NoticeUtils.sendAsyncNotice(NoticeMsgDTO.create(noticeDTO.getCreateBy(), NoticeFirstTypeEnum.ASYNC_TASK_NOTICE.getType(), noticeDTO)); + } + + @Override + @Transactional + public Integer read(AsyncTaskNoticeReadDTO readDTO) { + return asyncTaskNoticeMapper.read(readDTO); + } + + @Override + @Transactional + public void remove(Long id) { + asyncTaskNoticeMapper.deleteEntity(AsyncTaskNotice.builder().id(id).build(), + UserContextHolder.getLoginUserId()); + } + + @Override + public List list(AsyncTaskNoticeQueryDTO asyncTaskNoticeQueryDTO) { + asyncTaskNoticeQueryDTO.disablePage(); + return asyncTaskNoticeMapper.listAsyncTaskNoticeDTO(asyncTaskNoticeQueryDTO); + } + + @Override + public void page(AsyncTaskNoticeQueryDTO asyncTaskNoticeQueryDTO) { + asyncTaskNoticeMapper.listAsyncTaskNoticeDTO(asyncTaskNoticeQueryDTO); + } + + @Override + public AsyncTaskNoticeDTO find(AsyncTaskNoticeQueryDTO asyncTaskNoticeQueryDTO) { + List asyncTaskNoticeDTOs = this.list(asyncTaskNoticeQueryDTO); + return ListUtil.first(asyncTaskNoticeDTOs); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/asyntasknotice/util/AsyncTaskNoticeUtils.java b/backend/src/main/java/com/senmesh/component/asyntasknotice/util/AsyncTaskNoticeUtils.java new file mode 100644 index 0000000..0a4058e --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/asyntasknotice/util/AsyncTaskNoticeUtils.java @@ -0,0 +1,42 @@ +package com.senmesh.component.asyntasknotice.util; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeCreateDTO; +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeFinishDTO; +import com.senmesh.component.asyntasknotice.service.AsyncTaskNoticeService; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author sr on 2024-02-06 + */ +@Component +@Slf4j +public class AsyncTaskNoticeUtils { + + private static AsyncTaskNoticeService asyncTaskNoticeService; + + @Autowired + public void setAsyncTaskNoticeService(AsyncTaskNoticeService asyncTaskNoticeService) { + AsyncTaskNoticeUtils.asyncTaskNoticeService = asyncTaskNoticeService; + } + + public static void create(AsyncTaskNoticeCreateDTO createDTO) { + try { + asyncTaskNoticeService.create(createDTO); + } catch (Exception e) { + log.info("异步任务通知创建失败:{}", e.getMessage()); + } + } + + public static void finish(AsyncTaskNoticeFinishDTO finishDTO) { + try { + asyncTaskNoticeService.finish(finishDTO); + } catch (Exception e) { + log.info("异步任务通知结束失败:{}", e.getMessage()); + } + + } +} diff --git a/backend/src/main/java/com/senmesh/component/cardbin/dao/CardBinMapper.java b/backend/src/main/java/com/senmesh/component/cardbin/dao/CardBinMapper.java new file mode 100644 index 0000000..4976017 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/cardbin/dao/CardBinMapper.java @@ -0,0 +1,26 @@ +package com.senmesh.component.cardbin.dao; + +import java.util.List; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.senmesh.component.cardbin.entity.CardBin; + +/** + * @author sr on 2019-09-25 + */ +public interface CardBinMapper extends BaseMapper { + + /** + * 通过卡bin获取卡bin + * @param cardBin + * @return + */ + CardBin findByCardBin(String cardBin); + + /** + * 查询卡bin列表 + * @return + */ + List selectAllCardBinList(); + +} diff --git a/backend/src/main/java/com/senmesh/component/cardbin/entity/BankCode.java b/backend/src/main/java/com/senmesh/component/cardbin/entity/BankCode.java new file mode 100644 index 0000000..afa1207 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/cardbin/entity/BankCode.java @@ -0,0 +1,40 @@ +package com.senmesh.component.cardbin.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * + * + * @author sr on 2019-09-25 + */ +@TableName("xs_bank_code") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Builder +@Data +public class BankCode extends BaseEntity { + + /** + * 联行号 + **/ + private String bankCode; + + /** + * 银行名称 + **/ + private String bankName; + + /** + * 法人行号 + **/ + private String legalEntityCode; + +} diff --git a/backend/src/main/java/com/senmesh/component/cardbin/entity/CardBin.java b/backend/src/main/java/com/senmesh/component/cardbin/entity/CardBin.java new file mode 100644 index 0000000..353c228 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/cardbin/entity/CardBin.java @@ -0,0 +1,60 @@ +package com.senmesh.component.cardbin.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 卡bin表 + * + * @author sr on 2019-09-25 + */ +@TableName("xs_card_bin") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Builder +@Data +public class CardBin extends BaseEntity { + + /** + * 机构编号 + **/ + private String bankOrgCode; + /** + * 联网行编号 + **/ + private String bankNumber; + /** + * 机构名称 + **/ + private String bankOrgName; + /** + * 卡长度 + **/ + private Integer cardLength; + /** + * 卡BIN + **/ + private String cardBin; + /** + * 是否银联品牌卡 + **/ + private Boolean standardCard; + /** + * 卡种 + **/ + private String cardClassify; + + /** + * 总行行号(表里都没值,有点问题) + */ + private String bankNo; + + +} diff --git a/backend/src/main/java/com/senmesh/component/cardbin/mapper/CardBinMapper.xml b/backend/src/main/java/com/senmesh/component/cardbin/mapper/CardBinMapper.xml new file mode 100644 index 0000000..a21707a --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/cardbin/mapper/CardBinMapper.xml @@ -0,0 +1,26 @@ + + + + + + + + + diff --git a/backend/src/main/java/com/senmesh/component/cardbin/service/CardBinService.java b/backend/src/main/java/com/senmesh/component/cardbin/service/CardBinService.java new file mode 100644 index 0000000..a34a981 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/cardbin/service/CardBinService.java @@ -0,0 +1,53 @@ +package com.senmesh.component.cardbin.service; + +import com.senmesh.common.AlitaResult; +import com.senmesh.component.cardbin.entity.CardBin; + +import java.util.List; +import java.util.Set; + +/** + * @author sr on 2019-09-25 + */ +public interface CardBinService { + + /** + * 导入卡bin + * @author sr on 2019-09-25 + */ + void importCardBin(); + + /** + * 通过卡bin获取卡bin + * @param cardBin + * @return + */ + CardBin findByCardBin(String cardBin); + + /** + * + * @param bankNo + * @return + */ + AlitaResult isBankNo(String bankNo); + + /** + * 查询卡bin列表 + * + * @return + */ + List findAllCardBinList(); + + /** + * 校验银行卡 + * 如果返回null,代表没有可校验的资源 + * 否则,返回校验成功的银行卡号集合 + * + * @param bankNos 银行卡号集合 + * @return {@link Set}<{@link String}> + */ + Set checkBankNos(Set bankNos); + + String getBankNo(String bankNo); + +} diff --git a/backend/src/main/java/com/senmesh/component/cardbin/service/impl/CardBinServiceImpl.java b/backend/src/main/java/com/senmesh/component/cardbin/service/impl/CardBinServiceImpl.java new file mode 100644 index 0000000..12289fb --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/cardbin/service/impl/CardBinServiceImpl.java @@ -0,0 +1,85 @@ +package com.senmesh.component.cardbin.service.impl; + +import com.senmesh.common.AlitaResult; +import com.senmesh.component.cardbin.dao.CardBinMapper; +import com.senmesh.component.cardbin.entity.CardBin; +import com.senmesh.component.cardbin.service.CardBinService; +import com.senmesh.frame.redis.util.RedissonValueUtils; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author sr on 2019-09-25 + */ +@Service +@Slf4j +public class CardBinServiceImpl implements CardBinService { + + @Resource + private CardBinMapper cardBinMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public void importCardBin() { + } + + @Override + public CardBin findByCardBin(String cardBin) { + if(StringUtils.isBlank(cardBin)){ + return null; + } + return cardBinMapper.findByCardBin(cardBin); + } + + @Override + public AlitaResult isBankNo(String bankNo) { + if (StringUtils.isBlank(bankNo)) { + return AlitaResult.error("银行卡号为空"); + } + CardBin cardBin = findByCardBin(bankNo); + return cardBin != null ? AlitaResult.success(cardBin.getBankOrgName()) + : AlitaResult.error("银行卡号格式错误"); + } + + @Override + public List findAllCardBinList() { + String key = "alita:cardbin:list"; + List cardBinList; + if (RedissonValueUtils.hasKey(key)) { + cardBinList = (List) RedissonValueUtils.get(key); + } else { + cardBinList = cardBinMapper.selectAllCardBinList(); + RedissonValueUtils.set(key, cardBinList); + } + return cardBinList; + } + + @Override + public Set checkBankNos(Set bankNos) { + List allCardBinList = findAllCardBinList(); + if (CollectionUtils.isEmpty(allCardBinList)) { + return null; + } + return bankNos.stream().filter(bankNo -> allCardBinList.parallelStream().anyMatch(cardBin -> + bankNo.startsWith(cardBin.getCardBin()) && bankNo.length() == cardBin.getCardLength())) + .collect(Collectors.toSet()); + } + + @Override + public String getBankNo(String bankNo) { + if (StringUtils.isBlank(bankNo)) { + return null; + } + CardBin cardBin = findByCardBin(bankNo); + return cardBin == null ? null : cardBin.getBankOrgName(); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/chat/constant/ChatConstants.java b/backend/src/main/java/com/senmesh/component/chat/constant/ChatConstants.java new file mode 100644 index 0000000..79a0aa6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/constant/ChatConstants.java @@ -0,0 +1,8 @@ +package com.senmesh.component.chat.constant; + +/** + * @author sr on 2025-05-29 + */ +public interface ChatConstants { + +} diff --git a/backend/src/main/java/com/senmesh/component/chat/constant/ChatMsgStatusEnum.java b/backend/src/main/java/com/senmesh/component/chat/constant/ChatMsgStatusEnum.java new file mode 100644 index 0000000..02a78c2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/constant/ChatMsgStatusEnum.java @@ -0,0 +1,27 @@ +package com.senmesh.component.chat.constant; + + + +public enum ChatMsgStatusEnum { + + /** 未读 **/ + INIT(1), + /** 已读 **/ + READ(2), + ; + + + + + private Integer status; + + ChatMsgStatusEnum(Integer status) { + this.status = status; + } + + public Integer getStatus() { + return status; + } + + +} diff --git a/backend/src/main/java/com/senmesh/component/chat/constant/ChatMsgTypeEnum.java b/backend/src/main/java/com/senmesh/component/chat/constant/ChatMsgTypeEnum.java new file mode 100644 index 0000000..02fbfdb --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/constant/ChatMsgTypeEnum.java @@ -0,0 +1,19 @@ +package com.senmesh.component.chat.constant; + +public enum ChatMsgTypeEnum { + + /** 文字 */ + TEXT("text"), + ; + + private String type; + + ChatMsgTypeEnum(String type) { + this.type = type; + } + + public String getType() { + return type; + } + +} diff --git a/backend/src/main/java/com/senmesh/component/chat/constant/ChatStatusEnum.java b/backend/src/main/java/com/senmesh/component/chat/constant/ChatStatusEnum.java new file mode 100644 index 0000000..70bec10 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/constant/ChatStatusEnum.java @@ -0,0 +1,22 @@ +package com.senmesh.component.chat.constant; + +public enum ChatStatusEnum { + + /** 有效 **/ + ACTIVE(1), + /** 关闭 **/ + CLOSED(2), + ; + + private Integer status; + + ChatStatusEnum(Integer status) { + this.status = status; + } + + public Integer getStatus() { + return status; + } + + +} diff --git a/backend/src/main/java/com/senmesh/component/chat/constant/ChatTypeEnum.java b/backend/src/main/java/com/senmesh/component/chat/constant/ChatTypeEnum.java new file mode 100644 index 0000000..730c4d8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/constant/ChatTypeEnum.java @@ -0,0 +1,19 @@ +package com.senmesh.component.chat.constant; + +public enum ChatTypeEnum { + + /** 岗位 */ + POSITION("position"), + ; + + private String type; + + ChatTypeEnum(String type) { + this.type = type; + } + + public String getType() { + return type; + } + +} diff --git a/backend/src/main/java/com/senmesh/component/chat/controller/ChatController.java b/backend/src/main/java/com/senmesh/component/chat/controller/ChatController.java new file mode 100644 index 0000000..dbbc68d --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/controller/ChatController.java @@ -0,0 +1,80 @@ +package com.senmesh.component.chat.controller; + +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.user.constant.UserTypeEnum; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.PathVariable; + +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.component.chat.dto.ChatQueryDTO; +import com.senmesh.component.chat.service.ChatService; +import com.senmesh.component.chat.dto.ChatDTO; +import com.senmesh.component.chat.dto.ChatCreateDTO; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2025-05-29 + */ +@RestController +@RequestMapping("chat") +@Api(tags = "聊天会话") +public class ChatController { + + @Autowired + private ChatService chatService; + + @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create( + @Validated @RequestBody ChatCreateDTO chatOperateDTO){ + return AlitaResult.success(chatService.create(chatOperateDTO)); + } + +/* @PutMapping("/modify") + @ApiOperation("修改") + public AlitaResult modify( + @Validated(Update.class) @RequestBody ChatCreateDTO chatOperateDTO){ + chatService.modify(chatOperateDTO); + return AlitaResult.success(true); + }*/ + + @DeleteMapping("/remove/{id}") + @ApiOperation("删除") + public AlitaResult remove(@PathVariable Long id){ + chatService.remove(id); + return AlitaResult.success(true); + } + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(ChatQueryDTO chatQueryDTO){ + chatService.page(chatQueryDTO); + return AlitaResult.success(chatQueryDTO.getPageResult()); + } + + @GetMapping("/page_curr") + @ApiOperation("分页查询") + public AlitaResult> pageCurr(ChatQueryDTO chatQueryDTO){ + Long orgId = UserContextHolder.getLoginOrgId(); + chatQueryDTO.setOrgId(orgId); + Long userId = UserContextHolder.getLoginUserId(); + if (UserTypeEnum.PERSON.getType().equals(UserContextHolder.getUserType())){ + chatQueryDTO.setPersonUserId(userId); + } else { + chatQueryDTO.setOrgUserId(userId); + } + chatService.page(chatQueryDTO); + return AlitaResult.success(chatQueryDTO.getPageResult()); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/chat/controller/ChatMsgController.java b/backend/src/main/java/com/senmesh/component/chat/controller/ChatMsgController.java new file mode 100644 index 0000000..c77e60b --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/controller/ChatMsgController.java @@ -0,0 +1,42 @@ +package com.senmesh.component.chat.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.component.chat.dto.ChatMsgCreateDTO; +import com.senmesh.component.chat.dto.ChatMsgDTO; +import com.senmesh.component.chat.dto.ChatMsgQueryDTO; +import com.senmesh.component.chat.service.ChatMsgService; +import com.senmesh.tkmybatis.pojo.Page; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +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; + +@RestController +@RequestMapping("chat/msg") +@Api(tags = "聊天消息") +public class ChatMsgController { + + @Autowired + private ChatMsgService chatMsgService; + + + @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create( + @Validated @RequestBody ChatMsgCreateDTO chatMsgCreateDTO){ + return AlitaResult.success(chatMsgService.create(chatMsgCreateDTO)); + } + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> pageCurr(@Validated ChatMsgQueryDTO chatMsgQueryDTO){ + chatMsgService.page(chatMsgQueryDTO); + return AlitaResult.success(chatMsgQueryDTO.getPageResult()); + } +} diff --git a/backend/src/main/java/com/senmesh/component/chat/dao/ChatMapper.java b/backend/src/main/java/com/senmesh/component/chat/dao/ChatMapper.java new file mode 100644 index 0000000..43b6913 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/dao/ChatMapper.java @@ -0,0 +1,28 @@ +package com.senmesh.component.chat.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.component.chat.dto.ChatDTO; +import com.senmesh.component.chat.dto.ChatQueryDTO; +import com.senmesh.component.chat.entity.Chat; +import com.senmesh.tkmybatis.mybatis.MyMapper; + +/** + * 聊天会话 + * + * @author sr on 2025-05-29 + */ +public interface ChatMapper extends MyMapper { + + /** + * 查询 + * + * @param chatQueryDTO + * @return + * @author sr on 2025-05-29 + */ + List listChatDTO(@Param("param") ChatQueryDTO chatQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/component/chat/dao/ChatMsgMapper.java b/backend/src/main/java/com/senmesh/component/chat/dao/ChatMsgMapper.java new file mode 100644 index 0000000..45e3753 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/dao/ChatMsgMapper.java @@ -0,0 +1,28 @@ +package com.senmesh.component.chat.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.component.chat.dto.ChatMsgDTO; +import com.senmesh.component.chat.dto.ChatMsgQueryDTO; +import com.senmesh.component.chat.entity.ChatMsg; +import com.senmesh.tkmybatis.mybatis.MyMapper; + +/** + * 聊天消息 + * + * @author sr on 2025-05-29 + */ +public interface ChatMsgMapper extends MyMapper { + + /** + * 查询 + * + * @param chatMsgQueryDTO + * @return + * @author sr on 2025-05-29 + */ + List listChatMsgDTO(@Param("param") ChatMsgQueryDTO chatMsgQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/component/chat/dto/ChatCreateDTO.java b/backend/src/main/java/com/senmesh/component/chat/dto/ChatCreateDTO.java new file mode 100644 index 0000000..3aff155 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/dto/ChatCreateDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.component.chat.dto; + +import com.senmesh.component.chat.constant.ChatTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Builder.Default; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseOperateDTO; + +/** + * @author sr on 2025-05-29 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "聊天会话操作") +public class ChatCreateDTO extends BaseOperateDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + @NotNull(message = "机构id不能为空") + private Long orgId; + @NotNull(message = "个人用户id不能为空") + private Long personUserId; + /** @see ChatTypeEnum 类型 */ + @Default + private String type = ChatTypeEnum.POSITION.getType(); + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/chat/dto/ChatDTO.java b/backend/src/main/java/com/senmesh/component/chat/dto/ChatDTO.java new file mode 100644 index 0000000..c1c5157 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/dto/ChatDTO.java @@ -0,0 +1,47 @@ +package com.senmesh.component.chat.dto; + +import com.senmesh.common.dto.BaseDTO; + +import com.senmesh.component.chat.constant.ChatTypeEnum; +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2025-05-29 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "聊天会话") +public class ChatDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 机构id */ + private Long orgId; + /** 机构用户id */ + private Long orgUserId; + /** 个人用户id */ + private Long personUserId; + /** @see ChatTypeEnum 类型 */ + private String type; + /** 状态:1有效,2关闭 */ + private Integer status; + + /** 机构名称 */ + private String orgName; + /** 机构logo */ + private String orgLogo; + /** 个人用户昵称*/ + private String personUserNickname; + /** 个人用户头像 */ + private String personUserAvatar; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/chat/dto/ChatMsgCreateDTO.java b/backend/src/main/java/com/senmesh/component/chat/dto/ChatMsgCreateDTO.java new file mode 100644 index 0000000..34934c7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/dto/ChatMsgCreateDTO.java @@ -0,0 +1,42 @@ +package com.senmesh.component.chat.dto; + +import com.senmesh.component.chat.constant.ChatMsgTypeEnum; +import javax.validation.constraints.NotEmpty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Builder.Default; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; + +import com.senmesh.common.dto.BaseOperateDTO; + +/** + * @author sr on 2025-05-29 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "聊天消息操作") +public class ChatMsgCreateDTO extends BaseOperateDTO{ + + /** **/ + private static final long serialVersionUID = 1L; + + /** 聊天id */ + private Long chatId; + /** 机构id */ + private Long orgId; + /** 个人用户id */ + private Long personUserId; + /** --- 聊天id 或 orgId+personUserId 两者选其一不为空 --- */ + + /** 消息类型:text等 */ + @Default + private String msgType = ChatMsgTypeEnum.TEXT.getType(); + /** 内容 */ + @NotEmpty(message = "内容不能为空") + private String content; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/chat/dto/ChatMsgDTO.java b/backend/src/main/java/com/senmesh/component/chat/dto/ChatMsgDTO.java new file mode 100644 index 0000000..9d38eed --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/dto/ChatMsgDTO.java @@ -0,0 +1,41 @@ +package com.senmesh.component.chat.dto; + +import com.senmesh.common.dto.BaseDTO; + +import com.senmesh.component.chat.constant.ChatMsgStatusEnum; +import com.senmesh.component.chat.constant.ChatMsgTypeEnum; +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Builder.Default; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2025-05-29 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "聊天消息") +public class ChatMsgDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + /** 聊天id */ + private Long chatId; + /** 发送用户id */ + private Long senderId; + /** 消息类型:text等 */ + @Default + private String msgType = ChatMsgTypeEnum.TEXT.getType(); + /** 内容 */ + private String content; + /** 消息状态:1未读,2已读 */ + @Default + private Integer msgStatus = ChatMsgStatusEnum.INIT.getStatus(); + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/chat/dto/ChatMsgQueryDTO.java b/backend/src/main/java/com/senmesh/component/chat/dto/ChatMsgQueryDTO.java new file mode 100644 index 0000000..1fc3ebe --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/dto/ChatMsgQueryDTO.java @@ -0,0 +1,34 @@ +package com.senmesh.component.chat.dto; + + +import javax.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; + +import com.senmesh.common.dto.PageQueryDTO; + +/** + * @author sr on 2025-05-29 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "聊天消息查询条件") +public class ChatMsgQueryDTO extends PageQueryDTO{ + + /** **/ + private static final long serialVersionUID = 1L; + + private Long id; + @NotNull(message = "会话id不能为空") + private Long chatId; + + /** 大于id **/ + private Long idGt; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/chat/dto/ChatQueryDTO.java b/backend/src/main/java/com/senmesh/component/chat/dto/ChatQueryDTO.java new file mode 100644 index 0000000..5065520 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/dto/ChatQueryDTO.java @@ -0,0 +1,45 @@ +package com.senmesh.component.chat.dto; + + +import com.senmesh.component.chat.constant.ChatStatusEnum; +import com.senmesh.component.chat.constant.ChatTypeEnum; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Builder.Default; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; + +import com.senmesh.common.dto.PageQueryDTO; + +/** + * @author sr on 2025-05-29 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "聊天会话查询条件") +public class ChatQueryDTO extends PageQueryDTO{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + /** 机构id */ + private Long orgId; + /** 机构用户id */ + private Long orgUserId; + /** 个人用户id */ + private Long personUserId; + /** 状态:1有效,2关闭 */ + @Default + private Integer status = ChatStatusEnum.ACTIVE.getStatus(); + /** @see ChatTypeEnum 类型 */ + @Default + private String type = ChatTypeEnum.POSITION.getType(); + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/chat/entity/Chat.java b/backend/src/main/java/com/senmesh/component/chat/entity/Chat.java new file mode 100644 index 0000000..ac35441 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/entity/Chat.java @@ -0,0 +1,44 @@ +package com.senmesh.component.chat.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import com.senmesh.component.chat.constant.ChatStatusEnum; +import com.senmesh.component.chat.constant.ChatTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Builder.Default; +import lombok.experimental.SuperBuilder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 聊天会话 + * + * @author sr on 2025-05-29 + */ +@TableName("xs_chat") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class Chat extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + /** 机构id */ + private Long orgId; + /** 机构用户id */ + private Long orgUserId; + /** 个人用户id */ + private Long personUserId; + /** @see ChatTypeEnum 类型 */ + private String type; + /** 状态:1有效,2关闭 */ + @Default + private Integer status = ChatStatusEnum.ACTIVE.getStatus(); + + + +} diff --git a/backend/src/main/java/com/senmesh/component/chat/entity/ChatMsg.java b/backend/src/main/java/com/senmesh/component/chat/entity/ChatMsg.java new file mode 100644 index 0000000..5692c48 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/entity/ChatMsg.java @@ -0,0 +1,44 @@ +package com.senmesh.component.chat.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.component.chat.constant.ChatMsgStatusEnum; +import com.senmesh.component.chat.constant.ChatMsgTypeEnum; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Builder.Default; +import lombok.experimental.SuperBuilder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 聊天消息 + * + * @author sr on 2025-05-29 + */ +@TableName("xs_chat_msg") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class ChatMsg extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 聊天id */ + private Long chatId; + /** 发送用户id */ + private Long senderId; + /** 消息类型:text等 */ + @Default + private String msgType = ChatMsgTypeEnum.TEXT.getType(); + /** 内容 */ + private String content; + /** 消息状态:1未读,2已读 */ + @Default + private Integer msgStatus = ChatMsgStatusEnum.INIT.getStatus(); + +} diff --git a/backend/src/main/java/com/senmesh/component/chat/mapper/ChatMapper.xml b/backend/src/main/java/com/senmesh/component/chat/mapper/ChatMapper.xml new file mode 100644 index 0000000..ab15fa9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/mapper/ChatMapper.xml @@ -0,0 +1,34 @@ + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/chat/mapper/ChatMsgMapper.xml b/backend/src/main/java/com/senmesh/component/chat/mapper/ChatMsgMapper.xml new file mode 100644 index 0000000..498dc96 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/mapper/ChatMsgMapper.xml @@ -0,0 +1,23 @@ + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/chat/mapstruct/ChatMapMapper.java b/backend/src/main/java/com/senmesh/component/chat/mapstruct/ChatMapMapper.java new file mode 100644 index 0000000..3f98710 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/mapstruct/ChatMapMapper.java @@ -0,0 +1,39 @@ +package com.senmesh.component.chat.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.component.chat.dto.ChatDTO; +import com.senmesh.component.chat.entity.Chat; +import com.senmesh.component.chat.dto.ChatCreateDTO; + +/** + * @author sr on 2025-05-29 + */ +@Mapper +public interface ChatMapMapper { + + ChatMapMapper INSTANCE = + Mappers.getMapper(ChatMapMapper.class); + + /** + * dto to entity + * + * @param chatDto + * @return + * @author sr on 2025-05-29 + */ + Chat toEntity( + ChatDTO chatDto); + + + /** + * @param chatOperateDTO + * @return + * @author sr on 2025-05-29 + */ + Chat toEntity(ChatCreateDTO chatOperateDTO); + + ChatDTO toDTO(Chat chat); + +} diff --git a/backend/src/main/java/com/senmesh/component/chat/mapstruct/ChatMsgMapMapper.java b/backend/src/main/java/com/senmesh/component/chat/mapstruct/ChatMsgMapMapper.java new file mode 100644 index 0000000..25ed7ae --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/mapstruct/ChatMsgMapMapper.java @@ -0,0 +1,39 @@ +package com.senmesh.component.chat.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.component.chat.dto.ChatMsgDTO; +import com.senmesh.component.chat.entity.ChatMsg; +import com.senmesh.component.chat.dto.ChatMsgCreateDTO; + +/** + * @author sr on 2025-05-29 + */ +@Mapper +public interface ChatMsgMapMapper { + + ChatMsgMapMapper INSTANCE = + Mappers.getMapper(ChatMsgMapMapper.class); + + /** + * dto to entity + * + * @param chatMsgDto + * @return + * @author sr on 2025-05-29 + */ + ChatMsg toEntity( + ChatMsgDTO chatMsgDto); + + + /** + * @param chatMsgCreateDTO + * @return + * @author sr on 2025-05-29 + */ + ChatMsg toEntity(ChatMsgCreateDTO chatMsgCreateDTO); + + ChatMsgDTO toDto(ChatMsg chatMsg); + +} diff --git a/backend/src/main/java/com/senmesh/component/chat/service/ChatMsgService.java b/backend/src/main/java/com/senmesh/component/chat/service/ChatMsgService.java new file mode 100644 index 0000000..f08c31f --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/service/ChatMsgService.java @@ -0,0 +1,68 @@ +package com.senmesh.component.chat.service; + +import java.util.List; + +import com.senmesh.component.chat.dto.ChatMsgQueryDTO; +import com.senmesh.component.chat.dto.ChatMsgCreateDTO; +import com.senmesh.component.chat.dto.ChatMsgDTO; + +/** + * 聊天消息 + * + * @author sr on 2025-05-29 + */ +public interface ChatMsgService { + + /** + * 新增 + * + * @param chatMsgCreateDTO + * @return + * @author sr on 2025-05-29 + */ + Long create(ChatMsgCreateDTO chatMsgCreateDTO); + + /** + * 修改 + * + * @param chatMsgCreateDTO + * @author sr on 2025-05-29 + */ + void modify(ChatMsgCreateDTO chatMsgCreateDTO); + + /** + * 删除 + * + * @param id + * @author sr on 2025-05-29 + */ + void remove(Long id); + + /** + * 查询 + * + * @param chatMsgQueryDTO + * @return + * @author sr on 2025-05-29 + */ + List list(ChatMsgQueryDTO chatMsgQueryDTO); + + /** + * 分页查询 + * + * @param chatMsgQueryDTO + * @return + * @author sr on 2025-05-29 + */ + void page(ChatMsgQueryDTO chatMsgQueryDTO); + + /** + * 单个查询 + * + * @param chatMsgQueryDTO + * @return + * @author sr on 2025-05-29 + */ + ChatMsgDTO find(ChatMsgQueryDTO chatMsgQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/component/chat/service/ChatService.java b/backend/src/main/java/com/senmesh/component/chat/service/ChatService.java new file mode 100644 index 0000000..e36bea6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/service/ChatService.java @@ -0,0 +1,61 @@ +package com.senmesh.component.chat.service; + +import java.util.List; + +import com.senmesh.component.chat.dto.ChatQueryDTO; +import com.senmesh.component.chat.dto.ChatCreateDTO; +import com.senmesh.component.chat.dto.ChatDTO; + +/** + * 聊天会话 + * + * @author sr on 2025-05-29 + */ +public interface ChatService { + + /** + * 新增 + * + * @param chatCreateDTO + * @return + * @author sr on 2025-05-29 + */ + Long create(ChatCreateDTO chatCreateDTO); + + + /** + * 删除 + * + * @param id + * @author sr on 2025-05-29 + */ + void remove(Long id); + + /** + * 查询 + * + * @param chatQueryDTO + * @return + * @author sr on 2025-05-29 + */ + List list(ChatQueryDTO chatQueryDTO); + + /** + * 分页查询 + * + * @param chatQueryDTO + * @return + * @author sr on 2025-05-29 + */ + void page(ChatQueryDTO chatQueryDTO); + + /** + * 单个查询 + * + * @param chatQueryDTO + * @return + * @author sr on 2025-05-29 + */ + ChatDTO find(ChatQueryDTO chatQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/component/chat/service/impl/ChatMsgServiceImpl.java b/backend/src/main/java/com/senmesh/component/chat/service/impl/ChatMsgServiceImpl.java new file mode 100644 index 0000000..74a1369 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/service/impl/ChatMsgServiceImpl.java @@ -0,0 +1,107 @@ +package com.senmesh.component.chat.service.impl; + +import com.senmesh.component.chat.dto.ChatCreateDTO; +import com.senmesh.component.chat.dto.ChatDTO; +import com.senmesh.component.chat.dto.ChatQueryDTO; +import com.senmesh.component.chat.mapstruct.ChatMsgMapMapper; +import com.senmesh.component.chat.service.ChatService; +import com.senmesh.component.notice.constant.NoticeFirstTypeEnum; +import com.senmesh.component.notice.dto.NoticeMsgDTO; +import com.senmesh.component.notice.util.NoticeUtils; +import com.senmesh.usercenter.user.constant.UserTypeEnum; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.component.chat.dao.ChatMsgMapper; +import com.senmesh.component.chat.service.ChatMsgService; +import com.senmesh.component.chat.dto.ChatMsgQueryDTO; +import com.senmesh.component.chat.dto.ChatMsgDTO; +import com.senmesh.component.chat.dto.ChatMsgCreateDTO; +import com.senmesh.component.chat.entity.ChatMsg; + +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.common.util.ListUtil; + +/** + * @author sr on 2025-05-29 + */ +@Service +public class ChatMsgServiceImpl implements ChatMsgService { + + private static final Logger log = LoggerFactory.getLogger(ChatMsgServiceImpl.class); + @Autowired + private ChatMsgMapper chatMsgMapper; + + @Autowired + private ChatService chatService; + + @Override + @Transactional + public Long create(ChatMsgCreateDTO chatMsgCreateDTO) { + Long chatId = chatMsgCreateDTO.getChatId(); + Long senderId = UserContextHolder.getLoginUserId(); + Long personUserId = chatMsgCreateDTO.getPersonUserId(); + if (UserTypeEnum.PERSON.getType().equals(UserContextHolder.getUserType())){ + personUserId = senderId; + } + if (chatId == null) { + chatId = chatService.create(ChatCreateDTO.builder().orgId(chatMsgCreateDTO.getOrgId()) + .personUserId(personUserId).build()); + } + ChatMsg msg = ChatMsg.builder().chatId(chatId).senderId(senderId).content(chatMsgCreateDTO.getContent()).build(); + chatMsgMapper.saveEntity(msg); + // 发通知 + this.sendAsyncNotice(chatId, ChatMsgMapMapper.INSTANCE.toDto(msg)); + return msg.getId(); + } + + private void sendAsyncNotice(Long chatId, ChatMsgDTO msgDTO) { + try { + ChatDTO chatDTO = chatService.find(ChatQueryDTO.builder().id(chatId).build()); + Long receiverId = + msgDTO.getSenderId().equals(chatDTO.getPersonUserId()) ? chatDTO.getOrgUserId() + : chatDTO.getPersonUserId(); + NoticeUtils.sendAsyncNotice( + NoticeMsgDTO.create(receiverId, NoticeFirstTypeEnum.CHAT.getType(), msgDTO)); + } catch (Exception e) { + log.info("chat发送异步消息失败", e.getMessage()); + } + } + + + @Override + @Transactional + public void modify(ChatMsgCreateDTO chatMsgCreateDTO) { + // TODO Auto-generated method stub + + } + + @Override + @Transactional + public void remove(Long id) { + chatMsgMapper.deleteEntity(ChatMsg.builder().id(id).build(), + UserContextHolder.getLoginUserId()); + } + + @Override + public List list(ChatMsgQueryDTO chatMsgQueryDTO) { + chatMsgQueryDTO.disablePage(); + return chatMsgMapper.listChatMsgDTO(chatMsgQueryDTO); + } + + @Override + public void page(ChatMsgQueryDTO chatMsgQueryDTO) { + chatMsgMapper.listChatMsgDTO(chatMsgQueryDTO); + } + + @Override + public ChatMsgDTO find(ChatMsgQueryDTO chatMsgQueryDTO) { + List chatMsgDTOs = this.list(chatMsgQueryDTO); + return ListUtil.first(chatMsgDTOs); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/chat/service/impl/ChatServiceImpl.java b/backend/src/main/java/com/senmesh/component/chat/service/impl/ChatServiceImpl.java new file mode 100644 index 0000000..7d559b4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/service/impl/ChatServiceImpl.java @@ -0,0 +1,97 @@ +package com.senmesh.component.chat.service.impl; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.validation.util.ValidateUtils; +import com.senmesh.component.chat.constant.ChatStatusEnum; +import com.senmesh.component.chat.mapstruct.ChatMapMapper; +import com.senmesh.frame.redis.dto.LockDTO; +import com.senmesh.frame.redis.redisson.RedissonUtils; +import com.senmesh.usercenter.user.dao.OrgUserMapper; +import com.senmesh.usercenter.user.dto.OrgUserDTO; +import com.senmesh.usercenter.user.dto.OrgUserQueryDTO; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.component.chat.dao.ChatMapper; +import com.senmesh.component.chat.service.ChatService; +import com.senmesh.component.chat.dto.ChatQueryDTO; +import com.senmesh.component.chat.dto.ChatDTO; +import com.senmesh.component.chat.dto.ChatCreateDTO; +import com.senmesh.component.chat.entity.Chat; + +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.common.util.ListUtil; + +/** + * @author sr on 2025-05-29 + */ +@Service +public class ChatServiceImpl implements ChatService { + + @Autowired + private ChatMapper chatMapper; + + @Autowired + private OrgUserMapper orgUserMapper; + + public static LockDTO getLockDTO(Long orgId, Long personUserId) { + Assert.notNull(orgId, "机构id不能为空"); + Assert.notNull(personUserId, "个人用户id不能为空"); + return LockDTO.builder().methodName("chat").tryLockWaitTime(0L) + .arg(orgId.toString()) + .arg(personUserId.toString()) + .failMsg("该机构-个人聊天正在被操作") + .build(); + } + + @Override + @Transactional + public Long create(ChatCreateDTO createDTO) { + ValidateUtils.validateBiz(createDTO); + Long orgId = createDTO.getOrgId(); + Long personUserId = createDTO.getPersonUserId(); + ChatQueryDTO queryDTO = ChatQueryDTO.builder().orgId(orgId).personUserId(personUserId).status( + ChatStatusEnum.ACTIVE.getStatus()).build(); + + ChatDTO chatDTO = RedissonUtils.lockAndSave(getLockDTO(orgId, personUserId), + () -> this.find(queryDTO), () -> { + List orgUserDTOs = orgUserMapper.listOrgUserDTO( + OrgUserQueryDTO.builder().orgId(orgId).administrator(Boolean.TRUE).build()); + Assert.isTrue(orgUserDTOs.size() == 1, orgId + ":机构管理员信息异常,请联系管理员"); + Chat chat = + ChatMapMapper.INSTANCE.toEntity(createDTO); + chat.setOrgUserId(orgUserDTOs.get(0).getUserId()); + chat.setStatus(ChatStatusEnum.ACTIVE.getStatus()); + chatMapper.saveEntity(chat); + return ChatMapMapper.INSTANCE.toDTO(chat); + }); + return chatDTO.getId(); + } + + @Override + @Transactional + public void remove(Long id) { + chatMapper.deleteEntity(Chat.builder().id(id).build(), + UserContextHolder.getLoginUserId()); + } + + @Override + public List list(ChatQueryDTO chatQueryDTO) { + chatQueryDTO.disablePage(); + return chatMapper.listChatDTO(chatQueryDTO); + } + + @Override + public void page(ChatQueryDTO chatQueryDTO) { + chatMapper.listChatDTO(chatQueryDTO); + } + + @Override + public ChatDTO find(ChatQueryDTO chatQueryDTO) { + List chatDTOs = this.list(chatQueryDTO); + return ListUtil.first(chatDTOs); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/chat/util/ChatMsgUtils.java b/backend/src/main/java/com/senmesh/component/chat/util/ChatMsgUtils.java new file mode 100644 index 0000000..9ceed4c --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/util/ChatMsgUtils.java @@ -0,0 +1,8 @@ +package com.senmesh.component.chat.util; + +/** + * @author sr on 2025-05-29 + */ +public class ChatMsgUtils { + +} diff --git a/backend/src/main/java/com/senmesh/component/chat/util/ChatUtils.java b/backend/src/main/java/com/senmesh/component/chat/util/ChatUtils.java new file mode 100644 index 0000000..8a01ccd --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/chat/util/ChatUtils.java @@ -0,0 +1,8 @@ +package com.senmesh.component.chat.util; + +/** + * @author sr on 2025-05-29 + */ +public class ChatUtils { + +} diff --git a/backend/src/main/java/com/senmesh/component/commonimport/constant/ImportDetailStatusEnum.java b/backend/src/main/java/com/senmesh/component/commonimport/constant/ImportDetailStatusEnum.java new file mode 100644 index 0000000..02868fe --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/constant/ImportDetailStatusEnum.java @@ -0,0 +1,29 @@ +package com.senmesh.component.commonimport.constant; + +/** + * 通用导入明细状态 + * @author sr on 2024-01-19 + */ +public enum ImportDetailStatusEnum { + /** 新建 **/ + INIT(1), + /** 校验成功 **/ + CHECK_SUCCESS(2), + /** 校验失败 **/ + CHECK_FAIL(3), + ; + + + + private Integer status; + + ImportDetailStatusEnum(Integer status) { + this.status = status; + } + + public Integer getStatus() { + return status; + } + + +} diff --git a/backend/src/main/java/com/senmesh/component/commonimport/constant/ImportExecuteTypeEnum.java b/backend/src/main/java/com/senmesh/component/commonimport/constant/ImportExecuteTypeEnum.java new file mode 100644 index 0000000..870e7b2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/constant/ImportExecuteTypeEnum.java @@ -0,0 +1,28 @@ +package com.senmesh.component.commonimport.constant; + +/** + * 指定执行类型 + * @author sr on 2024-01-23 + */ +public enum ImportExecuteTypeEnum { + /** 普通 **/ + NORMAL(1), + /** 指定外部id **/ + EXTRA_ID(2), + /** 明细表单 **/ + DETAIL_FORM(3), + ; + + + + + private Integer type; + + ImportExecuteTypeEnum(Integer type) { + this.type = type; + } + + public Integer getType() { + return type; + } +} diff --git a/backend/src/main/java/com/senmesh/component/commonimport/constant/ImportStatusEnum.java b/backend/src/main/java/com/senmesh/component/commonimport/constant/ImportStatusEnum.java new file mode 100644 index 0000000..457b1b9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/constant/ImportStatusEnum.java @@ -0,0 +1,58 @@ +package com.senmesh.component.commonimport.constant; + +import java.util.Map; + +import com.google.common.collect.Maps; + +/** + * 通用导入状态 + * @author sr on 2024-01-19 + */ +public enum ImportStatusEnum { + + /** 新建 **/ + INIT(1, "新建"), + /** 解析失败 **/ + ANALY_FAIL(2, "解析失败"), + /** 校验中 **/ + CHECKING(3, "校验中"), + /** 校验失败 **/ + CHECK_FAIL(4, "校验失败"), + /** 校验完成 **/ + CHECKED(5, "校验完成"), + /** 执行导入完成 **/ + EXECUTE(6, "已完成"), + ; + + + private static Map importStatusMap ; + static { + ImportStatusEnum[] importStatusEnums = ImportStatusEnum.values(); + importStatusMap = Maps.newHashMapWithExpectedSize(importStatusEnums.length); + for(ImportStatusEnum e: importStatusEnums) { + importStatusMap.put(e.getStatus(), e); + } + } + + private Integer status; + private String name; + + ImportStatusEnum(Integer status, String name) { + this.status = status; + } + + public Integer getStatus() { + return status; + } + + public String getName() { + return name; + } + + public static ImportStatusEnum get(Integer status) { + return importStatusMap.get(status); + } + + + +} diff --git a/backend/src/main/java/com/senmesh/component/commonimport/constant/ImportTypeEnum.java b/backend/src/main/java/com/senmesh/component/commonimport/constant/ImportTypeEnum.java new file mode 100644 index 0000000..46172c8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/constant/ImportTypeEnum.java @@ -0,0 +1,50 @@ +package com.senmesh.component.commonimport.constant; + +import java.util.Map; + +import com.google.common.collect.Maps; + +/** + * 导入类型 + * @author sr on 2024-01-23 + */ +public enum ImportTypeEnum { + + TALENT("talent", "人才库导入"), + POSITION("position", "岗位导入"), + ADMIN_POSITION("admin_position", "admin岗位导入"), + ORG("org", "机构导入"), + ; + + private String type; + private String name; + + + private static Map importTypeMap ; + static { + ImportTypeEnum[] importTypeEnums = ImportTypeEnum.values(); + importTypeMap = Maps.newHashMapWithExpectedSize(importTypeEnums.length); + for(ImportTypeEnum e: importTypeEnums) { + importTypeMap.put(e.getType(), e); + } + } + + ImportTypeEnum(String type, String name) { + this.type = type; + this.name = name; + } + + public String getType() { + return type; + } + + public String getName() { + return name; + } + + public static ImportTypeEnum get(String type) { + return importTypeMap.get(type); + } + + +} diff --git a/backend/src/main/java/com/senmesh/component/commonimport/controller/CommonImportController.java b/backend/src/main/java/com/senmesh/component/commonimport/controller/CommonImportController.java new file mode 100644 index 0000000..d5ae573 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/controller/CommonImportController.java @@ -0,0 +1,107 @@ +package com.senmesh.component.commonimport.controller; + +import java.util.Map; + +import org.apache.poi.ss.formula.functions.T; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +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; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.component.commonimport.dto.ImportDetailPageDTO; +import com.senmesh.component.commonimport.dto.ImportMainCreateDTO; +import com.senmesh.component.commonimport.dto.ImportMainCreateFormDTO; +import com.senmesh.component.commonimport.dto.ImportMainDTO; +import com.senmesh.component.commonimport.dto.ImportMainQueryDTO; +import com.senmesh.component.commonimport.service.impl.CommonImportAdapter; +import com.senmesh.config.dto.ConfigDTO; +import com.senmesh.tkmybatis.pojo.Page; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2024-01-19 + */ +@RestController +@RequestMapping("common_import") +@Api(tags = "通用导入") +public class CommonImportController { + + @Autowired(required = false) + private CommonImportAdapter commonImportAdapter; + + @GetMapping("/template/{type}") + @ApiOperation("模版") + public AlitaResult template(@PathVariable String type){ + Assert.notNull(commonImportAdapter, "无通用导入提供者"); + return AlitaResult.success(commonImportAdapter.template(type)); + } + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(ImportMainQueryDTO queryDTO){ + Assert.notNull(commonImportAdapter, "无通用导入提供者"); + commonImportAdapter.page(queryDTO); + return AlitaResult.success(queryDTO.getPageResult()); + } + + @GetMapping("/find") + @ApiOperation("单个查询") + public AlitaResult find(ImportMainQueryDTO queryDTO){ + Assert.notNull(commonImportAdapter, "无通用导入提供者"); + return AlitaResult.success(commonImportAdapter.find(queryDTO)); + } + + @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create( + @Validated @RequestBody ImportMainCreateDTO createDTO){ + Assert.notNull(commonImportAdapter, "无通用导入提供者"); + return AlitaResult.success(commonImportAdapter.create(createDTO)); + } + + @PostMapping("/create_async") + @ApiOperation("创建(异步)") + public AlitaResult createAsync( + @Validated @RequestBody ImportMainCreateDTO createDTO){ + Assert.notNull(commonImportAdapter, "无通用导入提供者"); + return AlitaResult.success(commonImportAdapter.createAsync(createDTO)); + } + + @PostMapping("/create_form") + @ApiOperation("创建(明细form)") + public AlitaResult createForm( + @Validated @RequestBody ImportMainCreateFormDTO createDTO){ + Assert.notNull(commonImportAdapter, "无通用导入提供者"); + return AlitaResult.success(commonImportAdapter.createForm(createDTO)); + } + + @PostMapping("/confirm/{type}") + @ApiOperation("执行导入") + public AlitaResult confirm(@PathVariable String type, + @RequestBody Map executeDto){ + Assert.notNull(commonImportAdapter, "无通用导入提供者"); + return AlitaResult.success(commonImportAdapter.confirmImport(type, executeDto)); + } + + @GetMapping("/pageDetail") + @ApiOperation("导入明细分页") + public AlitaResult> pageDetail(@Validated ImportDetailPageDTO importDetailPageDTO) { + Assert.notNull(commonImportAdapter, "无通用导入提供者"); + return AlitaResult.success(commonImportAdapter.pageDetail(importDetailPageDTO)); + } + + @GetMapping("/importDetailExport") + @ApiOperation("导入明细分页") + public void importDetailExport(@Validated ImportDetailPageDTO importDetailPageDTO) { + Assert.notNull(commonImportAdapter, "无通用导入提供者"); + commonImportAdapter.importDetailExport(importDetailPageDTO); + } +} diff --git a/backend/src/main/java/com/senmesh/component/commonimport/dao/ImportMainMapper.java b/backend/src/main/java/com/senmesh/component/commonimport/dao/ImportMainMapper.java new file mode 100644 index 0000000..4cde287 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/dao/ImportMainMapper.java @@ -0,0 +1,31 @@ +package com.senmesh.component.commonimport.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.component.commonimport.dto.ImportMainDTO; +import com.senmesh.component.commonimport.dto.ImportMainQueryDTO; +import com.senmesh.component.commonimport.dto.ImportMainUpdateDTO; +import com.senmesh.component.commonimport.entity.UcImportMain; +import com.senmesh.tkmybatis.mybatis.MyMapper; + +/** + * 通用导入 + * + * @author sr on 2024-01-19 + */ +public interface ImportMainMapper extends MyMapper { + + /** + * 查询 + * + * @param importMainQueryDTO + * @return + * @author sr on 2024-01-19 + */ + List listImportMainDTO(@Param("param") ImportMainQueryDTO importMainQueryDTO); + + int modify(@Param("param") ImportMainUpdateDTO updateDto); + +} diff --git a/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportDetailPageDTO.java b/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportDetailPageDTO.java new file mode 100644 index 0000000..48a2c93 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportDetailPageDTO.java @@ -0,0 +1,36 @@ +package com.senmesh.component.commonimport.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotNull; + +import lombok.Data; + +/** + * @description: + * @author: guixinman + * @create: 2024-01-30 14:04 + **/ +@Data +public class ImportDetailPageDTO implements Serializable { + + @NotNull(message = "参数异常") + private Long mainId; + + @NotNull(message = "参数异常") + private String type; + + /** + * 第几页 + **/ + private Integer pageNo = 1; + /** + * 页宽 + **/ + private Integer pageSize = 20; + + /** 导入状态:1新建,2校验成功,3校验失败 **/ + private Integer detailStatus; +} + + diff --git a/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportDetailSuperDTO.java b/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportDetailSuperDTO.java new file mode 100644 index 0000000..13606d1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportDetailSuperDTO.java @@ -0,0 +1,41 @@ +package com.senmesh.component.commonimport.dto; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2024-01-19 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "通用导入") +public class ImportDetailSuperDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 批次id **/ + private Long mainId; + /** 导入状态:1新建,2校验成功,3校验失败 **/ + private Integer detailStatus; + /** 失败原因 **/ + private String failReason; + /** 备注 **/ + private String remark; + /** 外部生成明细id **/ + private Long extraDetailId; + + + + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportExecuteSuperDTO.java b/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportExecuteSuperDTO.java new file mode 100644 index 0000000..1f4952c --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportExecuteSuperDTO.java @@ -0,0 +1,40 @@ +package com.senmesh.component.commonimport.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotNull; + +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2024-01-19 + */ +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Data +@ApiModel(description = "通用导入执行") +public class ImportExecuteSuperDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + /** 批次id **/ + @NotNull(message = "导入id不能为空") + private Long mainId; + + + /**(后台设置)执行类型:1.普通,2.指定外部id **/ + private Integer executeType; + /**(后台设置)外部生成id(可为空) **/ + private Long extraId; + + + + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportMainCreateDTO.java b/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportMainCreateDTO.java new file mode 100644 index 0000000..0bbdd17 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportMainCreateDTO.java @@ -0,0 +1,45 @@ +package com.senmesh.component.commonimport.dto; + +import javax.validation.constraints.NotBlank; + +import com.senmesh.common.dto.BaseOperateDTO; +import com.senmesh.component.commonimport.constant.ImportExecuteTypeEnum; + +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.Builder.Default; + +/** + * @author sr on 2024-01-19 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "通用导入操作") +public class ImportMainCreateDTO extends BaseOperateDTO{ + + /** **/ + private static final long serialVersionUID = 1L; + /** 导入类型 **/ + @NotBlank(message = "导入类型不能为空") + private String type; + /** 文件CODE **/ + @NotBlank(message = "文件code不能为空") + private String fileCode; + /** 文件名称 **/ + @NotBlank(message = "文件名称不能为空") + private String fileName; + /** 备注 **/ + private String remark; + /** 执行类型:1.普通,2.指定外部id **/ + @Default + private Integer executeType = ImportExecuteTypeEnum.NORMAL.getType(); + /** 外部生成id **/ + private Long extraId; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportMainCreateFormDTO.java b/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportMainCreateFormDTO.java new file mode 100644 index 0000000..0dca8e5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportMainCreateFormDTO.java @@ -0,0 +1,39 @@ +package com.senmesh.component.commonimport.dto; + +import java.util.List; +import java.util.Map; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2024-01-19 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "通用导入操作(form)") +public class ImportMainCreateFormDTO extends BaseOperateDTO{ + + /** **/ + private static final long serialVersionUID = 1L; + /** 导入类型 **/ + @NotBlank(message = "导入类型不能为空") + private String type; + /** 备注 **/ + private String remark; + @NotNull(message = "明细不能为空") + private List> details; + + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportMainDTO.java b/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportMainDTO.java new file mode 100644 index 0000000..b118641 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportMainDTO.java @@ -0,0 +1,59 @@ +package com.senmesh.component.commonimport.dto; + +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2024-01-19 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "通用导入") +public class ImportMainDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 批次号 **/ + private String importNo; + /** 导入类型 **/ + private String type; + /** 导入状态:1新建,2解析失败,3校验中,4校验失败,5校验成功,6执行导入完成 **/ + private Integer importStatus; + /** 总数 **/ + private Integer totalNum; + /** 成功数 **/ + private Integer successNum; + /** 失败原因 **/ + private String failMsg; + /** 完成时间时间 **/ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date finishTime; + /** 执行类型:1.普通,2.指定外部id,3.明细表单 **/ + private Integer executeType; + /** 外部生成id **/ + private Long extraId; + /** 文件CODE **/ + private String fileCode; + /** 文件名称 **/ + private String fileName; + /** 机构ID **/ + private Long orgId; + /** 备注 **/ + private String remark; + + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportMainQueryDTO.java b/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportMainQueryDTO.java new file mode 100644 index 0000000..1bc5537 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportMainQueryDTO.java @@ -0,0 +1,64 @@ +package com.senmesh.component.commonimport.dto; + + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; + +import java.util.Date; + +import org.springframework.format.annotation.DateTimeFormat; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.senmesh.common.dto.PageQueryDTO; + +/** + * @author sr on 2024-01-19 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "通用导入查询条件") +public class ImportMainQueryDTO extends PageQueryDTO{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + /** 批次号 **/ + private String importNo; + /** 导入类型 **/ + private String type; + /** 导入状态:1新建,2解析失败,3校验中,4校验失败,5校验成功,6执行导入完成 **/ + private Integer importStatus; + /** 文件名称 **/ + private String fileNameLike; + /** 外部生成id **/ + private Long extraId; + + @ApiModelProperty("创建时间起,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTimeStart; + @ApiModelProperty("创建时间止,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTimeEnd; + + @ApiModelProperty("完成时间起,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date finishTimeStart; + @ApiModelProperty("完成时间止,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date finishTimeEnd; + + private Long orgId; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportMainUpdateDTO.java b/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportMainUpdateDTO.java new file mode 100644 index 0000000..725ad9e --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/dto/ImportMainUpdateDTO.java @@ -0,0 +1,48 @@ +package com.senmesh.component.commonimport.dto; + +import java.util.Date; +import java.util.Set; + +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2024-01-19 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "通用导入修改") +public class ImportMainUpdateDTO extends BaseOperateDTO{ + + /** **/ + private static final long serialVersionUID = 1L; + /** id **/ + @NotNull(message = "id不能为空") + private Long id; + /** 原状态 **/ + @NotNull(message = "原状态不能为空") + private Set oldStatusSet; + /** 新状态 **/ + @NotNull(message = "新状态不能为空") + private Integer newStatus; + /** 总数 **/ + private Integer totalNum; + /** 成功数 **/ + private Integer successNum; + /** 失败原因 **/ + private String failMsg; + /** 完成时间时间 **/ + private Date finishTime; + /** 外部生成id **/ + private Long extraId; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/commonimport/entity/UcImportMain.java b/backend/src/main/java/com/senmesh/component/commonimport/entity/UcImportMain.java new file mode 100644 index 0000000..76e8b50 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/entity/UcImportMain.java @@ -0,0 +1,57 @@ +package com.senmesh.component.commonimport.entity; + +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 通用导入 + * + * @author sr on 2024-01-19 + */ +@TableName("uc_import_main") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class UcImportMain extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 批次号 **/ + private String importNo; + /** 导入类型 **/ + private String type; + /** 导入状态:1新建,2解析失败,3校验中,4校验失败,5校验成功,6执行导入完成 **/ + private Integer importStatus; + /** 总数 **/ + private Integer totalNum; + /** 成功数 **/ + private Integer successNum; + /** 失败原因 **/ + private String failMsg; + /** 完成时间时间 **/ + private Date finishTime; + /** 执行类型:1.普通,2.指定外部id,3.明细表单 **/ + private Integer executeType; + /** 外部生成id **/ + private Long extraId; + /** 文件CODE **/ + private String fileCode; + /** 文件名称 **/ + private String fileName; + /** 机构ID **/ + private Long orgId; + /** 备注 **/ + private String remark; + +} diff --git a/backend/src/main/java/com/senmesh/component/commonimport/mapper/ImportMainMapper.xml b/backend/src/main/java/com/senmesh/component/commonimport/mapper/ImportMainMapper.xml new file mode 100644 index 0000000..fc5ec17 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/mapper/ImportMainMapper.xml @@ -0,0 +1,81 @@ + + + + + + + update uc_import_main + set + + import_status = #{param.newStatus}, + + + extra_id = #{param.extraId}, + + + total_num = #{param.totalNum}, + + + success_num = #{param.successNum}, + + + fail_msg = #{param.failMsg}, + + + finish_time = #{param.finishTime}, + + update_by = #{param.operateUserId}, + update_time = now() + where deleted = FALSE + and id = #{param.id} + and import_status in + + #{oldStatus} + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/commonimport/mapstruct/ImportMainMapMapper.java b/backend/src/main/java/com/senmesh/component/commonimport/mapstruct/ImportMainMapMapper.java new file mode 100644 index 0000000..93fb4b6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/mapstruct/ImportMainMapMapper.java @@ -0,0 +1,34 @@ +package com.senmesh.component.commonimport.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.component.commonimport.dto.ImportMainCreateDTO; +import com.senmesh.component.commonimport.dto.ImportMainCreateFormDTO; +import com.senmesh.component.commonimport.dto.ImportMainDTO; +import com.senmesh.component.commonimport.entity.UcImportMain; + +/** + * @author sr on 2024-01-19 + */ +@Mapper +public interface ImportMainMapMapper { + + ImportMainMapMapper INSTANCE = + Mappers.getMapper(ImportMainMapMapper.class); + + /** + * dto to entity + * + * @param importMainDto + * @return + * @author sr on 2024-01-19 + */ + UcImportMain toEntity( + ImportMainDTO importMainDto); + + UcImportMain to(ImportMainCreateDTO createDto); + UcImportMain to(ImportMainCreateFormDTO createDto); + + +} diff --git a/backend/src/main/java/com/senmesh/component/commonimport/service/ICommonImportProvider.java b/backend/src/main/java/com/senmesh/component/commonimport/service/ICommonImportProvider.java new file mode 100644 index 0000000..33075ff --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/service/ICommonImportProvider.java @@ -0,0 +1,64 @@ +package com.senmesh.component.commonimport.service; + +import java.util.List; + +import com.senmesh.component.commonimport.dto.ImportDetailPageDTO; +import com.senmesh.component.commonimport.dto.ImportDetailSuperDTO; +import com.senmesh.component.commonimport.dto.ImportExecuteSuperDTO; +import com.senmesh.component.commonimport.dto.ImportMainCreateDTO; +import com.senmesh.component.commonimport.dto.ImportMainCreateFormDTO; +import com.senmesh.tkmybatis.pojo.Page; + +public interface ICommonImportProvider { + + String getType(); + + /** + * 同步导入 + * @param createDto + * @return 导入批次头id + * @author sr on 2024-01-22 + */ + Long syncImport(ImportMainCreateDTO createDto); + + /** + * 异步导入 + * @param createDto + * @return 导入批次头id + * @author sr on 2024-01-22 + */ + Long ayncImport(ImportMainCreateDTO createDto); + + /** + * 确认导入 + * @param executeDto + * @return 外部id + * @author sr on 2024-01-23 + */ + Long confirmImport(IE executeDto); + + /** + * 同步导入(明细form) + * @param createDto + * @param detailCreateDtos + * @return + * @author sr on 2024-01-26 + */ + Long syncImportFrom(ImportMainCreateFormDTO createDto, List detailCreateDtos); + + /** + * @description: 通用明细查询 + * @return: + * @author: guixinman + * @param: + */ + Page pageDetail(ImportDetailPageDTO importDetailPageDTO); + + /** + * @description: 通用明细导出数据 + * @return: + * @author: guixinman + * @param: + */ + void importDetailExport(ImportDetailPageDTO importDetailPageDTO); +} diff --git a/backend/src/main/java/com/senmesh/component/commonimport/service/IImportDetailForm.java b/backend/src/main/java/com/senmesh/component/commonimport/service/IImportDetailForm.java new file mode 100644 index 0000000..4043c56 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/service/IImportDetailForm.java @@ -0,0 +1,9 @@ +package com.senmesh.component.commonimport.service; + +/** + * 明细form + * @author sr on 2024-01-26 + */ +public interface IImportDetailForm { + +} diff --git a/backend/src/main/java/com/senmesh/component/commonimport/service/ImportDetailSuperQueryDTO.java b/backend/src/main/java/com/senmesh/component/commonimport/service/ImportDetailSuperQueryDTO.java new file mode 100644 index 0000000..55715b8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/service/ImportDetailSuperQueryDTO.java @@ -0,0 +1,11 @@ +package com.senmesh.component.commonimport.service; + +/** + * @description: 导入详情分页查询 + * @author: guixinman + * @create: 2024-01-30 13:27 + **/ + +public interface ImportDetailSuperQueryDTO { + +} diff --git a/backend/src/main/java/com/senmesh/component/commonimport/service/ImportMainService.java b/backend/src/main/java/com/senmesh/component/commonimport/service/ImportMainService.java new file mode 100644 index 0000000..901343d --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/service/ImportMainService.java @@ -0,0 +1,78 @@ +package com.senmesh.component.commonimport.service; + +import java.util.List; + +import com.senmesh.component.commonimport.dto.ImportMainCreateDTO; +import com.senmesh.component.commonimport.dto.ImportMainCreateFormDTO; +import com.senmesh.component.commonimport.dto.ImportMainDTO; +import com.senmesh.component.commonimport.dto.ImportMainQueryDTO; +import com.senmesh.component.commonimport.dto.ImportMainUpdateDTO; + +/** + * 通用导入 + * + * @author sr on 2024-01-19 + */ +public interface ImportMainService { + + /** + * 新增 + * + * @param importMainOperateDTO + * @return + * @author sr on 2024-01-19 + */ + Long create(ImportMainCreateDTO createDto); + + /** + * 修改 + * + * @param updateDto + * @author sr on 2024-01-19 + */ + void modify(ImportMainUpdateDTO updateDto); + + /** + * 删除 + * + * @param id + * @author sr on 2024-01-19 + */ + void remove(Long id); + + /** + * 查询 + * + * @param importMainQueryDTO + * @return + * @author sr on 2024-01-19 + */ + List list(ImportMainQueryDTO importMainQueryDTO); + + /** + * 分页查询 + * + * @param importMainQueryDTO + * @return + * @author sr on 2024-01-19 + */ + void page(ImportMainQueryDTO importMainQueryDTO); + + /** + * 单个查询 + * + * @param importMainQueryDTO + * @return + * @author sr on 2024-01-19 + */ + ImportMainDTO find(ImportMainQueryDTO importMainQueryDTO); + + /** + * 明细表单保存 + * @param createDto + * @return + * @author sr on 2024-01-26 + */ + Long createForm(ImportMainCreateFormDTO createDto); + +} diff --git a/backend/src/main/java/com/senmesh/component/commonimport/service/impl/AbstractCommonImportProvider.java b/backend/src/main/java/com/senmesh/component/commonimport/service/impl/AbstractCommonImportProvider.java new file mode 100644 index 0000000..f9e283c --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/service/impl/AbstractCommonImportProvider.java @@ -0,0 +1,236 @@ +package com.senmesh.component.commonimport.service.impl; + +import java.util.Date; +import java.util.List; + +import com.google.common.collect.Sets; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.common.util.MockUtils; +import com.senmesh.common.validation.util.ValidateUtils; +import com.senmesh.component.asyntasknotice.constant.AsyncTaskTypeEnum; +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeCreateDTO; +import com.senmesh.component.asyntasknotice.dto.AsyncTaskNoticeFinishDTO; +import com.senmesh.component.asyntasknotice.util.AsyncTaskNoticeUtils; +import com.senmesh.component.commonimport.constant.ImportDetailStatusEnum; +import com.senmesh.component.commonimport.constant.ImportExecuteTypeEnum; +import com.senmesh.component.commonimport.constant.ImportStatusEnum; +import com.senmesh.component.commonimport.constant.ImportTypeEnum; +import com.senmesh.component.commonimport.dto.ImportDetailSuperDTO; +import com.senmesh.component.commonimport.dto.ImportExecuteSuperDTO; +import com.senmesh.component.commonimport.dto.ImportMainCreateDTO; +import com.senmesh.component.commonimport.dto.ImportMainCreateFormDTO; +import com.senmesh.component.commonimport.dto.ImportMainDTO; +import com.senmesh.component.commonimport.dto.ImportMainQueryDTO; +import com.senmesh.component.commonimport.dto.ImportMainUpdateDTO; +import com.senmesh.component.commonimport.service.ICommonImportProvider; +import com.senmesh.component.commonimport.service.IImportDetailForm; +import com.senmesh.component.commonimport.service.ImportMainService; +import com.senmesh.mq.consumer.handler.ITopicMqHandler; +import com.senmesh.mq.dto.TopicMqMessage; +import com.senmesh.mq.util.MqSendUtils; + +import org.springframework.aop.framework.AopContext; +import org.springframework.transaction.annotation.Transactional; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public abstract class AbstractCommonImportProvider + implements ICommonImportProvider, ITopicMqHandler { + + private ImportMainService imprImportMainService; + + public AbstractCommonImportProvider(ImportMainService imprImportMainService) { + this.imprImportMainService = imprImportMainService; + } + + @Override + public Long syncImport(ImportMainCreateDTO createDto) { + // 保存头 + Long mainId = imprImportMainService.create(createDto); + // 解析文件+明细 + analyAndCheck(mainId); + return mainId; + } + + /** + * 校验明细from + */ + protected void preCheckCreateForm(List detailCreateDtos) { + ValidateUtils.validateBiz(detailCreateDtos); + } + + @Override + public Long syncImportFrom(ImportMainCreateFormDTO createDto, List detailCreateDtos) { + preCheckCreateForm(detailCreateDtos); + // 保存头 + Long mainId = imprImportMainService.createForm(createDto); + checkAndSave(mainId, detailCreateDtos); + return mainId; + } + + /** + * 解析文件,校验明细 + */ + @Transactional(rollbackFor = Exception.class) + public void analyAndCheck(Long mainId) { + List detailCreateDtos = null; + try { + detailCreateDtos = analy(mainId); + Assert.notEmpty(detailCreateDtos, "文件明细不能为空"); + } catch (Exception e) { + analyFail(mainId, e.getMessage()); + return; + } + checkAndSave(mainId, detailCreateDtos); + } + /** + * 解析文件 + * @param mainId + * @return 文件明细dto + * @author sr on 2024-01-26 + */ + public abstract List analy(Long mainId); + /** + * 保存明细,校验明细 + * @param detailCreateDtos + * @author sr on 2024-01-26 + */ + public abstract void checkAndSave(Long mainId, List detailCreateDtos); + + /** + * 解析失败 + */ + protected void analyFail(Long mainId, String failMsg) { + ImportMainUpdateDTO updateDto = ImportMainUpdateDTO.builder().id(mainId) + .oldStatusSet(Sets.newHashSet(ImportStatusEnum.INIT.getStatus())) + .newStatus(ImportStatusEnum.ANALY_FAIL.getStatus()) + .failMsg(failMsg).build(); + imprImportMainService.modify(updateDto); + finishAsyncTask(mainId, ImportStatusEnum.ANALY_FAIL.getStatus()); + } + + /** + * 结束明细校验 + * @param mainId + * @param detailDtos 明细结果集 + * @author sr on 2024-01-26 + */ + protected void finishCheck(Long mainId, List detailDtos) { + Integer sucNum = 0; + Integer failNum = 0; + for(ID detailDto : detailDtos) { + if (ImportDetailStatusEnum.CHECK_SUCCESS.getStatus().equals(detailDto.getDetailStatus())) { + sucNum ++; + }else if (ImportDetailStatusEnum.CHECK_FAIL.getStatus().equals(detailDto.getDetailStatus())) { + failNum++; + } else { + throw new BusinessException("导入明细未全部校验结束"); + } + } + Integer totalNum = sucNum + failNum; + Integer importStatus = ImportStatusEnum.CHECKED.getStatus(); + if (sucNum == 0) { + importStatus = ImportStatusEnum.CHECK_FAIL.getStatus(); + } + ImportMainUpdateDTO updateDto = ImportMainUpdateDTO.builder().id(mainId) + .oldStatusSet(Sets.newHashSet(ImportStatusEnum.INIT.getStatus(), + ImportStatusEnum.CHECKING.getStatus())) + .newStatus(importStatus) + .totalNum(totalNum) + .successNum(sucNum).build(); + imprImportMainService.modify(updateDto); + finishAsyncTask(mainId, importStatus); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public Long confirmImport(IE executeDto) { + Long mainId = executeDto.getMainId(); + ImportMainDTO importMainDTO = imprImportMainService.find(ImportMainQueryDTO.builder().id(mainId).build()); + Assert.notNull(importMainDTO, "未找到指定导入批次"); + Assert.isTrue(ImportStatusEnum.CHECKED.getStatus().equals(importMainDTO.getImportStatus()), "校验完成状态才可确定导入"); + Integer executeType = importMainDTO.getExecuteType(); + executeDto.setExecuteType(executeType); + if (ImportExecuteTypeEnum.EXTRA_ID.getType().equals(executeType)) { + executeDto.setExtraId(importMainDTO.getExtraId()); + } else { + preCheckExecute(executeDto); + } + Long extraId = execute(executeDto); + finishExecute(executeDto.getMainId(), extraId); + return extraId; + } + + /** + * 执行dto参数校验 + * @author sr on 2024-01-26 + */ + protected void preCheckExecute(IE executeDto) { + ValidateUtils.validateBiz(executeDto); + } + + /** + * 执行(转正式业务数据) + * @param executeDto + * @return 正式数据头id + * @author sr on 2024-01-26 + */ + public abstract Long execute(IE executeDto); + + /** + * 完成执行 + * @author sr on 2024-01-26 + */ + protected void finishExecute(Long mainId, Long extraId) { + ImportMainUpdateDTO updateDto = ImportMainUpdateDTO.builder().id(mainId) + .oldStatusSet(Sets.newHashSet(ImportStatusEnum.CHECKED.getStatus())) + .newStatus(ImportStatusEnum.EXECUTE.getStatus()) + .extraId(extraId) + .finishTime(new Date()).build(); + imprImportMainService.modify(updateDto); + } + + @Override + public Long ayncImport(ImportMainCreateDTO createDto) { + // 保存头 + Long mainId = imprImportMainService.create(createDto); + MqSendUtils.send(TopicMqMessage.builder().routingKey(getRoutingKey()) + .data(mainId) + .build()); + AsyncTaskNoticeUtils.create(AsyncTaskNoticeCreateDTO.builder() + .unionType(AsyncTaskTypeEnum.COMMON_IMPORT.getType()) + .unionId(mainId) + .content(String.join(CommonConstants.HYPHEN, ImportTypeEnum.get(getType()).getName(), createDto.getFileName())) + .bizStatusStr(ImportStatusEnum.INIT.getName()).build()); + return mainId; + } + + @Override + public String getRoutingKey() { + return String.join(CommonConstants.UNDERLINE, + EnvironmentUtils.getApplicationName() + CommonConstants.POINT + "common_import", getType()); + } + + @Override + public void onMessage(TopicMqMessage message) { + try { + MockUtils.mockUser(message.getOperateUserId(), message.getOperateOrgId()); + AbstractCommonImportProvider abstractCommonImportProvider = (AbstractCommonImportProvider) AopContext.currentProxy(); + abstractCommonImportProvider.analyAndCheck(message.getData()); + } catch (Exception e) { + log.info("通用导入异步执行失败:", e); + } + } + + private static void finishAsyncTask(Long mainId, Integer importStatus) { + AsyncTaskNoticeUtils.finish(AsyncTaskNoticeFinishDTO.builder() + .unionType(AsyncTaskTypeEnum.COMMON_IMPORT.getType()).unionId(mainId) + .bizStatusStr(ImportStatusEnum.get(importStatus).getName()).build()); + } + + +} diff --git a/backend/src/main/java/com/senmesh/component/commonimport/service/impl/CommonImportAdapter.java b/backend/src/main/java/com/senmesh/component/commonimport/service/impl/CommonImportAdapter.java new file mode 100644 index 0000000..e5751a9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/service/impl/CommonImportAdapter.java @@ -0,0 +1,133 @@ +package com.senmesh.component.commonimport.service.impl; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.List; +import java.util.Map; + +import org.apache.poi.ss.formula.functions.T; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.stereotype.Service; + +import com.fasterxml.jackson.core.type.TypeReference; + +import com.google.common.collect.Maps; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.component.commonimport.dto.ImportDetailPageDTO; +import com.senmesh.component.commonimport.dto.ImportExecuteSuperDTO; +import com.senmesh.component.commonimport.dto.ImportMainCreateDTO; +import com.senmesh.component.commonimport.dto.ImportMainCreateFormDTO; +import com.senmesh.component.commonimport.dto.ImportMainDTO; +import com.senmesh.component.commonimport.dto.ImportMainQueryDTO; +import com.senmesh.component.commonimport.service.ICommonImportProvider; +import com.senmesh.component.commonimport.service.IImportDetailForm; +import com.senmesh.component.commonimport.service.ImportMainService; +import com.senmesh.config.dto.ConfigDTO; +import com.senmesh.config.service.ConfigService; +import com.senmesh.tkmybatis.pojo.Page; + +@Service +@ConditionalOnBean(AbstractCommonImportProvider.class) +public class CommonImportAdapter { + + private static Map providerMap = Maps.newHashMap(); + private static Map> executeTypeMap = Maps.newHashMap(); + private static Map> detailFormTypeMap = Maps.newHashMap(); + /** + * 通用导入模版前缀 + **/ + public static final String TEMPLATE_CODE_PREFIX = "common_import_template_"; + + public CommonImportAdapter(List providers) { + providers.forEach(provider -> { + String type = provider.getType(); + providerMap.put(type, provider); + ParameterizedType pt = (ParameterizedType) AopUtils.getTargetClass(provider).getGenericSuperclass(); + Type executeDtoType = pt.getActualTypeArguments()[0]; + TypeReference executeTypeReference = new TypeReference() { + @Override + public Type getType() { + return executeDtoType; + } + }; + Type detailFormType = pt.getActualTypeArguments()[2]; + TypeReference detailFormTypeReference = new TypeReference() { + @Override + public Type getType() { + return detailFormType; + } + }; + + executeTypeMap.put(type, executeTypeReference); + detailFormTypeMap.put(type, detailFormTypeReference); + }); + } + + @Autowired + private ConfigService configService; + @Autowired + private ImportMainService importMainService; + + private ICommonImportProvider getProvider(String type) { + ICommonImportProvider provider = providerMap.get(type); + Assert.notNull(provider, "通用导入类型有误:" + type); + return provider; + } + + public ConfigDTO template(String type) { + getProvider(type); + String configCode = TEMPLATE_CODE_PREFIX + type; + return configService.queryConfigByCode(CommonConstants.PLATFORM_ORG_ID, configCode); + } + + public void page(ImportMainQueryDTO queryDTO) { + importMainService.page(queryDTO); + } + + public ImportMainDTO find(ImportMainQueryDTO queryDTO) { + return importMainService.find(queryDTO); + } + + public Long create(ImportMainCreateDTO createDto) { + ICommonImportProvider provider = getProvider(createDto.getType()); + return provider.syncImport(createDto); + } + + public Long createAsync(ImportMainCreateDTO createDto) { + ICommonImportProvider provider = getProvider(createDto.getType()); + return provider.ayncImport(createDto); + } + + public Long createForm(ImportMainCreateFormDTO createDto) { + String type = createDto.getType(); + ICommonImportProvider provider = getProvider(type); + String detailJson = JsonUtils.toJsonString(JsonUtils.buildObjectMapper(), createDto.getDetails()); + List details = JsonUtils.toList(detailJson, (Class) detailFormTypeMap.get(type).getType()); + return provider.syncImportFrom(createDto, details); + } + + public Long confirmImport(String type, Map executeDtoMap) { + ICommonImportProvider provider = getProvider(type); + String executeJson = JsonUtils.toJsonString(JsonUtils.buildObjectMapper(), executeDtoMap); + ImportExecuteSuperDTO executeDto = JsonUtils.toObject(executeJson, executeTypeMap.get(type)); + return provider.confirmImport(executeDto); + } + + public Page pageDetail(ImportDetailPageDTO importDetailPageDTO) { + String type = importDetailPageDTO.getType(); + ICommonImportProvider provider = getProvider(type); + return provider.pageDetail(importDetailPageDTO); + } + + public void importDetailExport(ImportDetailPageDTO importDetailPageDTO) { + String type = importDetailPageDTO.getType(); + ICommonImportProvider provider = getProvider(type); + provider.importDetailExport(importDetailPageDTO); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/commonimport/service/impl/ImportMainServiceImpl.java b/backend/src/main/java/com/senmesh/component/commonimport/service/impl/ImportMainServiceImpl.java new file mode 100644 index 0000000..ccd5e19 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/commonimport/service/impl/ImportMainServiceImpl.java @@ -0,0 +1,100 @@ +package com.senmesh.component.commonimport.service.impl; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.codegenerator.util.CodeUtils; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.ListUtil; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.component.commonimport.constant.ImportExecuteTypeEnum; +import com.senmesh.component.commonimport.constant.ImportStatusEnum; +import com.senmesh.component.commonimport.dao.ImportMainMapper; +import com.senmesh.component.commonimport.dto.ImportMainCreateDTO; +import com.senmesh.component.commonimport.dto.ImportMainCreateFormDTO; +import com.senmesh.component.commonimport.dto.ImportMainDTO; +import com.senmesh.component.commonimport.dto.ImportMainQueryDTO; +import com.senmesh.component.commonimport.dto.ImportMainUpdateDTO; +import com.senmesh.component.commonimport.entity.UcImportMain; +import com.senmesh.component.commonimport.mapstruct.ImportMainMapMapper; +import com.senmesh.component.commonimport.service.ImportMainService; +import com.senmesh.component.constants.CodeTypeEnum; + +/** + * @author sr on 2024-01-19 + */ +@Service +public class ImportMainServiceImpl implements ImportMainService { + + @Autowired + private ImportMainMapper importMainMapper; + + @Override + @Transactional + public Long create(ImportMainCreateDTO createDto) { + Long extraId = createDto.getExtraId(); + UcImportMain ucImportMain = ImportMainMapMapper.INSTANCE.to(createDto); + init(ucImportMain); + if (extraId != null) { + ucImportMain.setExecuteType(ImportExecuteTypeEnum.EXTRA_ID.getType()); + } + importMainMapper.saveEntity(ucImportMain); + return ucImportMain.getId(); + } + + private void init(UcImportMain ucImportMain) { + ucImportMain.setImportNo(CodeUtils.getCode(CodeTypeEnum.COMMON_IMPORT)); + ucImportMain.setImportStatus(ImportStatusEnum.INIT.getStatus()); + ucImportMain.setOrgId(UserContextHolder.getExistLoginOrgId()); + } + + @Override + @Transactional + public Long createForm(ImportMainCreateFormDTO createDto) { + UcImportMain ucImportMain = ImportMainMapMapper.INSTANCE.to(createDto); + ucImportMain.setExecuteType(ImportExecuteTypeEnum.DETAIL_FORM.getType()); + ucImportMain.setFileName("快速发放"); + init(ucImportMain); + importMainMapper.saveEntity(ucImportMain); + return ucImportMain.getId(); + } + + @Override + @Transactional + public void modify(ImportMainUpdateDTO updateDto) { + int num = importMainMapper.modify(updateDto); + Assert.isTrue(num > 0, "修改导入批次失败"); + } + + @Override + @Transactional + public void remove(Long id) { + importMainMapper.deleteEntity(UcImportMain.builder().id(id).build(), + UserContextHolder.getLoginUserId()); + } + + @Override + public List list(ImportMainQueryDTO importMainQueryDTO) { + importMainQueryDTO.disablePage(); + return importMainMapper.listImportMainDTO(importMainQueryDTO); + } + + @Override + public void page(ImportMainQueryDTO importMainQueryDTO) { + if (!CommonConstants.PLATFORM_ORG_ID.equals(UserContextHolder.getExistLoginOrgId())) { + importMainQueryDTO.setOrgId(UserContextHolder.getExistLoginOrgId()); + } + importMainMapper.listImportMainDTO(importMainQueryDTO); + } + + @Override + public ImportMainDTO find(ImportMainQueryDTO importMainQueryDTO) { + List importMainDTOs = this.list(importMainQueryDTO); + return ListUtil.first(importMainDTOs); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/constants/CodeTypeEnum.java b/backend/src/main/java/com/senmesh/component/constants/CodeTypeEnum.java new file mode 100644 index 0000000..f16f2a2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/constants/CodeTypeEnum.java @@ -0,0 +1,29 @@ +package com.senmesh.component.constants; + +import com.senmesh.codegenerator.pojo.CodeParam; + +/** + * @author sr on 2020-08-04 + */ +public enum CodeTypeEnum { + + /** + * FileClass(备用) + **/ + FILE_CLASS(CodeParam.builder().type("FC").build()), + + /** 通用导入 **/ + COMMON_IMPORT(CodeParam.builder().type("CI").build()); + + private CodeParam codeParam; + + CodeTypeEnum(CodeParam codeParam) { + this.codeParam = codeParam; + } + + public CodeParam getCodeParam() { + return this.codeParam; + } + + +} diff --git a/backend/src/main/java/com/senmesh/component/dict/controller/DictController.java b/backend/src/main/java/com/senmesh/component/dict/controller/DictController.java new file mode 100644 index 0000000..d540d91 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dict/controller/DictController.java @@ -0,0 +1,104 @@ +package com.senmesh.component.dict.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.component.dict.dto.DictDTO; +import com.senmesh.component.dict.dto.DictDetailQueryDTO; +import com.senmesh.component.dict.dto.DictQueryDTO; +import com.senmesh.component.dict.dto.DropdownDictDetailDTO; +import com.senmesh.component.dict.service.DictCacheService; +import com.senmesh.component.dict.service.DictDetailService; +import com.senmesh.component.dict.service.DictService; +import com.senmesh.tkmybatis.pojo.Page; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Collection; + +/** + * + * + */ +@Api(tags = "字典表") +@RestController +@RequestMapping({"/dict"}) +public class DictController { + + @Autowired + private DictService dictService; + + @Autowired + private DictDetailService dictDetailService; + + @Autowired + private DictCacheService dictCacheService; + + /** + * 新增 + * + * @param dict + */ + @ApiOperation("新增字典") + @PostMapping("create") + public AlitaResult createDict(@RequestBody DictDTO dict) { + dictService.createDict(dict, UserContextHolder.getLoginUserId()); + return AlitaResult.success(dict); + } + + /** + * 修改 + * + * @param dict + */ + @ApiOperation("修改字典") + @PostMapping("modify") + public AlitaResult modifyDict(@RequestBody DictDTO dict) { + dictService.modifyDict(dict, UserContextHolder.getLoginUserId()); + return AlitaResult.success(dict); + } + + /** + * 删除 + * + * @param dict + */ + @ApiOperation("删除字典") + @PostMapping("remove") + public AlitaResult removeDict(@RequestBody DictDTO dict) { + dictService.removeDict(dict, UserContextHolder.getLoginUserId()); + return AlitaResult.success(dict); + } + + /** + * 查询 + * + * @param dict + */ + @ApiOperation("后边页面列出字典-带分页") + @GetMapping("page") + public AlitaResult> page(DictQueryDTO dict) { + dictService.page(dict); + return AlitaResult.success(dict.getPageResult()); + } + + /** + * 查询 + * + * @param dictDetailDTO + */ + @ApiOperation("列出字典") + @GetMapping("lookup") + public AlitaResult> find(DictDetailQueryDTO dictDetailDTO) { + return AlitaResult.success(dictDetailService.getDropdownDictDetails(dictDetailDTO)); + } + + @ApiOperation("刷新字典-dictCode") + @GetMapping("flush/{dictCode}") + public AlitaResult flushByDictCode(@PathVariable String dictCode){ + dictCacheService.removeTreeDictDetailByCode(dictCode); + return AlitaResult.success(Boolean.TRUE); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/dict/dao/DictDetailMapper.java b/backend/src/main/java/com/senmesh/component/dict/dao/DictDetailMapper.java new file mode 100644 index 0000000..eedbe2f --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dict/dao/DictDetailMapper.java @@ -0,0 +1,42 @@ +package com.senmesh.component.dict.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.component.dict.dto.DictDetailDTO; +import com.senmesh.component.dict.dto.DictDetailQueryDTO; +import com.senmesh.component.dict.dto.DropdownDictDetailDTO; +import com.senmesh.component.dict.entity.DictDetail; +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.tkmybatis.pojo.Page; + +public interface DictDetailMapper extends MyMapper { + + /** + * 查询 + * + * @param page 不为空分页 + * @param dictDetail + * @return + */ + List list(Page page, @Param("param") DictDetailQueryDTO dictDetailQueryDTO); + + /** + * 查询 + * + * @param dictDetailDTO + * @return + */ + List getDropdownDictDetails(@Param("param") DictDetailQueryDTO dictDetailQueryDTO); + + /** + * 获取字典编码 + * + * @param dictDetailQueryDTO + * @return + * @author sr on 2020-07-30 + */ + List getDictCode(@Param("param") DictDetailQueryDTO dictDetailQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/component/dict/dao/DictMapper.java b/backend/src/main/java/com/senmesh/component/dict/dao/DictMapper.java new file mode 100644 index 0000000..44cd901 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dict/dao/DictMapper.java @@ -0,0 +1,21 @@ +package com.senmesh.component.dict.dao; + +import com.senmesh.component.dict.dto.DictDTO; +import com.senmesh.component.dict.dto.DictQueryDTO; +import com.senmesh.component.dict.entity.Dict; +import com.senmesh.tkmybatis.mybatis.MyMapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +public interface DictMapper extends MyMapper { + + /** + * 分页查询 + * + * @param dict + * @return + */ + List list(@Param("param") DictQueryDTO dict); + +} diff --git a/backend/src/main/java/com/senmesh/component/dict/dto/DictDTO.java b/backend/src/main/java/com/senmesh/component/dict/dto/DictDTO.java new file mode 100644 index 0000000..c5237c9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dict/dto/DictDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.component.dict.dto; + +import java.io.Serializable; +import java.util.List; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2020-07-30 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@SuperBuilder +public class DictDTO extends BaseDTO implements Serializable { + + /** **/ + private static final long serialVersionUID = -8242172908364818906L; + + @ApiModelProperty("字典编码") + private String dictCode; + + @ApiModelProperty("字典名称") + private String dictName; + + @ApiModelProperty("数据字典详情列表") + private List dictDetailList; + +} diff --git a/backend/src/main/java/com/senmesh/component/dict/dto/DictDetailDTO.java b/backend/src/main/java/com/senmesh/component/dict/dto/DictDetailDTO.java new file mode 100644 index 0000000..c9c4a5b --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dict/dto/DictDetailDTO.java @@ -0,0 +1,54 @@ +package com.senmesh.component.dict.dto; + +import com.google.common.collect.Lists; +import com.senmesh.common.dto.BaseDTO; +import com.senmesh.common.util.TreeNode; + +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import java.util.List; + +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class DictDetailDTO extends BaseDTO implements TreeNode { + + /** + * + **/ + private static final long serialVersionUID = -1396551692759999448L; + + @ApiModelProperty("字典ID") + private Long dictId; + + @ApiModelProperty("字典编码") + private String dictCode; + + @ApiModelProperty("字典明细编码") + private String dictDetailCode; + + @ApiModelProperty("字典明细名称") + private String dictDetailName; + + @ApiModelProperty("顺序") + private Integer dictOrder; + + @ApiModelProperty("父子项的ID") + private Long parentId; + + @ApiModelProperty("父子项的Name") + private String parentName; + + private List children = Lists.newArrayList(); + + + @Override + public void addChildren(DictDetailDTO node) { + this.children.add(node); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/dict/dto/DictDetailQueryDTO.java b/backend/src/main/java/com/senmesh/component/dict/dto/DictDetailQueryDTO.java new file mode 100644 index 0000000..6cd7425 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dict/dto/DictDetailQueryDTO.java @@ -0,0 +1,58 @@ +package com.senmesh.component.dict.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * + * + */ +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Data +@ApiModel("字典详情") +public class DictDetailQueryDTO extends PageQueryDTO { + + /** + * + */ + private static final long serialVersionUID = 2138839246462138493L; + + @ApiModelProperty("字典类型") + private String type; + + @ApiModelProperty("字典类型-多个字典类型(查询)") + private String[] types; + + @ApiModelProperty("字典id") + private Long dictId; + + @ApiModelProperty("字典名称") + private String dictName; + + @ApiModelProperty("字典编码") + private String dictCode; + + @ApiModelProperty("字典明细id") + private Long dictDetailId; + + @ApiModelProperty("字典明细名称") + private String dictDetailName; + + @ApiModelProperty("字典明细编码") + private String dictDetailCode; + + @ApiModelProperty("父id") + private Long parentId; + + @ApiModelProperty("查询值,同时筛选 dictCode,dictName") + private String queryCode; + + +} diff --git a/backend/src/main/java/com/senmesh/component/dict/dto/DictQueryDTO.java b/backend/src/main/java/com/senmesh/component/dict/dto/DictQueryDTO.java new file mode 100644 index 0000000..3a5e160 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dict/dto/DictQueryDTO.java @@ -0,0 +1,34 @@ +package com.senmesh.component.dict.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-07-30 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DictQueryDTO extends PageQueryDTO { + + /** **/ + private static final long serialVersionUID = -8242172908364818906L; + + @ApiModelProperty("字典id") + private Long dictId; + + @ApiModelProperty("字典编码") + private String dictCode; + + @ApiModelProperty("字典名称") + private String dictName; + + @ApiModelProperty("查询值,同时筛选 dictCode,dictName") + private String queryCode; + +} diff --git a/backend/src/main/java/com/senmesh/component/dict/dto/DropdownDictDetailDTO.java b/backend/src/main/java/com/senmesh/component/dict/dto/DropdownDictDetailDTO.java new file mode 100644 index 0000000..17caad3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dict/dto/DropdownDictDetailDTO.java @@ -0,0 +1,38 @@ +package com.senmesh.component.dict.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Data +@ApiModel("下拉字典详情") +public class DropdownDictDetailDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = -6549004852720101531L; + + @ApiModelProperty("明细id") + private Long detailId; + + @ApiModelProperty("字典类型") + private String type; + + @ApiModelProperty("字典编码") + private String dictDetailCode; + + @ApiModelProperty("字典名称") + private String dictDetailName; + + @ApiModelProperty("顺序") + private Integer dictOrder; + + +} diff --git a/backend/src/main/java/com/senmesh/component/dict/entity/Dict.java b/backend/src/main/java/com/senmesh/component/dict/entity/Dict.java new file mode 100644 index 0000000..a7ff3c6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dict/entity/Dict.java @@ -0,0 +1,43 @@ +package com.senmesh.component.dict.entity; + +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@TableName("xs_dict") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Data +public class Dict extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1802939371884168684L; + + /** + * 字典编码 + */ + private String dictCode; + + /** + * 字典名称 + */ + private String dictName; + + @Builder + public Dict(Long id, Boolean deleted, Long createBy, Date createTime, Long updateBy, + Date updateTime, Long proxyBy, String dictCode, String dictName) { + super(id, deleted, createBy, createTime, updateBy, updateTime, proxyBy); + this.dictCode = dictCode; + this.dictName = dictName; + } + + +} diff --git a/backend/src/main/java/com/senmesh/component/dict/entity/DictDetail.java b/backend/src/main/java/com/senmesh/component/dict/entity/DictDetail.java new file mode 100644 index 0000000..2c20fb8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dict/entity/DictDetail.java @@ -0,0 +1,62 @@ +package com.senmesh.component.dict.entity; + +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@TableName("xs_dict_detail") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Builder +@Data +public class DictDetail extends BaseEntity { + + /** **/ + private static final long serialVersionUID = -1396551692759999448L; + + /** + * 字典ID + */ + private Long dictId; + + /** + * 字典明细编码 + */ + private String dictDetailCode; + + /** + * 字典明细名称 + */ + private String dictDetailName; + + /** + * 顺序 + */ + private Integer dictOrder; + + /** + * 父子项的ID + */ + private Long parentId; + + @Builder + public DictDetail(Long id, Boolean deleted, Long createBy, Date createTime, + Long updateBy, Date updateTime, Long proxyBy, Long dictId, + String dictDetailCode, String dictDetailName, Integer dictOrder, Long parentId) { + super(id, deleted, createBy, createTime, updateBy, updateTime, proxyBy); + this.dictId = dictId; + this.dictDetailCode = dictDetailCode; + this.dictDetailName = dictDetailName; + this.dictOrder = dictOrder; + this.parentId = parentId; + } + +} diff --git a/backend/src/main/java/com/senmesh/component/dict/mapper/DictDetailMapper.xml b/backend/src/main/java/com/senmesh/component/dict/mapper/DictDetailMapper.xml new file mode 100644 index 0000000..1b8064e --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dict/mapper/DictDetailMapper.xml @@ -0,0 +1,77 @@ + + + + + + from + xs_dict dict + inner join xs_dict_detail detail on dict.id = detail.dict_id + where + dict.deleted = FALSE and detail.deleted = FALSE + + + AND dict.dict_name like #{dictNameLike} + + + AND dict.dict_code = #{param.dictCode} + + + AND detail.dict_id = #{param.dictId} + + + AND detail.id = #{param.dictDetailId} + + + + AND detail.dict_detail_name like #{dictDetailNameLike} + + + AND detail.dict_detail_code = #{param.dictDetailCode} + + + AND detail.parent_id = #{param.parentId} + + + AND dict.dict_code = #{param.type} + + + AND dict.dict_code in + + #{code} + + + + + AND (detail.dict_detail_name like #{queryCodeLike} OR detail.dict_detail_code like #{queryCodeLike}) + + + + + + + + + + + diff --git a/backend/src/main/java/com/senmesh/component/dict/mapper/DictMapper.xml b/backend/src/main/java/com/senmesh/component/dict/mapper/DictMapper.xml new file mode 100644 index 0000000..f73245e --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dict/mapper/DictMapper.xml @@ -0,0 +1,29 @@ + + + + + + + + diff --git a/backend/src/main/java/com/senmesh/component/dict/mapstruct/DictDetailMapMapper.java b/backend/src/main/java/com/senmesh/component/dict/mapstruct/DictDetailMapMapper.java new file mode 100644 index 0000000..207beaa --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dict/mapstruct/DictDetailMapMapper.java @@ -0,0 +1,24 @@ +package com.senmesh.component.dict.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.component.dict.dto.DictDetailDTO; +import com.senmesh.component.dict.entity.DictDetail; + +/** + * @author sr on 2020-07-30 + */ +@Mapper +public interface DictDetailMapMapper { + + DictDetailMapMapper INSTANCE = Mappers.getMapper(DictDetailMapMapper.class); + + /** + * @param dictDetailDTO + * @return + * @author sr on 2020-07-30 + */ + DictDetail toEntity(DictDetailDTO dictDetailDTO); + +} diff --git a/backend/src/main/java/com/senmesh/component/dict/mapstruct/DictMapMapper.java b/backend/src/main/java/com/senmesh/component/dict/mapstruct/DictMapMapper.java new file mode 100644 index 0000000..ef6827c --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dict/mapstruct/DictMapMapper.java @@ -0,0 +1,39 @@ +package com.senmesh.component.dict.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.component.dict.dto.DictDTO; +import com.senmesh.component.dict.dto.DictQueryDTO; +import com.senmesh.component.dict.entity.Dict; + +/** + * @author sr on 2020-07-30 + */ +@Mapper +public interface DictMapMapper { + + DictMapMapper INSTANCE = Mappers.getMapper(DictMapMapper.class); + + /** + * @param dictDetailDTO + * @return + * @author sr on 2020-07-30 + */ + Dict toEntity(DictDTO dictDTO); + + /** + * @param dictQueryDTO + * @return + * @author sr on 2020-07-30 + */ + Dict toEntity(DictQueryDTO dictQueryDTO); + + /** + * @param dict + * @return + * @author sr on 2020-07-30 + */ + DictDTO toDto(Dict dict); + +} diff --git a/backend/src/main/java/com/senmesh/component/dict/service/DictCacheService.java b/backend/src/main/java/com/senmesh/component/dict/service/DictCacheService.java new file mode 100644 index 0000000..bc1c018 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dict/service/DictCacheService.java @@ -0,0 +1,47 @@ +package com.senmesh.component.dict.service; + +import java.util.List; + +import com.senmesh.component.dict.dto.DictDetailDTO; + +/** + * 字典缓存 + * + * @author sr on 2020-04-03 + */ +public interface DictCacheService { + + /** + * 获取dictCode的树形数据字典缓存 + * + * @param dictCode + * @return + * @author sr on 2020-04-03 + */ + List getTreeDictDetailByCode(String dictCode); + + /** + * 更新dictCode的树形数据字典缓存 + * + * @param dictCode + * @return + * @author sr on 2020-04-03 + */ + List putTreeDictDetailByCode(String dictCode); + + /** + * 清除dictCode的树形数据字典缓存 + * + * @param dictCode + * @author sr on 2020-04-03 + */ + void removeTreeDictDetailByCode(String dictCode); + + /** + * 清除树形数据字典缓存 + * + * @author sr on 2020-04-03 + */ + void removeTreeDictDetail(); + +} diff --git a/backend/src/main/java/com/senmesh/component/dict/service/DictDetailService.java b/backend/src/main/java/com/senmesh/component/dict/service/DictDetailService.java new file mode 100644 index 0000000..5e010e7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dict/service/DictDetailService.java @@ -0,0 +1,106 @@ +package com.senmesh.component.dict.service; + +import com.senmesh.component.dict.dto.DictDetailDTO; +import com.senmesh.component.dict.dto.DictDetailQueryDTO; +import com.senmesh.component.dict.dto.DropdownDictDetailDTO; +import com.senmesh.tkmybatis.pojo.Page; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * + * + */ +public interface DictDetailService { + + /** + * 新增 + * + * @param dictDetail + * @param operateUserId + */ + void createDictDetail(DictDetailDTO dictDetail, Long operateUserId); + + /** + * 修改 + * + * @param dictDetail + */ + void modifyDictDetail(DictDetailDTO dictDetail, Long operateUserId); + + /** + * 删除 + * + * @param dictDetail + */ + void removeDictDetail(DictDetailDTO dictDetail, Long operateUserId); + + /** + * 查询 + * + * @param page + * @param dictDetail + */ + void page(Page page, DictDetailQueryDTO dictDetail); + + /** + * 查询 + * + * @param dictDetailDTO + */ + Collection getDropdownDictDetails(DictDetailQueryDTO dictDetailDTO); + + /** + * 查询 + * + * @param dictDetail + */ + List list(DictDetailQueryDTO dictDetail); + + /** + * 获取map + * @param parentType + * @return + */ + Map getDictDetailsMap(String parentType); + + /** + * 获取map + * @param parentCode + * @param operateUserId + * @return + */ + Map getDictDetailMap(String parentCode, Long operateUserId); + + /** + * 获取字典详情 + * @param dictId + * @param code + * @param parentId + * @return + */ + DictDetailDTO findDetail(Long dictId, String code, Long parentId); + + /** + * 刷新字典缓存 + * + * @param dictDetail + * @author sr on 2020-07-30 + */ + void refreshDictCache(DictDetailQueryDTO dictDetailQueryDTO); + + /** + * 根据给定的type类型,返回Map + * 以 auth_status 为例子,返回的Map key->value 为 + * authStatus1->未认证 + * authStatus2->认证中 + * authStatus3->认证成功 + * authStatus4->认证失败 + * + * @param types + * @return + */ + Map getMapByTypes(List types); +} diff --git a/backend/src/main/java/com/senmesh/component/dict/service/DictService.java b/backend/src/main/java/com/senmesh/component/dict/service/DictService.java new file mode 100644 index 0000000..21d5293 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dict/service/DictService.java @@ -0,0 +1,45 @@ +package com.senmesh.component.dict.service; + +import com.senmesh.component.dict.dto.DictDTO; +import com.senmesh.component.dict.dto.DictQueryDTO; + +/** + * + * + */ +public interface DictService{ + + /** + * 新增 + * + * @param dict + * @return + */ + DictDTO createDict(DictDTO dict, Long operateUserId); + + /** + * 修改 + * + * @param dict + * @return + */ + DictDTO modifyDict(DictDTO dict, Long operateUserId); + + /** + * 删除 + * + * @param dict + */ + void removeDict(DictDTO dict, Long operateUserId); + + /** + * 查询 + * + * @param dict + */ + void page(DictQueryDTO dict); + + DictDTO find(DictQueryDTO dict); + + DictDTO findOrInsert(DictQueryDTO dict, Long operateUserId); +} diff --git a/backend/src/main/java/com/senmesh/component/dict/service/impl/DictCacheServiceImpl.java b/backend/src/main/java/com/senmesh/component/dict/service/impl/DictCacheServiceImpl.java new file mode 100644 index 0000000..a23f8fe --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dict/service/impl/DictCacheServiceImpl.java @@ -0,0 +1,55 @@ +package com.senmesh.component.dict.service.impl; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import com.senmesh.common.constant.CacheConstants; +import com.senmesh.common.util.TreeHelper; +import com.senmesh.component.dict.dao.DictDetailMapper; +import com.senmesh.component.dict.dto.DictDetailDTO; +import com.senmesh.component.dict.dto.DictDetailQueryDTO; +import com.senmesh.component.dict.service.DictCacheService; + +/** + * @author sr on 2020-04-03 + */ +@Service +public class DictCacheServiceImpl implements DictCacheService { + + @Autowired + private DictDetailMapper dictDetailMapper; + + @Override + @Cacheable(key = "#dictCode", value = CacheConstants.CACHE_NAME_DICT) + public List getTreeDictDetailByCode(String dictCode) { + DictDetailQueryDTO queryDTO = DictDetailQueryDTO.builder().dictCode(dictCode).build(); + queryDTO.disablePage(); + List details = + dictDetailMapper.list(null, queryDTO); + return TreeHelper.buildTree(null, details); + } + + @Override + @CachePut(key = "#dictCode", value = CacheConstants.CACHE_NAME_DICT) + public List putTreeDictDetailByCode(String dictCode) { + return this.getTreeDictDetailByCode(dictCode); + } + + @Override + @CacheEvict(key = "#dictCode", value = CacheConstants.CACHE_NAME_DICT) + public void removeTreeDictDetailByCode(String dictCode) { + // do nothing... + } + + @Override + @CacheEvict(allEntries = true, value = CacheConstants.CACHE_NAME_DICT) + public void removeTreeDictDetail() { + // do nothing... + } + +} diff --git a/backend/src/main/java/com/senmesh/component/dict/service/impl/DictDetailServiceImpl.java b/backend/src/main/java/com/senmesh/component/dict/service/impl/DictDetailServiceImpl.java new file mode 100644 index 0000000..77828b3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dict/service/impl/DictDetailServiceImpl.java @@ -0,0 +1,149 @@ +package com.senmesh.component.dict.service.impl; + +import com.google.common.base.CaseFormat; +import com.google.common.collect.Maps; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.component.dict.dao.DictDetailMapper; +import com.senmesh.component.dict.dto.*; +import com.senmesh.component.dict.mapstruct.DictDetailMapMapper; +import com.senmesh.component.dict.service.DictCacheService; +import com.senmesh.component.dict.service.DictDetailService; +import com.senmesh.component.dict.service.DictService; +import com.senmesh.tkmybatis.pojo.Page; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * + * + */ +@Service +public class DictDetailServiceImpl implements DictDetailService { + + @Resource + private DictDetailMapper dictDetailMapper; + + @Autowired + private DictService dictService; + + @Autowired + private DictCacheService dictCacheService; + + @Override + public Map getMapByTypes(List types) { + if (CollectionUtils.isEmpty(types)) { + return Maps.newHashMap(); + } + Map dictCodeMap = types.stream().collect(Collectors.toMap(dictCode -> dictCode, dictCode -> CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, dictCode))); + + List dictDetails = dictDetailMapper + .getDropdownDictDetails(DictDetailQueryDTO.builder().types(types.toArray(new String[0])).build()); + + return dictDetails.stream().collect(Collectors.toMap(item -> + dictCodeMap.get(item.getType()) + item.getDictDetailCode() + , DropdownDictDetailDTO::getDictDetailName)); + } + + @Override + public void createDictDetail(DictDetailDTO dictDetail, Long operateUserId) { + dictDetailMapper.saveEntity(DictDetailMapMapper.INSTANCE.toEntity(dictDetail), operateUserId); + refreshDictCache(dictDetail.getDictId()); + } + + @Override + public void modifyDictDetail(DictDetailDTO dictDetail, Long operateUserId) { + dictDetailMapper.updateEntitySelective(DictDetailMapMapper.INSTANCE.toEntity(dictDetail), operateUserId); + refreshDictCache(dictDetail.getDictId()); + } + + @Override + public void removeDictDetail(DictDetailDTO dictDetail, Long operateUserId) { + dictDetailMapper.deleteEntity(DictDetailMapMapper.INSTANCE.toEntity(dictDetail), operateUserId); + refreshDictCache(dictDetail.getDictId()); + } + + /** + * 刷新缓存 + * + * @param dictDetail 字典详情 + * @author sr on 2020-07-30 + */ + private void refreshDictCache(Long dictId) { + Assert.notNull(dictId, "字典id不能为空"); + this.refreshDictCache(DictDetailQueryDTO.builder().dictId(dictId).build()); + } + + @Override + public void page(Page page, DictDetailQueryDTO dictDetail) { + dictDetailMapper.list(page, dictDetail); + } + + @Override + public Collection getDropdownDictDetails(DictDetailQueryDTO dictDetailDTO) { + boolean dtoIsNull = dictDetailDTO == null || (StringUtils.isBlank(dictDetailDTO.getType()) + && ArrayUtils.isEmpty(dictDetailDTO.getTypes())); + if (dtoIsNull) { + return null; + } + return dictDetailMapper.getDropdownDictDetails(dictDetailDTO); + } + + @Override + public List list(DictDetailQueryDTO dictDetail) { + return dictDetailMapper.list(null, dictDetail); + } + + @Override + public Map getDictDetailsMap(String parentType) { + DictDetailQueryDTO queryDTO = new DictDetailQueryDTO(); + queryDTO.setType(parentType); + Collection details = getDropdownDictDetails(queryDTO); + if (details == null || details.size() == 0) { + return null; + } + Map dictMap = Maps.newHashMapWithExpectedSize(details.size()); + for (DropdownDictDetailDTO dto : details) { + dictMap.put(dto.getDictDetailName(), dto); + } + return dictMap; + } + + @Override + public Map getDictDetailMap(String parentCode, Long operateUserId) { + DictDTO dict = dictService.findOrInsert(DictQueryDTO.builder().dictCode(parentCode).build(), operateUserId); + List details = list(DictDetailQueryDTO.builder().dictId(dict.getId()).build()); + if (details == null || details.size() == 0) { + return Maps.newHashMap(); + } + Map dictMap = Maps.newHashMapWithExpectedSize(details.size()); + for (DictDetailDTO detail : details) { + dictMap.put(detail.getDictDetailCode(), detail.getDictDetailName()); + } + return dictMap; + } + + @Override + public DictDetailDTO findDetail(Long dictId, String code, Long parentId) { + List list = list(DictDetailQueryDTO.builder().dictId(dictId).dictDetailCode(code).parentId(parentId).build()); + if(CollectionUtils.isEmpty(list)){ + return null; + } + return list.get(0); + } + + @Override + public void refreshDictCache(DictDetailQueryDTO dictDetailQueryDTO) { + dictDetailQueryDTO.setNeedPage(Boolean.FALSE); + List dictCodes = dictDetailMapper.getDictCode(dictDetailQueryDTO); + dictCodes.forEach(dictCode -> dictCacheService.putTreeDictDetailByCode(dictCode)); + } +} diff --git a/backend/src/main/java/com/senmesh/component/dict/service/impl/DictServiceImpl.java b/backend/src/main/java/com/senmesh/component/dict/service/impl/DictServiceImpl.java new file mode 100644 index 0000000..9e8e469 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dict/service/impl/DictServiceImpl.java @@ -0,0 +1,93 @@ +package com.senmesh.component.dict.service.impl; + +import com.senmesh.common.constant.ExceptionMsgs; +import com.senmesh.common.exception.util.ExceptionUtils; +import com.senmesh.component.dict.dao.DictMapper; +import com.senmesh.component.dict.dto.DictDTO; +import com.senmesh.component.dict.dto.DictQueryDTO; +import com.senmesh.component.dict.entity.Dict; +import com.senmesh.component.dict.mapstruct.DictMapMapper; +import com.senmesh.component.dict.service.DictCacheService; +import com.senmesh.component.dict.service.DictService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class DictServiceImpl implements DictService { + + @Autowired + private DictMapper dictMapper; + + @Autowired + private DictCacheService dictCacheService; + + + @Override + public DictDTO createDict(DictDTO dict, Long operateUserId) { + String dictCode = dict.getDictCode(); + ExceptionUtils.throwBusinessException( + dictMapper.existsEntity(Dict.builder().dictCode(dictCode).build()), + ExceptionMsgs.ENTITY_HAS_EXISTS); + Dict dictEntity=DictMapMapper.INSTANCE.toEntity(dict); + dictMapper.saveEntity(dictEntity, operateUserId); + dictCacheService.putTreeDictDetailByCode(dictCode); + dict.setId(dictEntity.getId()); + return dict; + } + + @Override + public DictDTO modifyDict(DictDTO dict, Long operateUserId) { + String dictCode = dict.getDictCode(); + Long dictId = dict.getId(); + ExceptionUtils.throwBusinessException( + dictMapper.existsEntity(Dict.builder().id(dictId).dictCode(dictCode).build()), + ExceptionMsgs.ENTITY_HAS_EXISTS); + dictMapper.updateEntitySelective(DictMapMapper.INSTANCE.toEntity(dict), operateUserId); + refreshDictCache(dictId, dictCode); + return dict; + } + + private void refreshDictCache(Long dictId, String newDictCode) { + String dictCode = dictMapper.getById(dictId).getDictCode(); + if (newDictCode != null && !dictCode.equals(newDictCode)) { + dictCacheService.putTreeDictDetailByCode(newDictCode); + } + dictCacheService.putTreeDictDetailByCode(dictCode); + } + + @Override + public void removeDict(DictDTO dict, Long operateUserId) { + dictMapper.deleteEntity(DictMapMapper.INSTANCE.toEntity(dict), operateUserId); + refreshDictCache(dict.getId(), null); + } + + @Override + public void page(DictQueryDTO dict) { + dictMapper.list(dict); + } + + @Override + public DictDTO find(DictQueryDTO dict) { + List dictDtos = dictMapper.list(dict); + return dictDtos.isEmpty() ? null : dictDtos.get(0); + } + + @Override + public DictDTO findOrInsert(DictQueryDTO dictQueryDTO, Long operateUserId) { + DictDTO result = find(dictQueryDTO); + if (result == null) { + synchronized (this) { + result = find(dictQueryDTO); + if (result == null) { + Dict dict = DictMapMapper.INSTANCE.toEntity(dictQueryDTO); + dictMapper.saveEntity(dict, operateUserId); + result = DictMapMapper.INSTANCE.toDto(dict); + } + } + } + return result; + } + +} diff --git a/backend/src/main/java/com/senmesh/component/dict/util/DictUtils.java b/backend/src/main/java/com/senmesh/component/dict/util/DictUtils.java new file mode 100644 index 0000000..063efe4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dict/util/DictUtils.java @@ -0,0 +1,64 @@ +package com.senmesh.component.dict.util; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.senmesh.component.dict.dto.DictDetailDTO; +import com.senmesh.component.dict.entity.Dict; +import com.senmesh.component.dict.service.DictCacheService; + +/** + * 字典工具类 + * @author sr on 2019-12-09 + */ +@Component +public class DictUtils { + + private static DictCacheService dictCacheService; + + @Autowired + public void setDictCacheService(DictCacheService dictCacheService) { + this.dictCacheService = dictCacheService; + } + /** + * 校验对应字典编码是否存在 + * @param id + * @param dictCode + * @return + * @author sr on 2019-12-09 + */ + public static Dict toCheckDuplicateCode(Dict dict) { + return Dict.builder().id(dict.getId()).dictCode(dict.getDictCode()).build(); + } + + public static List getCacheTree(String dictCode){ + return dictCacheService.getTreeDictDetailByCode(dictCode); + } + + /** + * 获取数据字典明细map(detailCode:detailName) + * @param dictCode + * @return + * @author sr on 2022-02-21 + */ + public static Map getCodeNameMap(String dictCode) { + return dictCacheService.getTreeDictDetailByCode(dictCode).stream().collect( + Collectors.toMap(DictDetailDTO::getDictDetailCode, DictDetailDTO::getDictDetailName)); + } + + /** + * 获取数据字典明细map(detailName:detailCode) + * @param dictCode + * @return + * @author sr on 2022-06-30 + */ + public static Map getNameCodeMap(String dictCode) { + return dictCacheService.getTreeDictDetailByCode(dictCode).stream().collect( + Collectors.toMap(DictDetailDTO::getDictDetailName, DictDetailDTO::getDictDetailCode)); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/dropdown/constant/DropdownConstants.java b/backend/src/main/java/com/senmesh/component/dropdown/constant/DropdownConstants.java new file mode 100644 index 0000000..260634d --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dropdown/constant/DropdownConstants.java @@ -0,0 +1,23 @@ +package com.senmesh.component.dropdown.constant; + +/** + * 通用配置常量类 + * @author sr on 2019-10-22 + */ +public class DropdownConstants { + + /** 字典 **/ + public static final String PROVIDER_TYPE_DICT = "dict"; + /** 编码配置 **/ + public static final String PROVIDER_TYPE_CODE_SETTING = "code_setting"; + + + /** 参数名:编码 **/ + public static final String PARAM_CODE = "code"; + /** 参数名:编码配置类型 **/ + public static final String PARAM_CODE_TYPE = "codeType"; + /** 参数名:编码串 **/ + public static final String PARAM_CODES = "codes"; + + +} diff --git a/backend/src/main/java/com/senmesh/component/dropdown/controller/DropdownController.java b/backend/src/main/java/com/senmesh/component/dropdown/controller/DropdownController.java new file mode 100644 index 0000000..26760f8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dropdown/controller/DropdownController.java @@ -0,0 +1,63 @@ +package com.senmesh.component.dropdown.controller; + +import java.util.List; +import java.util.Map; + +import org.apache.commons.collections.MapUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.component.dropdown.dto.DropdownDTO; +import com.senmesh.component.dropdown.service.impl.DropdownServiceImpl; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2019-10-22 + */ +@Api(tags = "下拉框") +//@RestController +@RequestMapping("/anon/dropdown") +@ConditionalOnProperty(name = CommonConstants.USELOCAL_KEY, havingValue = "true", matchIfMissing = true) +public class DropdownController { + + @Autowired + private DropdownServiceImpl dropdownService; + + @GetMapping("/list") + @ApiOperation("获取数据字典列表") + public AlitaResult> list(DropdownDTO dropdownDTO, + @RequestHeader(value = "OEM", defaultValue = "1") String org) { + String type = dropdownDTO.getType(); + if (type == null || "dict".equals(type)) { + Map map = dropdownDTO.getParamMap(); + String codes = MapUtils.getString(map, "dictCode", ""); + map.put("dictCode", codes.replace("oem_config", "oem_config_" + org)); + dropdownDTO.setParams(JsonUtils.toJsonString(map)); + } + return AlitaResult.success(dropdownService.list(dropdownDTO, UserContextHolder.getLoginUser())); + } + + @GetMapping("/map") + @ApiOperation("获取多个数据字典map") + public AlitaResult> map(DropdownDTO dropdownDTO, + @RequestHeader(value = "OEM", defaultValue = "1") String org) { + String type = dropdownDTO.getType(); + if (type == null || "dict".equals(type)) { + Map map = dropdownDTO.getParamMap(); + String codes = MapUtils.getString(map, "codes", ""); + map.put("codes", codes.replace("oem_config", "oem_config_" + org)); + dropdownDTO.setParams(JsonUtils.toJsonString(map)); + } + return AlitaResult.success(dropdownService.map(dropdownDTO, UserContextHolder.getLoginUser())); + } +} diff --git a/backend/src/main/java/com/senmesh/component/dropdown/dto/DropdownDTO.java b/backend/src/main/java/com/senmesh/component/dropdown/dto/DropdownDTO.java new file mode 100644 index 0000000..6b6994f --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dropdown/dto/DropdownDTO.java @@ -0,0 +1,45 @@ +package com.senmesh.component.dropdown.dto; + +import java.io.Serializable; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; + +import com.google.common.collect.Maps; +import com.senmesh.common.util.JsonUtils; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 下拉框对象 + * + * @author sr on 2019-11-05 + */ +@ApiModel("下拉框对象") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class DropdownDTO implements Serializable { + + /** **/ + private static final long serialVersionUID = -8053031023722973608L; + + /** @link DropdownConstants **/ + @ApiModelProperty("类型") + private String type; + + @ApiModelProperty("参数") + private String params; + + public Map getParamMap() { + return StringUtils.isBlank(params) ? Maps.newHashMap() : JsonUtils.toMap(params); + } + + +} diff --git a/backend/src/main/java/com/senmesh/component/dropdown/service/DropdownProvider.java b/backend/src/main/java/com/senmesh/component/dropdown/service/DropdownProvider.java new file mode 100644 index 0000000..7a0bd62 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dropdown/service/DropdownProvider.java @@ -0,0 +1,39 @@ +package com.senmesh.component.dropdown.service; + +import java.util.List; +import java.util.Map; + +import com.senmesh.usercenter.dto.IUserDetail; + +/** + * 下拉框提供者 + * @author sr on 2019-10-22 + */ +public interface DropdownProvider { + + /** + * 下拉框类型 + * @return + * @author sr on 2019-11-05 + */ + String getType(); + + /** + * 根据参数获取下拉框对象列表(list) + * @param params + * @param userDto + * @return + * @author sr on 2019-11-05 + */ + List list(Map params, IUserDetail userDto); + + /** + * 根据参数获取多组下拉对象列表(map) + * @param params + * @param userDto + * @return + * @author sr on 2019-11-05 + */ + Map map(Map params, IUserDetail userDto); + +} diff --git a/backend/src/main/java/com/senmesh/component/dropdown/service/DropdownService.java b/backend/src/main/java/com/senmesh/component/dropdown/service/DropdownService.java new file mode 100644 index 0000000..d96c065 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dropdown/service/DropdownService.java @@ -0,0 +1,32 @@ +package com.senmesh.component.dropdown.service; + +import java.util.List; +import java.util.Map; + +import com.senmesh.component.dropdown.dto.DropdownDTO; +import com.senmesh.usercenter.dto.IUserDetail; + +/** + * 下拉框service + * @author sr on 2019-10-22 + */ +public interface DropdownService { + + /** + * 获取单个下拉框列表 + * @param dropdownDTO + * @param userDto 可为空 + * @return + * @author sr on 2019-11-05 + */ + List list(DropdownDTO dropdownDTO, IUserDetail userDto); + + /** + * 获取多组下拉框 + * @param dropdownDTO + * @param userDto 可为空 + * @return + * @author sr on 2019-11-05 + */ + Map map(DropdownDTO dropdownDTO, IUserDetail userDto); +} diff --git a/backend/src/main/java/com/senmesh/component/dropdown/service/impl/CodeSettingDropdownProvider.java b/backend/src/main/java/com/senmesh/component/dropdown/service/impl/CodeSettingDropdownProvider.java new file mode 100644 index 0000000..dfa9240 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dropdown/service/impl/CodeSettingDropdownProvider.java @@ -0,0 +1,46 @@ +package com.senmesh.component.dropdown.service.impl; + +import java.util.List; +import java.util.Map; + +import org.apache.commons.collections.MapUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.senmesh.codesetting.service.CodeSettingService; +import com.senmesh.common.exception.NoneLoginException; +import com.senmesh.common.exception.util.ExceptionUtils; +import com.senmesh.component.dropdown.constant.DropdownConstants; +import com.senmesh.component.dropdown.service.DropdownProvider; +import com.senmesh.usercenter.dto.IUserDetail; + +/** + * 编码配置下拉框 + * + * @author sr on 2019-11-05 + */ +@Service +public class CodeSettingDropdownProvider implements DropdownProvider { + + @Autowired + private CodeSettingService codeSettingService; + + @Override + public Map map(Map params, IUserDetail userDto) { + return null; + } + + @Override + public String getType() { + return DropdownConstants.PROVIDER_TYPE_CODE_SETTING; + } + + @Override + public List list(Map params, IUserDetail userDto) { + String codeSettingType = MapUtils.getString(params, DropdownConstants.PARAM_CODE_TYPE); + ExceptionUtils.throwBusinessException(userDto == null, NoneLoginException.ERROR_MSG); + String orgType = userDto.getOrgType(); + return codeSettingService.queryCode(codeSettingType, orgType); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/dropdown/service/impl/DictDropdownProvider.java b/backend/src/main/java/com/senmesh/component/dropdown/service/impl/DictDropdownProvider.java new file mode 100644 index 0000000..d1aff42 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dropdown/service/impl/DictDropdownProvider.java @@ -0,0 +1,62 @@ +package com.senmesh.component.dropdown.service.impl; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.google.common.collect.Maps; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.component.dict.dao.DictDetailMapper; +import com.senmesh.component.dict.dto.DictDetailDTO; +import com.senmesh.component.dict.dto.DictDetailQueryDTO; +import com.senmesh.component.dict.service.DictCacheService; +import com.senmesh.component.dropdown.constant.DropdownConstants; +import com.senmesh.component.dropdown.service.DropdownProvider; +import com.senmesh.usercenter.dto.IUserDetail; + +/** + * 数据字典下拉框 + * + * @author sr on 2019-11-05 + */ +@Service +public class DictDropdownProvider implements DropdownProvider { + + @Autowired + private DictDetailMapper dictDetailMapper; + + @Autowired + private DictCacheService dictCacheService; + + @Override + public Map> map(Map params, IUserDetail userDto) { + String codeString = MapUtils.getString(params, DropdownConstants.PARAM_CODES); + if (StringUtils.isBlank(codeString)) { + return Collections.emptyMap(); + } + String[] codes = codeString.split(CommonConstants.COMMA); + Map> resultMap = Maps.newHashMapWithExpectedSize(codes.length); + for (String code : codes) { + List details = dictCacheService.getTreeDictDetailByCode(code); + resultMap.put(code, details); + } + return resultMap; + } + + @Override + public String getType() { + return DropdownConstants.PROVIDER_TYPE_DICT; + } + + @Override + public List list(Map params, IUserDetail userDto) { + return dictDetailMapper.list(null, JsonUtils.objToClassObj(params, DictDetailQueryDTO.class)); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/dropdown/service/impl/DropdownServiceImpl.java b/backend/src/main/java/com/senmesh/component/dropdown/service/impl/DropdownServiceImpl.java new file mode 100644 index 0000000..63bbc01 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dropdown/service/impl/DropdownServiceImpl.java @@ -0,0 +1,47 @@ +package com.senmesh.component.dropdown.service.impl; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.senmesh.component.dropdown.constant.DropdownConstants; +import com.senmesh.component.dropdown.dto.DropdownDTO; +import com.senmesh.component.dropdown.service.DropdownProvider; +import com.senmesh.component.dropdown.service.DropdownService; +import com.senmesh.usercenter.dto.IUserDetail; + +/** + * 下拉框 + * + * @author sr on 2019-10-22 + */ +@Service +public class DropdownServiceImpl implements DropdownService { + + private Map providerMap; + + @Autowired + private void providers(List dropdownProviders) { + providerMap = dropdownProviders.stream() + .collect(Collectors.toMap(DropdownProvider::getType, provider -> provider)); + } + + private DropdownProvider getProvider(String type) { + DropdownProvider provider = providerMap.get(type); + return provider == null ? providerMap.get(DropdownConstants.PROVIDER_TYPE_DICT) : provider; + } + + @Override + public List list(DropdownDTO dropdownDTO, IUserDetail userDto) { + return getProvider(dropdownDTO.getType()).list(dropdownDTO.getParamMap(), userDto); + } + + @Override + public Map map(DropdownDTO dropdownDTO, IUserDetail userDto) { + return getProvider(dropdownDTO.getType()).map(dropdownDTO.getParamMap(), userDto); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/dynamictable/constant/DynamicTableConstants.java b/backend/src/main/java/com/senmesh/component/dynamictable/constant/DynamicTableConstants.java new file mode 100644 index 0000000..723e844 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dynamictable/constant/DynamicTableConstants.java @@ -0,0 +1,8 @@ +package com.senmesh.component.dynamictable.constant; + +/** + * @author sr on 2024-04-09 + */ +public interface DynamicTableConstants { + +} diff --git a/backend/src/main/java/com/senmesh/component/dynamictable/controller/DynamicTableController.java b/backend/src/main/java/com/senmesh/component/dynamictable/controller/DynamicTableController.java new file mode 100644 index 0000000..e5f4359 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dynamictable/controller/DynamicTableController.java @@ -0,0 +1,65 @@ +package com.senmesh.component.dynamictable.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +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; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.component.dynamictable.dto.DynamicTableCreateDTO; +import com.senmesh.component.dynamictable.dto.DynamicTableDTO; +import com.senmesh.component.dynamictable.dto.DynamicTableModifyDTO; +import com.senmesh.component.dynamictable.dto.DynamicTableQueryDTO; +import com.senmesh.component.dynamictable.service.DynamicTableService; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2024-04-09 + */ +@RestController +@RequestMapping("dynamic_table") +@Api(tags = "动态表格") +public class DynamicTableController { + + @Autowired + private DynamicTableService dynamicTableService; + + @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create( + @Validated @RequestBody DynamicTableCreateDTO dynamicTableCreateDTO){ + dynamicTableCreateDTO.setUserId(UserContextHolder.getExistLoginUserId()); + return AlitaResult.success(dynamicTableService.create(dynamicTableCreateDTO)); + } + + @PostMapping("/modify") + @ApiOperation("修改") + public AlitaResult modify( + @Validated @RequestBody DynamicTableModifyDTO dynamicTableModifyDTO){ + dynamicTableModifyDTO.setUserId(UserContextHolder.getExistLoginUserId()); + dynamicTableService.modify(dynamicTableModifyDTO); + return AlitaResult.success(true); + } + + @DeleteMapping("/remove/{tableType}") + @ApiOperation("删除") + public AlitaResult remove(@PathVariable String tableType){ + dynamicTableService.remove(tableType); + return AlitaResult.success(true); + } + + @GetMapping("/find") + @ApiOperation("查询") + public AlitaResult find(DynamicTableQueryDTO dynamicTableQueryDTO){ + return AlitaResult.success(dynamicTableService.find(dynamicTableQueryDTO)); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/dynamictable/dao/DynamicTableMapper.java b/backend/src/main/java/com/senmesh/component/dynamictable/dao/DynamicTableMapper.java new file mode 100644 index 0000000..9d37589 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dynamictable/dao/DynamicTableMapper.java @@ -0,0 +1,28 @@ +package com.senmesh.component.dynamictable.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.component.dynamictable.dto.DynamicTableDTO; +import com.senmesh.component.dynamictable.dto.DynamicTableQueryDTO; +import com.senmesh.component.dynamictable.entity.DynamicTable; +import com.senmesh.tkmybatis.mybatis.MyMapper; + +/** + * 动态表格 + * + * @author sr on 2024-04-09 + */ +public interface DynamicTableMapper extends MyMapper { + + /** + * 查询 + * + * @param dynamicTableQueryDTO + * @return + * @author sr on 2024-04-09 + */ + List listDynamicTableDTO(@Param("param") DynamicTableQueryDTO dynamicTableQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/component/dynamictable/dto/DynamicTableColumnDTO.java b/backend/src/main/java/com/senmesh/component/dynamictable/dto/DynamicTableColumnDTO.java new file mode 100644 index 0000000..e8a5971 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dynamictable/dto/DynamicTableColumnDTO.java @@ -0,0 +1,38 @@ +package com.senmesh.component.dynamictable.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 动态表格列 + * @author sr on 2024-04-09 + */ +@NoArgsConstructor +@AllArgsConstructor +@Data +@Builder +public class DynamicTableColumnDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = -218789958565751460L; + /** 列名 **/ + @NotBlank(message = "列名不能为空") + private String title; + /** 列标识 **/ + @NotBlank(message = "列标识不能为空") + private String dataIndex; + /** 固定类型 **/ + private String fixed; + /** 宽度 **/ + private Integer width; + /** 排序 **/ + private Integer order; + + +} diff --git a/backend/src/main/java/com/senmesh/component/dynamictable/dto/DynamicTableCreateDTO.java b/backend/src/main/java/com/senmesh/component/dynamictable/dto/DynamicTableCreateDTO.java new file mode 100644 index 0000000..c33a3db --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dynamictable/dto/DynamicTableCreateDTO.java @@ -0,0 +1,42 @@ +package com.senmesh.component.dynamictable.dto; + +import java.util.List; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2024-04-09 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Builder +@Data +@ApiModel(description = "动态表格") +public class DynamicTableCreateDTO extends BaseOperateDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 表格类型 **/ + @NotBlank(message = "表格类型不能为空") + private String tableType; + /** 用户id **/ + private Long userId; + /** 表格列配置数据 **/ + @NotNull(message = "表格配置不能为空") + @Valid + private List columnDTOs; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/dynamictable/dto/DynamicTableDTO.java b/backend/src/main/java/com/senmesh/component/dynamictable/dto/DynamicTableDTO.java new file mode 100644 index 0000000..bcaeb38 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dynamictable/dto/DynamicTableDTO.java @@ -0,0 +1,51 @@ +package com.senmesh.component.dynamictable.dto; + +import java.util.List; + +import org.apache.commons.collections.ListUtils; +import org.apache.commons.lang3.StringUtils; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.senmesh.common.dto.BaseDTO; +import com.senmesh.common.util.JsonUtils; + +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.Builder.Default; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2024-04-09 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "动态表格") +public class DynamicTableDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 类型 **/ + private String tableType; + /** 用户id **/ + private Long userId; + /** 表格列数据json **/ + @JsonIgnore + private String columnData; + @Default + private List columnDTOs = ListUtils.EMPTY_LIST; + + public void setColumnData(String columnData) { + this.columnData = columnData; + if (StringUtils.isNotBlank(columnData)) { + columnDTOs = JsonUtils.toList(columnData, DynamicTableColumnDTO.class); + } + } + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/dynamictable/dto/DynamicTableModifyDTO.java b/backend/src/main/java/com/senmesh/component/dynamictable/dto/DynamicTableModifyDTO.java new file mode 100644 index 0000000..e7466dd --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dynamictable/dto/DynamicTableModifyDTO.java @@ -0,0 +1,43 @@ +package com.senmesh.component.dynamictable.dto; + +import java.util.List; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2024-04-09 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Builder +@Data +@ApiModel(description = "动态表格") +public class DynamicTableModifyDTO extends BaseOperateDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 表格类型 **/ + @NotBlank(message = "表格类型不能为空") + private String tableType; + /** 用户id **/ + private Long userId; + /** 表格列配置数据 **/ + @NotNull(message = "表格配置不能为空") + @Valid + private List columnDTOs; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/dynamictable/dto/DynamicTableQueryDTO.java b/backend/src/main/java/com/senmesh/component/dynamictable/dto/DynamicTableQueryDTO.java new file mode 100644 index 0000000..e2917e6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dynamictable/dto/DynamicTableQueryDTO.java @@ -0,0 +1,33 @@ +package com.senmesh.component.dynamictable.dto; + + +import com.senmesh.common.dto.PageQueryDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2024-04-09 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "动态表格查询条件") +public class DynamicTableQueryDTO extends PageQueryDTO{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + /** 表格类型 **/ + private String tableType; + /** 用户id **/ + private Long userId; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/dynamictable/entity/DynamicTable.java b/backend/src/main/java/com/senmesh/component/dynamictable/entity/DynamicTable.java new file mode 100644 index 0000000..b320d20 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dynamictable/entity/DynamicTable.java @@ -0,0 +1,36 @@ +package com.senmesh.component.dynamictable.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 动态表格 + * + * @author sr on 2024-04-09 + */ +@TableName("uc_dynamic_table") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class DynamicTable extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 类型 **/ + private String tableType; + /** 用户id **/ + private Long userId; + /** 表格列数据json **/ + private String columnData; + + +} diff --git a/backend/src/main/java/com/senmesh/component/dynamictable/mapper/DynamicTableMapper.xml b/backend/src/main/java/com/senmesh/component/dynamictable/mapper/DynamicTableMapper.xml new file mode 100644 index 0000000..d646b21 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dynamictable/mapper/DynamicTableMapper.xml @@ -0,0 +1,22 @@ + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/dynamictable/mapstruct/DynamicTableMapMapper.java b/backend/src/main/java/com/senmesh/component/dynamictable/mapstruct/DynamicTableMapMapper.java new file mode 100644 index 0000000..742e8ff --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dynamictable/mapstruct/DynamicTableMapMapper.java @@ -0,0 +1,48 @@ +package com.senmesh.component.dynamictable.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.component.dynamictable.dto.DynamicTableCreateDTO; +import com.senmesh.component.dynamictable.dto.DynamicTableDTO; +import com.senmesh.component.dynamictable.dto.DynamicTableModifyDTO; +import com.senmesh.component.dynamictable.entity.DynamicTable; + +/** + * @author sr on 2024-04-09 + */ +@Mapper +public interface DynamicTableMapMapper { + + DynamicTableMapMapper INSTANCE = + Mappers.getMapper(DynamicTableMapMapper.class); + + /** + * dto to entity + * + * @param dynamicTableDto + * @return + * @author sr on 2024-04-09 + */ + DynamicTable toEntity( + DynamicTableDTO dynamicTableDto); + + /** + * entity to dto + * + * @param dynamicTable + * @return + * @author sr on 2024-04-09 + */ + DynamicTableDTO toDto(DynamicTable dynamicTable); + + + /** + * @param dynamicTableCreateDTO + * @return + * @author sr on 2024-04-09 + */ + DynamicTable toEntity(DynamicTableCreateDTO dynamicTableCreateDTO); + DynamicTable toEntity(DynamicTableModifyDTO dynamicTableModifyDTO); + +} diff --git a/backend/src/main/java/com/senmesh/component/dynamictable/service/DynamicTableService.java b/backend/src/main/java/com/senmesh/component/dynamictable/service/DynamicTableService.java new file mode 100644 index 0000000..a5c76a6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dynamictable/service/DynamicTableService.java @@ -0,0 +1,69 @@ +package com.senmesh.component.dynamictable.service; + +import java.util.List; + +import com.senmesh.component.dynamictable.dto.DynamicTableCreateDTO; +import com.senmesh.component.dynamictable.dto.DynamicTableDTO; +import com.senmesh.component.dynamictable.dto.DynamicTableModifyDTO; +import com.senmesh.component.dynamictable.dto.DynamicTableQueryDTO; + +/** + * 动态表格 + * + * @author sr on 2024-04-09 + */ +public interface DynamicTableService { + + /** + * 新增 + * + * @param dynamicTableCreateDTO + * @return + * @author sr on 2024-04-09 + */ + Long create(DynamicTableCreateDTO dynamicTableCreateDTO); + + /** + * 修改 + * + * @param dynamicTableOperateDTO + * @author sr on 2024-04-09 + */ + void modify(DynamicTableModifyDTO dynamicTableModifyDTO); + + /** + * 删除 + * + * @param tableType + * @author sr on 2024-04-09 + */ + void remove(String tableType); + + /** + * 查询 + * + * @param dynamicTableQueryDTO + * @return + * @author sr on 2024-04-09 + */ + List list(DynamicTableQueryDTO dynamicTableQueryDTO); + + /** + * 分页查询 + * + * @param dynamicTableQueryDTO + * @return + * @author sr on 2024-04-09 + */ + void page(DynamicTableQueryDTO dynamicTableQueryDTO); + + /** + * 单个查询 + * + * @param dynamicTableQueryDTO + * @return + * @author sr on 2024-04-09 + */ + DynamicTableDTO find(DynamicTableQueryDTO dynamicTableQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/component/dynamictable/service/impl/DynamicTableServiceImpl.java b/backend/src/main/java/com/senmesh/component/dynamictable/service/impl/DynamicTableServiceImpl.java new file mode 100644 index 0000000..23d38ef --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dynamictable/service/impl/DynamicTableServiceImpl.java @@ -0,0 +1,137 @@ +package com.senmesh.component.dynamictable.service.impl; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.common.util.ListUtil; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.component.dynamictable.dao.DynamicTableMapper; +import com.senmesh.component.dynamictable.dto.DynamicTableColumnDTO; +import com.senmesh.component.dynamictable.dto.DynamicTableCreateDTO; +import com.senmesh.component.dynamictable.dto.DynamicTableDTO; +import com.senmesh.component.dynamictable.dto.DynamicTableModifyDTO; +import com.senmesh.component.dynamictable.dto.DynamicTableQueryDTO; +import com.senmesh.component.dynamictable.entity.DynamicTable; +import com.senmesh.component.dynamictable.mapstruct.DynamicTableMapMapper; +import com.senmesh.component.dynamictable.service.DynamicTableService; +import com.senmesh.frame.redis.dto.LockDTO; +import com.senmesh.frame.redis.redisson.RedissonUtils; + +/** + * @author sr on 2024-04-09 + */ +@Service +public class DynamicTableServiceImpl implements DynamicTableService { + + @Autowired + private DynamicTableMapper dynamicTableMapper; + + public static LockDTO getLockDTO(Long userId, String tableType) { + Assert.notNull(userId, "用户id不能为空"); + Assert.notNull(tableType, "表格类型不能为空"); + return LockDTO.builder().methodName("dynamictable").tryLockWaitTime(0L) + .arg(userId.toString()) + .arg(tableType) + .failMsg("该用户表格配置正在被操作") + .build(); + } + + @Override + // @AutoUnLock + @Transactional + public Long create(DynamicTableCreateDTO dynamicTableCreateDTO) { + Long userId = dynamicTableCreateDTO.getUserId(); + String tableType = dynamicTableCreateDTO.getTableType(); + DynamicTableQueryDTO dynamicTableQueryDTO = DynamicTableQueryDTO.builder().userId(userId) + .tableType(tableType).build(); + // 校验 + List columnDTOs = dynamicTableCreateDTO.getColumnDTOs(); + checkColumn(columnDTOs); + + DynamicTableDTO dynamicTableDTO = RedissonUtils.lockAndSave(getLockDTO(userId, tableType), + () -> this.find(dynamicTableQueryDTO), () -> { + DynamicTable dynamicTable = + DynamicTableMapMapper.INSTANCE.toEntity(dynamicTableCreateDTO); + dynamicTable.setColumnData(JsonUtils.toDefaultJsonString(columnDTOs)); + dynamicTableMapper.saveEntity(dynamicTable); + return DynamicTableMapMapper.INSTANCE.toDto(dynamicTable); + }); + return dynamicTableDTO.getId(); + + // Long userId = dynamicTableCreateDTO.getUserId(); + // String tableType = dynamicTableCreateDTO.getTableType(); + // DynamicTableQueryDTO dynamicTableQueryDTO = DynamicTableQueryDTO.builder().userId(userId) + // .tableType(tableType).build(); + // + // DynamicTableDTO dynamicTableDTO = this.find(dynamicTableQueryDTO); + // if (dynamicTableDTO != null) { + // return dynamicTableDTO.getId(); + // } + // LockDTO lockDTO = getPhoneLockDTO(userId, tableType); + // Assert.isTrue(RedissonUtils.tryLockAutomatically(lockDTO), lockDTO.getFailMsg()); + // dynamicTableQueryDTO = this.find(dynamicTableQueryDTO); + // if (dynamicTableDTO != null) { + // return dynamicTableDTO.getId(); + // } + // DynamicTable dynamicTable = DynamicTableMapMapper.INSTANCE.toEntity(dynamicTableCreateDTO); + // dynamicTableMapper.saveEntity(dynamicTable); + // return dynamicTable.getId(); + } + + private void checkColumn(List columnDTOs) { + Assert.isTrue(!columnDTOs.isEmpty(), "表格配置不能为空"); + } + + @Override + @Transactional + public void modify(DynamicTableModifyDTO dynamicTableModifyDTO) { + Long userId = dynamicTableModifyDTO.getUserId(); + String tableType = dynamicTableModifyDTO.getTableType(); + DynamicTableQueryDTO dynamicTableQueryDTO = DynamicTableQueryDTO.builder().userId(userId) + .tableType(tableType).build(); + // 校验 + List columnDTOs = dynamicTableModifyDTO.getColumnDTOs(); + checkColumn(columnDTOs); + + DynamicTableDTO dynamicTableDTO = this.find(dynamicTableQueryDTO); + Assert.notNull(dynamicTableDTO, "该用户表格配置不存在"); + DynamicTable dynamicTable = + DynamicTableMapMapper.INSTANCE.toEntity(dynamicTableModifyDTO); + dynamicTable + .setColumnData(JsonUtils.toDefaultJsonString(dynamicTableModifyDTO.getColumnDTOs())); + dynamicTableMapper.updateEntitySelective(dynamicTable); + } + + @Override + @Transactional + public void remove(String tableType) { + DynamicTableDTO dynamicTableDTO = + this.find(DynamicTableQueryDTO.builder().userId(UserContextHolder.getExistLoginUserId()) + .tableType(tableType).build()); + Assert.notNull(dynamicTableDTO, "该用户表格配置不存在"); + dynamicTableMapper.deleteEntity(DynamicTable.builder().id(dynamicTableDTO.getId()).build()); + } + + @Override + public List list(DynamicTableQueryDTO dynamicTableQueryDTO) { + dynamicTableQueryDTO.disablePage(); + return dynamicTableMapper.listDynamicTableDTO(dynamicTableQueryDTO); + } + + @Override + public void page(DynamicTableQueryDTO dynamicTableQueryDTO) { + dynamicTableMapper.listDynamicTableDTO(dynamicTableQueryDTO); + } + + @Override + public DynamicTableDTO find(DynamicTableQueryDTO dynamicTableQueryDTO) { + List dynamicTableDTOs = this.list(dynamicTableQueryDTO); + return ListUtil.first(dynamicTableDTOs); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/dynamictable/util/DynamicTableUtils.java b/backend/src/main/java/com/senmesh/component/dynamictable/util/DynamicTableUtils.java new file mode 100644 index 0000000..8ca73c2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/dynamictable/util/DynamicTableUtils.java @@ -0,0 +1,8 @@ +package com.senmesh.component.dynamictable.util; + +/** + * @author sr on 2024-04-09 + */ +public class DynamicTableUtils { + +} diff --git a/backend/src/main/java/com/senmesh/component/exceptionrecord/dao/ExceptionRecordMapper.java b/backend/src/main/java/com/senmesh/component/exceptionrecord/dao/ExceptionRecordMapper.java new file mode 100644 index 0000000..3456b46 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/exceptionrecord/dao/ExceptionRecordMapper.java @@ -0,0 +1,11 @@ +package com.senmesh.component.exceptionrecord.dao; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.senmesh.component.exceptionrecord.entity.ExceptionRecord; + + +public interface ExceptionRecordMapper extends BaseMapper { + + int getExceptionRecordCount(); +} diff --git a/backend/src/main/java/com/senmesh/component/exceptionrecord/emuns/ExceptionRecordSysEnum.java b/backend/src/main/java/com/senmesh/component/exceptionrecord/emuns/ExceptionRecordSysEnum.java new file mode 100644 index 0000000..7f30fad --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/exceptionrecord/emuns/ExceptionRecordSysEnum.java @@ -0,0 +1,26 @@ +package com.senmesh.component.exceptionrecord.emuns; + +import com.baomidou.mybatisplus.annotation.EnumValue; + +/** + * 接口记录系统枚举 + */ +public enum ExceptionRecordSysEnum { + + HYG("1", "慧用工"), + XINPAI("2", "薪派"); + + @EnumValue + private final String source; + + private final String desc; + + ExceptionRecordSysEnum(String source, String desc) { + this.source = source; + this.desc = desc; + } + + public String getSource() { + return source; + } +} diff --git a/backend/src/main/java/com/senmesh/component/exceptionrecord/entity/ExceptionRecord.java b/backend/src/main/java/com/senmesh/component/exceptionrecord/entity/ExceptionRecord.java new file mode 100644 index 0000000..98d7dc6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/exceptionrecord/entity/ExceptionRecord.java @@ -0,0 +1,43 @@ +package com.senmesh.component.exceptionrecord.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; +import com.senmesh.component.exceptionrecord.emuns.ExceptionRecordSysEnum; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 异常接口调用记录 + * @author fzp on 2021年7月8日15:21:53 + */ +@EqualsAndHashCode(callSuper = true) +@TableName("xs_exception_record") +@NoArgsConstructor +@AllArgsConstructor +@Data +@Builder +public class ExceptionRecord extends BaseEntity { + + private static final long serialVersionUID = 1449782318298222341L; + /** + * 入参json + */ + private String paramJson; + /** + * 响应json + */ + private String resultJson; + /** + * 调用接口地址 + */ + private String url; + /** + * 系统 1 慧用工、2、3、4待定 + */ + private ExceptionRecordSysEnum sys; + +} diff --git a/backend/src/main/java/com/senmesh/component/exceptionrecord/mapper/ExceptionRecordMapper.xml b/backend/src/main/java/com/senmesh/component/exceptionrecord/mapper/ExceptionRecordMapper.xml new file mode 100644 index 0000000..abc5bfe --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/exceptionrecord/mapper/ExceptionRecordMapper.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/backend/src/main/java/com/senmesh/component/exceptionrecord/service/ExceptionRecordService.java b/backend/src/main/java/com/senmesh/component/exceptionrecord/service/ExceptionRecordService.java new file mode 100644 index 0000000..16b8afb --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/exceptionrecord/service/ExceptionRecordService.java @@ -0,0 +1,12 @@ +package com.senmesh.component.exceptionrecord.service; + + +import com.baomidou.mybatisplus.extension.service.IService; +import com.senmesh.component.exceptionrecord.entity.ExceptionRecord; + +/** + * @author sr on 2020-05-26 + */ +public interface ExceptionRecordService extends IService { + +} diff --git a/backend/src/main/java/com/senmesh/component/exceptionrecord/service/impl/ExceptionRecordServiceImpl.java b/backend/src/main/java/com/senmesh/component/exceptionrecord/service/impl/ExceptionRecordServiceImpl.java new file mode 100644 index 0000000..099c5b5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/exceptionrecord/service/impl/ExceptionRecordServiceImpl.java @@ -0,0 +1,18 @@ +package com.senmesh.component.exceptionrecord.service.impl; + + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.senmesh.component.exceptionrecord.dao.ExceptionRecordMapper; +import com.senmesh.component.exceptionrecord.entity.ExceptionRecord; +import com.senmesh.component.exceptionrecord.service.ExceptionRecordService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * @author fzp on 2021年7月8日15:16:46 + */ +@Slf4j +@Service +public class ExceptionRecordServiceImpl extends ServiceImpl implements ExceptionRecordService { + +} diff --git a/backend/src/main/java/com/senmesh/component/file/config/FileConfiguration.java b/backend/src/main/java/com/senmesh/component/file/config/FileConfiguration.java new file mode 100644 index 0000000..58dcef3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/config/FileConfiguration.java @@ -0,0 +1,28 @@ +package com.senmesh.component.file.config; + +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.component.file.constant.FileStorageEnum; +import com.senmesh.component.file.service.storage.AliFileStorage; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class FileConfiguration { + + @Autowired + private FileProperties fileProperties; + + /** + * @param environmentUtils 使其优先注入 + * @return + * @author sr on 2022-03-01 + */ + @Bean + @ConditionalOnProperty(name = "file.storage.type", havingValue = FileStorageEnum.ALI_NAME) + public AliFileStorage aliFileStorage(EnvironmentUtils environmentUtils) { + return new AliFileStorage(fileProperties); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/file/config/FileProperties.java b/backend/src/main/java/com/senmesh/component/file/config/FileProperties.java new file mode 100644 index 0000000..f5f2286 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/config/FileProperties.java @@ -0,0 +1,53 @@ +package com.senmesh.component.file.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@ConfigurationProperties(prefix = "file") +@Component +@Data +public class FileProperties { + + /** 文件上传路径 **/ + private String uploadDir; + + private final Storage storage = new Storage(); + + private final Transfer transfer = new Transfer(); + + @Data + @NoArgsConstructor + public static class Transfer { + /** 文件位置:1内网2外网 **/ + private String location; + + /** 传输发送目录 **/ + private String sendDir; + + /** 传输接收目录 **/ + private String receiveDir; + + /** 解包风险校验开关 **/ + private Boolean unpackRiskCheck = false; + } + + @Data + @NoArgsConstructor + public static class Storage{ + private String type; + private final AliStorage ali = new AliStorage(); + } + + @Data + @NoArgsConstructor + public static class AliStorage{ + private String endpoint; + private String accessKeyId; + private String accessKeySecret; + private String bucketName; + } + +} diff --git a/backend/src/main/java/com/senmesh/component/file/constant/FileClassCodeEnum.java b/backend/src/main/java/com/senmesh/component/file/constant/FileClassCodeEnum.java new file mode 100644 index 0000000..b7803ab --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/constant/FileClassCodeEnum.java @@ -0,0 +1,31 @@ +package com.senmesh.component.file.constant; + +/** + * 附件类型标识 + * @author sr on 2022-09-29 + */ +public enum FileClassCodeEnum { + + EXCEL("100", ".xls.xlsx"), + WORD("200", ".doc.docx"), + IMG("300", ".jpg.jpeg.gif.png.bmp"), + PDF("400", ".pdf"), + ; + + private String code; + private String suffix; + + FileClassCodeEnum (String code, String suffix) { + this.code = code; + this.suffix = suffix; + } + + public String getCode() { + return this.code; + } + + public String getSuffix() { + return this.suffix; + } + +} diff --git a/backend/src/main/java/com/senmesh/component/file/constant/FileConstants.java b/backend/src/main/java/com/senmesh/component/file/constant/FileConstants.java new file mode 100644 index 0000000..43d02d1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/constant/FileConstants.java @@ -0,0 +1,35 @@ +package com.senmesh.component.file.constant; + +import java.math.BigDecimal; + +/** + * + * + */ +public class FileConstants { + + /** 默认压缩比例 **/ + public static final BigDecimal DEFAULT_QUALITY = new BigDecimal("0.6"); + + + public enum Unit{ + //单位 + B("B", 1L), K("K", 1024L), M("B", 1048576L), G("G", 1073741824L), T("T", 1099511627776L); + private Unit(String name, long value){ + this.name = name; + this.value = value; + } + private String name; + + private Long value; + + public String getName() { + return name; + } + + public Long getValue() { + return value; + } + } + +} diff --git a/backend/src/main/java/com/senmesh/component/file/constant/FileStorageEnum.java b/backend/src/main/java/com/senmesh/component/file/constant/FileStorageEnum.java new file mode 100644 index 0000000..c91e3d7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/constant/FileStorageEnum.java @@ -0,0 +1,20 @@ +package com.senmesh.component.file.constant; + +public enum FileStorageEnum { + + LOCAL(FileStorageEnum.LOCAL_NAME),ALI(FileStorageEnum.ALI_NAME); + + public static final String LOCAL_NAME = "local"; + public static final String ALI_NAME = "ali"; + + private String type; + + FileStorageEnum(String type){ + this.type = type; + } + + public String getType() { + return this.type; + } + +} diff --git a/backend/src/main/java/com/senmesh/component/file/controller/AnonFileController.java b/backend/src/main/java/com/senmesh/component/file/controller/AnonFileController.java new file mode 100644 index 0000000..2fd9ded --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/controller/AnonFileController.java @@ -0,0 +1,48 @@ +package com.senmesh.component.file.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.component.file.dto.FileUploadDTO; +import com.senmesh.component.file.entity.FileRecord; +import com.senmesh.component.file.service.FileService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author sr on 2019-12-11 + */ +@RestController +@Api(tags = "匿名文件操作") +public class AnonFileController { + + @Autowired + private FileService fileService; + + @ApiOperation("根据code下载文件") + @GetMapping("/file/download/{fileCode}") + public void download(@PathVariable String fileCode, HttpServletRequest request, + HttpServletResponse response) throws IOException { + fileService.download(fileCode, request, response, Boolean.FALSE); + } + + @ApiOperation("根据code预览文件") + @GetMapping("/file/display/{fileCode}") + public void display(@PathVariable String fileCode, HttpServletRequest request, + HttpServletResponse response) throws IOException { + fileService.download(fileCode, request, response, Boolean.TRUE); + } + + @ApiOperation("附件上传") + @PostMapping(value = "/file/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public AlitaResult upload(@Validated FileUploadDTO fileUploadDTO) { + return AlitaResult.success(fileService.upload(fileUploadDTO)); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/file/controller/FileClassController.java b/backend/src/main/java/com/senmesh/component/file/controller/FileClassController.java new file mode 100644 index 0000000..8b3be44 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/controller/FileClassController.java @@ -0,0 +1,85 @@ +package com.senmesh.component.file.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +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; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; +import com.senmesh.component.file.dto.FileClassDTO; +import com.senmesh.component.file.service.FileClassService; +import com.senmesh.tkmybatis.pojo.Page; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +@Api(tags = "文件配置操作") +@RestController +@RequestMapping({"/file_class"}) +public class FileClassController { + + @Autowired + private FileClassService fileClassService; + + /** + * 新增 + * + * @param fileClass + */ + @ApiOperation("新增文件配置") + @PostMapping("save") + public AlitaResult saveFile(@Validated(Create.class) @RequestBody FileClassDTO fileClassDto) { + fileClassService.save(fileClassDto); + return AlitaResult.success(fileClassDto); + } + + /** + * 修改 + * + * @param fileClass + */ + @ApiOperation("修改文件配置") + @PostMapping("update") + public AlitaResult updateFile(@Validated(Update.class) @RequestBody FileClassDTO fileClassDto) { + fileClassService.upadte(fileClassDto); + return AlitaResult.success(fileClassDto); + } + + /** + * 删除 + * + * @param fileClassId + */ + @ApiOperation("删除文件配置") + @PostMapping("delete") + public AlitaResult deleteFile(@RequestBody Long fileClassId) { + fileClassService.delete(fileClassId); + return AlitaResult.success(true); + } + + /** + * 查询 + * + * @param page + * @param fileClass + */ + @ApiOperation("分页查询文件配置") + @GetMapping("list") + public AlitaResult> query(Page page, FileClassDTO fileClassDto) { + fileClassService.query(page, fileClassDto); + return AlitaResult.success(page); + } + + @ApiOperation("根据编码获取文件配置") + @GetMapping("find_by_code/{code}") + public AlitaResult findByCode(@PathVariable String code){ + return AlitaResult.success(fileClassService.findByCode(code)); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/file/controller/FileRecordController.java b/backend/src/main/java/com/senmesh/component/file/controller/FileRecordController.java new file mode 100644 index 0000000..315d84b --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/controller/FileRecordController.java @@ -0,0 +1,100 @@ +package com.senmesh.component.file.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.component.file.entity.FileRecord; +import com.senmesh.component.file.service.FileRecordService; +import com.senmesh.component.file.service.FileService; +import com.senmesh.tkmybatis.pojo.Page; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@Api(tags = "文件记录操作") +@RestController +@RequestMapping({"/file"}) +public class FileRecordController { + + @Autowired + private FileRecordService fileRecordService; + + @Autowired + private FileService fileService; + + /** + * 新增 + * + * @param fileRecord + */ + @ApiOperation("新增文件记录") + @PostMapping("save") + public AlitaResult saveFile(@RequestBody FileRecord fileRecord) { + fileRecordService.saveFileRecord(fileRecord); + return AlitaResult.success(fileRecord); + } + + /** + * 修改 + * + * @param fileRecord + */ + @ApiOperation("修改文件记录") + @PostMapping("update") + public AlitaResult updateFile(@RequestBody FileRecord fileRecord) { + fileRecordService.updateFileRecord(fileRecord); + return AlitaResult.success(fileRecord); + } + + /** + * 删除 + * + * @param fileRecord + */ + @ApiOperation("删除文件记录") + @PostMapping("delete") + public AlitaResult deleteFile(@RequestBody FileRecord fileRecord) { + fileRecordService.deleteFileRecord(fileRecord); + return AlitaResult.success(fileRecord); + } + + /** + * 查询 + * + * @param page + * @param fileRecord + */ + @ApiOperation("分页查询文件记录") + @GetMapping("list") + public AlitaResult> query(Page page, FileRecord fileRecord) { + fileRecordService.query(page, fileRecord); + return AlitaResult.success(page); + } + + @ApiOperation("查询单个文件") + @GetMapping("find") + public AlitaResult find(FileRecord fileRecord) { + return AlitaResult.success(fileRecordService.find(fileRecord)); + } + + + /** + * 附件下载 + */ + @ApiOperation("下载文件记录") + @PostMapping("download") + public void download(@RequestBody FileRecord fileRecord, HttpServletRequest request, HttpServletResponse response) { + fileRecord.setOrgId(UserContextHolder.getLoginOrgId()); + FileRecord temp = fileRecordService.find(fileRecord); + try { + fileService.download(temp, request, response, Boolean.FALSE); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/backend/src/main/java/com/senmesh/component/file/dao/FileClassMapper.java b/backend/src/main/java/com/senmesh/component/file/dao/FileClassMapper.java new file mode 100644 index 0000000..d1d087f --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/dao/FileClassMapper.java @@ -0,0 +1,27 @@ +package com.senmesh.component.file.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.component.file.dto.FileClassDTO; +import com.senmesh.component.file.entity.FileClass; +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.tkmybatis.pojo.Page; + +/** + * 文件类型 + * + * @author on 2019-11-05 + */ +public interface FileClassMapper extends MyMapper { + + /** + * 分页查询 + * + * @param page + * @param fileClass + * @return + */ + List query(Page page, @Param("param") FileClassDTO fileClassDto); +} diff --git a/backend/src/main/java/com/senmesh/component/file/dao/FileRecordMapper.java b/backend/src/main/java/com/senmesh/component/file/dao/FileRecordMapper.java new file mode 100644 index 0000000..e057521 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/dao/FileRecordMapper.java @@ -0,0 +1,30 @@ +package com.senmesh.component.file.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.component.file.entity.FileRecord; +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.tkmybatis.pojo.Page; + +public interface FileRecordMapper extends MyMapper { + + /** + * 分页查询 + * + * @param page + * @param file + * @return + */ + List query(Page page, @Param("param") FileRecord file); + + FileRecord find(@Param("param")FileRecord fileRecord); + + /** + * 根据fileCode获取导入文件路径 + * @param fileRecord + * @return + */ + String findFilePathByCode(@Param("param")FileRecord fileRecord); +} diff --git a/backend/src/main/java/com/senmesh/component/file/dto/FileClassDTO.java b/backend/src/main/java/com/senmesh/component/file/dto/FileClassDTO.java new file mode 100644 index 0000000..13931c0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/dto/FileClassDTO.java @@ -0,0 +1,45 @@ +package com.senmesh.component.file.dto; + +import javax.validation.constraints.NotEmpty; + +import com.senmesh.common.dto.BaseDTO; +import com.senmesh.common.validation.Create; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2019-12-10 + */ +@ApiModel("文件配置") +@Data +@EqualsAndHashCode(callSuper = false) +@NoArgsConstructor +@SuperBuilder +public class FileClassDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = -4289393281290178026L; + + @NotEmpty(message = "文件编码为空", groups = {Create.class}) + @ApiModelProperty("文件编码") + private String classCode; + + @ApiModelProperty("文件描述") + @NotEmpty(message = "文件描述为空", groups = {Create.class}) + private String className; + + @ApiModelProperty("文件最大大小(kb)") + private Integer fileMaxSize; + + @ApiModelProperty("支持的文件后缀") + private String fileSuffix; + + @ApiModelProperty("机构id") + private Long orgId; + +} diff --git a/backend/src/main/java/com/senmesh/component/file/dto/FileUploadDTO.java b/backend/src/main/java/com/senmesh/component/file/dto/FileUploadDTO.java new file mode 100644 index 0000000..92e019a --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/dto/FileUploadDTO.java @@ -0,0 +1,74 @@ +package com.senmesh.component.file.dto; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.math.BigDecimal; + +import javax.validation.constraints.NotNull; + +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.util.FileCopyUtils; +import org.springframework.web.multipart.MultipartFile; + +import com.senmesh.common.annotation.Mask; +import com.senmesh.common.exception.BusinessException; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel("附件上传") +@Slf4j +public class FileUploadDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 8811233334943715159L; + + @NotNull(message = "文件不能为空") + @ApiModelProperty("文件") + @Mask + private MultipartFile file; + @ApiModelProperty("文件名,如果未传,则通过file获取") + private String filename; + @ApiModelProperty("压缩比例(0-1) 一位小数 超出范围不进行压缩") + private BigDecimal quality; + @ApiModelProperty("文件类型编码") + private String fileClassCode; + @ApiModelProperty("是否临时文件") + private boolean temp; + @ApiModelProperty("文件上传大小限制") + private Long fileSizeLimit; + + public FileUploadDTO setIs(InputStream is) { + try { + return this.setByte(FileCopyUtils.copyToByteArray(is)); + } catch (IOException e) { + throw new BusinessException("文件流转byte失败"); + } + } + + public FileUploadDTO setByte(byte[] bytes) { + MockMultipartFile mockMultipartFile; + String fileName = this.getFilename(); + try { + mockMultipartFile = new MockMultipartFile(fileName, fileName, + MediaType.APPLICATION_OCTET_STREAM.toString(), bytes); + this.setFile(mockMultipartFile); + return this; + } catch (Exception e) { + log.info("构建mockMultipartFile失败", e); + throw new BusinessException("文件存储失败"); + } + } + +} diff --git a/backend/src/main/java/com/senmesh/component/file/entity/FileClass.java b/backend/src/main/java/com/senmesh/component/file/entity/FileClass.java new file mode 100644 index 0000000..0afcbeb --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/entity/FileClass.java @@ -0,0 +1,44 @@ +package com.senmesh.component.file.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.OrgBaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@TableName("xs_file_class") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class FileClass extends OrgBaseEntity { + + /** **/ + private static final long serialVersionUID = -6032690348770194026L; + + /** + * 文件编码 + */ + private String classCode; + + /** + * 文件描述 + */ + private String className; + + /** + * 文件最大大小(kb) + */ + private Integer fileMaxSize; + + /** + * 支持的文件后缀 + */ + private String fileSuffix; + + +} diff --git a/backend/src/main/java/com/senmesh/component/file/entity/FileRecord.java b/backend/src/main/java/com/senmesh/component/file/entity/FileRecord.java new file mode 100644 index 0000000..777bc17 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/entity/FileRecord.java @@ -0,0 +1,71 @@ +package com.senmesh.component.file.entity; + +import org.springframework.data.annotation.Transient; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@TableName("xs_file_record") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Builder +@Data +public class FileRecord extends BaseEntity { + + /** **/ + private static final long serialVersionUID = -4977814778074210092L; + + /** + * 文件编码 + */ + private String fileCode; + + /** + * 文件路径 + */ + private String filePath; + + /** + * 文件名 + */ + private String fileName; + + /** + * 文件大小(kb) + */ + private Long fileSize; + + /** + * 文件md5 + */ + private String md5Code; + + /** + * 文件后缀 + */ + private String fileSuffix; + + /** + * 所属机构 + */ + private Long orgId; + + /** 储存器类型 **/ + private String storageType; + + /** + * 外部文件url + */ + @Transient + private String externalFileUrl; + + @Transient + private String importType; +} diff --git a/backend/src/main/java/com/senmesh/component/file/mapper/FileClassMapper.xml b/backend/src/main/java/com/senmesh/component/file/mapper/FileClassMapper.xml new file mode 100644 index 0000000..462d33f --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/mapper/FileClassMapper.xml @@ -0,0 +1,51 @@ + + + + + + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/file/mapper/FileRecordMapper.xml b/backend/src/main/java/com/senmesh/component/file/mapper/FileRecordMapper.xml new file mode 100644 index 0000000..b1b7e1b --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/mapper/FileRecordMapper.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/component/file/service/FileClassMapMapper.java b/backend/src/main/java/com/senmesh/component/file/service/FileClassMapMapper.java new file mode 100644 index 0000000..e2d5cdc --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/service/FileClassMapMapper.java @@ -0,0 +1,34 @@ +package com.senmesh.component.file.service; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.component.file.dto.FileClassDTO; +import com.senmesh.component.file.entity.FileClass; + +/** + * 文件配置entity/dto转换 + * @author sr on 2019-12-10 + */ +@Mapper +public interface FileClassMapMapper { + + FileClassMapMapper INSTANCE = Mappers.getMapper(FileClassMapMapper.class); + + /** + * entity to dto + * @param fileClass + * @return + * @author sr on 2019-12-10 + */ + FileClassDTO entityToDto(FileClass fileClass); + + /** + * dto to entity + * @param fileClassDto + * @return + * @author sr on 2019-12-10 + */ + FileClass dtoToEntity(FileClassDTO fileClassDto); + +} diff --git a/backend/src/main/java/com/senmesh/component/file/service/FileClassService.java b/backend/src/main/java/com/senmesh/component/file/service/FileClassService.java new file mode 100644 index 0000000..cdaa939 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/service/FileClassService.java @@ -0,0 +1,45 @@ +package com.senmesh.component.file.service; + +import com.senmesh.component.file.dto.FileClassDTO; +import com.senmesh.tkmybatis.pojo.Page; + +/** + * 文件类型 + * + * @author on 2019-11-05 + */ +public interface FileClassService { + + /** + * 保存 + * @param fileClassDto + */ + void save(FileClassDTO fileClassDto); + + /** + * 更新 + * @param fileClassDto + */ + void upadte(FileClassDTO fileClassDto); + + /** + * 删除 + * @param id + */ + void delete(Long id); + + /** + * 分页查询 + * @param page + * @param fileClassDto + */ + + void query(Page page, FileClassDTO fileClassDto); + + /** + * 根据code获取 + * @param code + * @return + */ + FileClassDTO findByCode(String code); +} diff --git a/backend/src/main/java/com/senmesh/component/file/service/FileRecordService.java b/backend/src/main/java/com/senmesh/component/file/service/FileRecordService.java new file mode 100644 index 0000000..a5d879c --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/service/FileRecordService.java @@ -0,0 +1,51 @@ +package com.senmesh.component.file.service; + +import java.io.InputStream; + +import com.senmesh.component.file.entity.FileRecord; +import com.senmesh.tkmybatis.pojo.Page; + +public interface FileRecordService { + + /** + * 新增 + * + * @param file + */ + void saveFileRecord(FileRecord file); + + /** + * 修改 + * + * @param file + */ + void updateFileRecord(FileRecord file); + + /** + * 删除 + * + * @param file + */ + void deleteFileRecord(FileRecord file); + + /** + * 查询 + * + * @param page + * @param file + */ + void query(Page page, FileRecord file); + + /** + * @param fileRecord + * @return + */ + @Deprecated + InputStream getFile(FileRecord fileRecord); + + InputStream getFile(String fileCode); + + FileRecord find(FileRecord fileRecord); + + String findFilePathByCode(FileRecord fileRecord); +} diff --git a/backend/src/main/java/com/senmesh/component/file/service/FileService.java b/backend/src/main/java/com/senmesh/component/file/service/FileService.java new file mode 100644 index 0000000..02ace33 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/service/FileService.java @@ -0,0 +1,115 @@ +package com.senmesh.component.file.service; + +import com.senmesh.component.file.dto.FileUploadDTO; +import com.senmesh.component.file.entity.FileRecord; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; + +/** + * 文件 + * + * @author sr on 2019-10-24 + */ +public interface FileService { + + + /** + * 根据远程地址上传(非临时文件) + * + * @param url url + * @param fileName 文件名称 + * @param contentType 内容类型 + * @param fileSizeLimit 文件大小限制 + * @return {@link FileRecord} + */ + FileRecord upload(String url, String fileName, String contentType, long fileSizeLimit); + + /** + * 上传(非临时文件) + * + * @param file + * @return + * @author sr on 2019-10-24 + */ + FileRecord upload(MultipartFile file); + + /** + * 上传 + * + * @param fileUploadDTO + * @return {@link FileRecord} + */ + FileRecord upload(FileUploadDTO fileUploadDTO); + + /** + * 下载 + * + * @param fileCode + * @param request + * @param response + * @author sr on 2019-10-24 + */ + void download(String fileCode, HttpServletRequest request, HttpServletResponse response, + Boolean display) throws IOException; + + void download(FileRecord fileRecord, HttpServletRequest request, HttpServletResponse response, + Boolean display) throws IOException; + + /** + * 检查文件(非临时文件) + * @param file + * @param code + */ + void checkFile(MultipartFile file, String code); + + /** + * 根据url保存文件到服务器(非临时文件) + * @param externalFileUrl + * @param fileName + * @return + */ + FileRecord uploadFileByURL(String externalFileUrl, String fileName); + + /** + * (非临时文件) + * @param fileName + * @param bytes + * @return + * @author sr on 2021-12-20 + */ + FileRecord upload(String fileName, byte[] bytes); + + /** + * (临时文件) + * @param fileName + * @param bytes + * @return + * @author sr on 2023-12-07 + */ + FileRecord uploadTemp(String fileName, byte[] bytes); + + /** + * (非临时文件) + * @param fileName + * @param is + * @return + * @author sr on 2023-12-07 + */ + FileRecord upload(String fileName, InputStream is); + + /** + * (临时文件) + * @param fileName + * @param is + * @return + * @author sr on 2023-12-07 + */ + FileRecord uploadTemp(String fileName, InputStream is); + + InputStream getFile(String fileCode); + +} diff --git a/backend/src/main/java/com/senmesh/component/file/service/IFileStorage.java b/backend/src/main/java/com/senmesh/component/file/service/IFileStorage.java new file mode 100644 index 0000000..f2a9a2d --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/service/IFileStorage.java @@ -0,0 +1,35 @@ +package com.senmesh.component.file.service; + +import java.io.InputStream; +import java.io.OutputStream; + +public interface IFileStorage { + + String getType(); + + /** + * 上传 + * @param is + * @param filePath + * @author sr on 2022-03-01 + */ + void upload(InputStream is, String filePath); + + /** + * 下载 + * @param filePath + * @param os + * @param fileSize 文件大小 + * @author sr on 2022-03-01 + */ + void download(String filePath, OutputStream os, Long fileSize); + + /** + * @param filePath + * @return + * @author sr on 2022-03-08 + */ + InputStream download(String filePath); + + void downloadRange(String filePath, OutputStream outputStream, long start, long length); +} diff --git a/backend/src/main/java/com/senmesh/component/file/service/impl/FileClassServiceImpl.java b/backend/src/main/java/com/senmesh/component/file/service/impl/FileClassServiceImpl.java new file mode 100644 index 0000000..7d9afc8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/service/impl/FileClassServiceImpl.java @@ -0,0 +1,74 @@ +package com.senmesh.component.file.service.impl; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.codegenerator.util.CodeUtils; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.BaseDtoUtils; +import com.senmesh.common.util.ListUtil; +import com.senmesh.component.constants.CodeTypeEnum; +import com.senmesh.component.file.dao.FileClassMapper; +import com.senmesh.component.file.dto.FileClassDTO; +import com.senmesh.component.file.entity.FileClass; +import com.senmesh.component.file.service.FileClassMapMapper; +import com.senmesh.component.file.service.FileClassService; +import com.senmesh.tkmybatis.pojo.Page; + +/** + * 文件类型 + * + * @author on 2019-11-05 + */ +@Service +public class FileClassServiceImpl implements FileClassService { + + @Autowired + private FileClassMapper fileClassMapper; + + + @Override + @Transactional(rollbackFor = RuntimeException.class) + public void save(FileClassDTO fileClassDto) { + fileClassDto.setClassCode(CodeUtils.getCode(CodeTypeEnum.FILE_CLASS)); + FileClass fileClass = FileClassMapMapper.INSTANCE.dtoToEntity(fileClassDto); + fileClassMapper.saveEntity(fileClass); + BaseDtoUtils.createCopy(fileClass, fileClassDto); + } + + @Override + @Transactional(rollbackFor = RuntimeException.class) + public void upadte(FileClassDTO fileClassDto) { + FileClass fileClass = FileClassMapMapper.INSTANCE.dtoToEntity(fileClassDto); + fileClassMapper.updateEntity(fileClass); + BaseDtoUtils.updateCopy(fileClass, fileClassDto); + } + + @Override + @Transactional(rollbackFor = RuntimeException.class) + public void delete(Long id) { + FileClass fileClass = new FileClass(); + fileClass.setId(id); + fileClassMapper.deleteEntity(fileClass); + } + + + @Override + @Transactional(rollbackFor = RuntimeException.class) + public void query(Page page, FileClassDTO fileClassDto) { + fileClassMapper.query(page, fileClassDto); + } + + @Override + @Transactional(rollbackFor = RuntimeException.class) + public FileClassDTO findByCode(String code) { + List fileClassDTOs = fileClassMapper.query(null, + FileClassDTO.builder().classCode(code).deleted(Boolean.FALSE).build()); + Assert.isTrue(!fileClassDTOs.isEmpty(), "未找到指定编码的文件配置"); + return ListUtil.first(fileClassDTOs); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/file/service/impl/FileRecordServiceImpl.java b/backend/src/main/java/com/senmesh/component/file/service/impl/FileRecordServiceImpl.java new file mode 100644 index 0000000..e5615e4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/service/impl/FileRecordServiceImpl.java @@ -0,0 +1,91 @@ +package com.senmesh.component.file.service.impl; + +import java.io.InputStream; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.component.file.dao.FileRecordMapper; +import com.senmesh.component.file.entity.FileRecord; +import com.senmesh.component.file.service.FileRecordService; +import com.senmesh.component.file.util.FileStorageUtils; +import com.senmesh.tkmybatis.pojo.Page; + +@Service +public class FileRecordServiceImpl implements FileRecordService { + + @Autowired + private FileRecordMapper fileRecordMapper; + + /** + * 新增 + * + * @param fileRecord + */ + @Override + public void saveFileRecord(FileRecord fileRecord) { + fileRecordMapper.saveEntity(fileRecord); + } + + /** + * 修改 + * + * @param fileRecord + */ + @Override + public void updateFileRecord(FileRecord fileRecord) { + fileRecordMapper.updateEntity(fileRecord); + } + + /** + * 删除 + * + * @param fileRecord + */ + @Override + public void deleteFileRecord(FileRecord fileRecord) { + fileRecordMapper.deleteEntity(fileRecord); + } + + /** + * 查询 + * + * @param page + * @param fileRecord + */ + @Override + public void query(Page page, FileRecord fileRecord) { +// System.out.println("=================" + fileClassService.query(Maps.newHashMap())); + fileRecordMapper.query(page, fileRecord); + } + + + /** + * @param fileRecord + * @return + */ + @Override + public InputStream getFile(FileRecord fileRecord) { + // TODO 校验当前账号是否有权限操作文件 + return FileStorageUtils.get().download(fileRecord.getFilePath()); + } + + @Override + public InputStream getFile(String fileCode) { + FileRecord fileRecord = fileRecordMapper.find(FileRecord.builder().fileCode(fileCode).build()); + Assert.notNull(fileRecord, "文件不存在"); + return FileStorageUtils.get().download(fileRecord.getFilePath()); + } + + @Override + public FileRecord find(FileRecord fileRecord) { + return fileRecordMapper.find(fileRecord); + } + + @Override + public String findFilePathByCode(FileRecord fileRecord) { + return fileRecordMapper.findFilePathByCode(fileRecord); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/file/service/impl/FileServiceImpl.java b/backend/src/main/java/com/senmesh/component/file/service/impl/FileServiceImpl.java new file mode 100644 index 0000000..80835a9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/service/impl/FileServiceImpl.java @@ -0,0 +1,504 @@ +package com.senmesh.component.file.service.impl; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigDecimal; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.Objects; +import java.util.Optional; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.catalina.connector.ClientAbortException; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.tomcat.util.http.fileupload.ByteArrayOutputStream; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.MimeTypeUtils; +import org.springframework.web.multipart.MultipartFile; + +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.exception.util.ExceptionUtils; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.component.file.config.FileProperties; +import com.senmesh.component.file.constant.FileClassCodeEnum; +import com.senmesh.component.file.constant.FileConstants; +import com.senmesh.component.file.dto.FileClassDTO; +import com.senmesh.component.file.dto.FileUploadDTO; +import com.senmesh.component.file.entity.FileRecord; +import com.senmesh.component.file.service.FileClassService; +import com.senmesh.component.file.service.FileRecordService; +import com.senmesh.component.file.service.FileService; +import com.senmesh.component.file.service.IFileStorage; +import com.senmesh.component.file.util.FileUtils; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.img.Img; +import cn.hutool.core.img.ImgUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpUtil; +import lombok.extern.slf4j.Slf4j; + +/** + * 文件 + * + * @author sr on 2019-10-24 + */ +@Slf4j +@Service +public class FileServiceImpl implements FileService { + + @Autowired + private FileProperties fileProperties; + + @Autowired + private FileRecordService fileRecordService; + + @Autowired + private FileClassService fileClassService; + + @Autowired + private IFileStorage fileStorage; + + @Override + public void download(String fileCode, HttpServletRequest request, + HttpServletResponse response, Boolean display) throws IOException { + if (fileCode.contains(".")) { + fileCode = StrUtil.subBefore(fileCode, ".", true); + } + FileRecord fileRecord = fileRecordService.find(FileRecord.builder().fileCode(fileCode).build()); + this.download(fileRecord, request, response, display); + } + + @Override + public void download(FileRecord fileRecord, HttpServletRequest request, + HttpServletResponse response, Boolean display) throws IOException { + ExceptionUtils.throwBusinessException(fileRecord == null, "未找到对应文件"); + HttpSession session = request.getSession(); + + String filename = fileRecord.getFileName(); + if (StringUtils.isNotBlank(request.getParameter("filename"))) { + filename = URLDecoder.decode(request.getParameter("filename"),"utf-8"); + } + filename = filename.replaceAll("[\\r\\n\"']", ""); + + String mimeType = session.getServletContext().getMimeType(filename); + response.setContentType(mimeType); + String encodFilename = URLEncoder.encode(filename, "utf-8"); + response.setHeader("code", "200"); + response.setHeader("Cache-Control", "max-age=31556926"); + + // 检查是否为视频文件,如果是则支持Range请求 + boolean isVideo = mimeType != null && mimeType.startsWith("video/"); + + if (!Boolean.TRUE.equals(display)) { + response.setHeader("Content-Disposition", + String.format("attachment; filename=\"%1$s\"; filename*=utf-8''%1$s", encodFilename)); + } + + Long fileSize = fileRecord.getFileSize(); + + // 对于视频文件,支持Range请求 + if (isVideo) { + handleVideoDownloadWithRange(fileRecord, request, response, fileSize); + } else { + // 普通文件下载 + try (OutputStream outputStream = response.getOutputStream()) { + fileStorage.download(fileRecord.getFilePath(), outputStream, fileSize); + } catch (ClientAbortException e) { + log.warn("客户端主动断开连接: {}", e.getMessage()); + } + } + } + + /** + * 处理支持Range请求的视频文件下载 + */ + private void handleVideoDownloadWithRange(FileRecord fileRecord, HttpServletRequest request, + HttpServletResponse response, Long fileSize) throws IOException { + + // 设置支持Range请求的头部 + response.setHeader("Accept-Ranges", "bytes"); + + if (fileSize != null) { + response.setHeader("Content-Length", String.valueOf(fileSize)); + } + + String rangeHeader = request.getHeader("Range"); + + if (rangeHeader != null && rangeHeader.startsWith("bytes=")) { + // 处理Range请求 + handleRangeRequest(fileRecord, response, rangeHeader, fileSize); + } else { + // 普通请求,但设置正确的头部 + if (fileSize != null) { + response.setContentLengthLong(fileSize); + } + try (OutputStream outputStream = response.getOutputStream()) { + fileStorage.download(fileRecord.getFilePath(), outputStream, fileSize); + } catch (ClientAbortException e) { + log.warn("客户端主动断开连接: {}", e.getMessage()); + } + } + } + + /** + * 处理HTTP Range请求 + */ + private void handleRangeRequest(FileRecord fileRecord, HttpServletResponse response, + String rangeHeader, Long fileSize) throws IOException { + + if (fileSize == null) { + // 如果没有文件大小信息,降级为普通下载 + try (OutputStream outputStream = response.getOutputStream()) { + fileStorage.download(fileRecord.getFilePath(), outputStream, fileSize); + } catch (ClientAbortException e) { + log.warn("客户端主动断开连接: {}", e.getMessage()); + } + return; + } + + // 解析Range头部,格式:bytes=start-end + String range = rangeHeader.substring(6); // 去掉 "bytes=" + String[] ranges = range.split("-"); + + long start = 0; + long end = fileSize - 1; + + try { + if (ranges.length >= 1 && !ranges[0].isEmpty()) { + start = Long.parseLong(ranges[0]); + } + if (ranges.length >= 2 && !ranges[1].isEmpty()) { + end = Long.parseLong(ranges[1]); + } + + // 确保范围有效 + if (start < 0) start = 0; + if (end >= fileSize) end = fileSize - 1; + if (start > end) { + response.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); + return; + } + + long contentLength = end - start + 1; + + // 设置206 Partial Content响应 + response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); + response.setHeader("Content-Range", String.format("bytes %d-%d/%d", start, end, fileSize)); + response.setHeader("Content-Length", String.valueOf(contentLength)); + + // 下载指定范围的内容 + fileStorage.downloadRange(fileRecord.getFilePath(), response.getOutputStream(), start, contentLength); + + } catch (NumberFormatException e) { + log.warn("无效的Range请求: {}", rangeHeader); + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + } catch (ClientAbortException e) { + log.warn("客户端主动断开连接: {}", e.getMessage()); + } + } + + @Override + public void checkFile(MultipartFile file, String code) { + Assert.notBlank(code, "未指定文件配置"); + FileClassDTO fileClass = fileClassService.findByCode(code); + if (fileClass == null) { + throw new BusinessException("未设置文件配置,无法上传"); + } + if (!FileUtils.checkFileSize(file.getSize(), fileClass.getFileMaxSize(), + FileConstants.Unit.K)) { + throw new BusinessException( + "上传文件过大,最大不得超过" + fileClass.getFileMaxSize() + FileConstants.Unit.K.getName()); + } + String fileName = file.getOriginalFilename(); + if (StringUtils.isBlank(fileName)) { + throw new BusinessException(("文件名不能为空")); + } + String suffix = FileUtils.getSuffix(fileName); + if (!fileClass.getFileSuffix().contains(suffix)) { + throw new BusinessException("只能上传拓展名为" + fileClass.getFileSuffix() + "的文件"); + } + } + + @Override + public FileRecord upload(String url, String fileName, String contentType, long fileSizeLimit) { + Assert.isTrue(StringUtils.isNotEmpty(url) && StringUtils.startsWithAny(url, "http", "https"), + "上传地址有误"); + Assert.isTrue(StringUtils.isNotEmpty(contentType), "文件类型不能为空"); + byte[] bytes = HttpUtil.createGet(url).execute().bodyBytes(); + ByteArrayInputStream inputStream = IoUtil.toStream(bytes); + //文件类型校验 + String contentTypeAct = ""; + try { + contentTypeAct = HttpURLConnection.guessContentTypeFromStream(inputStream); + } catch (IOException e) { + e.printStackTrace(); + } + if (StringUtils.isEmpty(contentTypeAct) || !checkContentType(contentTypeAct, contentType)) { + log.info("上传文件格式校验失败,contentType:[{}],contentTypeAct:[{}]", contentType, contentTypeAct); + ExceptionUtils.throwBusinessException("文件格式错误"); + } + if (fileSizeLimit > 0) { + long fileSizeAct = inputStream.available(); + if (fileSizeAct > fileSizeLimit) { + log.info("上传文件大小校验失败,fileSizeLimit:[{}],fileSizeAct:[{}]", fileSizeLimit, fileSizeAct); + ExceptionUtils.throwBusinessException("文件超过限制"); + } + } + String fileNameAct = fileName + "." + contentType; + return upload(fileNameAct, bytes); + } + + /** + * 检查内容类型 + * + * @param contentTypeAct 内容类型的行为 + * @param contentType 内容类型 + * @return boolean + */ + private boolean checkContentType(String contentTypeAct, String contentType) { + if (StringUtils.isEmpty(contentType) || StringUtils.isEmpty(contentTypeAct)) { + return false; + } + String[] split = StringUtils.split(contentType, ","); + for (String s : split) { + if (contentTypeAct.contains(s)) { + return true; + } + } + return false; + } + + @Override + public FileRecord upload(MultipartFile file) { + return upload(FileUploadDTO.builder().file(file).build()); + } + + @Override + public FileRecord upload(FileUploadDTO fileUploadDTO) { + MultipartFile file = fileUploadDTO.getFile(); + //校验上传文件 + checkMultipartFile(file, fileUploadDTO.getFileClassCode()); + //构建FileRecord + FileRecord fileRecord = buildFileRecord(fileUploadDTO); + //复制属性返回 + FileRecord resultFile; + BeanUtils.copyProperties(fileRecord, + (resultFile = FileRecord.builder().build()), + "filePath"); + return resultFile; + } + + /** + * 构建FileRecord + * + * @param file 文件 + * @return {@link FileRecord} + */ + private FileRecord buildFileRecord(FileUploadDTO fileUploadDTO) { + MultipartFile file = fileUploadDTO.getFile(); + String filename = fileUploadDTO.getFilename(); + BigDecimal quality = fileUploadDTO.getQuality(); + boolean temp = fileUploadDTO.isTemp(); + // 文件code + String fileCode = IdUtil.fastSimpleUUID(); + // 文件名称 + String fileName = StrUtil.isEmpty(filename) ? file.getOriginalFilename() : filename; + // 文件后缀 + String fileSuffix = FilenameUtils.getExtension(fileName); + // 目标文件路径 + String targetPath; + if (!temp) { + targetPath = String.join(String.valueOf(File.separatorChar), + fileProperties.getUploadDir(), + Optional.ofNullable(UserContextHolder.getLoginOrgId()).map(Object::toString) + .orElse("null"), + fileCode); + } else { + targetPath = String.join(String.valueOf(File.separatorChar), + fileProperties.getUploadDir(), + "temp", + DateUtil.today(), + fileCode); + } + + String md5Code; + Long fileSize = file.getSize(); + FileRecord fileRecord = null; + try (InputStream is = file.getInputStream()) { + //验证通过则进行图片压缩处理ø + if (Boolean.TRUE.equals(checkNeedCompression(quality, fileSuffix))) { + log.info("file compress,before:{}, quality:{}", fileSize, quality); + try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { + Img.from(is).setQuality(quality.doubleValue()).write(os); + byte[] osByte = os.toByteArray(); + try (ByteArrayInputStream comIs = new ByteArrayInputStream(osByte)) { + fileSize = Long.valueOf(osByte.length); + // 判断文件大小限制 + Assert.isTrue(fileUploadDTO.getFileSizeLimit() == null + || fileSize < fileUploadDTO.getFileSizeLimit(), "上传文件超过限制"); + md5Code = DigestUtils.md5Hex(osByte).toUpperCase(); + fileRecord = fileRecordService.find(FileRecord.builder().md5Code(md5Code).build()); + if (fileRecord != null) { + return fileRecord; + } + fileStorage.upload(comIs, targetPath); + } catch (IOException ie) { + log.info("获取图片压缩输入流失败", ie); + throw new BusinessException("获取图片压缩输入流失败"); + } + } catch (IOException ie) { + log.info("图片文件压缩失败,请稍后重试", ie); + throw new BusinessException("图片文件压缩失败,请稍后重试"); + } + } else { + // 判断文件大小限制 + Assert.isTrue(fileUploadDTO.getFileSizeLimit() == null + || fileSize < fileUploadDTO.getFileSizeLimit(), "上传文件超过限制"); + md5Code = DigestUtils.md5Hex(file.getBytes()).toUpperCase(); + fileRecord = fileRecordService.find(FileRecord.builder().md5Code(md5Code).build()); + if (fileRecord != null) { + return fileRecord; + } + fileStorage.upload(is, targetPath); + } + + } catch (IOException e) { + log.error("文件上传io异常", e); + throw new BusinessException("文件上传异常"); + } + // 构建FileRecord + fileRecord = FileRecord.builder() + .orgId(UserContextHolder.getLoginOrgId()) + .fileName(fileName) + .fileSize(fileSize) + .fileCode(fileCode) + .filePath(targetPath) + .fileSuffix(fileSuffix) + .md5Code(md5Code) + .storageType(fileStorage.getType()).build(); + fileRecordService.saveFileRecord(fileRecord); + return fileRecord; + } + + public static ByteArrayInputStream getCompressIs(InputStream is, BigDecimal quality) { + try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { + Img.from(is).setQuality(quality.doubleValue()) + .write(os); + return new ByteArrayInputStream(os.toByteArray()); + } catch (IOException ie) { + log.info("图片文件压缩失败,请稍后重试", ie); + throw new BusinessException("图片文件压缩失败,请稍后重试"); + } + } + + /** + * 验证本次上传的文件是否能进行压缩处理 + * quality 在 0~1之间 + * fileSuffix 文件结尾是图片格式 + * + * @param quality 质量 + * @param fileSuffix 文件后缀 + * @return {@link Boolean} + */ + private Boolean checkNeedCompression(BigDecimal quality, String fileSuffix) { + return Objects.nonNull(quality) && + (BigDecimal.ZERO.compareTo(quality) < 0 && BigDecimal.ONE.compareTo(quality) > 0) && + StringUtils.equalsAnyIgnoreCase(fileSuffix, ImgUtil.IMAGE_TYPE_JPG, + ImgUtil.IMAGE_TYPE_BMP, ImgUtil.IMAGE_TYPE_GIF, ImgUtil.IMAGE_TYPE_JPEG, + ImgUtil.IMAGE_TYPE_PSD); + } + + + /** + * 检查上传文件 + * + * @param file 文件 + */ + private void checkMultipartFile(MultipartFile file, String fileClassCode) { + Assert.isTrue(Objects.nonNull(file) && !file.isEmpty(), "文件为空"); + if (StringUtils.isNotBlank(fileClassCode)) { + this.checkFile(file, fileClassCode); + } + + } + + + @Override + public FileRecord uploadFileByURL(String externalFileUrl, String fileName) { + // 搞不懂取名,取个链接下载,里面其实限制是图片/pdf下载,其他类型慎用!!! + if (StringUtils.isBlank(externalFileUrl)) { + return null; + } + try { + URL url = new URL(externalFileUrl); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + String fileSuffix = MimeTypeUtils.parseMimeType(connection.getContentType()).getSubtype().toLowerCase(); + String fileClassCode = null; + if (FileClassCodeEnum.IMG.getSuffix().contains(fileSuffix)) { + fileClassCode = FileClassCodeEnum.IMG.getCode(); + } else if(FileClassCodeEnum.PDF.getSuffix().contains(fileSuffix)){ + fileClassCode = FileClassCodeEnum.PDF.getCode(); + }else { + log.info("文件格式不是图片/pdf类型,url: {}, 当前文件格式:{}", externalFileUrl, fileSuffix); + throw new BusinessException("文件格式不是图片/pdf类型"); + } + try (BufferedInputStream is = new BufferedInputStream(connection.getInputStream())) { + FileUploadDTO fileUploadDTO = FileUploadDTO.builder().filename(fileName + "." + fileSuffix) + .fileClassCode(fileClassCode).build(); + return upload(fileUploadDTO.setIs(is)); + } finally { + connection.disconnect(); + } + } catch (Exception e) { + log.info("根据url下载照片失败!url:{}, fileName: {}", externalFileUrl, fileName, e); + return null; + } + } + + @Override + public FileRecord upload(String fileName, byte[] bytes) { + FileUploadDTO fileUploadDTO = FileUploadDTO.builder().filename(fileName).build(); + return upload(fileUploadDTO.setByte(bytes)); + } + + @Override + public FileRecord uploadTemp(String fileName, byte[] bytes) { + FileUploadDTO fileUploadDTO = FileUploadDTO.builder().filename(fileName).temp(true).build(); + return upload(fileUploadDTO.setByte(bytes)); + } + + @Override + public FileRecord upload(String fileName, InputStream is) { + FileUploadDTO fileUploadDTO = FileUploadDTO.builder().filename(fileName).build(); + return upload(fileUploadDTO.setIs(is)); + } + + @Override + public FileRecord uploadTemp(String fileName, InputStream is) { + FileUploadDTO fileUploadDTO = FileUploadDTO.builder().filename(fileName).temp(true).build(); + return upload(fileUploadDTO.setIs(is)); + } + + @Override + public InputStream getFile(String fileCode) { + return fileRecordService.getFile(fileCode); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/file/service/storage/AliFileStorage.java b/backend/src/main/java/com/senmesh/component/file/service/storage/AliFileStorage.java new file mode 100644 index 0000000..8f7b165 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/service/storage/AliFileStorage.java @@ -0,0 +1,165 @@ +package com.senmesh.component.file.service.storage; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.apache.catalina.connector.ClientAbortException; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; + +import com.aliyun.oss.ClientException; +import com.aliyun.oss.OSS; +import com.aliyun.oss.OSSClientBuilder; +import com.aliyun.oss.OSSException; +import com.aliyun.oss.model.GetObjectRequest; +import com.aliyun.oss.model.OSSObject; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.DevopsException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.component.file.config.FileProperties; +import com.senmesh.component.file.config.FileProperties.AliStorage; +import com.senmesh.component.file.constant.FileStorageEnum; +import com.senmesh.component.file.service.IFileStorage; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class AliFileStorage implements IFileStorage { + + private FileProperties fileProperties; + + private OSS ossClient; + + private String bucketName; + + public AliFileStorage(FileProperties fileProperties) { + this.fileProperties = fileProperties; + AliStorage aliStorage = fileProperties.getStorage().getAli(); + ossClient = new OSSClientBuilder().build(aliStorage.getEndpoint(), aliStorage.getAccessKeyId(), + aliStorage.getAccessKeySecret()); + this.bucketName = String.join(CommonConstants.HYPHEN, aliStorage.getBucketName(), EnvironmentUtils.getProfile()); + } + + @Override + public void upload(InputStream is, String filePath) { + try { + ossClient.putObject(bucketName, dealPath(filePath), is); + } catch (OSSException oe) { + log.info("Caught an OSSException, which means your request made it to OSS, " + + "but was rejected with an error response for some reason."); + log.info("Error Message:" + oe.getErrorMessage()); + log.info("Error Code:" + oe.getErrorCode()); + log.info("Request ID:" + oe.getRequestId()); + log.info("Host ID:" + oe.getHostId()); + throw new DevopsException("oss请求异常" + oe.getMessage()); + } catch (ClientException ce) { + log.info("Caught an ClientException, which means the client encountered " + + "a serious internal problem while trying to communicate with OSS, " + + "such as not being able to access the network."); + log.info("Error Message:" + ce.getMessage()); + throw new DevopsException("oss客户端异常" + ce.getMessage()); + } + } + + @Override + public void download(String filePath, OutputStream os, Long fileSize) { + try(InputStream is = download(filePath)) { + try { + IOUtils.copy(is, os, fileSize != null ? fileSize.intValue() : 4096); + } catch (ClientAbortException e) { + log.warn("客户端主动断开连接: {}", e.getMessage()); + } + } catch (IOException ie) { + log.info("Caught an IOException", ie); + throw new DevopsException("oss流处理异常" + ie.getMessage()); + } + } + + private String dealPath(String path) { + Assert.isTrue(StringUtils.isNotBlank(path), "文件地址不能为空"); + String seperate = String.valueOf(File.separatorChar); + if (path.startsWith("/")) { + return path.substring(1); + } + if (!path.startsWith(seperate)) { + return path; + } + return path.substring(seperate.length()); + } + + @Override + public String getType() { + return FileStorageEnum.ALI_NAME; + } + + @Override + public InputStream download(String filePath) { + try { + // 调用ossClient.getObject返回一个OSSObject实例,该实例包含文件内容及文件元信息。 + OSSObject ossObject = ossClient.getObject(bucketName, dealPath(filePath)); + // 调用ossObject.getObjectContent获取文件输入流,可读取此输入流获取其内容。 + InputStream content = ossObject.getObjectContent(); + return content; + } catch (OSSException oe) { + log.info("Caught an OSSException, which means your request made it to OSS, " + + "but was rejected with an error response for some reason."); + log.info("Error Message:" + oe.getErrorMessage()); + log.info("Error Code:" + oe.getErrorCode()); + log.info("Request ID:" + oe.getRequestId()); + log.info("Host ID:" + oe.getHostId()); + throw new DevopsException("oss请求异常" + oe.getMessage()); + } catch (ClientException ce) { + log.info("Caught an ClientException, which means the client encountered " + + "a serious internal problem while trying to communicate with OSS, " + + "such as not being able to access the network."); + log.info("Error Message:{}-{}", bucketName, ce.getMessage()); + throw new DevopsException("oss客户端异常" + ce.getMessage()); + } + } + + @Override + public void downloadRange(String filePath, OutputStream outputStream, long start, long length) { + try { + // 创建GetObjectRequest并设置Range + GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, dealPath(filePath)); + getObjectRequest.setRange(start, start + length - 1); + + // 调用ossClient.getObject返回一个OSSObject实例 + OSSObject ossObject = ossClient.getObject(getObjectRequest); + // 调用ossObject.getObjectContent获取文件输入流 + try (InputStream inputStream = ossObject.getObjectContent();) { + // 使用更大的缓冲区提高性能 + byte[] buffer = new byte[64 * 1024]; // 64KB缓冲区 + long remaining = length; + int bytesRead; + + while (remaining > 0 && (bytesRead = inputStream.read(buffer, 0, (int) Math.min(buffer.length, remaining))) != -1) { + outputStream.write(buffer, 0, bytesRead); + remaining -= bytesRead; + } + + outputStream.flush(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } catch (OSSException oe) { + log.info("Caught an OSSException, which means your request made it to OSS, " + + "but was rejected with an error response for some reason."); + log.info("Error Message:" + oe.getErrorMessage()); + log.info("Error Code:" + oe.getErrorCode()); + log.info("Request ID:" + oe.getRequestId()); + log.info("Host ID:" + oe.getHostId()); + throw new DevopsException("oss请求异常" + oe.getMessage()); + } catch (ClientException ce) { + log.info("Caught an ClientException, which means the client encountered " + + "a serious internal problem while trying to communicate with OSS, " + + "such as not being able to access the network."); + log.info("Error Message:" + ce.getMessage()); + throw new DevopsException("oss客户端异常" + ce.getMessage()); + } + } + +} diff --git a/backend/src/main/java/com/senmesh/component/file/service/storage/LocalFileStorage.java b/backend/src/main/java/com/senmesh/component/file/service/storage/LocalFileStorage.java new file mode 100644 index 0000000..67e3d43 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/service/storage/LocalFileStorage.java @@ -0,0 +1,83 @@ +package com.senmesh.component.file.service.storage; + +import com.senmesh.common.exception.BusinessException; +import com.senmesh.component.file.constant.FileStorageEnum; +import com.senmesh.component.file.service.IFileStorage; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; + +import java.io.*; +import java.nio.file.Files; + +@Slf4j +public class LocalFileStorage implements IFileStorage { + + @Override + public void upload(InputStream is, String filePath) { + File file = new File(filePath); + try { + FileUtils.forceMkdirParent(file); + } catch (IOException e) { + log.info("上传存储异常", e); + throw new BusinessException("上传存储异常 " + e.getMessage()); + } + try (OutputStream os = Files.newOutputStream(file.toPath())) { + IOUtils.copy(is, os); + } catch (IOException e) { + log.info("上传存储异常", e); + throw new BusinessException("上传存储异常 " + e.getMessage()); + } + } + + @Override + public void download(String filePath, OutputStream os, Long fileSize) { + try (InputStream inputStream = download(filePath)) { + IOUtils.copy(inputStream, os, fileSize != null ? fileSize.intValue() : 4096); + } catch (IOException e) { + log.info("下载异常", e); + throw new BusinessException("下载异常" + e.getMessage()); + } + } + + @Override + public String getType() { + return FileStorageEnum.LOCAL_NAME; + } + + @Override + public InputStream download(String filePath) { + try { + return new FileInputStream(filePath); + } catch (FileNotFoundException e) { + log.error("文件下载失败,文件不存在:{}", filePath, e); + throw new BusinessException("下载异常"); + } + } + + @Override + public void downloadRange(String filePath, OutputStream outputStream, long start, long length) { + try (InputStream inputStream = this.download(filePath)) { + // 跳过开始位置之前的字节 + long skipped = inputStream.skip(start); + if (skipped != start) { + log.warn("跳过字节数不匹配,期望: {}, 实际: {}", start, skipped); + } + + // 使用更大的缓冲区 + byte[] buffer = new byte[64 * 1024]; // 64KB缓冲区 + long remaining = length; + int bytesRead; + + while (remaining > 0 && (bytesRead = inputStream.read(buffer, 0, (int) Math.min(buffer.length, remaining))) != -1) { + outputStream.write(buffer, 0, bytesRead); + remaining -= bytesRead; + } + + outputStream.flush(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/backend/src/main/java/com/senmesh/component/file/util/FileStorageUtils.java b/backend/src/main/java/com/senmesh/component/file/util/FileStorageUtils.java new file mode 100644 index 0000000..f727089 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/util/FileStorageUtils.java @@ -0,0 +1,22 @@ +package com.senmesh.component.file.util; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.component.file.service.IFileStorage; + +/** + * @author sr on 2022-03-08 + */ +public class FileStorageUtils { + + public static IFileStorage fileStorage; + + public FileStorageUtils(IFileStorage fileStorage) { + Assert.isNull(FileStorageUtils.fileStorage, "文件存储器已存在..."); + FileStorageUtils.fileStorage = fileStorage; + } + + public static IFileStorage get() { + return fileStorage; + } + +} diff --git a/backend/src/main/java/com/senmesh/component/file/util/FileUtils.java b/backend/src/main/java/com/senmesh/component/file/util/FileUtils.java new file mode 100644 index 0000000..602a840 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/util/FileUtils.java @@ -0,0 +1,283 @@ +package com.senmesh.component.file.util; + +import com.senmesh.component.file.config.FileProperties; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.Charset; +import java.util.Base64; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import javax.imageio.ImageIO; + +import org.springframework.stereotype.Component; +import org.springframework.util.FileCopyUtils; + +import com.senmesh.common.exception.BusinessException; +import com.senmesh.component.file.constant.FileConstants; + +import cn.hutool.core.img.Img; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.IORuntimeException; +import lombok.extern.slf4j.Slf4j; +import ws.schild.jave.Encoder; +import ws.schild.jave.MultimediaObject; +import ws.schild.jave.encode.AudioAttributes; +import ws.schild.jave.encode.EncodingAttributes; + +/** + * 文件工具类 + * + * @author on 2019-12-10 + */ +@Slf4j +@Component +public class FileUtils { + + public static final double IMG_QUALITY = 0.6d; + + private static FileProperties fileProperties; + + FileUtils(FileProperties fileProperties) { + FileUtils.fileProperties = fileProperties; + } + + public static String getUploadDir(){ + return fileProperties.getUploadDir(); + } + + public static File createTempFile(String suffix) throws IOException { + File tempDir = new File(FileUtils.getUploadDir() + File.separator + "temp" + File.separator); + if (!tempDir.exists()) { + tempDir.mkdirs(); + } + File temp = File.createTempFile("tmp_", suffix, tempDir); + return temp; + } + + public static FileInputStream copyToTempFile(InputStream in, File temp) throws IOException { + temp.delete(); + try (OutputStream out = new FileOutputStream(temp)) { + byte[] buf = new byte[8192]; + int len; + while ((len = in.read(buf)) != -1) out.write(buf, 0, len); + } + return new FileInputStream(temp); + } + + /** + * 得到字节大小字符串 + * + * @param size 大小 + * @return {@link String} + */ + public static String getByteSizePretty(long size) { + //如果字节数少于1024,则直接以B为单位,否则先除于1024,后3位因太少无意义 + if (size < 1024) { + return String.valueOf(size) + "B"; + } else { + size = size / 1024; + } + //如果原字节数除于1024之后,少于1024,则可以直接以KB作为单位 + //因为还没有到达要使用另一个单位的时候 + //接下去以此类推 + if (size < 1024) { + return String.valueOf(size) + "KB"; + } else { + size = size / 1024; + } + if (size < 1024) { + //因为如果以MB为单位的话,要保留最后1位小数, + //因此,把此数乘以100之后再取余 + size = size * 100; + return String.valueOf((size / 100)) + "." + + String.valueOf((size % 100)) + "MB"; + } else { + //否则如果要以GB为单位的,先除于1024再作同样的处理 + size = size * 100 / 1024; + return String.valueOf((size / 100)) + "." + + String.valueOf((size % 100)) + "GB"; + } + } + + /** + * 判断文件大小 + * + * @param len 文件长度 + * @param size 限制大小 + * @param unit 限制单位(B,K,M,G) + * @return + */ + public static boolean checkFileSize(Long len, int size, FileConstants.Unit unit) { + Long fileSize = len / unit.getValue(); + if (fileSize > size) { + return false; + } + return true; + } + + /** + * Java文件操作 获取文件扩展名 + */ + public static String getSuffix(String filename) { + if ((filename != null) && (filename.length() > 0)) { + int dot = filename.lastIndexOf('.'); + if ((dot > -1) && (dot < (filename.length() - 1))) { + return filename.substring(dot + 1); + } + } + return filename; + } + + /** + * Java文件操作 获取不带扩展名的文件名 + */ + public static String getFileNameNoSuffix(String filename) { + if ((filename != null) && (filename.length() > 0)) { + int dot = filename.lastIndexOf('.'); + if ((dot > -1) && (dot < (filename.length()))) { + return filename.substring(0, dot); + } + } + return filename; + } + + /** + * 解压图片压缩包(带压缩功能) + * 默认utf-8解压,异常(zip流没问题,nextElement会非法参数malformed异常)后用gbk解压;原因:mac的压缩包得用utf-8解压、Windows的压缩包用gbk + * @param fileRecordPath + * @param targetPath + * @return !!!记得删解压后的文件 + * @author sr on 2022-01-25 + */ + public static List unzipImg(String fileRecordPath, String targetPath) { + try (ZipInputStream zipFile = + new ZipInputStream(FileStorageUtils.get().download(fileRecordPath))) { + return unzipImg(zipFile, targetPath, IMG_QUALITY); + } catch (Exception e) { + try (ZipInputStream zipFile = new ZipInputStream( + FileStorageUtils.get().download(fileRecordPath), Charset.forName("gbk"))) { + return unzipImg(zipFile, targetPath, IMG_QUALITY); + } catch (IOException e2) { + throw new BusinessException("zip编码异常", e2); + } + } + } + + public static List unzipImg(ZipInputStream zis, String targetPath, double quality) { + try { + ZipEntry zipEntry; + File outItemFile; + while ((zipEntry = zis.getNextEntry()) != null) { + if (zipEntry.isDirectory()) { + continue; + } + // 写出文件 + try { + InputStream in = zis; + if (quality >= 1) { + outItemFile = mkParentdirs(targetPath, zipEntry.getName()); + FileUtil.writeFromStream(in, outItemFile); + continue; + } + BufferedImage bi = ImageIO.read(in); + if (bi == null) { + // 图片为空 + continue; + } + outItemFile = mkParentdirs(targetPath, zipEntry.getName()); + Img.from(bi).setQuality(quality) + .write(outItemFile); + + } catch (IOException e) { + throw new IORuntimeException(e); + } + } + return FileUtil.loopFiles(targetPath); + } catch (Exception e) { + throw new BusinessException("解压异常", e); + } + } + + + public static File mkParentdirs(String targetPath, String namePath) { + File file = FileUtil.file(targetPath, namePath); + File parentFile = file.getParentFile(); + if (parentFile != null && !parentFile.exists()) { + parentFile.mkdirs(); + } + return file; + } + + /** + * 获取base64字符串 + * @param filePath + * @return + * @author sr on 2022-10-09 + */ + public static String encodeBase64(String filePath) { + try (InputStream is = FileStorageUtils.get().download(filePath)) { + byte[] buffer = FileCopyUtils.copyToByteArray(is); + byte[] data = Base64.getEncoder().encode(buffer); + return new String(data); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * @param base64 + * @return + * @author sr on 2022-10-09 + */ + public static byte[] decodeBase64(String base64) { + String[] split = base64.split(","); + if (split.length == 2) { + base64 = split[1]; + } + return Base64.getDecoder().decode(base64); + } + + /** + * WebmToMp3 + * @param webmFilePath + * @param mp3FilePath + * @author sr on 2025-01-10 + */ + public static InputStream convertWebmToMp3(File source) { + + AudioAttributes audio = new AudioAttributes(); + audio.setCodec("libmp3lame"); + // 设置音频编码格式为L16(这里假设目标是这个格式) + // audio.setCodec("pcm_s16le"); + // 设置采样率为16000Hz + audio.setSamplingRate(16000); + + EncodingAttributes attrs = new EncodingAttributes(); + attrs.setOutputFormat("mp3"); + attrs.setAudioAttributes(audio); + + try { + File tmpDir = new File("tmp/mebmtomp3"); + tmpDir.mkdirs(); + Encoder encoder = new Encoder(); + File target = File.createTempFile("/mp3", null, tmpDir); + encoder.encode(new MultimediaObject(source), target, attrs); + InputStream is = new FileInputStream(target); + target.delete(); + return is; + } catch (Exception e) { + log.info("使用JAVE库转换失败!", e); + throw new BusinessException("mp3转换失败"); + } + } + + +} diff --git a/backend/src/main/java/com/senmesh/component/file/util/PDFBuilder.java b/backend/src/main/java/com/senmesh/component/file/util/PDFBuilder.java new file mode 100644 index 0000000..dde5b48 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/util/PDFBuilder.java @@ -0,0 +1,465 @@ +package com.senmesh.component.file.util; + +import com.itextpdf.text.BaseColor; +import com.itextpdf.text.Document; +import com.itextpdf.text.DocumentException; +import com.itextpdf.text.Element; +import com.itextpdf.text.Font; +import com.itextpdf.text.PageSize; +import com.itextpdf.text.Paragraph; +import com.itextpdf.text.Phrase; +import com.itextpdf.text.Rectangle; +import com.itextpdf.text.pdf.BaseFont; +import com.itextpdf.text.pdf.PdfPCell; +import com.itextpdf.text.pdf.PdfPTable; +import com.itextpdf.text.pdf.PdfWriter; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.lang.reflect.Field; + +public class PDFBuilder { + // 表头背景色 + private BaseColor headerBgColor = BaseColor.GRAY; + // 表头文字色 + private BaseColor headerFontColor = BaseColor.WHITE; + // 表格文字色 + private BaseColor cellFontColor = BaseColor.BLACK; + // 表格背景色 + private BaseColor cellBgColor = BaseColor.WHITE; + // 表格内距 + private float padding = 0f; + // 表格离标题的距离 + private float spacing = 50f; + // 表格的宽度, 默认自适应 + private float tableWidth = 0f; + // pdf大小 + private Rectangle pageSize = PageSize.A4; + // 段落文字大小 + private int paragraphFontSize = 20; + // 表格文字大小 + private int cellFontSize = 14; + // 表头文字大小 + private int headerFontSize = 16; + // 自动分页,默认自适应 + private int limit = 0; + // 标题 + private String title; + + private Document document; + private boolean isHorizontal = true; + // private LinkedList data = new LinkedList<>(); + private Object[] data; + private Class clazz = null; + private BaseFont baseFont; + private Font bodyFont; + private Font headerFont; + private float[] ratio; + + + public void setRatio(float[] ratio) { + this.ratio = ratio; + } + + public void setHeaderBgColor(BaseColor headerBgColor) { + this.headerBgColor = headerBgColor; + } + + public void setHeaderFontColor(BaseColor headerFontColor) { + this.headerFontColor = headerFontColor; + } + + public void setCellFontColor(BaseColor cellFontColor) { + this.cellFontColor = cellFontColor; + } + + public void setCellBgColor(BaseColor cellBgColor) { + this.cellBgColor = cellBgColor; + } + + public void setPadding(float padding) { + this.padding = padding; + } + + public void setSpacing(float spacing) { + this.spacing = spacing; + } + + public void setTableWidth(float tableWidth) { + this.tableWidth = tableWidth; + } + + public void setPageSize(Rectangle pageSize) { + this.pageSize = pageSize; + } + + public void setParagraphFontSize(int paragraphFontSize) { + this.paragraphFontSize = paragraphFontSize; + } + + public void setCellFontSize(int cellFontSize) { + this.cellFontSize = cellFontSize; + } + + public void setHeaderFontSize(int headerFontSize) { + this.headerFontSize = headerFontSize; + } + + public void setTitle(String title) { + this.title = title; + } + + /* ----- */ + private PDFBuilder() { + try { + baseFont = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED); + } catch (Exception exception) { + exception.printStackTrace(); + } + } + + public void setData(Object[] data){ + if(data == null || data.length == 0) { + System.err.println("set data null"); + return; + }else if(limit > 0){ + int page = (int) Math.ceil((double) data.length / limit); + document.setPageCount(page); + } + this.data = data; + } + + public void setHead(Class clazz){ + this.clazz = clazz; + } + + public void horizontal(boolean horizontal) { + isHorizontal = horizontal; + } + + public static PDFBuilder builder(){ + return new PDFBuilder(); + } + + public void build(){ + document.close(); + } + + public void autoPage(int limit){ + this.limit = limit; + } + + private void addHeadCell(PdfPTable table, Phrase phrase){ + PdfPCell cell = new PdfPCell(phrase); + cell.setPadding(padding); + cell.setBackgroundColor(headerBgColor); + cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); + cell.setUseAscender(true); + cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE); + table.addCell(cell); + } + + private void addHeadCell(PdfPTable table, PdfPCell cell,int index){ + if(index % 2 == 0) + cell.setBackgroundColor(BaseColor.WHITE); + cell.setUseAscender(true); + cell.setBorder(0); + cell.setPadding(padding); + cell.setBackgroundColor(headerBgColor); + table.addCell(cell); + } + + private void addHeadCell2(PdfPTable table, Phrase phrase,int index){ + PdfPCell cell = new PdfPCell(phrase); + cell.setPadding(padding); + cell.setBackgroundColor(headerBgColor); + cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); + cell.setUseAscender(true); + cell.setBorder(0); + if(index % 2 == 0) + cell.setBackgroundColor(BaseColor.WHITE); + cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE); + table.addCell(cell); + } + + private void addBodyCell(PdfPTable table,Phrase phrase, int index){ + PdfPCell cell = new PdfPCell(phrase); + cell.setPadding(padding); + cell.setBackgroundColor(cellBgColor); + cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); + cell.setUseAscender(true); + cell.setBorder(0); + if(index % 2 == 0) + cell.setBackgroundColor(BaseColor.WHITE); + cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE); + table.addCell(cell); + } + + private void addBodyCell(PdfPTable table,PdfPCell cell){ + cell.setPadding(padding); + cell.setBackgroundColor(cellBgColor); + cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); + cell.setUseAscender(true); + cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE); + table.addCell(cell); + } + + private void addParagraph(Document document, Phrase phrase) throws DocumentException { + Paragraph paragraph=new Paragraph(); + paragraph.add(phrase); + paragraph.setAlignment(Element.ALIGN_CENTER); + document.add(paragraph); + } + + public PDFBuilder addDocument(File file){ + try { + FileOutputStream out = new FileOutputStream(file); + return addDocument(out); + } catch (Exception e) { + System.err.println("create document error"); + e.printStackTrace(); + } + return null; + } + + public PDFBuilder addDocument(OutputStream outputStream){ + try{ + document = new Document(pageSize); + PdfWriter.getInstance(document, outputStream); + document.open(); + return this; + }catch (Exception e) { + System.err.println("create document error"); + e.printStackTrace(); + } + return null; + } + + private void nextLine(PdfPTable table){ + table.completeRow(); + } + + public void nextPage(){ + document.newPage(); + } + + private PdfPTable addCellNumber(int cellNumber){ + return new PdfPTable(cellNumber); + } + + private void attach(PdfPTable table, String[] strArr) { + try{ + table.getDefaultCell().setBorder(0); + Font font = new Font(baseFont, cellFontSize, Font.NORMAL, BaseColor.BLACK); + + for (String s : strArr) { + PdfPCell pdfPCell = new PdfPCell(new Phrase(s, font)); + pdfPCell.setBorder(0); + pdfPCell.setPadding(5f); + addBodyCell(table,pdfPCell); + } + nextLine(table); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + private void clear(){ + this.data = null; + this.clazz = null; + this.padding = 0f; + this.spacing = 50f; + this.tableWidth = 0f; + this.pageSize = PageSize.A4; + this.paragraphFontSize = 20; + this.cellFontSize = 14; + this.headerFontSize = 16; + this.limit = 0; + this.title = null; + this.headerBgColor = BaseColor.GRAY; + this.headerFontColor = BaseColor.WHITE; + this.cellFontColor = BaseColor.BLACK; + this.cellBgColor = BaseColor.WHITE; + this.horizontal(Boolean.TRUE); + this.ratio = null; + } + + public void addTable(){ + addTable(null); + } + + public void addTable(String[] content){ + try{ + if (clazz == null) { + System.err.println("class not be defined"); + return; + } + Font paragraphFont = new Font(baseFont, paragraphFontSize, Font.BOLD); + addParagraph(document, new Phrase(title, paragraphFont)); + + headerFont = new Font(baseFont, headerFontSize, Font.NORMAL, headerFontColor); + bodyFont = new Font(baseFont, cellFontSize, Font.NORMAL,cellFontColor); + + Field[] declaredFields = clazz.getDeclaredFields(); + PdfPTable table; + if (isHorizontal) { + table = renderByHorizontal(declaredFields,content); + } else { + table = renderByVertical(declaredFields,content); + } +// table.setSpacingAfter(spacing); + document.add(table); + }catch (Exception exception){ + System.err.println("add table error"); + exception.printStackTrace(); + }finally { + clear(); + } + } + + private int calcTableCol(Field[] declaredFields) { + for (Field declaredField : declaredFields) { + declaredField.setAccessible(true); + PDFProperty annotation = declaredField.getAnnotation(PDFProperty.class); + if(null != annotation && null != annotation.value()){ + return 1; + } + } + return 0; + } + + private PdfPTable renderByHorizontal(Field[] declaredFields, String[] content) { + int col = calcTableCol(declaredFields); + PdfPTable table; + if(ratio == null || ratio.length != declaredFields.length){ + table = addCellNumber(declaredFields.length); + }else{ + table = new PdfPTable(ratio); + } + + table.getDefaultCell().setBorder(0); + table.getDefaultCell().setBorder(0); + table.setSpacingBefore(spacing); + if(content != null && content.length > 0){ + attach(table,content); + } + if(tableWidth > 0){ + table.setLockedWidth(true); + table.setTotalWidth(tableWidth); + } + try{ + for (Field declaredField : declaredFields) { + PDFProperty annotation = declaredField.getAnnotation(PDFProperty.class); + if(col > 0){ + if(null != annotation){ + addHeadCell(table,new Phrase(annotation.value(),headerFont)); + }else{ + addHeadCell(table,new Phrase("",headerFont)); + } + } + } + nextLine(table); + int counter = 0; + for (int i = 0; i < data.length; i++) { + for (Field field : declaredFields) { + field.setAccessible(true); + if(null == data[i] || null == field.get(data[i])){ + addBodyCell(table, new Phrase(""),i); + }else{ + addBodyCell(table, new Phrase(field.get(data[i]).toString(), bodyFont),i); + } + } + counter++; + if(limit > 0 && counter == limit){ + table.completeRow(); + document.add(table); + document.newPage(); + if(ratio == null || ratio.length != declaredFields.length){ + table = addCellNumber(declaredFields.length); + }else{ + table = new PdfPTable(ratio); + } + if(limit > 0 && tableWidth > 0){ + table.setLockedWidth(true); + table.setTotalWidth(tableWidth); + } + counter = 0; + } + } + + } catch (Exception e) { + System.err.println("render pdf page error"); + e.printStackTrace(); + } + return table; + } + + private PdfPTable renderByVertical(Field[] declaredFields, String[] content) { + + int col = calcTableCol(declaredFields); + PdfPTable table; + if(ratio == null || ratio.length != data.length + col){ + table = addCellNumber(data.length + col); + }else{ + table = new PdfPTable(ratio); + } + table.setSpacingBefore(spacing); + if(content != null && content.length > 0){ + attach(table,content); + } + if(tableWidth > 0){ + table.setLockedWidth(true); + table.setTotalWidth(tableWidth); + } + try{ + int counter = 0; + for (int i = 0; i < declaredFields.length; i++) { + Field declaredField = declaredFields[i]; + PDFProperty annotation = declaredField.getAnnotation(PDFProperty.class); + if(col > 0){ + if(null != annotation){ + PdfPCell pdfPCell = new PdfPCell(new Phrase(annotation.value(), headerFont)); + pdfPCell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE); + pdfPCell.setHorizontalAlignment(PdfPCell.ALIGN_LEFT); + addHeadCell(table,pdfPCell,i); + }else{ + addHeadCell2(table, new Phrase("",headerFont),i); + } + } + + for (Object meta : data) { + declaredField.setAccessible(true); + if(null == data || null == declaredField.get(meta)){ + addBodyCell(table, new Phrase(""),i); + }else{ + addBodyCell(table, new Phrase(declaredField.get(meta).toString(), bodyFont),i); + } + } + counter++; + nextLine(table); + if(limit > 0 && counter == limit){ + nextLine(table); + document.add(table); + document.newPage(); + if(ratio == null || ratio.length != data.length + col){ + table = addCellNumber(data.length + col); + }else{ + table = new PdfPTable(ratio); + } + if(tableWidth > 0){ + table.setLockedWidth(true); + table.setTotalWidth(tableWidth); + } + counter = 0; + } + } + }catch (Exception exception){ + System.err.println("render pdf page error"); + exception.printStackTrace(); + } + return table; + } + +} diff --git a/backend/src/main/java/com/senmesh/component/file/util/PDFProperty.java b/backend/src/main/java/com/senmesh/component/file/util/PDFProperty.java new file mode 100644 index 0000000..b9f101d --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/util/PDFProperty.java @@ -0,0 +1,13 @@ +package com.senmesh.component.file.util; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface PDFProperty { + + String value() default ""; +} diff --git a/backend/src/main/java/com/senmesh/component/file/util/Pdf2ImageUtil.java b/backend/src/main/java/com/senmesh/component/file/util/Pdf2ImageUtil.java new file mode 100644 index 0000000..b4168b3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/util/Pdf2ImageUtil.java @@ -0,0 +1,191 @@ +package com.senmesh.component.file.util; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.util.List; +import java.util.function.Supplier; + +import javax.imageio.ImageIO; + +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.rendering.PDFRenderer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.google.common.collect.Lists; +import com.senmesh.component.file.entity.FileRecord; +import com.senmesh.component.file.service.FileService; + +import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +public class Pdf2ImageUtil { + + private static final int DEFAULT_DPI = 99; + + private static final List SEPARATORS = Lists.newArrayList("/", "\\"); + + private static final long MAX_BYTE_NUM = 10 * 1024 * 1024; +// private static final int MAX_BYTE_NUM = 10; + + private Pdf2ImageUtil() { + } + + private static FileService fileService; + + @Autowired + public void setFileService(FileService fileService) { + this.fileService = fileService; + } + + /** + * 远程PDF链接转长图 + * + * @param pdfRemoteUrl 远程PDF链接 + * @param imgFilePath 目标图片文件路径 /usr/local/contract.png + * @return + */ + public static FileRecord pdf2Image(String pdfRemoteUrl, String imgFilePath) { + return pdf2Image("1", pdfRemoteUrl, imgFilePath); + } + + /** + * 远程PDF链接转长图 + * + * @param pdfType 1:远程 2:文件系统 + * @param pdfRemoteUrl 远程PDF链接 + * @return + */ + public static FileRecord pdf2Image(String pdfType, String pdfRemoteUrl, String imgFileName) { + log.info("PDF链接转图片,pdfRemoteUrl:[{}],imgFilePath:[{}]", pdfRemoteUrl, imgFileName); + if (StrUtil.equals(pdfType, "2")) { + return filePdf2Image(pdfRemoteUrl, imgFileName, DEFAULT_DPI); + } + return remotePdf2Image(pdfRemoteUrl, imgFileName, DEFAULT_DPI); + } + + /** + * PDF文件转PNG图片 + * + * @param filePdfPath PDF文件路径 + * @param imgFileName 图片文件名称 + * @param dpi 清晰度 + * @return + */ + public static FileRecord filePdf2Image(String filePdfPath, String imgFileName, int dpi) { + log.info("文件PDF链接转图片,filePdfPath:[{}],imgFileFolder:[{}],imgFileName:[{}],dpi:[{}]", filePdfPath, imgFileName, dpi); + return pdf2Image(imgFileName, dpi, () -> { + try { + return PDDocument.load(FileStorageUtils.get().download(filePdfPath)); + } catch (Exception e) { + log.error("获取文件资源错误, filePdfPath: [{}]", filePdfPath, e); + e.printStackTrace(); + return null; + } + }); + } + + /** + * 远程PDF链接转长图 + * + * @param pdfRemoteUrl 远程PDF链接 + * @param imgFileName 图片文件名 contract.png + * @param dpi 图片精度 + * @return + */ + public static FileRecord remotePdf2Image(String pdfRemoteUrl, String imgFileName, int dpi) { + log.info("远程PDF链接转图片,pdfRemoteUrl:[{}],imgFileFolder:[{}],imgFileName:[{}],dpi:[{}]", pdfRemoteUrl, imgFileName, dpi); + return pdf2Image(imgFileName, dpi, () -> { + URL url = null; + try { + url = new URL(pdfRemoteUrl); + URLConnection urlConnection = url.openConnection(); + int contentLength = urlConnection.getContentLength(); + if (contentLength > MAX_BYTE_NUM) { + log.info("PDF文件过大,文件大小:[{}]", FileUtils.getByteSizePretty(contentLength)); + return null; + } + } catch (IOException e) { + e.printStackTrace(); + return null; + } + + try (InputStream is = url.openStream()) { + return PDDocument.load(is); + } catch (Exception e) { + log.error("获取远程资源错误, pdfRemoteUrl: [{}]", pdfRemoteUrl, e); + e.printStackTrace(); + return null; + } + }); + } + + + /** + * PDF转图片内部处理逻辑 + * + * @param imgFileName 图片名称带后缀 + * @param dpi 图片清晰度 + * @param supplier + * @param + * @return + */ + private static FileRecord pdf2Image(String imgFileName, int dpi, Supplier supplier) { + String fileFormat = ""; + if (StrUtil.isNotEmpty(imgFileName)) { + List split = StrUtil.split(imgFileName, "."); + if (split.size() == 2) { + fileFormat = split.get(1); + } + + } + if (StrUtil.isEmpty(fileFormat)) { + return null; + } + + try (PDDocument pdDocument = supplier.get()) { + if (pdDocument == null) { + return null; + } + //定义PDF转换器 + PDFRenderer renderer = new PDFRenderer(pdDocument); + /* dpi越大转换后越清晰,相对转换速度越慢 */ + int numberOfPages = pdDocument.getNumberOfPages(); + int width = 0; + int height = 0; + BufferedImage bi = null; + for (int i = 0; i < numberOfPages; i++) { + BufferedImage image = renderer.renderImageWithDPI(i, dpi); + if (bi == null) { + width = image.getWidth(); + height = image.getHeight(); + bi = new BufferedImage(width, height * numberOfPages, BufferedImage.TYPE_4BYTE_ABGR); + } + //复制图片像素点,将多个图片合并成一个长图 + int nowHeight = i * height; + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + bi.setRGB(x, nowHeight + y, image.getRGB(x, y)); + } + } + } + + try (ByteArrayOutputStream out = new ByteArrayOutputStream(2 << 12)){ + ImageIO.write(bi, fileFormat, out); + return fileService.upload(imgFileName, out.toByteArray()); + } catch (Exception e) { + return null; + } + } catch (Exception e) { + log.error("PDF链接转PNG图片失败,", e); + } + return null; + } + +} diff --git a/backend/src/main/java/com/senmesh/component/file/util/PdfUtils.java b/backend/src/main/java/com/senmesh/component/file/util/PdfUtils.java new file mode 100644 index 0000000..cc8a7fe --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/file/util/PdfUtils.java @@ -0,0 +1,116 @@ +package com.senmesh.component.file.util; + +import java.awt.geom.Rectangle2D; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; + +import com.senmesh.common.exception.BusinessException; +import com.spire.pdf.FileFormat; +import com.spire.pdf.PdfDocument; +import com.spire.pdf.PdfPageBase; +import com.spire.pdf.annotations.PdfRubberStampAnnotation; +import com.spire.pdf.annotations.appearance.PdfAppearance; +import com.spire.pdf.graphics.PdfImage; +import com.spire.pdf.graphics.PdfTemplate; +import com.spire.pdf.widget.PdfPageCollection; + +import lombok.extern.slf4j.Slf4j; + + +@Slf4j +public class PdfUtils { + + /** + * pdf盖章(每页) + * @param pdfIn pdf + * @param stampIn 章 + * @param pdfOut + * @author sr on 2023-11-16 + */ + public static void pdfStampPerPage(InputStream pdfIn, InputStream stampIn, OutputStream pdfOut) { + PdfDocument doc = new PdfDocument(); + doc.loadFromStream(pdfIn); + //添加空白文档 + doc.getPages().add(); + PdfPageCollection pages = doc.getPages(); + if (pages.getCount() == 0) { + return; + } + PdfRubberStampAnnotation stamp = getStamp(doc.getPages().get(0), stampIn); + for (int i = 0; i < pages.getCount(); i++) { + PdfPageBase page = doc.getPages().get(i); + //添加图章到PDF + page.getAnnotationsWidget().add(stamp); + } + //保存文档 + try (ByteArrayOutputStream pdfStampOut = new ByteArrayOutputStream()) { + doc.saveToStream(pdfStampOut, FileFormat.PDF); + //删除空白文档 + removeLast(pdfStampOut.toByteArray(), pdfOut); + } catch (IOException e) { + log.info("pdf添加印章失败:", e); + throw new BusinessException("pdf添加印章失败:" + e.getMessage()); + } + } + + + + /** + * 删除pdf最后一页 + * @param pdfStampBytes + * @param pdfOut + * @author sr on 2023-11-16 + */ + public static void removeLast(byte[] pdfStampBytes, OutputStream pdfOut) { + try { + // 加载PDF文档 + PDDocument document = PDDocument.load(pdfStampBytes); + int pageNumberToRemove = document.getPages().getCount() - 1; + // 获取要删除的页 + PDPage pageToRemove = document.getPage(pageNumberToRemove); + // 删除页 + document.removePage(pageToRemove); + // 保存修改后的PDF + document.save(pdfOut); + // 关闭文档 + document.close(); + } catch (IOException e) { + log.info("pdf删除最后页失败:", e); + throw new BusinessException("pdf删除最后页失败:" + e.getMessage()); + } + } + + + private static PdfRubberStampAnnotation getStamp(PdfPageBase page, InputStream stampIn) { + //加载印章图片 + PdfImage image = PdfImage.fromStream(stampIn); + //获取印章图片的宽度和高度 + int width = image.getWidth(); + int height = image.getHeight(); + + //创建PdfTemplate对象 + PdfTemplate template = new PdfTemplate(width, height); + //将图片绘制到模板 要在pdf上调整好大小 + template.getGraphics().drawImage(image, 20, 0, 100, 100); + + //创建PdfRubebrStampAnnotation对象,指定大小和位置 + Rectangle2D rect = new Rectangle2D.Float((float) (page.getActualSize().getWidth() - width - 0), + (float) (page.getActualSize().getHeight() - height + 50), width, height); + + PdfRubberStampAnnotation stamp = new PdfRubberStampAnnotation(rect); + + //创建PdfAppearance对象 + PdfAppearance pdfAppearance = new PdfAppearance(stamp); + //将模板应用为PdfAppearance的一般状态 + pdfAppearance.setNormal(template); + //将PdfAppearance 应用为图章的样式 + stamp.setAppearance(pdfAppearance); + return stamp; + } + +} diff --git a/backend/src/main/java/com/senmesh/component/notice/constant/NoticeFirstTypeEnum.java b/backend/src/main/java/com/senmesh/component/notice/constant/NoticeFirstTypeEnum.java new file mode 100644 index 0000000..da1feeb --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/notice/constant/NoticeFirstTypeEnum.java @@ -0,0 +1,26 @@ +package com.senmesh.component.notice.constant; + +/** + * 通知大类 + */ +public enum NoticeFirstTypeEnum { + + /** 异步任务 */ + ASYNC_TASK_NOTICE("async_task_notice"), + /** 聊天 */ + CHAT("chat"), + /** 站内信 */ + SITE("site") + ; + + private String type; + + NoticeFirstTypeEnum(String type) { + this.type = type; + } + + public String getType() { + return type; + } + +} diff --git a/backend/src/main/java/com/senmesh/component/notice/dto/NoticeMsgDTO.java b/backend/src/main/java/com/senmesh/component/notice/dto/NoticeMsgDTO.java new file mode 100644 index 0000000..5faf01b --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/notice/dto/NoticeMsgDTO.java @@ -0,0 +1,26 @@ +package com.senmesh.component.notice.dto; + +import com.senmesh.component.notice.constant.NoticeFirstTypeEnum; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class NoticeMsgDTO implements Serializable { + + private Long receiverId; + /** @see NoticeFirstTypeEnum 类型 **/ + private String type; + /** 消息对象 */ + private T data; + + public static NoticeMsgDTO create(Long receiverId, String type, T data) { + return new NoticeMsgDTO(receiverId, type, data); + } + +} diff --git a/backend/src/main/java/com/senmesh/component/notice/service/AsyncNoticeHandler.java b/backend/src/main/java/com/senmesh/component/notice/service/AsyncNoticeHandler.java new file mode 100644 index 0000000..e28ab05 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/notice/service/AsyncNoticeHandler.java @@ -0,0 +1,41 @@ +package com.senmesh.component.notice.service; + +import com.senmesh.component.notice.dto.NoticeMsgDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.stereotype.Service; + +import com.senmesh.mq.consumer.handler.ITopicMqHandler; +import com.senmesh.mq.dto.TopicMqMessage; + +@Service +@ConditionalOnBean(INoticeSendProvider.class) +public class AsyncNoticeHandler implements ITopicMqHandler{ + + @Autowired(required = false) + private INoticeSendProvider noticeSendProvider; + + public static final String ROUTING_KEY = "async_notice"; + + @Override + public String getRoutingKey() { + return ROUTING_KEY; + } + + @Override + public void onMessage(TopicMqMessage message) { + try { + if (noticeSendProvider != null) { + noticeSendProvider.send(message.getData()); + } + } catch (Exception e) { + } + } + + @Override + public boolean isBroadcast() { + return true; + } + + +} diff --git a/backend/src/main/java/com/senmesh/component/notice/service/INoticeSendProvider.java b/backend/src/main/java/com/senmesh/component/notice/service/INoticeSendProvider.java new file mode 100644 index 0000000..2271e69 --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/notice/service/INoticeSendProvider.java @@ -0,0 +1,13 @@ +package com.senmesh.component.notice.service; + +import com.senmesh.component.notice.dto.NoticeMsgDTO; + +/** + * 异步任务发送 + * @author sr on 2024-03-06 + */ +public interface INoticeSendProvider { + + void send(NoticeMsgDTO msg); + +} diff --git a/backend/src/main/java/com/senmesh/component/notice/util/NoticeUtils.java b/backend/src/main/java/com/senmesh/component/notice/util/NoticeUtils.java new file mode 100644 index 0000000..15a773d --- /dev/null +++ b/backend/src/main/java/com/senmesh/component/notice/util/NoticeUtils.java @@ -0,0 +1,17 @@ +package com.senmesh.component.notice.util; + +import com.senmesh.component.notice.dto.NoticeMsgDTO; +import com.senmesh.component.notice.service.AsyncNoticeHandler; +import com.senmesh.mq.util.MqSendUtils; + +public class NoticeUtils { + + /** + * 发送异步通知 + * @param msg + */ + public static void sendAsyncNotice(NoticeMsgDTO msg){ + MqSendUtils.send(AsyncNoticeHandler.ROUTING_KEY, msg); + } + +} diff --git a/backend/src/main/java/com/senmesh/config/constant/ConfigConstants.java b/backend/src/main/java/com/senmesh/config/constant/ConfigConstants.java new file mode 100644 index 0000000..113d648 --- /dev/null +++ b/backend/src/main/java/com/senmesh/config/constant/ConfigConstants.java @@ -0,0 +1,28 @@ +package com.senmesh.config.constant; + +/** + * 配置常量类 + * @author sr on 2019-10-20 + */ +public class ConfigConstants { + + /** + * -----校验信息----- + **/ + public static final String CONFIG_ID_NULL = "配置id不能为空"; + public static final String CONFIG_CODE_EMPTY = "配置编码不能为空"; + /** -----校验信息----- **/ + + + /** + * -----异常信息----- + **/ + public static final String CONFIG_CODE_EXIST = "配置编码已存在"; + public static final String CONFIG_NOT_EXIST = "未找到对应配置"; + /** -----异常信息----- **/ + + /** + * 业务数据忽略机构配置 + */ + public static final String CONFIG_IGNORE_ORG_INFO = "ignore_org_info"; +} diff --git a/backend/src/main/java/com/senmesh/config/controller/AnonConfigController.java b/backend/src/main/java/com/senmesh/config/controller/AnonConfigController.java new file mode 100644 index 0000000..779c9f4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/config/controller/AnonConfigController.java @@ -0,0 +1,30 @@ +package com.senmesh.config.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.config.dto.*; +import com.senmesh.config.service.ConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * 配置操作 + * + * @author on 2019-11-05 + */ +@RestController +@RequestMapping("anon/config") +public class AnonConfigController { + + @Autowired + private ConfigService configService; + + + @GetMapping("/code/{configCode}") + public AlitaResult getAppVersion(@PathVariable("configCode") String configCode) { + ConfigDTO configDto = configService.getConfigDto(configCode, CommonConstants.PLATFORM_ORG_ID, Boolean.TRUE); + return AlitaResult.success(configDto); + } + + +} diff --git a/backend/src/main/java/com/senmesh/config/controller/ConfigController.java b/backend/src/main/java/com/senmesh/config/controller/ConfigController.java new file mode 100644 index 0000000..49c0596 --- /dev/null +++ b/backend/src/main/java/com/senmesh/config/controller/ConfigController.java @@ -0,0 +1,92 @@ +package com.senmesh.config.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.config.dao.ConfigMapper; +import com.senmesh.config.dto.*; +import com.senmesh.config.service.ConfigService; +import com.senmesh.tkmybatis.pojo.Page; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 配置操作 + * + * @author on 2019-11-05 + */ +@RestController +@RequestMapping("config") +@Api(tags = "配置操作") +public class ConfigController { + + @Autowired + private ConfigService configService; + + @Resource + private ConfigMapper configMapper; + + @PostMapping + @ApiOperation("配置表-创建") + public AlitaResult create(@RequestBody ConfigOperatorDTO operatorDTO) { + return AlitaResult.success(configService.create(operatorDTO)); + } + + @PutMapping + @ApiOperation("配置表-修改") + public AlitaResult modify(@RequestBody ConfigOperatorDTO operatorDTO) { + return AlitaResult.success(configService.modify(operatorDTO)); + } + + @DeleteMapping("{id}") + @ApiOperation("配置表-删除") + public AlitaResult delete(@PathVariable("id") Long id) { + return AlitaResult.success(configService.delete(id)); + } + + @GetMapping("{id}") + @ApiOperation("配置表-查询单个") + public AlitaResult findById(@PathVariable("id") Long id) { + return AlitaResult.success(configService.findById(id)); + } + + @GetMapping("list") + @ApiOperation("配置表-列表查询") + public AlitaResult> list(ConfigQueryDTO queryDTO) { + return AlitaResult.success(configService.list(queryDTO)); + } + + @GetMapping("page") + @ApiOperation("配置表-分页查询") + public AlitaResult> page(ConfigPageQueryDTO queryDTO) { + configService.page(queryDTO); + return AlitaResult.success(queryDTO.getPageResult()); + } + + @GetMapping("org_list/{configCode}") + @ApiOperation("可分配的机构列表") + public AlitaResult> orgListCanSelect(@PathVariable("configCode") String configCode) { + return AlitaResult.success(configMapper.orgList(configCode)); + } + + + + @ApiOperation("根据编码获取配置") + @GetMapping("/code/{configCode}") + public AlitaResult getTemplate(@PathVariable("configCode") String configCode) { + return AlitaResult + .success(configService.queryConfigByCode(UserContextHolder.getExistLoginOrgId(), configCode)); + } + + @ApiOperation("根据编码获取配置") + @GetMapping("/org_code/{configCode}") + public AlitaResult getOrgConfig(@PathVariable("configCode") String configCode) { + return AlitaResult + .success(configService.queryOrgConfigByCode(UserContextHolder.getExistLoginOrgId(), configCode)); + } + +} diff --git a/backend/src/main/java/com/senmesh/config/convert/ConfigConvert.java b/backend/src/main/java/com/senmesh/config/convert/ConfigConvert.java new file mode 100644 index 0000000..3b20b52 --- /dev/null +++ b/backend/src/main/java/com/senmesh/config/convert/ConfigConvert.java @@ -0,0 +1,25 @@ +package com.senmesh.config.convert; + +import com.senmesh.config.dto.ConfigDTO; +import com.senmesh.config.dto.ConfigOperatorDTO; +import com.senmesh.config.entity.Config; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * 配置表 + * + * @author chenyun chenyun.home@outlook.com + * @since 1.0.0 2023-01-04 + */ +@Mapper +public interface ConfigConvert { + ConfigConvert INSTANCE = Mappers.getMapper(ConfigConvert.class); + + Config convert(ConfigDTO dto); + + ConfigDTO convert(Config entity); + + Config convert(ConfigOperatorDTO dto); + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/config/dao/ConfigMapper.java b/backend/src/main/java/com/senmesh/config/dao/ConfigMapper.java new file mode 100644 index 0000000..16d6eec --- /dev/null +++ b/backend/src/main/java/com/senmesh/config/dao/ConfigMapper.java @@ -0,0 +1,94 @@ +package com.senmesh.config.dao; + +import com.senmesh.config.dto.ConfigDTO; +import com.senmesh.config.dto.ConfigPageQueryDTO; +import com.senmesh.config.dto.ConfigQueryDTO; +import com.senmesh.config.dto.OrgInfoDTO; +import com.senmesh.config.entity.Config; +import com.senmesh.tkmybatis.mybatis.MyMapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Set; + +/** + * 配置mapper + * + * @author sr on 2019-10-20 + */ +public interface ConfigMapper extends MyMapper { + + /** + * 排除已经被分配的配置机构,剩余的机构 + * + * @param configCode 配置代码 + * @return {@link List}<{@link OrgInfoDTO}> + */ + List orgList(@Param("configCode") String configCode); + + List page(@Param("param") ConfigPageQueryDTO queryDTO); + + List list(@Param("param") ConfigQueryDTO queryDTO); + + /** + * 查询配置 + * + * @param config + * @return + * @author sr on 2019-11-05 + */ + List find(@Param("param") Config config); + + /** + * + * @param configCode + * @param orgIds + * @return + */ + List listByCodeAndOrgIds(@Param("configCode") String configCode, @Param("orgIds") Set orgIds); + + /** + * 校验配置编码是否存在 + * @param orgId + * @param configCode + * @param configId 为空则判断所有(新增),不为空代表判断除该id之外的(修改) + * @return + * @author sr on 2019-10-20 + */ + int existConfigCode(@Param("orgId") Long orgId, @Param("configCode") String configCode, @Param("configId") Long configId); + + /** + * 根据编码获取配置 + * @param platformOrgId + * @param orgId + * @param configCode + * @return + * @author sr on 2019-10-23 + */ + ConfigDTO queryConfigByCode(@Param("platformOrgId") Long platformOrgId, + @Param("orgId") Long orgId, @Param("configCode") String configCode); + + /** + * 根据编码获取机构配置 + * @param orgId + * @param configCode + * @return + * @author sr on 2019-10-23 + */ + ConfigDTO queryOrgConfigByCode(@Param("orgId") Long orgId, @Param("configCode") String configCode); + + /** + * 新增并校验是否重复(org_id,config_code),重复则不新增 + * + * @param config + */ + int saveAndCheckExist(@Param("param") Config config, @Param("userId") Long userId); + + /** + * 批量删除 + * + * @param configCode 配置代码 + * @param userId 用户id + */ + void batchDelete(@Param("configCode") String configCode, @Param("userId") Long userId); +} diff --git a/backend/src/main/java/com/senmesh/config/dto/AppVersionConfigInfo.java b/backend/src/main/java/com/senmesh/config/dto/AppVersionConfigInfo.java new file mode 100644 index 0000000..be5d92b --- /dev/null +++ b/backend/src/main/java/com/senmesh/config/dto/AppVersionConfigInfo.java @@ -0,0 +1,17 @@ +package com.senmesh.config.dto; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class AppVersionConfigInfo implements Serializable { + + private String versionName; + private String platform; + private String autoUpdate; + private String updateContent; + private String updateTime; + private String updateType; + private String downloadUrl; +} diff --git a/backend/src/main/java/com/senmesh/config/dto/ConfigDTO.java b/backend/src/main/java/com/senmesh/config/dto/ConfigDTO.java new file mode 100644 index 0000000..c00528d --- /dev/null +++ b/backend/src/main/java/com/senmesh/config/dto/ConfigDTO.java @@ -0,0 +1,52 @@ +package com.senmesh.config.dto; + +import com.senmesh.common.dto.BaseDTO; +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; +import com.senmesh.config.constant.ConfigConstants; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + * 配置 + * + * @author on 2019-11-05 + */ +@ApiModel("配置") +@Data +@EqualsAndHashCode(callSuper = true) +public class ConfigDTO extends BaseDTO implements Serializable { + + /** + * + **/ + private static final long serialVersionUID = -7378966546274876887L; + + @ApiModelProperty("配置id") + @NotNull(message = ConfigConstants.CONFIG_ID_NULL, groups = {Update.class}) + private Long id; + + @ApiModelProperty("机构名称") + private String orgName; + + private Long orgId; + + @ApiModelProperty("编码") + @NotBlank(message = ConfigConstants.CONFIG_CODE_EMPTY, groups = {Create.class, Update.class}) + private String configCode; + + @ApiModelProperty("配置值") + private String configValue; + + @ApiModelProperty("备注") + private String remark; + + @ApiModelProperty("是否启用") + private Boolean enable; +} diff --git a/backend/src/main/java/com/senmesh/config/dto/ConfigOperatorDTO.java b/backend/src/main/java/com/senmesh/config/dto/ConfigOperatorDTO.java new file mode 100644 index 0000000..8851c65 --- /dev/null +++ b/backend/src/main/java/com/senmesh/config/dto/ConfigOperatorDTO.java @@ -0,0 +1,45 @@ +package com.senmesh.config.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** +* 配置表 +* +* @author chenyun chenyun.home@outlook.com +* @since 1.0.0 2023-01-04 +*/ +@ApiModel("配置表") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ConfigOperatorDTO implements Serializable { + + private static final long serialVersionUID = -6593867699038600971L; + + private Long id; + + @ApiModelProperty("编码") + private String configCode; + + @ApiModelProperty("配置值") + private String configValue; + + @ApiModelProperty("机构") + private Long orgId; + + @ApiModelProperty("备注") + private String remark; + + @ApiModelProperty("是否启用") + private Boolean enable; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/config/dto/ConfigPageQueryDTO.java b/backend/src/main/java/com/senmesh/config/dto/ConfigPageQueryDTO.java new file mode 100644 index 0000000..ce967f8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/config/dto/ConfigPageQueryDTO.java @@ -0,0 +1,77 @@ +package com.senmesh.config.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.senmesh.common.annotation.trimAndUpper.TrimAndUpper; +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +/** + * 配置表 + * + * @author chenyun chenyun.home@outlook.com + * @since 1.0.0 2023-01-04 + */ + +@ApiModel("配置表") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class ConfigPageQueryDTO extends PageQueryDTO { + + private static final long serialVersionUID = -2457835934025456625L; + + @ApiModelProperty("主键ID") + private Long id; + + @ApiModelProperty("机构名称 (模糊匹配)") + @TrimAndUpper(TrimAndUpper.ExecuteType.TRIM) + private String orgNameLike; + + @ApiModelProperty("编码") + private String configCode; + + @ApiModelProperty("编码(模糊匹配)") + @TrimAndUpper(TrimAndUpper.ExecuteType.TRIM) + private String configCodeLike; + + @ApiModelProperty("配置值") + private String configValue; + + @ApiModelProperty("机构") + private Long orgId; + + @ApiModelProperty("备注") + private String remark; + + @ApiModelProperty("是否启用") + private Boolean enable; + + @ApiModelProperty("创建时间起,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTimeStart; + + @ApiModelProperty("创建时间止,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTimeEnd; + + @ApiModelProperty("修改时间起,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTimeStart; + + @ApiModelProperty("修改时间止,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTimeEnd; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/config/dto/ConfigQueryDTO.java b/backend/src/main/java/com/senmesh/config/dto/ConfigQueryDTO.java new file mode 100644 index 0000000..05748d6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/config/dto/ConfigQueryDTO.java @@ -0,0 +1,76 @@ +package com.senmesh.config.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serializable; +import java.util.Date; +import java.util.Set; + +/** + * 配置表 + * + * @author chenyun chenyun.home@outlook.com + * @since 1.0.0 2023-01-04 + */ +@ApiModel("配置表") +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ConfigQueryDTO implements Serializable { + + private static final long serialVersionUID = 2141446474852301916L; + + @ApiModelProperty("主键ID") + private Long id; + + @ApiModelProperty("编码") + private String configCode; + + @ApiModelProperty("编码(模糊匹配)") + private String configCodeLike; + + @ApiModelProperty("配置值") + private String configValue; + + @ApiModelProperty("机构") + private Long orgId; + + @ApiModelProperty("机构集合") + private Set orgIds; + + @ApiModelProperty("备注") + private String remark; + + @ApiModelProperty("是否启用") + private Boolean enable; + + @ApiModelProperty("创建时间起,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTimeStart; + + @ApiModelProperty("创建时间止,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTimeEnd; + + @ApiModelProperty("修改时间起,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTimeStart; + + @ApiModelProperty("修改时间止,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTimeEnd; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/config/dto/OrgInfoDTO.java b/backend/src/main/java/com/senmesh/config/dto/OrgInfoDTO.java new file mode 100644 index 0000000..e9ce0a6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/config/dto/OrgInfoDTO.java @@ -0,0 +1,26 @@ +package com.senmesh.config.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OrgInfoDTO implements Serializable { + private static final long serialVersionUID = 4030022865543182548L; + + /** + * id + */ + private Long id; + + /** + * 机构名字 + */ + private String orgName; +} diff --git a/backend/src/main/java/com/senmesh/config/entity/Config.java b/backend/src/main/java/com/senmesh/config/entity/Config.java new file mode 100644 index 0000000..17f9f8d --- /dev/null +++ b/backend/src/main/java/com/senmesh/config/entity/Config.java @@ -0,0 +1,64 @@ +package com.senmesh.config.entity; + + +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 配置 + * + * @author on 2019-11-05 + */ +@TableName(value = "xs_config") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Data +public class Config extends BaseEntity { + + /** **/ + private static final long serialVersionUID = -4915635782620683517L; + /** + * 编码 + */ + private String configCode; + /** + * 配置值 + */ + private String configValue; + /** + * 机构 + */ + private Long orgId; + /** + * 备注 + */ + private String remark; + /** + * 是否启用 + */ + private Boolean enable; + + @Builder + public Config(Long id, Boolean deleted, Long createBy, Date createTime, Long updateBy, + Date updateTime, Long proxyBy, String configCode, String configValue, Long orgId, + String remark, Boolean enable) { + super(id, deleted, createBy, createTime, updateBy, updateTime, proxyBy); + this.configCode = configCode; + this.configValue = configValue; + this.orgId = orgId; + this.remark = remark; + this.enable = enable; + } + + + +} diff --git a/backend/src/main/java/com/senmesh/config/mapper/ConfigMapper.xml b/backend/src/main/java/com/senmesh/config/mapper/ConfigMapper.xml new file mode 100644 index 0000000..0b8812a --- /dev/null +++ b/backend/src/main/java/com/senmesh/config/mapper/ConfigMapper.xml @@ -0,0 +1,222 @@ + + + + + UPDATE xs_config + SET deleted = TRUE, + update_time = NOW(), + update_by = #{userId} + WHERE deleted = FALSE + AND config_code = #{configCode} + + + + + + + + FROM + xs_config t + WHERE t.deleted = FALSE + + AND t.id = #{param.id} + + + AND t.config_code = #{param.configCode} + + + AND t.config_value = #{param.configValue} + + + + and config_code like #{configCodeLike} + + + AND t.org_id = #{param.orgId} + + + AND t.remark = #{param.remark} + + + AND t.enable = #{param.enable} + + + AND t.create_time >= #{param.createTimeStart} + + + AND t.create_time <= #{param.createTimeEnd} + + + AND t.update_time >= #{param.updateTimeStart} + + + AND t.update_time <= #{param.updateTimeEnd} + + ORDER BY t.id DESC + + + + + + + + + + + + + + + INSERT INTO xs_config (config_code, + config_value, + org_id, + remark, + enable, + deleted, + create_time, + create_by) + SELECT #{param.configCode}, + #{param.configValue}, + #{param.orgId}, + #{param.remark}, + #{param.enable}, + 0 AS deleted, + NOW() AS create_time, + #{userId} AS create_by + FROM DUAL + WHERE NOT EXISTS(SELECT 1 + FROM xs_config + WHERE org_id = #{param.orgId} + and config_code = #{param.configCode} + and deleted = FALSE) + + diff --git a/backend/src/main/java/com/senmesh/config/service/ConfigService.java b/backend/src/main/java/com/senmesh/config/service/ConfigService.java new file mode 100644 index 0000000..c1db565 --- /dev/null +++ b/backend/src/main/java/com/senmesh/config/service/ConfigService.java @@ -0,0 +1,142 @@ +package com.senmesh.config.service; + +import com.senmesh.config.dto.ConfigDTO; +import com.senmesh.config.dto.ConfigOperatorDTO; +import com.senmesh.config.dto.ConfigPageQueryDTO; +import com.senmesh.config.dto.ConfigQueryDTO; +import com.senmesh.config.entity.Config; + +import javax.validation.Valid; +import java.util.List; +import java.util.Set; + +/** + * 配置 + * + * @author sr on 2019-10-20 + */ +public interface ConfigService { + + + /** + * 配置表 - 创建 + * + * @param operatorDto 操作dto + * @return {@link com.senmesh.config.dto.ConfigDTO} + */ + ConfigDTO create(@Valid ConfigOperatorDTO operatorDto); + + /** + * 配置表 - 修改 + * + * @param operatorDto 操作dto + * @return {@link com.senmesh.config.dto.ConfigDTO} + */ + ConfigDTO modify(@Valid ConfigOperatorDTO operatorDto); + + /** + * 配置表 - 删除 + * + * @param id id + * @return {@link com.senmesh.config.dto.ConfigDTO} + */ + ConfigDTO delete(Long id); + + /** + * 配置表 - 根据ID查询单个 + * + * @param id id + * @return {@link com.senmesh.config.dto.ConfigDTO} + */ + ConfigDTO findById(Long id); + + /** + * 配置表 - 列表查询 + * + * @param queryDTO 列表查询dto + * @return {@link List}<{@link com.senmesh.config.dto.ConfigDTO}> + */ + List list(ConfigQueryDTO queryDTO); + + /** + * 配置表 - 分页查询 + * + * @param queryDTO 分页查询dto + * @return {@link com.senmesh.config.dto.ConfigDTO} + */ + List page(ConfigPageQueryDTO queryDTO); + + /** + * 查询配置 + * + * @param config + * @return + * @author sr on 2019-11-05 + */ + List find(Config config); + + /** + * 根据code和机构id集合查询配置 + * @param code + * @param orgIds + * @return + */ + List findByCodeAndOrgIds(String code, Set orgIds); + + /** + * 获取配置值 + * @param code + * @param orgId + * @param enable + * @return + */ + String getConfigValue(String code, Long orgId, boolean enable); + + + /** + * 根据code查询配置 + * @param orgId + * @param configCode + * @return + * @author sr on 2019-10-23 + */ + ConfigDTO queryConfigByCode(Long orgId, String configCode); + + /** + * 根据code查询配置 + * @param orgId + * @param configCode + * @return + * @author sr on 2019-10-23 + */ + ConfigDTO queryOrgConfigByCode(Long orgId, String configCode); + + /** + * 获取配置 + * @param code + * @param orgId + * @param enable + * @return + */ + Config getConfig(String code, Long orgId, boolean enable); + + /** + * 获取配置的dto + * @param code + * @param orgId + * @param enable + * @return + */ + ConfigDTO getConfigDto(String code, Long orgId, boolean enable); + + /** + * 创建或修改配置 + * 如果配置已存在则修改,不存在则创建 + * + * @param orgId 机构ID + * @param configCode 配置编码 + * @param configValue 配置值 + */ + void createOrModify(Long orgId, String configCode, String configValue); + +} diff --git a/backend/src/main/java/com/senmesh/config/service/impl/ConfigServiceImpl.java b/backend/src/main/java/com/senmesh/config/service/impl/ConfigServiceImpl.java new file mode 100644 index 0000000..4c01ac4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/config/service/impl/ConfigServiceImpl.java @@ -0,0 +1,179 @@ +package com.senmesh.config.service.impl; + + +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.util.ExceptionUtils; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.config.constant.ConfigConstants; +import com.senmesh.config.convert.ConfigConvert; +import com.senmesh.config.dao.ConfigMapper; +import com.senmesh.config.dto.ConfigDTO; +import com.senmesh.config.dto.ConfigOperatorDTO; +import com.senmesh.config.dto.ConfigPageQueryDTO; +import com.senmesh.config.dto.ConfigQueryDTO; +import com.senmesh.config.entity.Config; +import com.senmesh.config.service.ConfigService; + +/** + * 配置 + * + * @author sr on 2019-10-20 + */ +@Service +public class ConfigServiceImpl implements ConfigService { + + @Autowired + private ConfigMapper configMapper; + + + @Override + public ConfigDTO create(ConfigOperatorDTO operatorDto) { + Config config = ConfigConvert.INSTANCE.convert(operatorDto); + configMapper.saveEntity(config); + + return ConfigConvert.INSTANCE.convert(config); + } + + @Override + public ConfigDTO modify(ConfigOperatorDTO operatorDto) { + ConfigDTO configDto = this.findById(operatorDto.getId()); + if (Objects.isNull(configDto)) { + return null; + } + Config config = ConfigConvert.INSTANCE.convert(operatorDto); + configMapper.updateEntity(config); + return this.findById(operatorDto.getId()); + } + + @Override + public ConfigDTO delete(Long id) { + ConfigDTO configDto = this.findById(id); + if (Objects.isNull(configDto)) { + return null; + } + Config config = Config.builder().build(); + config.setId(id); + configMapper.deleteEntity(config, UserContextHolder.getLoginUserId()); + return configDto; + } + + @Override + public ConfigDTO findById(Long id) { + Config config = configMapper.getById(id); + if (Objects.isNull(config)) { + return null; + } + return ConfigConvert.INSTANCE.convert(config); + } + + @Override + public List list(ConfigQueryDTO queryDTO) { + return configMapper.list(queryDTO); + } + + @Override + public List page(ConfigPageQueryDTO queryDTO) { + return configMapper.page(queryDTO); + } + + + @Override + public List find(Config config) { + return configMapper.find(config); + } + + @Override + public List findByCodeAndOrgIds(String code, Set orgIds) { + return configMapper.listByCodeAndOrgIds(code, orgIds); + } + + @Override + public String getConfigValue(String code, Long orgId, boolean enable) { + List configs = find(Config.builder().configCode(code).orgId(orgId).enable(enable).deleted(false).build()); + if(CollectionUtils.isEmpty(configs)) { + return null; + } + return configs.get(0).getConfigValue(); + } + + /** + * 校验配置编码是否存在 + * @param + * @param + */ + private void checkTemplateCode(Long orgId, String configCode, Long configId) { + int num = configMapper.existConfigCode(orgId, configCode, configId); + ExceptionUtils.throwBusinessException(num > 0, ConfigConstants.CONFIG_CODE_EXIST); + } + + + @Override + @Transactional(rollbackFor = RuntimeException.class) + public ConfigDTO queryConfigByCode(Long orgId, String configCode) { + return configMapper.queryConfigByCode(CommonConstants.PLATFORM_ORG_ID, orgId, configCode); + } + + @Override + public ConfigDTO queryOrgConfigByCode(Long orgId, String configCode) { + return configMapper.queryOrgConfigByCode(orgId, configCode); + } + + @Override + public Config getConfig(String code, Long orgId, boolean enable) { + Config query = Config.builder().configCode(code).orgId(orgId).enable(enable).build(); + List configs = find(query); + if(CollectionUtils.isEmpty(configs) && ObjectUtils.notEqual(CommonConstants.PLATFORM_ORG_ID, orgId)) { + query.setOrgId(CommonConstants.PLATFORM_ORG_ID); + configs = find(query); + } + if(CollectionUtils.isEmpty(configs)){ + return null; + } + return configs.get(0); + } + + @Override + public ConfigDTO getConfigDto(String code, Long orgId, boolean enable) { + Config config = getConfig(code, orgId, enable); + if(config == null){ + return null; + } + ConfigDTO dto = new ConfigDTO(); + BeanUtils.copyProperties(config, dto); + return dto; + } + + @Override + @Transactional + public void createOrModify(Long orgId, String configCode, String configValue) { + // 查询是否已存在配置 + ConfigDTO existConfig = queryOrgConfigByCode(orgId, configCode); + + if (existConfig != null) { + // 存在则修改 + configMapper.updateEntitySelective( + Config.builder().id(existConfig.getId()).configValue(configValue).build()); + } else { + // 不存在则创建 + Config config = Config.builder() + .configCode(configCode) + .configValue(configValue) + .orgId(orgId) + .enable(true) + .build(); + configMapper.saveEntity(config); + } + } + +} diff --git a/backend/src/main/java/com/senmesh/config/util/ConfigUtils.java b/backend/src/main/java/com/senmesh/config/util/ConfigUtils.java new file mode 100644 index 0000000..5a39a6e --- /dev/null +++ b/backend/src/main/java/com/senmesh/config/util/ConfigUtils.java @@ -0,0 +1,40 @@ +package com.senmesh.config.util; + +import com.senmesh.config.dto.ConfigDTO; +import com.senmesh.config.entity.Config; + +/** + * 配置工具类 + * + * @author sr on 2019-10-20 + */ +public class ConfigUtils { + + /** + * dto转entity, 新增 + * + * @param + * @param orgId + * @return + */ + public static Config toCreate(ConfigDTO configDTO, Long orgId) { + Config config = Config.builder().configCode(configDTO.getConfigCode()) + .configValue(configDTO.getConfigValue()).remark(configDTO.getRemark()) + .enable(!Boolean.FALSE.equals(configDTO.getEnable())).orgId(orgId).build(); + return config; + } + + /** + * dto转entity,修改,有id;orgId不变(置空) + * + * @param + * @return + */ + public static Config toUpdate(ConfigDTO configDTO) { + Config config = Config.builder().id(configDTO.getId()).configCode(configDTO.getConfigCode()) + .configValue(configDTO.getConfigValue()).remark(configDTO.getRemark()) + .enable(!Boolean.FALSE.equals(configDTO.getEnable())).build(); + return config; + } + +} diff --git a/backend/src/main/java/com/senmesh/frame/redis/aop/annotation/AutoUnLock.java b/backend/src/main/java/com/senmesh/frame/redis/aop/annotation/AutoUnLock.java new file mode 100644 index 0000000..0809012 --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/aop/annotation/AutoUnLock.java @@ -0,0 +1,17 @@ +package com.senmesh.frame.redis.aop.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 自动解锁 + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface AutoUnLock { + +} diff --git a/backend/src/main/java/com/senmesh/frame/redis/aop/annotation/RedissonLock.java b/backend/src/main/java/com/senmesh/frame/redis/aop/annotation/RedissonLock.java new file mode 100644 index 0000000..add62b9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/aop/annotation/RedissonLock.java @@ -0,0 +1,60 @@ +package com.senmesh.frame.redis.aop.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.concurrent.TimeUnit; + +/** + * @author dylanyuan + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +@Repeatable(RedissonLocks.class) +public @interface RedissonLock { + + /** + * 前缀 + * @return + */ + String prefix() default ""; + + /** + * 指定参数名 只支持字符串和字符串数组 + * @return + */ + String paramName(); + + /** + * 超时时间 默认-1:即为1天失效 + * 不允许不添加失效时间 + * @return + */ + long expires() default -1L; + + /** + * 时间单位,默认为秒 + * @return + */ + TimeUnit timeUnit() default TimeUnit.SECONDS; + + /** + * 尝试加锁等待时时间 默认0, + * -1则不进行trylock + * @return + */ + long tryLockWaitTime() default 0; + + /** + * 允许param值为空则跳过加锁 + * @return + */ + boolean skipIfNull() default false; + +} diff --git a/backend/src/main/java/com/senmesh/frame/redis/aop/annotation/RedissonLocks.java b/backend/src/main/java/com/senmesh/frame/redis/aop/annotation/RedissonLocks.java new file mode 100644 index 0000000..e8ac2b9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/aop/annotation/RedissonLocks.java @@ -0,0 +1,21 @@ +package com.senmesh.frame.redis.aop.annotation; + + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author dylanyuan + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD}) +@Documented +@Inherited +public @interface RedissonLocks { + + RedissonLock[] value(); +} diff --git a/backend/src/main/java/com/senmesh/frame/redis/aop/annotation/RedissonMultiLock.java b/backend/src/main/java/com/senmesh/frame/redis/aop/annotation/RedissonMultiLock.java new file mode 100644 index 0000000..185f71b --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/aop/annotation/RedissonMultiLock.java @@ -0,0 +1,66 @@ +package com.senmesh.frame.redis.aop.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.concurrent.TimeUnit; + +/** + * @author dylanyuan + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +public @interface RedissonMultiLock { + + /** + * 前缀 + * @return + */ + String prefix() default ""; + + /** + * 指定参数名 只支持字符串和字符串数组 + * @return + */ + String paramName(); + + /** + * 超时时间 默认-1:即为1天失效 + * 不允许不添加失效时间 + * @return + */ + long expires() default -1L; + + /** + * 时间单位 默认为秒 + * @return + */ + TimeUnit timeUnit() default TimeUnit.SECONDS; + + /** + * 尝试加锁等待时时间 默认-1则不进行trylock + * @return + */ + long tryLockWaitTime() default -1; + + /** + * 是否允许部分成功 + * true, 入参必须存在Set failSet, 失败的会从加入失败队列,原始数据不移除 + * false, 不允许部分成功,所有的lock,必须全部成功 + * 默认是false + * @return + */ + boolean allowPartSuccess() default false; + + + /** + * 允许param值为空则跳过加锁 + * @return + */ + boolean skipIfNull() default false; +} diff --git a/backend/src/main/java/com/senmesh/frame/redis/aop/aspect/RedissonLockAop.java b/backend/src/main/java/com/senmesh/frame/redis/aop/aspect/RedissonLockAop.java new file mode 100644 index 0000000..8086ad2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/aop/aspect/RedissonLockAop.java @@ -0,0 +1,44 @@ +package com.senmesh.frame.redis.aop.aspect; + +import com.senmesh.frame.redis.aop.annotation.RedissonLock; +import com.senmesh.frame.redis.util.IAopUtils; +import com.senmesh.frame.redis.util.LockUtils; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.redisson.api.RLock; +import org.springframework.stereotype.Component; + +/** + * @author dylanyuan + */ +@Aspect +@Component +@Slf4j +public class RedissonLockAop { + + @Pointcut("@annotation(com.senmesh.frame.redis.aop.annotation.RedissonLock)") + public void annotationPointCut() { + } + + @Around("annotationPointCut()") + public Object around(ProceedingJoinPoint joinPoint) throws Throwable { + log.info("redisson lock {}方法 加锁开始:{}", joinPoint.getSignature().getName(), + joinPoint.toString()); + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + RedissonLock redissonLock = signature.getMethod().getAnnotation(RedissonLock.class); + RLock lock = null; + try { + lock = IAopUtils.lock(joinPoint, redissonLock); + return joinPoint.proceed(); + } finally { + LockUtils.unlock(lock); + log.info("redisson lock {}方法 加锁结束:{}", joinPoint.getSignature().getName(), joinPoint.toString()); + } + } + + +} diff --git a/backend/src/main/java/com/senmesh/frame/redis/aop/aspect/RedissonLocksAop.java b/backend/src/main/java/com/senmesh/frame/redis/aop/aspect/RedissonLocksAop.java new file mode 100644 index 0000000..851d4e2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/aop/aspect/RedissonLocksAop.java @@ -0,0 +1,52 @@ +package com.senmesh.frame.redis.aop.aspect; + +import com.senmesh.frame.redis.aop.annotation.RedissonLock; +import com.senmesh.frame.redis.aop.annotation.RedissonLocks; +import com.senmesh.frame.redis.util.IAopUtils; +import com.senmesh.frame.redis.util.LockUtils; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.redisson.api.RLock; +import org.springframework.stereotype.Component; + +/** + * @author dylanyuan + */ +@Aspect +@Component +@Slf4j +public class RedissonLocksAop { + + @Pointcut("@annotation(com.senmesh.frame.redis.aop.annotation.RedissonLocks)") + public void annotationPointCut() { + } + + @Around("annotationPointCut()") + public Object around(ProceedingJoinPoint joinPoint) throws Throwable { + log.info("redisson locks {}方法 加锁开始:{}", joinPoint.getSignature().getName(), joinPoint.toString()); + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + RedissonLocks redissonLocks = signature.getMethod().getAnnotation(RedissonLocks.class); + RedissonLock[] redissonLockArray = redissonLocks.value(); + RLock[] locks = new RLock[redissonLockArray.length]; + try { + for (int i = 0; i < redissonLockArray.length; i++) { + locks[i] = IAopUtils.lock(joinPoint, redissonLockArray[i]); + } + return joinPoint.proceed(); + }finally { + for (RLock lock : locks) { + try { + LockUtils.unlock(lock); + }catch (Exception e){ + log.error("redisson locks 锁【{}】解锁失败", lock.getName(), e); + } + } + log.info("redisson locks {}方法 加锁结束:{}", joinPoint.getSignature().getName(), + joinPoint.toString()); + } + } +} diff --git a/backend/src/main/java/com/senmesh/frame/redis/aop/aspect/RedissonMultiLockAop.java b/backend/src/main/java/com/senmesh/frame/redis/aop/aspect/RedissonMultiLockAop.java new file mode 100644 index 0000000..784cc06 --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/aop/aspect/RedissonMultiLockAop.java @@ -0,0 +1,166 @@ +package com.senmesh.frame.redis.aop.aspect; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang3.StringUtils; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.redisson.api.RLock; +import org.springframework.stereotype.Component; + +import com.senmesh.common.util.JsonUtils; +import com.senmesh.frame.redis.aop.annotation.RedissonMultiLock; +import com.senmesh.frame.redis.exception.RedisLockErrorParamException; +import com.senmesh.frame.redis.exception.RedisLockFailException; +import com.senmesh.frame.redis.redisson.RedissonUtils; +import com.senmesh.frame.redis.util.IAopUtils; +import com.senmesh.frame.redis.util.LockUtils; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author dylanyuan + */ +@Aspect +@Component +@Slf4j +public class RedissonMultiLockAop { + + public static final String FAIL_SET = "failSet"; + + @Pointcut("@annotation(com.senmesh.frame.redis.aop.annotation.RedissonMultiLock)") + public void annotationPointCut() {} + + @Around("annotationPointCut()") + public Object around(ProceedingJoinPoint joinPoint) throws Throwable { + String methodName = joinPoint.getSignature().getName(); + log.info("redisson batchlock {}方法 加锁开始:{}", methodName, joinPoint.toString()); + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + RedissonMultiLock redisMultiLock = signature.getMethod().getAnnotation(RedissonMultiLock.class); + String paramName = redisMultiLock.paramName(); + if (StringUtils.isBlank(paramName)) { + throw new RedisLockErrorParamException( + "redisson batchlock 方法 " + methodName + " paramName不能为空"); + } + Object paramValue = IAopUtils.getParamValue(joinPoint, paramName); + if (paramValue == null) { + boolean skipIfNull = redisMultiLock.skipIfNull(); + if (skipIfNull) { + return joinPoint.proceed(); + } + throw new RedisLockErrorParamException( + "redisson batchlock 方法 " + methodName + " paramName[" + paramName + "]所对应的参数内容不能为空"); + } + IAopUtils.checkParamType(IAopUtils.getMethod(joinPoint), paramName, paramValue, true); + boolean allowPartSuccess = redisMultiLock.allowPartSuccess(); + Collection failSet = null; + if (allowPartSuccess) { + try { + Object temp = IAopUtils.getParamValue(joinPoint, FAIL_SET); + if (temp == null) { + throw new RedisLockErrorParamException("redisson batchlock 方法 " + methodName + + " 使用部分成功加锁时必须存在失败集合参数[Collection failSet]"); + } + failSet = (Collection) temp; + } catch (Exception e) { + throw new RedisLockErrorParamException( + "redisson batchlock 方法 " + methodName + " 使用部分成功加锁时必须存在失败集合参数[Set failSet]"); + } + } else { + failSet = new ArrayList<>(); + } + long expires = redisMultiLock.expires(); + TimeUnit timeUnit = redisMultiLock.timeUnit(); + if (expires == -1) { + expires = 1; + timeUnit = TimeUnit.DAYS; + } + long tryLockWaitTime = redisMultiLock.tryLockWaitTime(); + Map key2ParamMap = new HashMap<>(); + if (paramValue instanceof String[]) { + String[] values = (String[]) paramValue; + for (String value : values) { + key2ParamMap.put(redisMultiLock.prefix() + value, value); + } + } else if (paramValue instanceof Iterable) { + Iterable iterable = (Iterable) paramValue; + Iterator iterator = iterable.iterator(); + while (iterator.hasNext()) { + String value = iterator.next(); + key2ParamMap.put(redisMultiLock.prefix() + value, value); + } + } + return partSuccessBatchLock(joinPoint, expires, timeUnit, tryLockWaitTime, key2ParamMap, + paramValue, failSet, allowPartSuccess); + } + + private Object partSuccessBatchLock(ProceedingJoinPoint joinPoint, long expires, + TimeUnit timeUnit, long tryLockWaitTime, Map key2ParamMap, Object paramValue, + Collection failSet, boolean allowPartSuccess) throws Throwable { + Map map = new HashMap<>(key2ParamMap.size()); + for (String key : key2ParamMap.keySet()) { + map.put(key, RedissonUtils.getLock(key)); + } + try { + for (Entry entry : map.entrySet()) { + LockUtils.lock(expires, timeUnit, tryLockWaitTime, entry.getValue()); + if (!entry.getValue().isLocked()) { + String value = key2ParamMap.get(entry.getKey()); + log.error("方法[{}]所对应的参数[{}]正在运行中,请不要重复操作!", joinPoint.getSignature().getName(), value); + failSet.add(value); + } + } + if (allowPartSuccess) { + if (map.size() == failSet.size()) { + throw new RedisLockFailException( + "方法[" + joinPoint.getSignature().getName() + "]所对应的参数[" + + JsonUtils.toJsonString(key2ParamMap.values()) + + "]正在运行中,请不要重复操作!"); + } else if (failSet.size() > 0) { + if (paramValue instanceof String[]) { + String[] values = (String[]) paramValue; + for (int i = 0; i < values.length; i++) { + if (failSet.contains(values[i])) { + values[i] = null; + } + } + } else if (paramValue instanceof Iterable) { + Iterable iterable = (Iterable) paramValue; + Iterator iterator = iterable.iterator(); + while (iterator.hasNext()) { + if (failSet.contains(iterator.next())) { + iterator.remove(); + } + } + } + } + } else { + if (failSet.size() > 0) { + throw new RedisLockFailException("方法[" + joinPoint.getSignature().getName() + "]所对应的参数[" + + JsonUtils.toJsonString(key2ParamMap.values()) + "]正在运行中,请不要重复操作!"); + } + } + return joinPoint.proceed(); + } finally { + for (RLock lock : map.values()) { + try { + LockUtils.unlock(lock); + } catch (Exception e) { + log.error("redisson batchlock 锁【{}】解锁失败", lock.getName(), e); + } + } + log.info("redisson batchlock {}方法 加锁结束:{}", joinPoint.getSignature().getName(), + joinPoint.toString()); + } + } + +} diff --git a/backend/src/main/java/com/senmesh/frame/redis/aop/aspect/UnLockAutomaticallyAop.java b/backend/src/main/java/com/senmesh/frame/redis/aop/aspect/UnLockAutomaticallyAop.java new file mode 100644 index 0000000..704b850 --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/aop/aspect/UnLockAutomaticallyAop.java @@ -0,0 +1,33 @@ +package com.senmesh.frame.redis.aop.aspect; + +import com.senmesh.frame.redis.redisson.RedissonUtils; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +/** + * 自动解锁 + */ +@Aspect +@Component +@Order(1) +@Slf4j +public class UnLockAutomaticallyAop { + + @Pointcut("@annotation(com.senmesh.frame.redis.aop.annotation.AutoUnLock)") + public void annotationPointCut() { + } + + @Around("annotationPointCut()") + public Object around(ProceedingJoinPoint joinPoint) throws Throwable { + try { + return joinPoint.proceed(); + } finally { + RedissonUtils.unLockAutomatically(); + } + } +} diff --git a/backend/src/main/java/com/senmesh/frame/redis/config/RedisCacheConfig.java b/backend/src/main/java/com/senmesh/frame/redis/config/RedisCacheConfig.java new file mode 100644 index 0000000..182675e --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/config/RedisCacheConfig.java @@ -0,0 +1,110 @@ +package com.senmesh.frame.redis.config; + +import java.util.LinkedHashSet; +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizer; +import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizers; +import org.springframework.boot.autoconfigure.cache.CacheProperties; +import org.springframework.boot.autoconfigure.cache.CacheProperties.Redis; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.core.io.ResourceLoader; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.cache.RedisCacheManager.RedisCacheManagerBuilder; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; +import org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair; + +/** + * 参考 org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration + * org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration + * + * @author sr on 2020-07-16 + */ +@Configuration +@AutoConfigureAfter({RedisAutoConfiguration.class}) +@ConditionalOnClass(RedisConnectionFactory.class) +//@ConditionalOnBean(RedisConnectionFactory.class) +@ConditionalOnMissingBean(RedisCacheManager.class) +@EnableConfigurationProperties({CacheProperties.class}) +public class RedisCacheConfig { + + private final CacheProperties cacheProperties; + + /** CacheAutoConfiguration中定义,自动注入 **/ + @Autowired + private CacheManagerCustomizers customizerInvoker; + + private final org.springframework.data.redis.cache.RedisCacheConfiguration redisCacheConfiguration; + + RedisCacheConfig(CacheProperties cacheProperties, + ObjectProvider redisCacheConfiguration) { + this.cacheProperties = cacheProperties; + this.redisCacheConfiguration = redisCacheConfiguration.getIfAvailable(); + } + + @Bean + @ConditionalOnMissingBean + public CacheManagerCustomizers cacheManagerCustomizers( + ObjectProvider> customizers) { + return new CacheManagerCustomizers(customizers.orderedStream().collect(Collectors.toList())); + } + + /** + * redis缓存,默认缓存 + * + * @param redisConnectionFactory + * @param resourceLoader + * @return + * @author sr on 2020-07-16 + */ + @Bean + @Primary + public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory, + ResourceLoader resourceLoader) { + RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory) + .cacheDefaults(determineConfiguration(resourceLoader.getClassLoader())); + List cacheNames = this.cacheProperties.getCacheNames(); + if (!cacheNames.isEmpty()) { + builder.initialCacheNames(new LinkedHashSet<>(cacheNames)); + } + return this.customizerInvoker.customize(builder.build()); + } + + private org.springframework.data.redis.cache.RedisCacheConfiguration determineConfiguration( + ClassLoader classLoader) { + if (this.redisCacheConfiguration != null) { + return this.redisCacheConfiguration; + } + Redis redisProperties = this.cacheProperties.getRedis(); + org.springframework.data.redis.cache.RedisCacheConfiguration config = + org.springframework.data.redis.cache.RedisCacheConfiguration + .defaultCacheConfig(); + config = config.serializeValuesWith( + SerializationPair.fromSerializer(new JdkSerializationRedisSerializer(classLoader))); + if (redisProperties.getTimeToLive() != null) { + config = config.entryTtl(redisProperties.getTimeToLive()); + } + if (redisProperties.getKeyPrefix() != null) { + config = config.prefixKeysWith(redisProperties.getKeyPrefix()); + } + if (!redisProperties.isCacheNullValues()) { + config = config.disableCachingNullValues(); + } + if (!redisProperties.isUseKeyPrefix()) { + config = config.disableKeyPrefix(); + } + return config; + } + +} diff --git a/backend/src/main/java/com/senmesh/frame/redis/config/RedisConfig.java b/backend/src/main/java/com/senmesh/frame/redis/config/RedisConfig.java new file mode 100644 index 0000000..ec34604 --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/config/RedisConfig.java @@ -0,0 +1,50 @@ +package com.senmesh.frame.redis.config; + +import org.redisson.api.RedissonClient; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.senmesh.frame.redis.redisson.RedissonUtils; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author Jerry.li + * @description Redis配置类 + * @date 2020/4/16 + */ +@Slf4j +@Configuration +public class RedisConfig { + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory factory) { + log.info("--------RedisConfig redisTemplate 初始化----->>"); + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(factory); + + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); + + Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = + new Jackson2JsonRedisSerializer(Object.class); + jackson2JsonRedisSerializer.setObjectMapper(objectMapper); + + redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); + redisTemplate.setKeySerializer(jackson2JsonRedisSerializer); + redisTemplate.setHashKeySerializer(new StringRedisSerializer()); + redisTemplate.afterPropertiesSet(); + return redisTemplate; + } + + +} diff --git a/backend/src/main/java/com/senmesh/frame/redis/dto/LockDTO.java b/backend/src/main/java/com/senmesh/frame/redis/dto/LockDTO.java new file mode 100644 index 0000000..8505359 --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/dto/LockDTO.java @@ -0,0 +1,136 @@ +package com.senmesh.frame.redis.dto; + +import com.senmesh.common.util.EnvironmentUtils; +import lombok.*; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.io.Serializable; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * @author chenyun + * @description 锁的key对象 + * @date 2020/9/11 13:44 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class LockDTO implements Serializable { + + private static final long serialVersionUID = 5125024940029525121L; + + private static final String SPLIT; + + private static final Long DEFAULT_TIME; + + static { + SPLIT = ":"; + DEFAULT_TIME = 60L; + } + + /** + * 系统编码 + */ + private Integer systemCode; + + + /** + * 锁执行的业务方法名 + */ + private String methodName; + + /** + * 锁对象其他参数 + */ + @Singular + private List args; + + /** + * 锁的key + */ + private String lockKey; + + /** + * 时间单位 + */ + private TimeUnit unit; + + /** + * 尝试获取锁的时间,超过这个时间表示获取锁失败 + */ + private Long tryLockWaitTime; + + /** + * 锁对象存活时间,超过这个时间,锁自动释放 + */ + private Long lockTimeout; + + private String failMsg; + + + public TimeUnit getUnit() { + if (this.unit == null) { + this.unit = TimeUnit.SECONDS; + } + return this.unit; + } + + public Long getTryLockWaitTime() { + if (this.tryLockWaitTime == null) { + this.tryLockWaitTime = DEFAULT_TIME; + } + return this.tryLockWaitTime; + } + + public Long getLockTimeout() { + if (this.lockTimeout == null) { + this.lockTimeout = DEFAULT_TIME; + } + return this.lockTimeout; + } + + public String getLockKey() { + return StringUtils.isEmpty(lockKey) ? lockKey = invoke() : lockKey; + } + + public Integer getSystem() { + if (systemCode == null) { + this.systemCode = EnvironmentUtils.getSystemCode(); + } + return this.systemCode; + } + + /** + * 组装lockKey + * + * @return + */ + private String invoke() { + StringBuilder sb = new StringBuilder(); + if (getSystem() != null) { + sb.append(getSystem()).append(SPLIT); + } + if (StringUtils.isNotEmpty(getMethodName())) { + sb.append(getMethodName()).append(SPLIT); + } + List args = getArgs(); + if (CollectionUtils.isNotEmpty(args)) { + int size = args.size(); + for (int i = 0; i < size; i++) { + String arg = args.get(i); + if (StringUtils.isEmpty(arg)) { + continue; + } + sb.append(arg); + + if (i < size - 1) { + sb.append(SPLIT); + } + } + } + return sb.toString(); + } +} diff --git a/backend/src/main/java/com/senmesh/frame/redis/exception/RedisLockErrorParamException.java b/backend/src/main/java/com/senmesh/frame/redis/exception/RedisLockErrorParamException.java new file mode 100644 index 0000000..f17f0f6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/exception/RedisLockErrorParamException.java @@ -0,0 +1,24 @@ +package com.senmesh.frame.redis.exception; + +/** + * redis锁错误参数异常 + * @author dylanyuan + */ +public class RedisLockErrorParamException extends RedisLockException { + + private static final long serialVersionUID = -2632401028683380018L; + + public RedisLockErrorParamException() {} + + public RedisLockErrorParamException(String message) { + super(message); + } + + public RedisLockErrorParamException(String message, Throwable cause) { + super(message, cause); + } + + public RedisLockErrorParamException(Throwable cause) { + super(cause); + } +} diff --git a/backend/src/main/java/com/senmesh/frame/redis/exception/RedisLockException.java b/backend/src/main/java/com/senmesh/frame/redis/exception/RedisLockException.java new file mode 100644 index 0000000..6fd6230 --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/exception/RedisLockException.java @@ -0,0 +1,27 @@ +package com.senmesh.frame.redis.exception; + + +import com.senmesh.common.exception.AlitaException; + +/** + * redis锁专用异常父类 + * @author dylanyuan + */ +public class RedisLockException extends AlitaException { + + private static final long serialVersionUID = -6487400012014351701L; + + public RedisLockException() {} + + public RedisLockException(String message) { + super(message); + } + + public RedisLockException(String message, Throwable cause) { + super(message, cause); + } + + public RedisLockException(Throwable cause) { + super(cause); + } +} diff --git a/backend/src/main/java/com/senmesh/frame/redis/exception/RedisLockFailException.java b/backend/src/main/java/com/senmesh/frame/redis/exception/RedisLockFailException.java new file mode 100644 index 0000000..67fe068 --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/exception/RedisLockFailException.java @@ -0,0 +1,24 @@ +package com.senmesh.frame.redis.exception; + +/** + * 加锁失败异常 + * @author dylanyuan + */ +public class RedisLockFailException extends RedisLockException { + + private static final long serialVersionUID = 8204346409836254547L; + + public RedisLockFailException() {} + + public RedisLockFailException(String message) { + super(message); + } + + public RedisLockFailException(String message, Throwable cause) { + super(message, cause); + } + + public RedisLockFailException(Throwable cause) { + super(cause); + } +} diff --git a/backend/src/main/java/com/senmesh/frame/redis/property/RedissonProperties.java b/backend/src/main/java/com/senmesh/frame/redis/property/RedissonProperties.java new file mode 100644 index 0000000..3ebaaf3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/property/RedissonProperties.java @@ -0,0 +1,18 @@ +package com.senmesh.frame.redis.property; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * @Author dylanyuan + * @Date 2020/12/10 11:37 上午 + * @Version 1.0 + */ +@ConfigurationProperties( + prefix = "alita.redisson" +) +@Data +public class RedissonProperties { + + private int pingConnectionInterval = 0; +} diff --git a/backend/src/main/java/com/senmesh/frame/redis/redisson/RedissonConfig.java b/backend/src/main/java/com/senmesh/frame/redis/redisson/RedissonConfig.java new file mode 100644 index 0000000..8670dd2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/redisson/RedissonConfig.java @@ -0,0 +1,158 @@ +package com.senmesh.frame.redis.redisson; + +import com.senmesh.frame.redis.property.RedissonProperties; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.redisson.Redisson; +import org.redisson.api.RedissonClient; +import org.redisson.config.Config; +import org.redisson.spring.data.connection.RedissonConnectionFactory; +//import org.redisson.spring.data.connection.RedissonConnectionFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties.Sentinel; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisOperations; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.util.ReflectionUtils; + +/** + * 参考redisson-spring-boot-starter的RedissonAutoConfiguration,沿用redis配置,移除自定义配置文件解析配置 + * + * @author sr on 2020-05-26 + */ +@Configuration +@ConditionalOnClass({Redisson.class, RedisOperations.class}) +@AutoConfigureAfter({RedisAutoConfiguration.class}) +@EnableConfigurationProperties({RedisProperties.class, RedissonProperties.class}) +@Import({RedisAutoConfiguration.class}) +public class RedissonConfig { + + @Autowired + private RedisProperties redisProperties; + + @Autowired + private RedissonProperties redissonProperties; + + @Bean + @ConditionalOnMissingBean(name = "redisTemplate") + public RedisTemplate redisTemplate( + RedisConnectionFactory redisConnectionFactory) { + RedisTemplate template = new RedisTemplate(); + template.setConnectionFactory(redisConnectionFactory); + return template; + } + + @Bean + @ConditionalOnMissingBean(StringRedisTemplate.class) + public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) { + StringRedisTemplate template = new StringRedisTemplate(); + template.setConnectionFactory(redisConnectionFactory); + return template; + } + + @Bean + @ConditionalOnMissingBean(RedisConnectionFactory.class) + public RedissonConnectionFactory redissonConnectionFactory(RedissonClient redisson) { + return new RedissonConnectionFactory(redisson); + } + + @SuppressWarnings("unchecked") + @Bean(destroyMethod = "shutdown") + @ConditionalOnMissingBean(RedissonClient.class) + public RedissonClient redisson() { + Config config = null; + Method clusterMethod = ReflectionUtils.findMethod(RedisProperties.class, "getCluster"); + Method timeoutMethod = ReflectionUtils.findMethod(RedisProperties.class, "getTimeout"); + Object timeoutValue = ReflectionUtils.invokeMethod(timeoutMethod, redisProperties); + int timeout; + if (null == timeoutValue) { + timeout = 0; + } else if (!(timeoutValue instanceof Integer)) { + Method millisMethod = ReflectionUtils.findMethod(timeoutValue.getClass(), "toMillis"); + timeout = ((Long) ReflectionUtils.invokeMethod(millisMethod, timeoutValue)).intValue(); + } else { + timeout = (Integer) timeoutValue; + } + + // 修复不设置密码,传入空字符串,置为空 + String password = redisProperties.getPassword(); + password = StringUtils.isBlank(password) ? null : password; + if (redisProperties.getSentinel() != null) { + Method nodesMethod = ReflectionUtils.findMethod(Sentinel.class, "getNodes"); + Object nodesValue = ReflectionUtils.invokeMethod(nodesMethod, redisProperties.getSentinel()); + + String[] nodes; + if (nodesValue instanceof String) { + nodes = convert(Arrays.asList(((String) nodesValue).split(","))); + } else { + nodes = convert((List) nodesValue); + } + + config = new Config(); + config.useSentinelServers() + .setPingConnectionInterval(redissonProperties.getPingConnectionInterval()) + .setMasterName(redisProperties.getSentinel().getMaster()) + .addSentinelAddress(nodes).setDatabase(redisProperties.getDatabase()) + .setConnectTimeout(timeout).setPassword(password); + } else if (clusterMethod != null + && ReflectionUtils.invokeMethod(clusterMethod, redisProperties) != null) { + Object clusterObject = ReflectionUtils.invokeMethod(clusterMethod, redisProperties); + Method nodesMethod = ReflectionUtils.findMethod(clusterObject.getClass(), "getNodes"); + List nodesObject = (List) ReflectionUtils.invokeMethod(nodesMethod, clusterObject); + + String[] nodes = convert(nodesObject); + + config = new Config(); + config.useClusterServers() + .setPingConnectionInterval(redissonProperties.getPingConnectionInterval()) + .addNodeAddress(nodes).setConnectTimeout(timeout) + .setPassword(password); + } else { + config = new Config(); + String prefix = "redis://"; + Method method = ReflectionUtils.findMethod(RedisProperties.class, "isSsl"); + if (method != null && (Boolean) ReflectionUtils.invokeMethod(method, redisProperties)) { + prefix = "rediss://"; + } + + config.useSingleServer() + .setPingConnectionInterval(redissonProperties.getPingConnectionInterval()) + .setAddress(prefix + redisProperties.getHost() + ":" + redisProperties.getPort()) + .setConnectTimeout(timeout).setDatabase(redisProperties.getDatabase()) + .setPassword(password); + } + return Redisson.create(config); + } + + private String[] convert(List nodesObject) { + List nodes = new ArrayList(nodesObject.size()); + for (String node : nodesObject) { + if (!node.startsWith("redis://") && !node.startsWith("rediss://")) { + nodes.add("redis://" + node); + } else { + nodes.add(node); + } + } + return nodes.toArray(new String[nodes.size()]); + } + + @Bean + public RedissonUtils redissonUtils() { + return new RedissonUtils(redisson()); + } + +} diff --git a/backend/src/main/java/com/senmesh/frame/redis/redisson/RedissonUtils.java b/backend/src/main/java/com/senmesh/frame/redis/redisson/RedissonUtils.java new file mode 100644 index 0000000..1541d7f --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/redisson/RedissonUtils.java @@ -0,0 +1,380 @@ +package com.senmesh.frame.redis.redisson; + +import com.google.common.collect.Lists; +import com.senmesh.common.dto.IBaseDTO; +import com.senmesh.common.exception.ExistException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.function.TransactionAfterCommit; +import com.senmesh.frame.redis.dto.LockDTO; +import lombok.extern.slf4j.Slf4j; + +import org.apache.commons.lang3.StringUtils; +import org.redisson.RedissonMultiLock; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; + +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.Stack; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +/** + * 使用@Autowired注入工具类 + * + * @author sr on 2020-05-26 + */ +@Slf4j +public class RedissonUtils { + + private static RedissonClient client; + + /** + * 锁对象缓存实现 ,同一个线程可能持有多把锁 + */ + private static final ThreadLocal> LOCK_DTO_THREAD_LOCAL = new ThreadLocal<>(); + + public RedissonUtils(RedissonClient redissonClient) { + RedissonUtils.client = redissonClient; + } + + public static RedissonClient getClient() { + return client; + } + + /** + * 获取锁对象 + * @param lockKey + * @return + */ + public static RLock getLock(String lockKey) { + return client.getLock(lockKey); + } + + /** + * 获取连所对象 + * @param lockKeys + * @return + */ + public static RLock getMultiLock(String... lockKeys) { + RLock[] locks = new RLock[lockKeys.length]; + for (int i = 0; i < lockKeys.length; i++) { + locks[i] = client.getLock(lockKeys[i]); + } + return client.getMultiLock(locks); + } + + /** + * 获取连所对象 + * @param lockKeys + * @return + */ + public static RLock getMultiLock(List lockKeys) { + RLock[] locks = new RLock[lockKeys.size()]; + for (int i = 0; i < lockKeys.size(); i++) { + locks[i] = client.getLock(lockKeys.get(i)); + } + return client.getMultiLock(locks); + } + + + /** + * 获取锁(自旋等待锁) + * + * @param lockDTO + * @return + * @author sr on 2020-05-26 + */ + public static RLock lock(LockDTO lockDTO) { + RLock lock = client.getLock(lockDTO.getLockKey()); + lock.lock(); + return lock; + } + + /** + * 获取锁(自旋等待锁) + * + * @param lockKey + * @return + * @author sr on 2020-05-26 + */ + public static RLock lock(String lockKey) { + RLock lock = client.getLock(lockKey); + lock.lock(); + return lock; + } + + /** + * 获取超时锁(自旋等待锁) + * + * @param lockKey + * @param timeout 加锁后自动释放时间(秒) + * @return + * @author sr on 2020-05-26 + */ + public static RLock lock(String lockKey, long timeout) { + return lock(lockKey, TimeUnit.SECONDS, timeout); + } + + /** + * 超时锁 + * + * @param lockKey + * @param unit 时间单位 + * @param timeout 加锁后自动释放时间 + * @return + * @author sr on 2020-05-26 + */ + public static RLock lock(String lockKey, TimeUnit unit, long timeout) { + log.info("lockKey:{}" + lockKey); + RLock lock = client.getLock(lockKey); + lock.lock(timeout, unit); + return lock; + } + + /** + * 尝试获取锁(时间-秒) + * + * @param lockDTO + * @return + */ + public static boolean tryLock(LockDTO lockDTO) { + return tryLock(lockDTO.getLockKey(), lockDTO.getUnit(), lockDTO.getTryLockWaitTime(), lockDTO.getLockTimeout()); + } + + /** + * 将锁对象缓存入ThreadLocal中 + * 尝试获取锁(时间-秒) + * + * @param lockDTO 锁对象 + * @return true: 加锁成功 false: 加锁失败 + */ + public static boolean tryLockAutomatically(LockDTO lockDTO) { + Stack stack = LOCK_DTO_THREAD_LOCAL.get(); + if (Objects.isNull(stack)) { + LOCK_DTO_THREAD_LOCAL.set(stack = new Stack<>()); + } + stack.push(lockDTO); + return tryLock(lockDTO); + } + + /** + * 自动解锁 + * + * @return true: 解锁成功 false: 解锁失败 + */ + public static boolean unLockAutomatically() { + Stack stack = LOCK_DTO_THREAD_LOCAL.get(); + if (Objects.nonNull(stack) && !stack.isEmpty()) { + return unlock(stack.pop()); + } + return false; + } + + /** + * 尝试获取锁(时间-秒) + * + * @param lockKey + * @param waitTime 最多等待时间,未拿到锁返回false + * @param timeout 上锁后自动释放锁时间 + * @return + * @author sr on 2020-08-28 + */ + public static boolean tryLock(String lockKey, long waitTime, long timeout) { + return tryLock(lockKey, TimeUnit.SECONDS, waitTime, timeout); + } + + /** + * 尝试获取锁 + * + * @param lockKey + * @param unit 时间单位 + * @param waitTime 最多等待时间,未拿到锁返回false + * @param timeout 上锁后自动释放锁时间 + * @return + * @author sr on 2020-05-26 + */ + public static boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long timeout) { + RLock lock = client.getLock(lockKey); + try { + return lock.tryLock(waitTime, timeout, unit); + } catch (InterruptedException e) { + return false; + } + } + + /** + * 释放锁 + * + * @param lockKey + * @author sr on 2020-05-26 + */ + public static boolean unlock(String lockKey) { + try { + RLock lock = client.getLock(lockKey); + return unlock(lock); + } catch (Exception e) { + log.error("unlock key:{}, error:{}", lockKey, e.getMessage()); + return false; + } + } + + /** + * 释放锁 + * + * @param lockDTO + * @return + */ + public static boolean unlock(LockDTO lockDTO) { + RLock lock = client.getLock(lockDTO.getLockKey()); + if (lock.isLocked() && lock.isHeldByCurrentThread()) { + return unlock(lockDTO.getLockKey()); + } + return true; + } + + /** + * 释放锁 + * + * @param lock + * @author sr on 2020-05-26 + */ + public static boolean unlock(RLock lock) { + try { + if (!lock.isLocked()) { + return true; + } + lock.unlock(); + } catch (Exception e) { + log.error("unlock key:{}, error msg:{}", lock.getName(), e.getMessage()); + return false; + } + return true; + } + + /** + * 联锁 + * + * @param lockKeys + * @return + * @author sr on 2020-05-28 + */ + public static RLock multiLock(Set lockKeys) { + RLock[] locks = (RLock[]) lockKeys.stream().map(lockKey -> client.getLock(lockKey)).toArray(); + RedissonMultiLock multiLock = new RedissonMultiLock(locks); + multiLock.lock(); + return multiLock; + } + + /** + * 尝试获取联锁 + * + * @param lockKeys + * @param unit 时间单位 + * @param waitTime 最多等待时间,未拿到锁返回false + * @param timeout 上锁后自动释放锁时间 + * @return + * @author sr on 2020-05-28 + */ + public static boolean tryMultiLock(Set lockKeys, TimeUnit unit, long waitTime, long timeout) { + RLock[] locks = new RLock[lockKeys.size()]; + locks = lockKeys.stream().map(lockKey -> client.getLock(lockKey)).collect(Collectors.toList()).toArray(locks); + RedissonMultiLock multiLock = new RedissonMultiLock(locks); + try { + return multiLock.tryLock(waitTime, timeout, unit); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return false; + } + + /** + * 尝试获取联锁 + * + * @param lockKeys 锁的钥匙 + * @param unit 单位 + * @param waitTime 等待时间 + * @param timeout 超时 + * @return {@link RLock} + */ + public static RLock tryMultiLockAndReturn(Set lockKeys, TimeUnit unit, long waitTime, long timeout) { + RLock multiLock = getMultiLock(Lists.newArrayList(lockKeys)); + try { + if (multiLock.tryLock(waitTime, timeout, unit)){ + return multiLock; + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + return null; + } + + + /** + * 校验上锁保存(有事务幂等) + * @param + * @param lockDTO + * @param existSupplier + * @param saveSupplier + * @return + * @author sr on 2024-04-18 + */ + public static T lockAndSave(LockDTO lockDTO, Supplier existSupplier, + Supplier saveSupplier) { + return lockAndSave(lockDTO, existSupplier, saveSupplier, true, null); + } + + + public static T lockAndSave(LockDTO lockDTO, Supplier existSupplier, + Supplier saveSupplier, String existMsg) { + return lockAndSave(lockDTO, existSupplier, saveSupplier, true, existMsg); + } + + /** + * 校验上锁保存 + * @param + * @param lockDTO 锁 + * @param existSupplier 查询存在的dto + * @param saveSupplier 保存 + * @param hasTransaction 当前是否有事务 + * @param existMsg 存在抛的异常消息,空则不抛异常返回id + * @return + * @author sr on 2024-04-18 + */ + public static T lockAndSave(LockDTO lockDTO, Supplier existSupplier, + Supplier saveSupplier, boolean hasTransaction, String existMsg) throws ExistException { + IBaseDTO baseDTO = existSupplier.get(); + if (baseDTO != null) { + if (StringUtils.isBlank(existMsg)) { + return (T) baseDTO; + } else { + throw new ExistException(existMsg); + } + } + try { + Assert.isTrue(RedissonUtils.tryLock(lockDTO), lockDTO.getFailMsg()); + baseDTO = existSupplier.get(); + if (baseDTO != null) { + if (StringUtils.isBlank(existMsg)) { + return (T) baseDTO; + } else { + throw new ExistException(existMsg); + } + } + return saveSupplier.get(); + } finally { + if (hasTransaction) { + TransactionAfterCommit.doSomeThingAfterCompletion(()->{ + RedissonUtils.unlock(lockDTO); + }); + } else { + RedissonUtils.unlock(lockDTO); + } + } + } + +} + + diff --git a/backend/src/main/java/com/senmesh/frame/redis/util/IAopUtils.java b/backend/src/main/java/com/senmesh/frame/redis/util/IAopUtils.java new file mode 100644 index 0000000..cd1c477 --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/util/IAopUtils.java @@ -0,0 +1,148 @@ +package com.senmesh.frame.redis.util; + +import com.senmesh.frame.redis.aop.annotation.RedissonLock; +import com.senmesh.frame.redis.exception.RedisLockErrorParamException; +import com.senmesh.frame.redis.exception.RedisLockFailException; +import com.senmesh.frame.redis.redisson.RedissonUtils; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.concurrent.TimeUnit; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.reflect.MethodSignature; +import org.redisson.api.RLock; + +/** + * @author Created by dylan_yuan + */ +@Slf4j +public class IAopUtils { + + public static Method getMethod(JoinPoint joinPoint) throws Exception { + String methodName = joinPoint.getSignature().getName(); + // 获取目标对象 + Class classTarget = joinPoint.getTarget().getClass(); + // 获取目标对象类型 + Class[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getParameterTypes(); + // 获取目标对象方法 + return classTarget.getMethod(methodName, parameterTypes); + } + + public static Type getType(Method method, String paramName) { + Type[] types = method.getGenericParameterTypes(); + if(types == null || types.length == 0){ + return null; + } + for (Type type : types) { + if (paramName.equals(type.getTypeName())) { + return type; + } + } + return null; + } + + public static Object getParamValue(ProceedingJoinPoint joinPoint, String paramName) { + if (joinPoint == null || StringUtils.isBlank(paramName)) { + return null; + } + Object[] args = joinPoint.getArgs(); + Signature signature = joinPoint.getSignature(); + MethodSignature methodSignature = (MethodSignature) signature; + String[] names = methodSignature.getParameterNames(); + if (names == null || names.length == 0) { + return null; + } + for (int i = 0; i < names.length; i++) { + if (names[i].equals(paramName)) { + return args[i]; + } + } + return null; + } + + public static Object getParamValue(ProceedingJoinPoint joinPoint, int index) { + if (joinPoint == null || index < 0) { + return null; + } + Object[] args = joinPoint.getArgs(); + Signature signature = joinPoint.getSignature(); + MethodSignature methodSignature = (MethodSignature) signature; + String[] names = methodSignature.getParameterNames(); + if (names == null || names.length == 0 || names.length < index) { + return null; + } + return args[index]; + } + + + public static void checkParamType(Method method, String paramName, Object paramValue, boolean isArray){ + String prefix = "redis" + (isArray?"batch":"") + "lock"; + String suffix = "字符串" + (isArray?"数组或集合":""); + boolean classTypeMatching; + if(isArray){ + Type type = getType(method, paramName); + classTypeMatching = paramValue instanceof String[] || (paramValue instanceof Iterable && checkGenericTypeIsString(type)); + }else{ + classTypeMatching = paramValue instanceof String; + } + if(!classTypeMatching) { + throw new RedisLockErrorParamException(prefix + + " paramName[" + paramName + "]所对应的参数类型必须为" + suffix); + } + } + + private static boolean checkGenericTypeIsString(Type type){ + if(type == null){ + return false; + } + try { + ParameterizedType pt = (ParameterizedType)type; + Type[] tempTypes = pt.getActualTypeArguments(); + if(tempTypes == null || tempTypes.length != 1){ + return false; + } + Type temp = tempTypes[0]; + if("java.lang.String".equals(temp.getTypeName())) { + return true; + } + }catch (Exception e){ + log.error("获取方法入参数类型失败,{}", type.getTypeName()); + } + return false; + } + + public static RLock lock(ProceedingJoinPoint joinPoint, RedissonLock redissonLock) + throws Exception { + String paramName = redissonLock.paramName(); + if (StringUtils.isBlank(paramName)) { + throw new RedisLockErrorParamException("redisson lock paramName不能为空"); + } + Object paramValue = IAopUtils.getParamValue(joinPoint, paramName); + if (paramValue == null) { + boolean skipIfNull = redissonLock.skipIfNull(); + if(skipIfNull){ + return null; + } + throw new RedisLockErrorParamException("redisson lock paramName[" + paramName + "]所对应的参数内容不能为空"); + } + IAopUtils.checkParamType(IAopUtils.getMethod(joinPoint), paramName, paramValue, false); + long expires = redissonLock.expires(); + TimeUnit timeUnit = redissonLock.timeUnit(); + if(expires == -1){ + expires = 1; + timeUnit = TimeUnit.DAYS; + } + long tryLockWaitTime = redissonLock.tryLockWaitTime(); + String key = redissonLock.prefix() + paramValue; + RLock lock = RedissonUtils.getLock(key); + LockUtils.lock(expires, timeUnit, tryLockWaitTime, lock); + if(!lock.isLocked()) { + throw new RedisLockFailException("方法["+joinPoint.getSignature().getName()+"]所对应的参数["+key+"]正在运行中,请不要重复操作!"); + } + return lock; + } +} diff --git a/backend/src/main/java/com/senmesh/frame/redis/util/LockUtils.java b/backend/src/main/java/com/senmesh/frame/redis/util/LockUtils.java new file mode 100644 index 0000000..75bd290 --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/util/LockUtils.java @@ -0,0 +1,84 @@ +package com.senmesh.frame.redis.util; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.frame.redis.redisson.RedissonUtils; +import java.util.concurrent.TimeUnit; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.redisson.RedissonMultiLock; +import org.redisson.api.RLock; + +/** + * @author dylanyuan + */ +@Slf4j +public class LockUtils { + + + public static void unlock(RLock lock) { + if (lock == null){ + return; + } + if(lock instanceof RedissonMultiLock){ + lock.unlock(); + return; + } + if(lock.isLocked() && lock.isHeldByCurrentThread()){ + lock.unlock(); + return; + } + } + + public static void lock(long expires, TimeUnit timeUnit, RLock lock) { + lock(expires, timeUnit, -1, lock); + } + + public static void lock(long expires, TimeUnit timeUnit, long tryLockWaitTime, RLock lock) { + Assert.isTrue(lock != null, "锁不能为空"); + if(tryLockWaitTime == -1){ + lock.lock(expires, timeUnit); + }else { + try { + lock.tryLock(tryLockWaitTime, expires, timeUnit); + } catch (InterruptedException e) { + //如果出现异常的话,当前线程立刻解锁 + unlock(lock); + log.error("[{}] try lock 失败", lock.getName(), e); + } + } + } + + public static boolean trylock(long expires, TimeUnit timeUnit, long tryLockWaitTime, RLock lock) { + Assert.isTrue(lock != null, "锁不能为空"); + Assert.isTrue(tryLockWaitTime >=0, "等待时间必须大于-1"); + try { + return lock.tryLock(tryLockWaitTime, expires, timeUnit); + } catch (InterruptedException e) { + //如果出现异常的话,当前线程立刻解锁 + unlock(lock); + log.error("[{}] try lock 失败", lock.getName(), e); + } + return false; + } + + public static RLock simpleLock(long expires, TimeUnit timeUnit, String key) { + return simpleLock(expires, timeUnit, -1, key); + } + + public static RLock simpleLock(long expires, TimeUnit timeUnit, long tryLockWaitTime, String key) { + Assert.isTrue(StringUtils.isNotBlank(key), "锁值不能为空"); + RLock lock = RedissonUtils.getLock(key); + if(tryLockWaitTime == -1){ + lock.lock(expires, timeUnit); + }else { + try { + lock.tryLock(tryLockWaitTime, expires, timeUnit); + } catch (InterruptedException e) { + //如果出现异常的话,当前线程立刻解锁 + unlock(lock); + log.error("[{}] try lock 失败", lock.getName(), e); + } + } + return lock; + } +} diff --git a/backend/src/main/java/com/senmesh/frame/redis/util/RedisUtils.java b/backend/src/main/java/com/senmesh/frame/redis/util/RedisUtils.java new file mode 100644 index 0000000..75fed33 --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/util/RedisUtils.java @@ -0,0 +1,323 @@ +package com.senmesh.frame.redis.util; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import javax.annotation.PostConstruct; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import com.google.common.base.Objects; + +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; + +/** + * + * @author Jerry.li + * @description Redis工具类 + * @date 2020/4/16 + * + * 使用案例 + * @Autowired private RedisUtils redisUtils; redisUtils.getExpire(key); + */ +@Slf4j +@Component +public class RedisUtils{ + + + @Autowired + private RedisTemplate redisTemplateClient; + + private static RedisTemplate redisTemplate; + + @PostConstruct + private void init() { + redisTemplate = redisTemplateClient; + } + + + /** + * 指定缓存失效时间 + * + * @param key 键 + * @param expireTime 过期时间(秒) + * @return + */ + public static void expire(@NonNull String key, long expireTime) { + if (expireTime > 0 && hasKey(key)) { + redisTemplate.expire(key, expireTime, TimeUnit.SECONDS); + } + } + + /** + * 根据key 获取过期时间 + * + * @param key 键 不能为null + * @return 时间(秒) 返回0代表为永久有效 + */ + public static Long getExpire(@NonNull String key) { + if (!hasKey(key)) { + return null; + } + return redisTemplate.getExpire(key, TimeUnit.SECONDS); + } + + /** + * 判断key是否存在 + * + * @param key 键 + * @return true 存在 false不存在 + */ + public static boolean hasKey(@NonNull String key) { + Boolean hasKey = redisTemplate.hasKey(key); + if (Objects.equal(hasKey, null)) { + return false; + } + return hasKey; + } + + /** + * 删除缓存 + * + * @param key 可以传一个值 或多个 + */ + public static void remove(@NonNull String key) { + try { + if (hasKey(key)) { + redisTemplate.delete(key); + } + } catch (Exception e) { + log.info("redis remove key:{}, error:{}", key, e.getMessage()); + } + + } + + /** + * 普通缓存获取 + * + * @param key 键 + * @return 值 + */ + public static Object get(String key) { + return key == null ? null : redisTemplate.opsForValue().get(key); + } + + /** + * 永久普通缓存放入 + * + * @param key 键 + * @param value 值 + * @return true成功 false失败 + */ + public static void add(@NonNull String key, Object value) { + redisTemplate.opsForValue().set(key, value); + } + + /** + * 普通缓存放入并设置时间 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期 + * @return true成功 false 失败 + */ + public static void add(@NonNull String key, Object value, long time) { + if (time > 0) { + redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); + } else { + add(key, value); + } + } + + /** + * 删除缓存 + * + * @param key 可以传一个值 或多个 + */ + public static void removeList(@NonNull String key, Object value) { + try { + if (hasKey(key)) { + redisTemplate.opsForList().remove(key,0,value); + } + } catch (Exception e) { + log.info("redis remove key:{} value:{}, error:{}", key, value, e.getMessage()); + } + + } + + /** + * 将list放入缓存(向后追加方式) + * @param key + * @param value + */ + public static void listAddAll(@NonNull String key, Object... value) { + redisTemplate.opsForList().rightPushAll(key,value); + } + + /** + * 将list放入缓存(向后追加方式) + * + * @param key 键 + * @param value 值 + */ + public static void listAdd(@NonNull String key, Object value) { + redisTemplate.opsForList().rightPush(key, value); + } + + /** + * 将list放入缓存(向后追加方式) + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + */ + public static void listAdd(@NonNull String key, Object value, long time) { + listAdd(key, value); + if (time > 0) { + expire(key, time); + } + } + + /** + * 获取list缓存的内容 + * + * @param key 键 + * @return List + */ + public static List listGet(@NonNull String key) { + return redisTemplate.opsForList().range(key, 0, -1); + } + + /** + * 获取list缓存的内容 + * + * @param key 键 + * @param start 开始 + * @param end 结束 0 到 -1代表所有值 + * @return List + */ + public static List listGet(@NonNull String key, long start, long end) { + return redisTemplate.opsForList().range(key, start, end); + } + + /** + * 获取list缓存的长度 + * + * @param key 键 + * @return + */ + public static Long getListSize(@NonNull String key) { + return redisTemplate.opsForList().size(key); + } + + /** + * HashMap + * + * @param key 键 + * @param map 对应多个键值 + */ + public static void mapAdd(@NonNull String key, Map map) { + redisTemplate.opsForHash().putAll(key, map); + } + + /** + * HashMap 并设置时间 + * + * @param key 键 + * @param map 对应多个键值 + * @param time 时间(秒) + */ + public static void mapAdd(@NonNull String key, Map map, long time) { + redisTemplate.opsForHash().putAll(key, map); + if (time > 0) { + expire(key, time); + } + } + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * + * @param key redis键 + * @param hashKey 项 + * @param value 值 + */ + public static void mapAdd(@NonNull String key, @NonNull String hashKey, Object value) { + redisTemplate.opsForHash().put(key, hashKey, value); + } + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * + * @param key 键 + * @param hashKey 项 + * @param value 值 + * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间 + */ + public static void mapAdd(String key, String hashKey, Object value, long time) { + redisTemplate.opsForHash().put(key, hashKey, value); + if (time > 0) { + expire(key, time); + } + } + + /** + * 判断hash表中是否有该项的值 + * + * @param key 键 不能为null + * @param hashKey map key 不能为null + */ + public static boolean mapHasValue(@NonNull String key, @NonNull String hashKey) { + return redisTemplate.opsForHash().hasKey(key, hashKey); + } + + /** + * HashGet + * + * @param key 键 不能为null + * @param hashKey 项 不能为null + * @return 值 + */ + public static Object mapGet(@NonNull String key, @NonNull String hashKey) { + return redisTemplate.opsForHash().get(key, hashKey); + } + + /** + * 获取hashKey对应的所有键值 + * + * @param key 键 + * @return 对应的多个键值 + */ + public static Map mapGet(@NonNull String key) { + return redisTemplate.opsForHash().entries(key); + } + + /** + * 自增并设置过期时间 + * @param key + * @param expireTime + * @return + * @author sr on 2020-08-03 + */ + public static long increment(@NonNull String key, long expireTime) { + long data = redisTemplate.opsForValue().increment(key); + if (data == 1L) { + redisTemplate.expire(key, expireTime, TimeUnit.SECONDS); + } + return data; + } + + /** + * 自减 + * @param key + * @return + * @author sr on 2021-06-16 + */ + public static long decrement(@NonNull String key) { + return redisTemplate.opsForValue().decrement(key); + } + +} diff --git a/backend/src/main/java/com/senmesh/frame/redis/util/RedissonHashUtils.java b/backend/src/main/java/com/senmesh/frame/redis/util/RedissonHashUtils.java new file mode 100644 index 0000000..b872774 --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/util/RedissonHashUtils.java @@ -0,0 +1,44 @@ +package com.senmesh.frame.redis.util; + +import com.senmesh.frame.redis.redisson.RedissonUtils; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import org.apache.commons.lang3.ObjectUtils; +import org.redisson.api.RMap; + +/** + * @Author dylanyuan + * @Date 2020/11/27 下午6:29 + * @Version 1.0 + */ +public class RedissonHashUtils { + + public static void clear(String hashKey){ + RedissonUtils.getClient().getMap(hashKey).clear(); + } + + public static void set(String hashKey, String key, Object value){ + RMap rMap = RedissonUtils.getClient().getMap(hashKey); + rMap.put(key, value); + } + + public static void set(String hashKey, String key, Object value, Long expires, TimeUnit timeUnit){ + RMap rMap = RedissonUtils.getClient().getMap(hashKey); + rMap.expire(expires, timeUnit); + rMap.put(key, value); + } + + public static Map get(String hashKey){ + return RedissonUtils.getClient().getMap(hashKey); + } + + public static Object get(String hashKey, String key){ + RMap rMap = RedissonUtils.getClient().getMap(hashKey); + return rMap.get(key); + } + + public static String getString(String hashKey, String key){ + RMap rMap = RedissonUtils.getClient().getMap(hashKey); + return ObjectUtils.identityToString(rMap.get(key)); + } +} diff --git a/backend/src/main/java/com/senmesh/frame/redis/util/RedissonSetUtils.java b/backend/src/main/java/com/senmesh/frame/redis/util/RedissonSetUtils.java new file mode 100644 index 0000000..01eb1eb --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/util/RedissonSetUtils.java @@ -0,0 +1,33 @@ +package com.senmesh.frame.redis.util; + +import com.senmesh.frame.redis.redisson.RedissonUtils; +import java.util.concurrent.TimeUnit; +import org.redisson.api.RSet; + +/** + * @Author dylanyuan + * @Date 2020/11/27 下午6:29 + * @Version 1.0 + */ +public class RedissonSetUtils { + + public static void set(String setKey, Object value){ + RSet rSet = RedissonUtils.getClient().getSet(setKey); + rSet.add(value); + } + + public static void set(String setKey, Object value, Long expires, TimeUnit timeUnit){ + RSet rSet = RedissonUtils.getClient().getSet(setKey); + rSet.expire(expires, timeUnit); + rSet.add(value); + } + + public static void clear(String setKey){ + RedissonUtils.getClient().getSet(setKey).clear(); + } + + public static RSet get(String setKey){ + RSet rSet = RedissonUtils.getClient().getSet(setKey); + return rSet; + } +} diff --git a/backend/src/main/java/com/senmesh/frame/redis/util/RedissonValueUtils.java b/backend/src/main/java/com/senmesh/frame/redis/util/RedissonValueUtils.java new file mode 100644 index 0000000..097d94d --- /dev/null +++ b/backend/src/main/java/com/senmesh/frame/redis/util/RedissonValueUtils.java @@ -0,0 +1,39 @@ +package com.senmesh.frame.redis.util; + +import com.senmesh.frame.redis.redisson.RedissonUtils; +import java.util.concurrent.TimeUnit; +import org.apache.commons.lang3.ObjectUtils; +import org.redisson.api.RBucket; + +/**nng + * @Author dylanyuan + * @Date 2020/11/27 下午6:29 + * @Version 1.0 + */ +public class RedissonValueUtils { + + public static void set(String key, Object value){ + RBucket rBucket = RedissonUtils.getClient().getBucket(key); + rBucket.set(value); + } + + public static void set(String key, Object value, Long expires, TimeUnit timeUnit){ + RBucket rBucket = RedissonUtils.getClient().getBucket(key); + rBucket.set(value, expires, timeUnit); + } + + public static boolean hasKey(String key){ + RBucket rBucket = RedissonUtils.getClient().getBucket(key); + return rBucket.isExists(); + } + + public static Object get(String key){ + RBucket rBucket = RedissonUtils.getClient().getBucket(key); + return rBucket.get(); + } + + public static String getString(String key){ + RBucket rBucket = RedissonUtils.getClient().getBucket(key); + return ObjectUtils.identityToString(rBucket.get()); + } +} diff --git a/backend/src/main/java/com/senmesh/mq/config/ExchangeManager.java b/backend/src/main/java/com/senmesh/mq/config/ExchangeManager.java new file mode 100644 index 0000000..dd9812b --- /dev/null +++ b/backend/src/main/java/com/senmesh/mq/config/ExchangeManager.java @@ -0,0 +1,54 @@ +package com.senmesh.mq.config; + +import org.springframework.amqp.core.Exchange; +import org.springframework.amqp.core.TopicExchange; +import org.springframework.beans.factory.annotation.Autowired; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.mq.constant.ExchangeTypeEnum; +import com.senmesh.mq.exception.MqException; + +public class ExchangeManager { + + @Autowired + private TopicExchange topicExchange; + +// @Autowired +// private CustomExchange delayedCustomExchange; + + public TopicExchange getTopicExchange() { + return topicExchange; + } + +// public CustomExchange getDelayedCustomExchange() { +// return delayedCustomExchange; +// } + + /** + * 获取交换器名称 + * + * @return + * @author sr on 2020-07-27 + */ + public String getTopicExchangeName() { + return topicExchange.getName(); + } + + public Exchange getExchangeByType(String exchangeType) { + Assert.notNull(exchangeType, "交换机不能为空"); + ExchangeTypeEnum exchangeTypeEnum = ExchangeTypeEnum.valueOf(exchangeType); + switch (exchangeTypeEnum) { + case TOPIC: + return topicExchange; +// case DELAYED: +// return delayedCustomExchange; + default: + throw new MqException("未找到对应交换机"); + } + } + + public String getExchangeNameByType(String exchangeType) { + return getExchangeByType(exchangeType).getName(); + } + +} diff --git a/backend/src/main/java/com/senmesh/mq/config/QueueManager.java b/backend/src/main/java/com/senmesh/mq/config/QueueManager.java new file mode 100644 index 0000000..699e1ce --- /dev/null +++ b/backend/src/main/java/com/senmesh/mq/config/QueueManager.java @@ -0,0 +1,65 @@ +package com.senmesh.mq.config; + +import org.springframework.amqp.core.*; +import org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * 消息管理(queue/binding) + * + * @author sr on 2020-07-22 + */ +public class QueueManager { + + @Autowired + private AmqpAdmin amqpAdmin; + + @Autowired + private ExchangeManager exchangeManager; + + @Autowired + private AbstractMessageListenerContainer messageListenerContainer; + + /** + * 添加队列 + * + * @param queueName + * @return + * @author sr on 2020-07-27 + */ + public Queue addQueue(String queueName) { + Queue queue = new Queue(queueName); + if (amqpAdmin.getQueueProperties(queueName) == null) { + amqpAdmin.declareQueue(queue); + } + return queue; + } + + /** + * 绑定队列和路由键 + * + * @param queueName + * @param routingKey + * @author sr on 2020-07-27 + */ + public void addQueueAndRoutingKey(String queueName, String routingKey) { + Queue queue = this.addQueue(queueName); + Binding binding = BindingBuilder.bind(queue).to(exchangeManager.getTopicExchange()).with(routingKey); + amqpAdmin.declareBinding(binding); + messageListenerContainer.addQueues(queue); + } + + /** + * 绑定队列和路由键 + * + * @param queueName + * @param routingKey + * @author sr on 2020-07-27 + */ + public void addQueueAndRoutingKey(Exchange exchange, String queueName, String routingKey) { + Queue queue = this.addQueue(queueName); + amqpAdmin.declareBinding(BindingBuilder.bind(queue).to(exchange).with(routingKey).noargs()); + messageListenerContainer.addQueues(queue); + } + +} diff --git a/backend/src/main/java/com/senmesh/mq/config/RabbitCustomProperties.java b/backend/src/main/java/com/senmesh/mq/config/RabbitCustomProperties.java new file mode 100644 index 0000000..3f82bd2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/mq/config/RabbitCustomProperties.java @@ -0,0 +1,37 @@ +package com.senmesh.mq.config; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * 定制配置 + * + * @author sr on 2020-07-22 + */ +@ConfigurationProperties(prefix = "rabbitmq.custom") +@Data +@NoArgsConstructor +public class RabbitCustomProperties { + + /** + * 通配符交换器名称 + **/ + private String topicExchangeName; + + /** + * 延时队里名称 + */ + private String delayedExchangeName; + + /** + * 指定消费者ip + **/ + private String consumerAppId; + + /** + * 广播id-同系统内需要广播时配置 + **/ + private String broadcastId; + +} diff --git a/backend/src/main/java/com/senmesh/mq/config/RabbitMqConfiguration.java b/backend/src/main/java/com/senmesh/mq/config/RabbitMqConfiguration.java new file mode 100644 index 0000000..222a09a --- /dev/null +++ b/backend/src/main/java/com/senmesh/mq/config/RabbitMqConfiguration.java @@ -0,0 +1,194 @@ +package com.senmesh.mq.config; + +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.amqp.core.TopicExchange; +import org.springframework.amqp.rabbit.config.AbstractRabbitListenerContainerFactory; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer; +import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter; +import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.senmesh.common.CommonConfiguration; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.mq.consumer.ConsumerDeliverer; +import com.senmesh.mq.consumer.InitHandler; +import com.senmesh.mq.consumer.handler.IMqHandler; +import com.senmesh.mq.producer.sender.DefaultMqSender; +import com.senmesh.mq.producer.sender.IMqSender; +import com.senmesh.mq.util.MqSendUtils; + +/** + * @author sr on 2020-07-22 + */ +/*@Configuration +@EnableConfigurationProperties(RabbitCustomProperties.class) +@AutoConfigureAfter(CommonConfiguration.class)*/ +public class RabbitMqConfiguration { + + public static final String DEFAULT_EXCHANGE_NAME = "alita_exchange"; + + /** + * 默认延时队列交换机名称 + */ + public static final String DEFAULT_DELAYED_EXCHANGE_NAME = "alita_delayed_exchange"; + + @Autowired + private RabbitCustomProperties rabbitCustomProperties; + + private String getExchangeName() { + String exchangeName = rabbitCustomProperties.getTopicExchangeName(); + if (StringUtils.isBlank(exchangeName)) { + exchangeName = DEFAULT_EXCHANGE_NAME; + } + return String.join(CommonConstants.UNDERLINE, exchangeName, + EnvironmentUtils.getProfile()); + } + + private String getDelayedExchangeName() { + String delayedExchangeName = rabbitCustomProperties.getDelayedExchangeName(); + if (StringUtils.isEmpty(delayedExchangeName)) { + delayedExchangeName = DEFAULT_DELAYED_EXCHANGE_NAME; + } + return String.join(CommonConstants.UNDERLINE, delayedExchangeName, + EnvironmentUtils.getProfile()); + } + + + /** + * 交换器 + * + * @return + * @author sr on 2020-07-22 + */ + @Bean + TopicExchange topicExchange(EnvironmentUtils environmentUtils) { + return new TopicExchange(getExchangeName()); + } + + /*@Bean + public CustomExchange delayedCustomExchange(EnvironmentUtils environmentUtils) { + Map args = Maps.newHashMap(); + //延时交换机一定要设置x-delayed-type属性 + args.put("x-delayed-type", "direct"); + //第二个参数type需要设置成x-delayed-message + return new CustomExchange(getDelayedExchangeName(), "x-delayed-message", true, false, args); + }*/ + + /** + * 消息监听容器 + * + * @param containerFactory + * @param messageListenerAdapter + * @return + * @author sr on 2020-07-22 + */ + @Bean + T messageListenerContainer( + AbstractRabbitListenerContainerFactory containerFactory, + MessageListenerAdapter messageListenerAdapter) { + AbstractMessageListenerContainer container = + containerFactory.createListenerContainer(); + container.setMessageListener(messageListenerAdapter); + return (T) container; + } + + /** + * 消息监听适配器 + * + * @param consumerDeliverer + * @return + * @author sr on 2020-07-22 + */ + @Bean + MessageListenerAdapter messageListenerAdapter(ConsumerDeliverer consumerDeliverer) { + MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(consumerDeliverer); + // 暂不做消息转换, 交给consumerDeliverer处理 + messageListenerAdapter.setMessageConverter(null); + return messageListenerAdapter; + } + + /** + * 初始化消息处理器,注册队列,绑定路由 + * + * @param messageManager + * @param handlers + * @return + * @author sr on 2020-07-24 + */ + @Bean + InitHandler initHandler() { + return new InitHandler(); + } + + /** + * 消息转换器 + * + * @return + * @author sr on 2020-07-24 + */ + @Bean + Jackson2JsonMessageConverter jackson2JsonMessageConverter() { + return new Jackson2JsonMessageConverter("com.senmesh"); + } + + /** + * 队列管理 + * + * @return + * @author sr on 2020-07-24 + */ + @Bean + QueueManager queueManager() { + return new QueueManager(); + } + + /** + * 交换机管理 + * @return + * @author sr on 2021-01-06 + */ + @Bean + ExchangeManager exchangeManager() { + return new ExchangeManager(); + } + + /** + * 消息消费分发 + * + * @param handlers + * @param handlers + * @return + * @author sr on 2020-07-24 + */ + @Bean + ConsumerDeliverer consumerDeliverer(List> handlers) { + ConsumerDeliverer consumerDeliverer = new ConsumerDeliverer(handlers); + consumerDeliverer.setMessageConvert(jackson2JsonMessageConverter()); + return consumerDeliverer; + } + + /** + * 消息发送者 + * + * @param rabbitTemplate + * @param messageManager + * @return + * @author sr on 2020-07-24 + */ + @Bean + IMqSender mqSender(RabbitTemplate rabbitTemplate, QueueManager messageManager, + RabbitCustomProperties rabbitCustomProperties) { + DefaultMqSender defaultMqSender = new DefaultMqSender(); + MqSendUtils mqSendUtils = new MqSendUtils(defaultMqSender); + return defaultMqSender; + } + +} diff --git a/backend/src/main/java/com/senmesh/mq/constant/ExchangeTypeEnum.java b/backend/src/main/java/com/senmesh/mq/constant/ExchangeTypeEnum.java new file mode 100644 index 0000000..38a7381 --- /dev/null +++ b/backend/src/main/java/com/senmesh/mq/constant/ExchangeTypeEnum.java @@ -0,0 +1,15 @@ +package com.senmesh.mq.constant; + +/** + * 交换机 + * @author sr on 2021-01-06 + */ +public enum ExchangeTypeEnum { + + /** (通用)主题交换机 **/ + TOPIC, + /** 延迟交换机 **/ + DELAYED; + + +} diff --git a/backend/src/main/java/com/senmesh/mq/constant/MqConstant.java b/backend/src/main/java/com/senmesh/mq/constant/MqConstant.java new file mode 100644 index 0000000..4f3a0f7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/mq/constant/MqConstant.java @@ -0,0 +1,12 @@ +package com.senmesh.mq.constant; + +/** + * mq常数 + * + * @author Carlye + * @date 2021/01/14 + */ +public interface MqConstant { + + String NACOS_DISCOVERY_IP = "spring.cloud.nacos.discovery.ip"; +} diff --git a/backend/src/main/java/com/senmesh/mq/consumer/ConsumerDeliverer.java b/backend/src/main/java/com/senmesh/mq/consumer/ConsumerDeliverer.java new file mode 100644 index 0000000..74e5908 --- /dev/null +++ b/backend/src/main/java/com/senmesh/mq/consumer/ConsumerDeliverer.java @@ -0,0 +1,138 @@ +package com.senmesh.mq.consumer; + +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.amqp.core.Message; +import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener; +import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; +import org.springframework.amqp.support.converter.MessageConversionException; +import org.springframework.aop.support.AopUtils; +import org.springframework.core.ParameterizedTypeReference; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.senmesh.common.constant.ProjectProfileEnum; +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.common.util.ParameterizedTypeImpl; +import com.senmesh.mq.constant.MqConstant; +import com.senmesh.mq.consumer.handler.IMqHandler; +import com.senmesh.mq.dto.IMqMessage; +import com.rabbitmq.client.Channel; + +import lombok.extern.slf4j.Slf4j; + +/** + * 消息分发 + * + * @author sr on 2020-07-22 + */ +@Slf4j +public class ConsumerDeliverer implements ChannelAwareMessageListener { + + private Jackson2JsonMessageConverter jackson2JsonMessageConverter = + new Jackson2JsonMessageConverter(); + + public static final Map> MQ_HANDLER_MAP = Maps.newHashMap(); + + /** + * key-routingKey,value-ParameterizedTypeReference + **/ + @SuppressWarnings("rawtypes") + private Map messqgeTypeMap = Maps.newConcurrentMap(); + + public ConsumerDeliverer(List> handlers) { + handlers.forEach(handler -> MQ_HANDLER_MAP.put(handler.getRoutingKey(), handler)); + } + + public void setMessageConvert(Jackson2JsonMessageConverter jackson2JsonMessageConverter) { + this.jackson2JsonMessageConverter = jackson2JsonMessageConverter; + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public void onMessage(Message message, Channel channel) throws Exception { + String routingKey = message.getMessageProperties().getReceivedRoutingKey(); + String appId = StringUtils.defaultString(message.getMessageProperties().getAppId(), ""); + Set appIp = Sets.newHashSet(appId.split(",")); + //TODO 重复失败消费三次,进死信 + + IMqHandler handler = MQ_HANDLER_MAP.get(routingKey); + if (handler == null) { + log.info(routingKey + "未找到对应routingKey消费者..."); + return; + } + + // 非广播消息&指定消费者ip消费&只能开发环境 + if (!handler.isBroadcast() + && ProjectProfileEnum.DEV.getValue().equals(EnvironmentUtils.getProfile()) + && StringUtils.isNotBlank(appId)) { + // String ip = InetAddress.getLocalHost().getHostAddress(); + String ip = EnvironmentUtils.getProperty(MqConstant.NACOS_DISCOVERY_IP); + log.info("Mq消息消费指定appId:{},当前ip:{}", appId, ip); + if (!appIp.contains(ip)) { + log.info("Mq消息消费异常,appId:[{}],ip:[{}],message:[{}]", appId, ip, JsonUtils.toJsonString(message)); + //放回queue使用其他消费者消费 + channel.basicRecover(true); + return; + } + } + + Object obj = null; + try { + obj = jackson2JsonMessageConverter.fromMessage(message, + getParameterizedTypeReference(routingKey, handler)); + log.info("mqDeliverer msg:{}", message); + handler.onMessage((IMqMessage) obj); + return; + } catch (MessageConversionException e) { + // 转换失败异常处理 + log.info("mqMessage convert error:{}", e); + } catch (Exception e) { + // TODO 消息消费异常处理 + log.info("mqMessage deal obj:{}", obj, e); + //throw new MqException("message consume error:" + e.getMessage()); + } + } + + /** + * 获取消息范型对象 + * + * @param routingKey + * @param handler + * @return + * @author sr on 2020-09-02 + */ + @SuppressWarnings("rawtypes") + private ParameterizedTypeReference getParameterizedTypeReference(String routingKey, + IMqHandler handler) { + ParameterizedTypeReference type = messqgeTypeMap.get(routingKey); + if (type != null) { + return type; + } + // 有可能是代理对象 + for(Method method :AopUtils.getTargetClass(handler).getMethods()) { + // 有可能是同名方法,非桥接 + if ("onMessage".equals(method.getName()) && !method.isBridge()) { + try { + Type argType = method.getGenericParameterTypes()[0]; + ParameterizedType parameterizedType = (ParameterizedType) (argType); + type = ParameterizedTypeReference.forType(new ParameterizedTypeImpl( + new Type[] {parameterizedType.getActualTypeArguments()[0]}, null, parameterizedType.getRawType())); + messqgeTypeMap.put(routingKey, type); + break; + } catch (Exception e) { + log.error(e.getMessage()); + } + } + } + return type; + } + +} diff --git a/backend/src/main/java/com/senmesh/mq/consumer/InitHandler.java b/backend/src/main/java/com/senmesh/mq/consumer/InitHandler.java new file mode 100644 index 0000000..2058770 --- /dev/null +++ b/backend/src/main/java/com/senmesh/mq/consumer/InitHandler.java @@ -0,0 +1,56 @@ +package com.senmesh.mq.consumer; + +import com.google.common.collect.Lists; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.mq.config.ExchangeManager; +import com.senmesh.mq.config.QueueManager; +import com.senmesh.mq.config.RabbitCustomProperties; +import com.senmesh.mq.constant.MqConstant; +import com.senmesh.mq.consumer.handler.IMqHandler; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.List; + +/** + * 初始化消息消费处理类,初始queue/binding + * + * @author sr on 2020-07-24 + */ +public class InitHandler implements InitializingBean { + + @Autowired(required = false) + private List> handlers = Lists.newArrayList(); + + @Autowired + private QueueManager queueManager; + + @Autowired + private ExchangeManager exchangeManager; + + @Autowired + private RabbitCustomProperties rabbitCustomProperties; + + @Override + public void afterPropertiesSet() throws Exception { + String applicationName = EnvironmentUtils.getApplicationName(); + handlers.forEach(handler -> { + String routingKey = handler.getRoutingKey(); + String queueName = handler.getQueueName(); + // 初始化binding + if (queueName == null) { + queueName = String.join(CommonConstants.UNDERLINE, applicationName, + EnvironmentUtils.getProfile(), routingKey); + if (handler.isBroadcast()) { +// queueName = String.join(CommonConstants.UNDERLINE, queueName,rabbitCustomProperties.getBroadcastId()); + String nacosDiscoveryIp = EnvironmentUtils.getProperty(MqConstant.NACOS_DISCOVERY_IP); + queueName = String.join(CommonConstants.UNDERLINE, queueName, nacosDiscoveryIp); + } + } + queueManager.addQueueAndRoutingKey( + exchangeManager.getExchangeByType(handler.getExchangeType()), queueName, routingKey); + }); + } + +} diff --git a/backend/src/main/java/com/senmesh/mq/consumer/handler/IDelayedMqHandler.java b/backend/src/main/java/com/senmesh/mq/consumer/handler/IDelayedMqHandler.java new file mode 100644 index 0000000..291a84d --- /dev/null +++ b/backend/src/main/java/com/senmesh/mq/consumer/handler/IDelayedMqHandler.java @@ -0,0 +1,22 @@ +//package com.newyetai.mq.consumer.handler; +// +//import com.newyetai.mq.constant.ExchangeTypeEnum; +//import com.newyetai.mq.dto.DelayedMqMessage; +// +///** +// * 消费者处理类(延时交换机) +// * +// * @author sr on 2021-01-06 +// * @param +// */ +//public interface IDelayedMqHandler extends IMqHandler>{ +// +// default String getExchangeType() { +// return ExchangeTypeEnum.DELAYED.name(); +// } +// +// default Class getMessageTypeClazz() { +// return DelayedMqMessage.class; +// } +// +//} diff --git a/backend/src/main/java/com/senmesh/mq/consumer/handler/IMqHandler.java b/backend/src/main/java/com/senmesh/mq/consumer/handler/IMqHandler.java new file mode 100644 index 0000000..c0ad74b --- /dev/null +++ b/backend/src/main/java/com/senmesh/mq/consumer/handler/IMqHandler.java @@ -0,0 +1,67 @@ +package com.senmesh.mq.consumer.handler; + +import com.senmesh.mq.constant.ExchangeTypeEnum; +import com.senmesh.mq.dto.IMqMessage; + +/** + * 消费者处理类 + * + * @author sr on 2021-01-06 + * @param + */ +public interface IMqHandler> { + + /** + * 为空,默认:系统名_routingKey;每个routingkey有专属queue + * + * @return + * @author sr on 2020-07-24 + */ + default String getQueueName() { + return null; + } + + /** + * 是否同项目广播,默认否 + * @return + * @author sr on 2020-08-04 + */ + default boolean isBroadcast() { + return false; + } + + /** + * routingKey 路由键 + * + * @return + * @author sr on 2020-07-24 + */ + String getRoutingKey(); + + /** + * 消费消息 + * + * @param message + * @return 如果抛异常,则代表消费失败,会重新入队 + * @author sr on 2020-07-24 + */ + void onMessage(M message); + + /** + * 获取mq消息对象class + * + * @return + * @author sr on 2021-01-06 + */ + Class getMessageTypeClazz(); + + + /** + * 交换机 + * + * @return {@link ExchangeTypeEnum}.name() + * @author sr on 2021-01-06 + */ + String getExchangeType(); + +} diff --git a/backend/src/main/java/com/senmesh/mq/consumer/handler/ITopicMqHandler.java b/backend/src/main/java/com/senmesh/mq/consumer/handler/ITopicMqHandler.java new file mode 100644 index 0000000..5bb8aab --- /dev/null +++ b/backend/src/main/java/com/senmesh/mq/consumer/handler/ITopicMqHandler.java @@ -0,0 +1,28 @@ +package com.senmesh.mq.consumer.handler; + +import com.senmesh.mq.constant.ExchangeTypeEnum; +import com.senmesh.mq.dto.TopicMqMessage; + +/** + * 消费者处理类(通用交换机) + * + * @author sr on 2020-07-22 + * @param + */ +public interface ITopicMqHandler extends IMqHandler>{ + + default Class getMessageTypeClazz() { + return TopicMqMessage.class; + } + + /** + * 交换机 + * + * @return {@link ExchangeTypeEnum}.name() + * @author sr on 2021-01-06 + */ + default String getExchangeType() { + return ExchangeTypeEnum.TOPIC.name(); + } + +} diff --git a/backend/src/main/java/com/senmesh/mq/dto/AbstractMqMessage.java b/backend/src/main/java/com/senmesh/mq/dto/AbstractMqMessage.java new file mode 100644 index 0000000..24f7586 --- /dev/null +++ b/backend/src/main/java/com/senmesh/mq/dto/AbstractMqMessage.java @@ -0,0 +1,38 @@ +package com.senmesh.mq.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public abstract class AbstractMqMessage implements IMqMessage{ + + /** + * 消息id,可为空(uuid生成) + **/ + private String messageId; + + /** + * 路由键,不能为空 + **/ + private String routingKey; + + /** + * 消息对象 + **/ + private T data; + + /** 操作机构ID(发送方有登录信息时有值) **/ + private Long operateOrgId; + + /** 操作用户ID(发送方有登录信息时有值) **/ + private Long operateUserId; + + /** 用户类型 **/ + private Integer operateUserType; + +} diff --git a/backend/src/main/java/com/senmesh/mq/dto/DelayedMqMessage.java b/backend/src/main/java/com/senmesh/mq/dto/DelayedMqMessage.java new file mode 100644 index 0000000..9e8054a --- /dev/null +++ b/backend/src/main/java/com/senmesh/mq/dto/DelayedMqMessage.java @@ -0,0 +1,39 @@ +package com.senmesh.mq.dto; + +import com.senmesh.mq.constant.ExchangeTypeEnum; + +import lombok.AllArgsConstructor; +import lombok.Builder.Default; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; +import lombok.experimental.SuperBuilder; + +@Data +@ToString(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class DelayedMqMessage extends AbstractMqMessage{ + + /** 交换机,可为空(DELAYED) **/ + @Default + private String exchangeType = ExchangeTypeEnum.DELAYED.name(); + +// /** +// * 延时发送时间,不能为空 +// */ +// private Long delayedTime; +// +// /** +// * 时间类型,可为空 +// */ +// @Default +// private TimeUnit timeUnit = TimeUnit.SECONDS; +// +// +// public TimeUnit getTimeUnit() { +// return Optional.ofNullable(timeUnit).orElse(TimeUnit.SECONDS); +// } + +} diff --git a/backend/src/main/java/com/senmesh/mq/dto/IMqMessage.java b/backend/src/main/java/com/senmesh/mq/dto/IMqMessage.java new file mode 100644 index 0000000..5a5a31e --- /dev/null +++ b/backend/src/main/java/com/senmesh/mq/dto/IMqMessage.java @@ -0,0 +1,35 @@ +package com.senmesh.mq.dto; + +import com.senmesh.mq.constant.ExchangeTypeEnum; + +/** + * 消息 + * + * @author sr on 2021-01-06 + * @param + */ +public interface IMqMessage { + + /** + * 交换机类型 + * @return {@link ExchangeTypeEnum} + * @author sr on 2021-01-06 + */ + String getExchangeType(); + + /** + * routingKey 路由键 + * + * @return + * @author sr on 2021-01-06 + */ + String getRoutingKey(); + + /** + * 消息体 + * @return + * @author sr on 2021-01-06 + */ + T getData(); + +} diff --git a/backend/src/main/java/com/senmesh/mq/dto/TopicMqMessage.java b/backend/src/main/java/com/senmesh/mq/dto/TopicMqMessage.java new file mode 100644 index 0000000..ee12132 --- /dev/null +++ b/backend/src/main/java/com/senmesh/mq/dto/TopicMqMessage.java @@ -0,0 +1,26 @@ +package com.senmesh.mq.dto; + +import com.senmesh.mq.constant.ExchangeTypeEnum; + +import lombok.AllArgsConstructor; +import lombok.Builder.Default; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2020-07-24 + */ +@Data +@ToString(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class TopicMqMessage extends AbstractMqMessage{ + + /** 交换机 **/ + @Default + private String exchangeType = ExchangeTypeEnum.TOPIC.name(); + +} diff --git a/backend/src/main/java/com/senmesh/mq/exception/MqException.java b/backend/src/main/java/com/senmesh/mq/exception/MqException.java new file mode 100644 index 0000000..c23ec96 --- /dev/null +++ b/backend/src/main/java/com/senmesh/mq/exception/MqException.java @@ -0,0 +1,29 @@ +package com.senmesh.mq.exception; + +import com.senmesh.common.exception.BusinessException; + +/** + * 异常 + * + * @author sr on 2020-07-24 + */ +public class MqException extends BusinessException { + + /** **/ + private static final long serialVersionUID = -7022341715833999512L; + + public MqException() {} + + public MqException(String message) { + super(message); + } + + public MqException(String message, Throwable cause) { + super(message, cause); + } + + public MqException(Throwable cause) { + super(cause); + } + +} diff --git a/backend/src/main/java/com/senmesh/mq/producer/sender/DefaultMqSender.java b/backend/src/main/java/com/senmesh/mq/producer/sender/DefaultMqSender.java new file mode 100644 index 0000000..3a05b1e --- /dev/null +++ b/backend/src/main/java/com/senmesh/mq/producer/sender/DefaultMqSender.java @@ -0,0 +1,92 @@ +package com.senmesh.mq.producer.sender; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.mq.config.ExchangeManager; +import com.senmesh.mq.config.RabbitCustomProperties; +import com.senmesh.mq.dto.AbstractMqMessage; +import com.senmesh.mq.dto.TopicMqMessage; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.amqp.AmqpException; +import org.springframework.amqp.core.Message; +import org.springframework.amqp.core.MessageProperties; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.concurrent.TimeUnit; + +/** + * @author sr on 2020-07-24 + */ +@Slf4j +public class DefaultMqSender implements IMqSender { + + @Autowired + private RabbitTemplate rabbitTemplate; + + @Autowired + private RabbitCustomProperties rabbitCustomProperties; + + @Autowired + private ExchangeManager exchangeManager; + + @Override + public AlitaResult send(String routingKey, T msg){ + return this.send(TopicMqMessage.builder().routingKey(routingKey).data(msg).build()); + } + + + @Override + public AlitaResult sendDelayed(String routingKey, T msg, Long delayedTime, TimeUnit timeUnit) { + throw new BusinessException("延迟队列不可用"); +// return this.send(DelayedMqMessage.builder().routingKey(routingKey).data(msg) +// .delayedTime(delayedTime).timeUnit(timeUnit).build()); + } + + @Override + public AlitaResult send(AbstractMqMessage iMqMessage) { + try { + iMqMessage.setOperateUserId(UserContextHolder.getLoginUserId()); + iMqMessage.setOperateOrgId(UserContextHolder.getLoginOrgId()); + iMqMessage.setOperateUserType(UserContextHolder.getUserType()); + String routingKey = iMqMessage.getRoutingKey(); + Assert.notBlank(routingKey, "routingKey不能为空"); + // 获取 exchange + String exchangeName = exchangeManager.getExchangeNameByType(iMqMessage.getExchangeType()); + + MessageProperties messageProperties = new MessageProperties(); + // 指定消费者 + String consumerAppId = rabbitCustomProperties.getConsumerAppId(); + if (StringUtils.isNotBlank(consumerAppId)) { + messageProperties.setAppId(consumerAppId); + } + // 处理延时 +// this.dealDelayed(iMqMessage, messageProperties); + + Message msg = rabbitTemplate.getMessageConverter().toMessage(iMqMessage, messageProperties); + log.info("mqSender msg:{}", msg); + rabbitTemplate.send(exchangeName, routingKey, msg); + } catch (AmqpException e) { + log.info("mqSender send error:{}", e.getMessage()); + return AlitaResult.bizError(e.getMessage()); + } + return AlitaResult.success(); + } + + /*private void dealDelayed(IMqMessage mqMessage, MessageProperties messageProperties) { + // 延时消息设置 + if (mqMessage instanceof DelayedMqMessage) { + Long delayedTime = ((DelayedMqMessage) mqMessage).getDelayedTime(); + Assert.notNull(delayedTime, "延时时间不能为空"); + TimeUnit timeUnit = ((DelayedMqMessage) mqMessage).getTimeUnit(); + if (delayedTime != null && delayedTime > 0L) { + messageProperties.setHeader("x-delay", timeUnit.toMillis(delayedTime)); + } + } + }*/ + + +} diff --git a/backend/src/main/java/com/senmesh/mq/producer/sender/IMqSender.java b/backend/src/main/java/com/senmesh/mq/producer/sender/IMqSender.java new file mode 100644 index 0000000..606d68f --- /dev/null +++ b/backend/src/main/java/com/senmesh/mq/producer/sender/IMqSender.java @@ -0,0 +1,50 @@ +package com.senmesh.mq.producer.sender; + +import java.util.concurrent.TimeUnit; + +import com.senmesh.common.AlitaResult; +import com.senmesh.mq.dto.AbstractMqMessage; + +/** + * 消息发送者 + * + * @author sr on 2020-07-24 + */ +public interface IMqSender { + + /** + * 消息发送 + * + * @param + * @param routingKey + * @param msg + * @return + * @author sr on 2020-07-24 + */ + AlitaResult send(String routingKey, T msg); + + /** + * 发送延迟消息 + * + * @param + * @param routingKey + * @param msg + * @param delayedTime + * @param timeUnit + * @return + * @author sr on 2021-01-06 + */ + AlitaResult sendDelayed(String routingKey, T msg, Long delayedTime, TimeUnit timeUnit); + + + /** + * 消息发送 + * + * @param + * @param iMqMessage + * @return + * @author sr on 2020-07-24 + */ + AlitaResult send(AbstractMqMessage iMqMessage); + +} diff --git a/backend/src/main/java/com/senmesh/mq/util/MqSendUtils.java b/backend/src/main/java/com/senmesh/mq/util/MqSendUtils.java new file mode 100644 index 0000000..e98ef60 --- /dev/null +++ b/backend/src/main/java/com/senmesh/mq/util/MqSendUtils.java @@ -0,0 +1,62 @@ +package com.senmesh.mq.util; + +import com.senmesh.common.AlitaResult; +import com.senmesh.mq.dto.AbstractMqMessage; +import com.senmesh.mq.producer.sender.IMqSender; + +/** + * @Author dylanyuan + * @Date 2020/12/1 下午1:58 + * @Version 1.0 + */ +public class MqSendUtils { + + private static IMqSender iMqSender; + + public MqSendUtils(IMqSender iMqSender) { + MqSendUtils.iMqSender = iMqSender; + } + + /** + * 消息发送 + * + * @param + * @param routingKey + * @param msg + * @return + * @author sr on 2020-07-24 + */ + public static AlitaResult send(String routingKey, T msg) { + return iMqSender.send(routingKey, msg); + } + + /** + * 发送延迟消息 + * + * @param + * @param routingKey + * @param msg + * @param delayedTime + * @param timeUnit + * @return + * @author sr on 2021-01-06 + */ +// public static AlitaResult sendDelayed(String routingKey, T msg, Long delayedTime, +// TimeUnit timeUnit) { +// return iMqSender.sendDelayed(routingKey, msg, delayedTime, timeUnit); +// } + + + /** + * 消息发送 + * + * @param + * @param iMqMessage + * @return + * @author sr on 2020-07-24 + */ + public static AlitaResult send(AbstractMqMessage iMqMessage) { + return iMqSender.send(iMqMessage); + } + +} diff --git a/backend/src/main/java/com/senmesh/mybatis/config/MybatisConfig.java b/backend/src/main/java/com/senmesh/mybatis/config/MybatisConfig.java new file mode 100644 index 0000000..b22ce6d --- /dev/null +++ b/backend/src/main/java/com/senmesh/mybatis/config/MybatisConfig.java @@ -0,0 +1,47 @@ +package com.senmesh.mybatis.config; + +import java.util.List; + +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.type.TypeHandlerRegistry; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; + +import com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration; +import com.senmesh.mybatis.handle.BaseEnumTypeHandler; +import com.senmesh.mybatis.interceptor.MyPageInterceptor; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author guhong + * @date 2019/8/19 + * 设置mapper扫描的包 + */ +@Configuration +@Slf4j +public class MybatisConfig { + + @Autowired + private List sqlSessionFactoryList; + + /** + * 添加自定义的分页插件,pageHelper 的分页插件PageInterceptor是用@PostConstruct添加的,自定义的应该在其后面添加 + * 真正执行时顺序是反过来,先执行MyPageInterceptor,再执行 PageInterceptor + * + * 所以要保证 PageHelperAutoConfiguration 先执行 + */ + @Autowired + public void addPageInterceptor(PageHelperAutoConfiguration pageHelperAutoConfiguration) { + MyPageInterceptor interceptor = new MyPageInterceptor(); + for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) { + sqlSessionFactory.getConfiguration().addInterceptor(interceptor); + log.info("注册自定义分页插件成功"); + // 取得类型转换注册器 + TypeHandlerRegistry typeHandlerRegistry = sqlSessionFactory.getConfiguration().getTypeHandlerRegistry(); + // 注册默认枚举转换器 + typeHandlerRegistry.setDefaultEnumTypeHandler(BaseEnumTypeHandler.class); + } + } + +} diff --git a/backend/src/main/java/com/senmesh/mybatis/converters/ObjectToBaseEnumConverter.java b/backend/src/main/java/com/senmesh/mybatis/converters/ObjectToBaseEnumConverter.java new file mode 100644 index 0000000..633558e --- /dev/null +++ b/backend/src/main/java/com/senmesh/mybatis/converters/ObjectToBaseEnumConverter.java @@ -0,0 +1,35 @@ +package com.senmesh.mybatis.converters; + +import com.google.common.collect.Sets; +import com.senmesh.mybatis.handle.BaseEnum; +import java.util.Arrays; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.core.convert.converter.GenericConverter; + +/** + * @description: baseEnum转换 + * @author: chenyun.huang + * @create: 2021-04-01 11:52 + **/ +public class ObjectToBaseEnumConverter implements GenericConverter { + @Override + public Set getConvertibleTypes() { + return Sets.newHashSet(new ConvertiblePair(Integer.class, BaseEnum.class),new ConvertiblePair(String.class, BaseEnum.class)); + } + + @Override + public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + if (Objects.isNull(source)){ + return null; + } + Class type = (Class) targetType.getType(); + BaseEnum[] enumConstants = type.getEnumConstants(); + Map collect = Arrays.stream(enumConstants) + .collect(Collectors.toMap(BaseEnum::getValue, v -> v, (v1, v2) -> v2)); + return collect.get(source); + } +} diff --git a/backend/src/main/java/com/senmesh/mybatis/handle/BaseEnum.java b/backend/src/main/java/com/senmesh/mybatis/handle/BaseEnum.java new file mode 100644 index 0000000..72282f4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/mybatis/handle/BaseEnum.java @@ -0,0 +1,11 @@ +package com.senmesh.mybatis.handle; + +public interface BaseEnum { + + /** + * 获取枚举的值 + * + * @return 枚举的值 + */ + T getValue(); +} diff --git a/backend/src/main/java/com/senmesh/mybatis/handle/BaseEnumTypeHandler.java b/backend/src/main/java/com/senmesh/mybatis/handle/BaseEnumTypeHandler.java new file mode 100644 index 0000000..2b9e5cc --- /dev/null +++ b/backend/src/main/java/com/senmesh/mybatis/handle/BaseEnumTypeHandler.java @@ -0,0 +1,103 @@ +package com.senmesh.mybatis.handle; + +import org.apache.ibatis.type.BaseTypeHandler; +import org.apache.ibatis.type.JdbcType; +import org.apache.ibatis.type.MappedJdbcTypes; +import org.apache.ibatis.type.MappedTypes; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Objects; + +/** + * @description: 通用枚举转换 + * @author: chenyun.huang + * @create: 2020-04-14 20:00 + **/ +@MappedJdbcTypes(value = JdbcType.VARCHAR, includeNullJdbcType = true) +@MappedTypes({BaseEnum.class}) +public class BaseEnumTypeHandler & BaseEnum> extends BaseTypeHandler { + + /** + * 枚举的class + */ + private Class type; + /** + * 枚举的每个子类枚 + */ + private E[] enums; + + /** + * 一定要有默认的构造函数,不然抛出 not found method 异常 + */ + public BaseEnumTypeHandler() { + } + + /** + * 设置配置文件设置的转换类以及枚举类内容,供其他方法更便捷高效的实现 + * + * @param type 配置文件中设置的转换类 + */ + public BaseEnumTypeHandler(Class type) { + if (type == null) { + throw new IllegalArgumentException("Type argument cannot be null"); + } + this.type = type; + this.enums = type.getEnumConstants(); + if (this.enums == null) { + throw new IllegalArgumentException(type.getSimpleName() + + " does not represent an enum type."); + } + } + + @Override + public void setNonNullParameter(PreparedStatement ps, int i, E parameter, + JdbcType jdbcType) throws SQLException { + /* + * BaseTypeHandler已经帮我们做了parameter的null判断 + * 数据库存储的是枚举的值,所以我们这里使用 value , 如果需要存储 name,可以自定义修改 + */ + if (jdbcType == null) { + Object value = parameter.getValue(); + ps.setString(i, Objects.toString(value)); + } else { + ps.setObject(i, parameter.getValue(), jdbcType.TYPE_CODE); + } + } + + @Override + public E getNullableResult(ResultSet rs, String columnName) + throws SQLException { + return locateEnumStatus(rs.getString(columnName)); + } + + @Override + public E getNullableResult(ResultSet rs, int columnIndex) + throws SQLException { + return locateEnumStatus(rs.getString(columnIndex)); + } + + @Override + public E getNullableResult(CallableStatement cs, int columnIndex) + throws SQLException { + return locateEnumStatus(cs.getString(columnIndex)); + } + + /** + * 枚举类型转换,由于构造函数获取了枚举的子类 enums,让遍历更加高效快捷, + *

+ * 我将取出来的值 全部转换成字符串 进行比较, + * + * @param value 数据库中存储的自定义value属性 + * @return value 对应的枚举类 + */ + private E locateEnumStatus(String value) { + return Arrays.stream(enums) + .filter(e -> Objects.toString(e.getValue()).equals(value)) + .findFirst() + .orElse(null); + } +} diff --git a/backend/src/main/java/com/senmesh/mybatis/interceptor/MyPageInterceptor.java b/backend/src/main/java/com/senmesh/mybatis/interceptor/MyPageInterceptor.java new file mode 100644 index 0000000..2714299 --- /dev/null +++ b/backend/src/main/java/com/senmesh/mybatis/interceptor/MyPageInterceptor.java @@ -0,0 +1,87 @@ +package com.senmesh.mybatis.interceptor; + +import com.github.pagehelper.Page; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageRowBounds; +import com.senmesh.common.dto.IPage; +import org.apache.ibatis.cache.CacheKey; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.plugin.*; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; + +import java.util.List; +import java.util.Map; +import java.util.Properties; + +/** + * @author guhong + * @date 2019/8/19 + */ +@Intercepts({ + @Signature(type = Executor.class, method = "query", + args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}), + @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, + RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),}) +public class MyPageInterceptor implements Interceptor { + + @SuppressWarnings({"unchecked", "rawtypes"}) + @Override + public Object intercept(Invocation invocation) throws Throwable { + Object[] args = invocation.getArgs(); + Object parameter = args[1]; + IPage page = null; + + if (parameter instanceof IPage) { + page = (IPage) parameter; + } else if (parameter instanceof Map) { + for (Map.Entry entry : ((Map) parameter).entrySet()) { + Object value = entry.getValue(); + if (value instanceof IPage) { + page = (IPage) value; + break; + } + } + } + + PageRowBounds pageRowBounds = null; + if (page != null && page.getNeedPage() && page.getPageSize() > 0) { + pageRowBounds = + new PageRowBounds(page.getPageSize() * (page.getPageNo() - 1), page.getPageSize()); + pageRowBounds.setCount(true); + args[2] = pageRowBounds; + } + + // 判断pageSize=0,兼容老版本=0不分页 + Page pageHelperPage = PageHelper.getLocalPage(); + if (pageHelperPage != null && pageHelperPage.getPageSize() == 0) { + PageHelper.clearPage(); + } + + Object value = invocation.proceed(); + + if (page != null && page.getNeedPage() && page.getPageSize() > 0) { + page.setPageResult(pageRowBounds.getTotal().intValue(), (List)value); + } + + + return value; + } + + @Override + public Object plugin(Object target) { + if (target instanceof Executor) { + return Plugin.wrap(target, this); + } else { + return target; + } + } + + @Override + public void setProperties(Properties properties) { + + } + +} diff --git a/backend/src/main/java/com/senmesh/mybatisplus/config/AutoMetaObjectHandler.java b/backend/src/main/java/com/senmesh/mybatisplus/config/AutoMetaObjectHandler.java new file mode 100644 index 0000000..a8c7fdf --- /dev/null +++ b/backend/src/main/java/com/senmesh/mybatisplus/config/AutoMetaObjectHandler.java @@ -0,0 +1,25 @@ +package com.senmesh.mybatisplus.config; + +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import com.senmesh.common.util.UserContextHolder; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.reflection.MetaObject; + +import java.util.Date; + +@Slf4j +//@Component +public class AutoMetaObjectHandler implements MetaObjectHandler { + @Override + public void insertFill(MetaObject metaObject) { + this.strictInsertFill(metaObject, "deleted", Boolean.class, Boolean.FALSE); + this.strictInsertFill(metaObject, "createTime", Date.class, new Date()); + this.strictInsertFill(metaObject, "createBy", Long.class, UserContextHolder.getLoginUserId()); + } + + @Override + public void updateFill(MetaObject metaObject) { + this.strictUpdateFill(metaObject, "updateBy", Long.class, UserContextHolder.getLoginUserId()); + this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date()); + } +} diff --git a/backend/src/main/java/com/senmesh/mybatisplus/config/MybatisPlusConfig.java b/backend/src/main/java/com/senmesh/mybatisplus/config/MybatisPlusConfig.java new file mode 100644 index 0000000..17d7288 --- /dev/null +++ b/backend/src/main/java/com/senmesh/mybatisplus/config/MybatisPlusConfig.java @@ -0,0 +1,24 @@ +package com.senmesh.mybatisplus.config; + +import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; +import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@MapperScan(basePackages = {"com.senmesh.**.dao.**"}) +public class MybatisPlusConfig { + + @Bean + public PaginationInterceptor paginationInterceptor() { + PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); + // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false + // paginationInterceptor.setOverflow(false); + // 设置最大单页限制数量,默认 500 条,-1 不受限制 + // paginationInterceptor.setLimit(500); + // 开启 count 的 join 优化,只针对部分 left join + paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true)); + return paginationInterceptor; + } +} diff --git a/backend/src/main/java/com/senmesh/mybatisplus/injector/Exists.java b/backend/src/main/java/com/senmesh/mybatisplus/injector/Exists.java new file mode 100644 index 0000000..d8a634c --- /dev/null +++ b/backend/src/main/java/com/senmesh/mybatisplus/injector/Exists.java @@ -0,0 +1,46 @@ +package com.senmesh.mybatisplus.injector; + +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlSource; + +import com.baomidou.mybatisplus.core.enums.SqlMethod; +import com.baomidou.mybatisplus.core.injector.AbstractMethod; +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils; + +public class Exists extends AbstractMethod { + + @Override + public MappedStatement injectMappedStatement(Class mapperClass, Class modelClass, + TableInfo tableInfo) { + SqlMethod sqlMethod = SqlMethod.SELECT_COUNT; + String sql = + String.format("", tableInfo.getTableName(), + sqlWhereEntity(true, tableInfo)); + SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass); + return this.addSelectMappedStatementForOther(mapperClass, getMethod(sqlMethod), sqlSource, Boolean.class); + } + + protected String sqlWhereEntity(boolean newLine, TableInfo table) { + + String sqlScript = table.getAllSqlWhere(false, false, ENTITY_DOT); + + String newKeyProperty = ENTITY_DOT + table.getKeyProperty(); + String keySqlScript = + table.getKeyColumn() + HTML_LT + HTML_GT + SqlScriptUtils.safeParam(newKeyProperty); + sqlScript = + SqlScriptUtils.convertIf(keySqlScript, String.format("%s != null", newKeyProperty), false) + + NEWLINE + sqlScript; + + sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", ENTITY), true); + sqlScript = SqlScriptUtils.convertWhere(sqlScript) + NEWLINE; + return newLine ? NEWLINE + sqlScript : sqlScript; + } + + @Override + public String getMethod(SqlMethod sqlMethod) { + // 自定义 mapper 方法名 + return "existsEntity"; + } + +} diff --git a/backend/src/main/java/com/senmesh/mybatisplus/injector/MySqlInjector.java b/backend/src/main/java/com/senmesh/mybatisplus/injector/MySqlInjector.java new file mode 100644 index 0000000..967e6b8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/mybatisplus/injector/MySqlInjector.java @@ -0,0 +1,25 @@ +package com.senmesh.mybatisplus.injector; + +import java.util.List; + +import org.springframework.stereotype.Component; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.core.injector.AbstractMethod; +import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector; +import com.baomidou.mybatisplus.extension.injector.methods.AlwaysUpdateSomeColumnById; + +@Component +public class MySqlInjector extends DefaultSqlInjector { + @Override + public List getMethodList(Class mapperClass) { + List methodList = super.getMethodList(mapperClass); + /** + * 把两个扩展内置扩展SQL注入器注入 + */ +// methodList.add(new InsertBatchSomeColumn(i -> i.getFieldFill() != FieldFill.UPDATE)); + methodList.add(new AlwaysUpdateSomeColumnById(i -> i.getFieldFill() != FieldFill.INSERT)); + methodList.add(new Exists()); + return methodList; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/mybatisplus/util/MybatisPlusUtils.java b/backend/src/main/java/com/senmesh/mybatisplus/util/MybatisPlusUtils.java new file mode 100644 index 0000000..594316f --- /dev/null +++ b/backend/src/main/java/com/senmesh/mybatisplus/util/MybatisPlusUtils.java @@ -0,0 +1,33 @@ +package com.senmesh.mybatisplus.util; + +import java.lang.reflect.Field; +import java.util.Arrays; + +import com.baomidou.mybatisplus.annotation.EnumValue; + +public class MybatisPlusUtils { + + /** + * 处理枚举字段 + * @param obj + * @return + * @throws IllegalArgumentException + * @throws IllegalAccessException + * @author sr on 2022-02-21 + */ + public static Object dealEnumField(Object obj) throws IllegalArgumentException, IllegalAccessException { + if (obj == null) { + return null; + } + Class clazz = obj.getClass(); + if (!clazz.isEnum()) { + return obj; + } + Field f = Arrays.stream(clazz.getDeclaredFields()) + .filter(field -> field.isAnnotationPresent(EnumValue.class)).findFirst().get(); + f.setAccessible(true); + return f.get(obj); + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/ai/config/AiProperties.java b/backend/src/main/java/com/senmesh/sdk/ai/config/AiProperties.java new file mode 100644 index 0000000..fdc740a --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/ai/config/AiProperties.java @@ -0,0 +1,29 @@ +package com.senmesh.sdk.ai.config; + +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@ConfigurationProperties(prefix = AiProperties.PREFIX) +@Data +@Component +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AiProperties implements Serializable{ + + /** **/ + private static final long serialVersionUID = 6362606996602121889L; + + public static final String PREFIX = "ai"; + + /** 对话提供者 **/ + private String chatProvider; + + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/ai/service/service/AiProvider.java b/backend/src/main/java/com/senmesh/sdk/ai/service/service/AiProvider.java new file mode 100644 index 0000000..0712f1b --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/ai/service/service/AiProvider.java @@ -0,0 +1,37 @@ +package com.senmesh.sdk.ai.service.service; + +import com.senmesh.common.AlitaResult; +import com.senmesh.sdk.ai.config.AiProperties; +import com.senmesh.sdk.deepseek.service.DeepSeekProvider; +import com.senmesh.sdk.xf.config.XfProperties; +import com.senmesh.sdk.xf.model.ChatReq; +import com.senmesh.sdk.xf.service.XfSparkProvider; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class AiProvider { + + private static AiProperties aiProperties; + + @Autowired + private DeepSeekProvider deepSeekProvider; + @Autowired + private XfSparkProvider xfSparkProvider; + + private AiProvider(AiProperties aiProperties) { + AiProvider.aiProperties = aiProperties; + } + + public static AlitaResult httpChat(ChatReq req) { + if (aiProperties.getChatProvider().equals(XfProperties.PREFIX)) { + return XfSparkProvider.httpChat(req); + } else { + req.setModel("deepseek-chat"); + return DeepSeekProvider.httpChat(req); + } + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/ai/util/AIUtils.java b/backend/src/main/java/com/senmesh/sdk/ai/util/AIUtils.java new file mode 100644 index 0000000..e00fc34 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/ai/util/AIUtils.java @@ -0,0 +1,24 @@ +package com.senmesh.sdk.ai.util; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.sdk.ai.service.service.AiProvider; +import com.senmesh.sdk.xf.model.ChatReq; +import org.springframework.stereotype.Component; + +@Component +public class AIUtils { + + /** + * 对话 + * @param req + * @return + */ + public static String chat(ChatReq req) { + AlitaResult result = AiProvider.httpChat(req); + Assert.isTrue(result.getSuccess(), result.getMsg()); + return result.getData(); + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/ali/config/AliProperties.java b/backend/src/main/java/com/senmesh/sdk/ali/config/AliProperties.java new file mode 100644 index 0000000..5627464 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/ali/config/AliProperties.java @@ -0,0 +1,44 @@ +package com.senmesh.sdk.ali.config; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Builder.Default; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + + +@ConfigurationProperties(prefix = AliProperties.PREFIX) +@Data +@Component +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AliProperties { + + /** 配置前缀 */ + public static final String PREFIX = "ali"; + public static final String IDCARD_PREFIX = PREFIX + ".idcard"; + + /** 二要素配置 */ + private IdcardProperties idcard; + + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class IdcardProperties { + + /** 是否启用 **/ + @Default + private Boolean enable = Boolean.FALSE; + /** 次数限制 **/ + private Long numLimit; + private String url; + /** */ + private String appcode; + + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/ali/dto/IdCardReq.java b/backend/src/main/java/com/senmesh/sdk/ali/dto/IdCardReq.java new file mode 100644 index 0000000..444d7d4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/ali/dto/IdCardReq.java @@ -0,0 +1,27 @@ +package com.senmesh.sdk.ali.dto; + +import com.senmesh.sdk.common.dto.ISdkRequest; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.core.ParameterizedTypeReference; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class IdCardReq implements ISdkRequest> { + + private static ParameterizedTypeReference> type = new ParameterizedTypeReference>() { + }; + + private String name; + private String idcard; + + @Override + public ParameterizedTypeReference> getResponseType() { + return type; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/ali/dto/IdCardRes.java b/backend/src/main/java/com/senmesh/sdk/ali/dto/IdCardRes.java new file mode 100644 index 0000000..ab98a72 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/ali/dto/IdCardRes.java @@ -0,0 +1,27 @@ +package com.senmesh.sdk.ali.dto; + +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class IdCardRes implements Serializable { + + /** code为200 data才会有值,400参数格式错误 */ + public static final Integer SUC_CODE = 200; + /** 1.不一致 0.一致 */ + public static final Integer SUC_RESULT = 0; + + private String birthday; + private Integer result; + private String address; + private String orderNo; + private String sex; + private String desc; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/ali/dto/VerifyRes.java b/backend/src/main/java/com/senmesh/sdk/ali/dto/VerifyRes.java new file mode 100644 index 0000000..fe874bd --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/ali/dto/VerifyRes.java @@ -0,0 +1,17 @@ +package com.senmesh.sdk.ali.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class VerifyRes { + + private String msg; + private String success; + private Integer code; + private T data; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/ali/service/AliVerifyService.java b/backend/src/main/java/com/senmesh/sdk/ali/service/AliVerifyService.java new file mode 100644 index 0000000..a91384a --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/ali/service/AliVerifyService.java @@ -0,0 +1,14 @@ +package com.senmesh.sdk.ali.service; + +import com.senmesh.common.AlitaResult; +import com.senmesh.sdk.ali.dto.IdCardReq; +import com.senmesh.sdk.ali.dto.IdCardRes; + +public interface AliVerifyService { + + String BEAN_ID = "sdk.aliVerifyService"; + String MOCK_BEAN_ID = "mock.aliVerifyService"; + + AlitaResult verify(IdCardReq req); + +} diff --git a/backend/src/main/java/com/senmesh/sdk/ali/service/impl/AliVerifyServiceImpl.java b/backend/src/main/java/com/senmesh/sdk/ali/service/impl/AliVerifyServiceImpl.java new file mode 100644 index 0000000..d02008c --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/ali/service/impl/AliVerifyServiceImpl.java @@ -0,0 +1,78 @@ +package com.senmesh.sdk.ali.service.impl; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.annotation.CheckAndMock; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.common.util.StrUtils; +import com.senmesh.sdk.ali.config.AliProperties; +import com.senmesh.sdk.ali.config.AliProperties.IdcardProperties; +import com.senmesh.sdk.ali.dto.IdCardReq; +import com.senmesh.sdk.ali.dto.IdCardRes; +import com.senmesh.sdk.ali.dto.VerifyRes; +import com.senmesh.sdk.ali.service.AliVerifyService; +import com.senmesh.sdk.common.constant.SdkConstants; +import com.senmesh.sdk.common.dto.DefaultSdkInvokeLogDTO; +import com.senmesh.sdk.common.util.HttpUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +@Slf4j +@Service(AliVerifyService.BEAN_ID) +public class AliVerifyServiceImpl implements AliVerifyService { + + private static RestTemplate restTemplate = HttpUtils.restTemplate; + @Autowired + private AliProperties aliProperties; + + @Override + @CheckAndMock(mockClass = MockAliVerifyServiceImpl.class, + propertyPrefix = AliProperties.IDCARD_PREFIX) + public AlitaResult verify(IdCardReq req){ + return this.verify(req, aliProperties.getIdcard()); + } + + public static AlitaResult verify(IdCardReq req, IdcardProperties idcardProperties){ + VerifyRes res = null; + + try { + try { + // 构建请求头 + HttpHeaders header = new HttpHeaders(); + header.add("Authorization", "APPCODE " + idcardProperties.getAppcode()); + header.add("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); + // 发送请求 + HttpEntity requestEntity = new HttpEntity(StrUtils.buildQueryValue(req), header); + + ResponseEntity> result = restTemplate.exchange(idcardProperties.getUrl(), + HttpMethod.POST, requestEntity, req.getResponseType()); + res = result.getBody(); + } catch (Exception e) { + log.info("invoke error :{}", e); + return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_ERROR_CODE, e.getMessage()); + } + try { + if (IdCardRes.SUC_CODE.equals(res.getCode()) && IdCardRes.SUC_RESULT.equals(res.getData().getResult())) { + return AlitaResult.success(res.getData()); + } + return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_RESPONSE_FAIL_CODE, + res.getData() == null ? res.getMsg() : res.getData().getDesc()); + } catch (Exception e) { + return AlitaResult.error(SdkConstants.SDK_RESPONSE_CONVERT_ERROR_CODE, + e.getMessage()); + } + } finally { + log.info("invoke:{}", + JsonUtils + .toJsonString( + DefaultSdkInvokeLogDTO.builder().requestData(req).responseData(res) + .build())); + } + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/ali/service/impl/MockAliVerifyServiceImpl.java b/backend/src/main/java/com/senmesh/sdk/ali/service/impl/MockAliVerifyServiceImpl.java new file mode 100644 index 0000000..ec7f8e0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/ali/service/impl/MockAliVerifyServiceImpl.java @@ -0,0 +1,19 @@ +package com.senmesh.sdk.ali.service.impl; + +import com.senmesh.common.AlitaResult; +import com.senmesh.sdk.ali.dto.IdCardReq; +import com.senmesh.sdk.ali.dto.IdCardRes; +import com.senmesh.sdk.ali.service.AliVerifyService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Slf4j +@Service(AliVerifyService.MOCK_BEAN_ID) +public class MockAliVerifyServiceImpl implements AliVerifyService { + + @Override + public AlitaResult verify(IdCardReq req) { + log.info("ali idcard mock..."); + return AlitaResult.success(IdCardRes.builder().result(IdCardRes.SUC_RESULT).build()); + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/bytedance/ByteDanceUtils.java b/backend/src/main/java/com/senmesh/sdk/bytedance/ByteDanceUtils.java new file mode 100644 index 0000000..6b5614c --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/bytedance/ByteDanceUtils.java @@ -0,0 +1,30 @@ +package com.senmesh.sdk.bytedance; + +import com.senmesh.common.AlitaResult; +import com.senmesh.sdk.bytedance.constant.ByteDanceConstants; +import com.senmesh.sdk.bytedance.model.BaseByteDanceDTO; +import com.senmesh.sdk.common.constant.SdkConstants; +import com.senmesh.sdk.common.dto.ISdkRequest; +import com.senmesh.sdk.common.exception.SdkException; +import com.senmesh.sdk.common.util.HttpUtils; + +/** + * @author sr on 2021-11-25 + */ +public class ByteDanceUtils { + + public static AlitaResult execute(ISdkRequest> req) { + try { + BaseByteDanceDTO dto = HttpUtils.post(req); + Long errNo = dto.getErrNo(); + if (ByteDanceConstants.SUCCESS_CODE.equals(errNo)) { + return AlitaResult.success(dto.getData()); + } + return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_RESPONSE_FAIL_CODE, + dto.getErrNo() + dto.getErrTips()); + } catch (SdkException e) { + return AlitaResult.error("字节接口调用失败:" + e.getMessage()); + } + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/bytedance/constant/ByteDanceConstants.java b/backend/src/main/java/com/senmesh/sdk/bytedance/constant/ByteDanceConstants.java new file mode 100644 index 0000000..74fdde3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/bytedance/constant/ByteDanceConstants.java @@ -0,0 +1,11 @@ +package com.senmesh.sdk.bytedance.constant; + +/** + * 字节常量 + * @author sr on 2021-11-25 + */ +public interface ByteDanceConstants { + + Long SUCCESS_CODE = 0L; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/bytedance/model/AccessTokenDataDTO.java b/backend/src/main/java/com/senmesh/sdk/bytedance/model/AccessTokenDataDTO.java new file mode 100644 index 0000000..7438001 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/bytedance/model/AccessTokenDataDTO.java @@ -0,0 +1,25 @@ +package com.senmesh.sdk.bytedance.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class AccessTokenDataDTO { + + /** **/ + private static final long serialVersionUID = 814049874223007628L; + + /** 接口调用凭证 **/ + @JsonProperty("access_token") + private String accessToken; + + /** access_token接口调用凭证超时时间,单位(秒) **/ + @JsonProperty("expires_in") + private String expiresIn; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/bytedance/model/AccessTokenReqDTO.java b/backend/src/main/java/com/senmesh/sdk/bytedance/model/AccessTokenReqDTO.java new file mode 100644 index 0000000..2df732a --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/bytedance/model/AccessTokenReqDTO.java @@ -0,0 +1,48 @@ +package com.senmesh.sdk.bytedance.model; + +import org.springframework.core.ParameterizedTypeReference; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.senmesh.common.annotation.Mask; +import com.senmesh.sdk.common.dto.ISdkRequest; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Builder.Default; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AccessTokenReqDTO implements ISdkRequest>{ + + /** **/ + private static final long serialVersionUID = 197693764614332172L; + private static ParameterizedTypeReference> type = + new ParameterizedTypeReference>() {}; + + /** 第三方用户唯一凭证 **/ + @JsonProperty("appid") + private String appId; + @Mask + /** 第三方用户唯一凭证密钥,即appsecret **/ + private String secret; + @Default + @JsonProperty("grant_type") + private String grantType = "client_credential"; + + @Override + public String getUri() { + return "https://developer.toutiao.com/api/apps/v2/token"; + } + + @Override + public ParameterizedTypeReference> getResponseType() { + return type; + } + + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/bytedance/model/BaseByteDanceDTO.java b/backend/src/main/java/com/senmesh/sdk/bytedance/model/BaseByteDanceDTO.java new file mode 100644 index 0000000..18cf53c --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/bytedance/model/BaseByteDanceDTO.java @@ -0,0 +1,23 @@ +package com.senmesh.sdk.bytedance.model; + +import lombok.Data; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.senmesh.sdk.common.dto.ISdkResponse; + +@Data +public class BaseByteDanceDTO implements ISdkResponse, Serializable { + + /** 错误编码 **/ + @JsonProperty("err_no") + private Long errNo; + + /** 错误信息 **/ + @JsonProperty("err_tips") + private String errTips; + + private T data; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/bytedance/model/Code2SessionDataDTO.java b/backend/src/main/java/com/senmesh/sdk/bytedance/model/Code2SessionDataDTO.java new file mode 100644 index 0000000..e590186 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/bytedance/model/Code2SessionDataDTO.java @@ -0,0 +1,40 @@ +package com.senmesh.sdk.bytedance.model; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2021-11-25 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Code2SessionDataDTO implements Serializable { + + /** **/ + private static final long serialVersionUID = -5908915158294552716L; + + /** 会话密钥,如果请求时有 code 参数才会返回 **/ + @JsonProperty("session_key") + private String sessionKey; + + /** 用户在当前小程序的 ID,如果请求时有 code 参数才会返回 **/ + @JsonProperty("openid") + private String openId; + + /** 匿名用户在当前小程序的 ID,如果请求时有 anonymous_code 参数才会返回 **/ + @JsonProperty("anonymous_openid") + private String anonymousOpenId; + + + /** 用户在小程序平台的唯一标识符,请求时有 code 参数才会返回。如果开发者拥有多个小程序,可通过 unionid 来区分用户的唯一性 **/ + @JsonProperty("unionid") + private String unionId; + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/bytedance/model/Code2SessionReqDTO.java b/backend/src/main/java/com/senmesh/sdk/bytedance/model/Code2SessionReqDTO.java new file mode 100644 index 0000000..af1b1e2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/bytedance/model/Code2SessionReqDTO.java @@ -0,0 +1,49 @@ +package com.senmesh.sdk.bytedance.model; + +import org.springframework.core.ParameterizedTypeReference; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.senmesh.common.annotation.Mask; +import com.senmesh.sdk.common.dto.ISdkRequest; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Code2SessionReqDTO implements ISdkRequest> { + + /** **/ + private static final long serialVersionUID = 197693764614332172L; + private static ParameterizedTypeReference> type = + new ParameterizedTypeReference>() {}; + + /** 第三方用户唯一凭证 **/ + @JsonProperty("appid") + private String appId; + @Mask + /** 第三方用户唯一凭证密钥,即appsecret **/ + private String secret; + /** login 接口返回的登录凭证 **/ + private String code; + /** login 接口返回的匿名登录凭证 **/ + @JsonProperty("anonymous_code") + private String anonymousCode; + + @Override + public String getUri() { + return "https://developer.toutiao.com/api/apps/v2/jscode2session"; + } + + @Override + public ParameterizedTypeReference> getResponseType() { + return type; + } + + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/captcha/config/CaptchaConfiguration.java b/backend/src/main/java/com/senmesh/sdk/captcha/config/CaptchaConfiguration.java new file mode 100644 index 0000000..cd3e874 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/captcha/config/CaptchaConfiguration.java @@ -0,0 +1,39 @@ +package com.senmesh.sdk.captcha.config; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.senmesh.sdk.captcha.service.ITencentCaptchaService; +import com.senmesh.sdk.captcha.service.impl.LoginCaptchaAppProvider; +import com.senmesh.sdk.captcha.service.impl.TencentCaptchaServiceImpl; +import com.tencentcloudapi.common.Credential; + +/** + * 验证码配置类 + * + * @author sr on 2020-08-10 + */ +@Configuration +@EnableConfigurationProperties({CaptchaProperties.class}) +public class CaptchaConfiguration { + + @Bean + @ConditionalOnProperty(havingValue = "true", name = "captcha.tencent.enable") + public ITencentCaptchaService tencentCaptchaService(CaptchaProperties captchaProperties) { + Credential credential = new Credential(captchaProperties.getTencent().getSecretId(), + captchaProperties.getTencent().getSecretKey()); + return new TencentCaptchaServiceImpl(credential); + } + + + @Bean + @ConditionalOnBean(ITencentCaptchaService.class) + public LoginCaptchaAppProvider loginCaptchaAppProvider( + ITencentCaptchaService tencentCaptchaService, CaptchaProperties captchaProperties) { + return new LoginCaptchaAppProvider(tencentCaptchaService, captchaProperties); + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/captcha/config/CaptchaProperties.java b/backend/src/main/java/com/senmesh/sdk/captcha/config/CaptchaProperties.java new file mode 100644 index 0000000..ab1c034 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/captcha/config/CaptchaProperties.java @@ -0,0 +1,23 @@ +package com.senmesh.sdk.captcha.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 属性配置 + * + * @author sr on 2020-08-10 + */ +@ConfigurationProperties(prefix = CaptchaProperties.PREFIX) +@Data +@NoArgsConstructor +public class CaptchaProperties { + + public static final String PREFIX = "captcha"; + + /** 腾讯配置 **/ + private TencentProperties tencent; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/captcha/config/TencentAppProperties.java b/backend/src/main/java/com/senmesh/sdk/captcha/config/TencentAppProperties.java new file mode 100644 index 0000000..b33e8c5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/captcha/config/TencentAppProperties.java @@ -0,0 +1,18 @@ +package com.senmesh.sdk.captcha.config; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 腾讯验证码应用配置 + * + * @author sr on 2020-08-11 + */ +@Data +@NoArgsConstructor +public class TencentAppProperties { + + private String appId; + private String appSecret; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/captcha/config/TencentProperties.java b/backend/src/main/java/com/senmesh/sdk/captcha/config/TencentProperties.java new file mode 100644 index 0000000..7548486 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/captcha/config/TencentProperties.java @@ -0,0 +1,24 @@ +package com.senmesh.sdk.captcha.config; + +import java.util.HashMap; +import java.util.Map; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 腾讯配置 + * + * @author sr on 2020-08-11 + */ +@Data +@NoArgsConstructor +public class TencentProperties { + + private Boolean enable; + private String secretId; + private String secretKey; + + private final Map app = new HashMap<>(); + +} diff --git a/backend/src/main/java/com/senmesh/sdk/captcha/dto/TencentCaptchaDTO.java b/backend/src/main/java/com/senmesh/sdk/captcha/dto/TencentCaptchaDTO.java new file mode 100644 index 0000000..aac9ec2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/captcha/dto/TencentCaptchaDTO.java @@ -0,0 +1,57 @@ +package com.senmesh.sdk.captcha.dto; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-08-10 + */ +@Data +@NoArgsConstructor +public class TencentCaptchaDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 2301105027025640174L; + + /** 前端回调函数返回的用户验证票据(必填) **/ + @JsonProperty("Ticket") + private String ticket; + /** 用户操作来源的外网 IP(可为空,前提是上下文request不为空) **/ + @JsonProperty("UserIp") + private String userIp; + /** 前端回调函数返回的随机字符串(必填) **/ + @JsonProperty("Randstr") + private String randstr; + /** 验证码应用ID;(可为空,配置文件获取) **/ + @JsonProperty("CaptchaAppId") + private Long captchaAppId; + /** 用于服务器端校验验证码票据的验证密钥;(可为空,配置文件获取) **/ + @JsonProperty("AppSecretKey") + private String appSecretKey; + /** 业务 ID,网站或应用在多个业务中使用此服务,通过此 ID 区分统计数据(可为空) **/ + @JsonProperty("BusinessId") + private Long businessId; + /** 场景 ID,网站或应用的业务下有多个场景使用此服务,通过此 ID 区分统计数据(可为空)**/ + @JsonProperty("SceneId") + private Long sceneId; + /** mac 地址或设备唯一标识(可为空) **/ + @JsonProperty("MacAddress") + private String macAddress; + /** 手机设备号(可为空) **/ + @JsonProperty("Imei") + private String imei; + /** 是否返回前端获取验证码时间,取值1:需要返回(可为空) **/ + @JsonProperty("NeedGetCaptchaTime") + private Long needGetCaptchaTime; + + public TencentCaptchaDTO(String ticket, String randstr) { + super(); + this.ticket = ticket; + this.randstr = randstr; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/captcha/mapstruct/CaptchaRequestMapMapper.java b/backend/src/main/java/com/senmesh/sdk/captcha/mapstruct/CaptchaRequestMapMapper.java new file mode 100644 index 0000000..f1ab685 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/captcha/mapstruct/CaptchaRequestMapMapper.java @@ -0,0 +1,29 @@ +package com.senmesh.sdk.captcha.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +import com.senmesh.sdk.captcha.dto.TencentCaptchaDTO; +import com.tencentcloudapi.captcha.v20190722.models.DescribeCaptchaResultRequest; + +/** + * @author sr on 2020-08-10 + */ +@Mapper +public interface CaptchaRequestMapMapper { + + CaptchaRequestMapMapper INSTANCE = Mappers.getMapper(CaptchaRequestMapMapper.class); + + /** + * @param dto + * @return + * @author sr on 2020-08-10 + */ + @Mappings({ + @Mapping(target = "captchaType", constant = "9l") + }) + DescribeCaptchaResultRequest toRequest(TencentCaptchaDTO dto); + +} diff --git a/backend/src/main/java/com/senmesh/sdk/captcha/service/AbstractTencentCaptchaAppProvider.java b/backend/src/main/java/com/senmesh/sdk/captcha/service/AbstractTencentCaptchaAppProvider.java new file mode 100644 index 0000000..81c2d2e --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/captcha/service/AbstractTencentCaptchaAppProvider.java @@ -0,0 +1,78 @@ +package com.senmesh.sdk.captcha.service; + +import org.apache.commons.lang3.StringUtils; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.common.util.RequestUtils; +import com.senmesh.common.util.SpringContextHolder; +import com.senmesh.sdk.captcha.config.CaptchaProperties; +import com.senmesh.sdk.captcha.dto.TencentCaptchaDTO; +import com.senmesh.sdk.captcha.mapstruct.CaptchaRequestMapMapper; +import com.tencentcloudapi.captcha.v20190722.models.DescribeCaptchaResultRequest; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author sr on 2020-08-10 + */ +@Slf4j +public abstract class AbstractTencentCaptchaAppProvider implements ITencentCaptchaAppProvider { + + private static final String PARAM_NOT_ENOUTH = "参数缺失"; + private ITencentCaptchaService tencentCaptchaService; + private String appIdKey; + private String appSecretKey; + private CaptchaProperties captchaProperties; + + protected AbstractTencentCaptchaAppProvider(ITencentCaptchaService tencentCaptchaService, + CaptchaProperties captchaProperties) { + this.tencentCaptchaService = tencentCaptchaService; + this.captchaProperties = captchaProperties; + } + + private String getAppIdKey() { + if (appIdKey == null) { + appIdKey = captchaProperties.getTencent().getApp().get(getAppType()).getAppId(); + } + return appIdKey; + } + + private String getAppSecretKey() { + if (appSecretKey == null) { + appSecretKey = captchaProperties.getTencent().getApp().get(getAppType()).getAppSecret(); + } + return appSecretKey; + } + + @Override + public AlitaResult verify(TencentCaptchaDTO tencentCaptchaDTO) { + try { + if (StringUtils.isBlank(tencentCaptchaDTO.getTicket()) || StringUtils.isBlank(tencentCaptchaDTO.getRandstr())) { + return AlitaResult.bizError(PARAM_NOT_ENOUTH); + } + DescribeCaptchaResultRequest request = + CaptchaRequestMapMapper.INSTANCE.toRequest(tencentCaptchaDTO); + // 用户ip + if (StringUtils.isBlank(request.getUserIp())) { + request.setUserIp(RequestUtils.getIpAddress(SpringContextHolder.getRequest())); + } + // 应用id secret + if (request.getCaptchaAppId() == null) { + request.setCaptchaAppId(Long.valueOf(EnvironmentUtils.getProperty(getAppIdKey()))); + request.setAppSecretKey(EnvironmentUtils.getProperty(getAppSecretKey())); + } + return tencentCaptchaService.verify(request); + + } catch (Exception e) { + log.error("tencent captcha verify error", e); + return AlitaResult.bizError("验证失败:{}" + e.getMessage()); + } + } + + public AlitaResult verify(String ticket, String randstr) { + TencentCaptchaDTO tencentCaptchaDTO = new TencentCaptchaDTO(ticket, randstr); + return this.verify(tencentCaptchaDTO); + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/captcha/service/ITencentCaptchaAppProvider.java b/backend/src/main/java/com/senmesh/sdk/captcha/service/ITencentCaptchaAppProvider.java new file mode 100644 index 0000000..6bbc226 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/captcha/service/ITencentCaptchaAppProvider.java @@ -0,0 +1,23 @@ +package com.senmesh.sdk.captcha.service; + +import com.senmesh.common.AlitaResult; +import com.senmesh.sdk.captcha.dto.TencentCaptchaDTO; + +/** + * @author sr on 2020-08-10 + */ +public interface ITencentCaptchaAppProvider { + + /** + * 验证应用类型; + * 同时确定应用id属性配置键 + * id键:captcha.tencent.${appType}.appId,secret键:id键:captcha.tencent.${appType}.appSecret + * + * @return + * @author sr on 2020-08-10 + */ + String getAppType(); + + AlitaResult verify(TencentCaptchaDTO tencentCaptchaDTO); + +} diff --git a/backend/src/main/java/com/senmesh/sdk/captcha/service/ITencentCaptchaService.java b/backend/src/main/java/com/senmesh/sdk/captcha/service/ITencentCaptchaService.java new file mode 100644 index 0000000..153540c --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/captcha/service/ITencentCaptchaService.java @@ -0,0 +1,20 @@ +package com.senmesh.sdk.captcha.service; + +import com.senmesh.common.AlitaResult; +import com.tencentcloudapi.captcha.v20190722.models.DescribeCaptchaResultRequest; + +/** + * @author sr on 2020-08-10 + */ +public interface ITencentCaptchaService { + + /** + * 验证 + * + * @param request + * @return + * @author sr on 2020-08-10 + */ + AlitaResult verify(DescribeCaptchaResultRequest request); + +} diff --git a/backend/src/main/java/com/senmesh/sdk/captcha/service/impl/LoginCaptchaAppProvider.java b/backend/src/main/java/com/senmesh/sdk/captcha/service/impl/LoginCaptchaAppProvider.java new file mode 100644 index 0000000..d235268 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/captcha/service/impl/LoginCaptchaAppProvider.java @@ -0,0 +1,23 @@ +package com.senmesh.sdk.captcha.service.impl; + +import com.senmesh.sdk.captcha.config.CaptchaProperties; +import com.senmesh.sdk.captcha.service.AbstractTencentCaptchaAppProvider; +import com.senmesh.sdk.captcha.service.ITencentCaptchaService; + +/** + * 登录防水墙 + * + * @author sr on 2020-08-11 + */ +public class LoginCaptchaAppProvider extends AbstractTencentCaptchaAppProvider { + + public LoginCaptchaAppProvider(ITencentCaptchaService tencentCaptchaService, CaptchaProperties captchaProperties) { + super(tencentCaptchaService, captchaProperties); + } + + @Override + public String getAppType() { + return "login"; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/captcha/service/impl/TencentCaptchaServiceImpl.java b/backend/src/main/java/com/senmesh/sdk/captcha/service/impl/TencentCaptchaServiceImpl.java new file mode 100644 index 0000000..2e2f2a1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/captcha/service/impl/TencentCaptchaServiceImpl.java @@ -0,0 +1,55 @@ +package com.senmesh.sdk.captcha.service.impl; + +import org.apache.commons.lang3.StringUtils; + +import com.senmesh.common.AlitaResult; +import com.senmesh.sdk.captcha.service.ITencentCaptchaService; +import com.tencentcloudapi.captcha.v20190722.CaptchaClient; +import com.tencentcloudapi.captcha.v20190722.models.DescribeCaptchaResultRequest; +import com.tencentcloudapi.captcha.v20190722.models.DescribeCaptchaResultResponse; +import com.tencentcloudapi.common.Credential; +import com.tencentcloudapi.common.exception.TencentCloudSDKException; +import com.tencentcloudapi.common.profile.ClientProfile; +import com.tencentcloudapi.common.profile.HttpProfile; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author sr on 2020-08-10 + */ +@Slf4j +public class TencentCaptchaServiceImpl implements ITencentCaptchaService { + + private static final Long SUCCESS_CODE = 1L; + + private Credential defaultCredential; + + public TencentCaptchaServiceImpl(Credential defaultCredential) { + this.defaultCredential = defaultCredential; + } + + @Override + public AlitaResult verify(DescribeCaptchaResultRequest request) { + try { + Credential cred = defaultCredential; + HttpProfile httpProfile = new HttpProfile(); + ClientProfile clientProfile = new ClientProfile(); + clientProfile.setHttpProfile(httpProfile); + CaptchaClient client = new CaptchaClient(cred, "", clientProfile); + log.info("tencent captcha request:{}", request); + DescribeCaptchaResultResponse resp = client.DescribeCaptchaResult(request); + log.info("tencent captcha response:{}", resp); + Long captchaCode = resp.getCaptchaCode(); + if (SUCCESS_CODE.equals(captchaCode)) { + return AlitaResult.success(true); + } + String msg = resp.getCaptchaMsg(); + return AlitaResult.success(StringUtils.isBlank(msg) ? captchaCode.toString() : msg, false); + } catch (TencentCloudSDKException e) { + log.info("tencent captcha error", e); + return AlitaResult.bizError(e.getMessage()); + } + + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/chuanglan/config/ChuangLanCommonProperties.java b/backend/src/main/java/com/senmesh/sdk/chuanglan/config/ChuangLanCommonProperties.java new file mode 100644 index 0000000..1e02f38 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/chuanglan/config/ChuangLanCommonProperties.java @@ -0,0 +1,21 @@ +package com.senmesh.sdk.chuanglan.config; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 接口链接地址映射 + * @author fzp on 2021年6月17日09:29:06 + */ +@Data +@NoArgsConstructor +public class ChuangLanCommonProperties { + + /** 是否启用 **/ + private Boolean enable = Boolean.FALSE; + /** 接口地址 **/ + private String url; + /** 次数限制 **/ + private Long numLimit; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/chuanglan/config/ChuangLanProperties.java b/backend/src/main/java/com/senmesh/sdk/chuanglan/config/ChuangLanProperties.java new file mode 100644 index 0000000..9a8afd6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/chuanglan/config/ChuangLanProperties.java @@ -0,0 +1,59 @@ +package com.senmesh.sdk.chuanglan.config; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 创蓝配置 + * + * @author sr on 2020-04-09 + */ +@ConfigurationProperties(prefix = ChuangLanProperties.PREFIX) +@Data +@Component +@NoArgsConstructor +public class ChuangLanProperties { + + /** 创蓝配置前缀 */ + public static final String PREFIX = "chuanglan"; + /** 创蓝三要素配置前缀 */ + public static final String PHONE_THREE_PREFIX = PREFIX + ".phone3"; + /** 创蓝三要素配置前缀 */ + public static final String BANK_CARD_THREE_PREFIX = PREFIX + ".bankCard3"; + /** 创蓝四要素配置前缀 */ + public static final String BANK_CARD_FOUR_PREFIX = PREFIX + ".bankCard4"; + + /** 创蓝二要素实名认证配置前缀 */ + public static final String REAL_NAME_TWO_PREFIX = PREFIX + ".realName2"; + + /** 创蓝二要素实名认证配置前缀 */ + public static final String REAL_NAME_TWO_BASE_PREFIX = PREFIX + ".realName2Base"; + + /** 是否启用 **/ + private Boolean enable; + /** https://api.253.com */ + private String domain; + + /** 系统预留手机号 */ + private String phone; + + private String appId; + + private String appSecret; + + /** 手机号三要素配置 */ + private ChuangLanCommonProperties phone3; + + /** 银行卡三要素配置 */ + private ChuangLanCommonProperties bankCard3; + + /** 银行卡四要素配置 */ + private ChuangLanCommonProperties bankCard4; + /** 实名认证二要素配置 */ + private ChuangLanCommonProperties realName2; + + /** 实名认证二要素配置 (id-card-auth) */ + private ChuangLanCommonProperties realName2Base; +} diff --git a/backend/src/main/java/com/senmesh/sdk/chuanglan/constant/BankCardVerifyStateEnum.java b/backend/src/main/java/com/senmesh/sdk/chuanglan/constant/BankCardVerifyStateEnum.java new file mode 100644 index 0000000..da48fdb --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/chuanglan/constant/BankCardVerifyStateEnum.java @@ -0,0 +1,83 @@ +package com.senmesh.sdk.chuanglan.constant; + +import com.google.common.collect.Maps; +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.sdk.chuanglan.dto.ChuangLanResponseDTO; +import com.senmesh.sdk.chuanglan.dto.ChuangLanResultDTO; +import java.util.Map; + +/** + * @author czy + * @date 2021-07-05 + */ + +public enum BankCardVerifyStateEnum { + + /** 认证一致 **/ + SUC("01", "认证一致", Boolean.TRUE), + /** 认证不一致 **/ + FAIL("02", "认证不一致", Boolean.FALSE), + /** 认证不确定 **/ + UNCERTAIN("03", "认证不确定", null), + /** 认证失败 **/ + EXCEPTION_FAIL("04", "认证失败", null), + /** 手机号码不匹配 **/ + MOBILE_ERROR("05", "手机号码不匹配", Boolean.FALSE), + /** 身份证号码不匹配 **/ + CARD_NO_ERROR("06", "身份证号码不匹配", Boolean.FALSE), + /** 姓名不匹配 **/ + NAME_ERROR("07", "姓名不匹配", Boolean.FALSE); + + private static Map stateMap; + /** 验证结果 **/ + private String state; + /** 说明 **/ + private String msg; + /** 认证结果 **/ + private Boolean result; + + + BankCardVerifyStateEnum(String state, String msg, Boolean result) { + this.state = state; + this.msg = msg; + this.result = result; + } + + static { + BankCardVerifyStateEnum[] array = BankCardVerifyStateEnum.values(); + stateMap = Maps.newHashMapWithExpectedSize(array.length); + for (BankCardVerifyStateEnum stateEnum : array) { + stateMap.put(stateEnum.getState(), stateEnum); + } + } + + public String getState() { + return state; + } + + public String getMsg() { + return msg; + } + + public Boolean getResult() { + return result; + } + + public static AlitaResult dealState(ChuangLanResponseDTO responseDto) { + ChuangLanResultDTO resultDTO = ChuangLanResultDTO.builder() + .jsonData(JsonUtils.toJsonString(responseDto)).build(); + String status = responseDto.getData().getResult(); + BankCardVerifyStateEnum stateEnum = stateMap.get(status); + if (stateEnum == null) { + return AlitaResult.success("state not available...", resultDTO); + } + if (stateEnum == SUC || stateEnum == FAIL || stateEnum == MOBILE_ERROR || stateEnum == CARD_NO_ERROR || stateEnum == NAME_ERROR) { + resultDTO.setStatus(stateEnum.getResult()); + return AlitaResult.success(stateEnum.getMsg(), resultDTO); + } + return AlitaResult.error(stateEnum.getMsg(), resultDTO); + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/chuanglan/constant/ChuangLanConstants.java b/backend/src/main/java/com/senmesh/sdk/chuanglan/constant/ChuangLanConstants.java new file mode 100644 index 0000000..987ff78 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/chuanglan/constant/ChuangLanConstants.java @@ -0,0 +1,22 @@ +package com.senmesh.sdk.chuanglan.constant; + +import com.senmesh.sdk.common.constant.SdkConstants; + +/** + * @author sr on 2020-04-10 + */ +public interface ChuangLanConstants { + + /** 创蓝接口调用,验证成功码 **/ + String IMPL_CODE = "01"; + + /** 成功码 **/ + String SUC_CODE = "200000"; + + /** ================ chuanglan 调起真实服务前异常msg ================= **/ + String PROPERTIES_NOT_SET = SdkConstants.CL_CODE + ":配置文件未配置"; + String ID_SECRET_NOT_ENOUGH = SdkConstants.CL_CODE + ":参数appId或appSecret缺失"; + /** ================ chuanglanW 调起真实服务前异常msq ================= **/ + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/chuanglan/constant/ChuangLanErrorCodeEnum.java b/backend/src/main/java/com/senmesh/sdk/chuanglan/constant/ChuangLanErrorCodeEnum.java new file mode 100644 index 0000000..02f9f9a --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/chuanglan/constant/ChuangLanErrorCodeEnum.java @@ -0,0 +1,33 @@ +package com.senmesh.sdk.chuanglan.constant; + +/** + * sdk创蓝错误码枚举;标识:创蓝(01) + * @author sr on 2020-05-22 + */ +public enum ChuangLanErrorCodeEnum { + + /** 创蓝调用返回错误码 **/ + INVOKE_RETURN_ERROR("060101", "创蓝接口调用失败,返回错误码"), + /** 创蓝调用成功,但信息不匹配 **/ + NOT_EQUAL("060102", "不匹配"); + + /** 错误码 **/ + private String code; + /** 错误信息 **/ + private String msg; + + ChuangLanErrorCodeEnum(String code, String msg){ + this.code = code; + this.msg = msg; + } + + public String getCode() { + return code; + } + + public String getMsg() { + return msg; + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/BankCardFourRequestDTO.java b/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/BankCardFourRequestDTO.java new file mode 100644 index 0000000..b422600 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/BankCardFourRequestDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.sdk.chuanglan.dto; + +import lombok.*; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +/** + * 银行卡四要素请求 + * + * @author fzp 2021年6月15日15:11:31 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class BankCardFourRequestDTO extends ChuangLanRequestDTO implements Serializable { + + /** **/ + private static final long serialVersionUID = 3807618123977056991L; + + /** 姓名 **/ + @NotBlank(message = "姓名不能为空") + private String name; + /** 身份证号 **/ + @NotBlank(message = "身份证号不能为空") + private String idNum; + /** 银行卡号 **/ + @NotBlank(message = "银行卡号不能为空") + private String cardNo; + @NotBlank(message = "手机号码不能为空") + private String mobile; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/BankCardThreeRequestDTO.java b/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/BankCardThreeRequestDTO.java new file mode 100644 index 0000000..5dc4738 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/BankCardThreeRequestDTO.java @@ -0,0 +1,33 @@ +package com.senmesh.sdk.chuanglan.dto; + +import lombok.*; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +/** + * 银行卡三要素请求 + * + * @author sr on 2020-04-09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class BankCardThreeRequestDTO extends ChuangLanRequestDTO implements Serializable { + + /** **/ + private static final long serialVersionUID = -6539738426193243916L; + + /** 姓名 **/ + @NotBlank(message = "姓名不能为空") + private String name; + /** 身份证号 **/ + @NotBlank(message = "身份证号不能为空") + private String idNum; + /** 银行卡号 **/ + @NotBlank(message = "银行卡号不能为空") + private String cardNo; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/ChuangLanRequestDTO.java b/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/ChuangLanRequestDTO.java new file mode 100644 index 0000000..0b09a07 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/ChuangLanRequestDTO.java @@ -0,0 +1,27 @@ +package com.senmesh.sdk.chuanglan.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 创蓝请求父类dto + * + * @author fzp on 2021年6月15日16:39:50 + */ +@Data +@NoArgsConstructor +public class ChuangLanRequestDTO implements Serializable { + + private static final long serialVersionUID = 3960499271644654446L; + /** + * id + **/ + private String appId; + /** + * secret + **/ + private String appKey; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/ChuangLanResponseDTO.java b/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/ChuangLanResponseDTO.java new file mode 100644 index 0000000..36b0127 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/ChuangLanResponseDTO.java @@ -0,0 +1,81 @@ +package com.senmesh.sdk.chuanglan.dto; + +import com.senmesh.common.AlitaResult; +import com.senmesh.sdk.fangxinqian.constant.FxqConstants; +import com.senmesh.sdk.fangxinqian.constant.FxqErrorCodeEnum; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.util.StringUtils; + +import java.io.Serializable; + +/** + * 创蓝返回 + * + * @param + * @author fzp on 2021年6月15日14:55:38 + */ +@Data +@NoArgsConstructor +public class ChuangLanResponseDTO implements Serializable { + + /** + * + **/ + private static final long serialVersionUID = -4576000729533850612L; + /** + * 错误码 + **/ + private String code; + /** + * 序列号(每次调用接口返回的唯一值,seqNo 如有接口问题,请提供此值) + **/ + private String seqNo; + /** + * 错误信息 1 + **/ + private String message; + + /** + * 错误信息 2 + */ + private String msg; + + /** + * 响应结果 + */ + private StatusDataDTO data; + + + public static ChuangLanResponseDTO buildCommonError() { + ChuangLanResponseDTO clResponseDTO = new ChuangLanResponseDTO(); + clResponseDTO.setCode("999"); + return clResponseDTO; + } + + /** + * 返回结果处理 + * + * @return + */ + public AlitaResult handleResult() { + if (FxqConstants.SUC_CODE.equals(this.getCode())) { + return AlitaResult.success(handleData()); + } else { + return AlitaResult.error(FxqErrorCodeEnum.INVOKE_RETURN_ERROR.getCode(), + StringUtils.isEmpty(this.getMsg()) ? + StringUtils.isEmpty(this.getMessage()) ? FxqErrorCodeEnum.INVOKE_RETURN_ERROR.getMsg() : this.getMessage() + : this.getMsg()); + } + } + + /** + * 子类DTO实现 转换为AlitaResult时 + * 通过 handleData()决定转换为AlitaResult的data返回什么 + * + * @return + */ + protected T handleData() { + return null; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/ChuangLanResultDTO.java b/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/ChuangLanResultDTO.java new file mode 100644 index 0000000..c47f837 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/ChuangLanResultDTO.java @@ -0,0 +1,23 @@ +package com.senmesh.sdk.chuanglan.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author czy + * @date 2021-07-05 + */ + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ChuangLanResultDTO { + + private Boolean status; + + private String jsonData; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/PhoneThreeRequestDTO.java b/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/PhoneThreeRequestDTO.java new file mode 100644 index 0000000..ab0eb61 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/PhoneThreeRequestDTO.java @@ -0,0 +1,36 @@ +package com.senmesh.sdk.chuanglan.dto; + +import java.io.Serializable; +import javax.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 手机号三要素请求 + * + * @author sr on 2020-04-09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class PhoneThreeRequestDTO extends ChuangLanRequestDTO implements Serializable { + + /** **/ + private static final long serialVersionUID = -6539738426193243916L; + + /** 姓名 **/ + @NotBlank(message = "姓名不能为空") + private String name; + /** 身份证号 **/ + @NotBlank(message = "身份证号不能为空") + private String idNum; + /** 银行卡号 **/ + @NotBlank(message = "手机号不能为空") + private String mobile; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/RealNameTwoBaseRequestDTO.java b/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/RealNameTwoBaseRequestDTO.java new file mode 100644 index 0000000..71e502e --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/RealNameTwoBaseRequestDTO.java @@ -0,0 +1,28 @@ +package com.senmesh.sdk.chuanglan.dto; + +import lombok.*; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +/** + * 实名认证(基础) + * + * @author fzp 2021年6月15日15:11:31 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class RealNameTwoBaseRequestDTO extends ChuangLanRequestDTO implements Serializable { + + private static final long serialVersionUID = -3985001434329229012L; + + /** 姓名 **/ + @NotBlank(message = "姓名不能为空") + private String name; + /** 身份证号 **/ + @NotBlank(message = "身份证号不能为空") + private String idNum; +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/RealNameTwoRequestDTO.java b/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/RealNameTwoRequestDTO.java new file mode 100644 index 0000000..4e5f2af --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/RealNameTwoRequestDTO.java @@ -0,0 +1,38 @@ +package com.senmesh.sdk.chuanglan.dto; + +import lombok.*; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +/** + * 实名认证 + * + * @author fzp 2021年6月15日15:11:31 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class RealNameTwoRequestDTO extends ChuangLanRequestDTO implements Serializable { + + /** **/ + private static final long serialVersionUID = 3807618123977056991L; + + /** 姓名 **/ + @NotBlank(message = "姓名不能为空") + private String name; + /** 身份证号 **/ + @NotBlank(message = "身份证号不能为空") + private String idNum; + + /** 身份证有效开始日期 **/ + @NotBlank(message = "startTime") + private String startTime; + + /** 身份证有效结束日期 **/ + @NotBlank(message = "startTime") + private String endTime; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/StatusDataDTO.java b/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/StatusDataDTO.java new file mode 100644 index 0000000..ea1b8da --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/chuanglan/dto/StatusDataDTO.java @@ -0,0 +1,41 @@ +package com.senmesh.sdk.chuanglan.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author czy + * @date 2021-07-05 + */ + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class StatusDataDTO { + + @ApiModelProperty("业务唯一流水号") + private String orderNo; + + @ApiModelProperty("查询时间") + private String handleTime; + + @ApiModelProperty("认证结果代码") + private String result; + + @ApiModelProperty("备注") + private String remark; + + @ApiModelProperty("银行卡所属银行") + private String bankName; + + @ApiModelProperty("银行卡类型") + private String cardType; + + @ApiModelProperty("银行卡类型") + private String cardCategory; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/chuanglan/service/ChuangLanService.java b/backend/src/main/java/com/senmesh/sdk/chuanglan/service/ChuangLanService.java new file mode 100644 index 0000000..52b6fa7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/chuanglan/service/ChuangLanService.java @@ -0,0 +1,71 @@ +package com.senmesh.sdk.chuanglan.service; + +import com.senmesh.common.AlitaResult; +import com.senmesh.sdk.chuanglan.dto.*; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.groups.Default; + +/** + * 创蓝 + * + * @author sr on 2020-04-09 + */ +@Validated(Default.class) +public interface ChuangLanService { + + String BEAN_ID = "sdk.chuangLanService"; + String MOCK_BEAN_ID = "mock.chuangLanService"; + + /** + * 二要素(基础) + * + * @param requestDTO 请求dto + * @return {@link AlitaResult}<{@link ChuangLanResultDTO}> + */ + AlitaResult checkRealNameTwoBase(RealNameTwoBaseRequestDTO requestDTO); + + /** + * 手机三要素 + * + * @param phoneThreeRequestDTO 电话请求dto + * @return {@link AlitaResult}<{@link ChuangLanResultDTO}> + */ + AlitaResult checkPhoneThree( + @NotNull @Valid PhoneThreeRequestDTO phoneThreeRequestDTO); + + /** + * 银行卡三要素 + * + * @param bankCardThreeRequestDto + * @return success-false真实调用第三方未成功,未拿到返回值; + * success-true获取到第三方返回,data-true校验成功,data-false校验不一致并返回失败原因(msg) + * @author sr on 2020-04-10 + */ + AlitaResult checkBankCardThree( + @NotNull @Valid BankCardThreeRequestDTO bankCardThreeRequestDto); + + /** + * 银行卡四要素 + * + * @param bankCardFourRequestDto + * @return success-false真实调用第三方未成功,未拿到返回值; + * success-true获取到第三方返回,data-true校验成功,data-false校验不一致并返回失败原因(msg) + * @author sr on 2020-05-22 + */ + AlitaResult checkBankCardFour( + @NotNull @Valid BankCardFourRequestDTO bankCardFourRequestDto); + + /** + * 二要素--实名认证 + * + * @param realNameTwoRequestDTO + * @return success-false真实调用第三方未成功,未拿到返回值; + * success-true获取到第三方返回,data-true校验成功,data-false校验不一致并返回失败原因(msg) + * @author sr on 2020-05-22 + */ + AlitaResult realNameTwoAuthentication( + @NotNull @Valid RealNameTwoRequestDTO realNameTwoRequestDTO); +} diff --git a/backend/src/main/java/com/senmesh/sdk/chuanglan/service/impl/ChuangLanServiceImpl.java b/backend/src/main/java/com/senmesh/sdk/chuanglan/service/impl/ChuangLanServiceImpl.java new file mode 100644 index 0000000..e71456b --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/chuanglan/service/impl/ChuangLanServiceImpl.java @@ -0,0 +1,97 @@ +package com.senmesh.sdk.chuanglan.service.impl; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.annotation.CheckAndMock; +import com.senmesh.sdk.chuanglan.config.ChuangLanCommonProperties; +import com.senmesh.sdk.chuanglan.config.ChuangLanProperties; +import com.senmesh.sdk.chuanglan.constant.BankCardVerifyStateEnum; +import com.senmesh.sdk.chuanglan.constant.ChuangLanConstants; +import com.senmesh.sdk.chuanglan.dto.*; +import com.senmesh.sdk.chuanglan.service.ChuangLanService; +import com.senmesh.sdk.chuanglan.util.ChuangLanUtils; +import com.senmesh.sdk.chuanglan.util.HttpUtilCl; +import com.senmesh.sdk.common.constant.SdkConstants; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * @author fzp on 2021年6月15日16:46:26 + */ +@Slf4j +@Service(ChuangLanService.BEAN_ID) +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class ChuangLanServiceImpl implements ChuangLanService { + + private final ChuangLanProperties chuangLanProperties; + + @Override + @CheckAndMock(mockClass = MockChuangLanServiceImpl.class, + propertyPrefix = ChuangLanProperties.REAL_NAME_TWO_BASE_PREFIX) + public AlitaResult checkRealNameTwoBase(RealNameTwoBaseRequestDTO requestDTO) { + return this.check(requestDTO, chuangLanProperties.getRealName2Base()); + } + + @Override + @CheckAndMock(mockClass = MockChuangLanServiceImpl.class, + propertyPrefix = ChuangLanProperties.PHONE_THREE_PREFIX) + public AlitaResult checkPhoneThree(PhoneThreeRequestDTO requestDTO) { + return this.check(requestDTO, chuangLanProperties.getPhone3()); + } + + @Override + @CheckAndMock(mockClass = MockChuangLanServiceImpl.class, + propertyPrefix = ChuangLanProperties.BANK_CARD_THREE_PREFIX) + public AlitaResult checkBankCardThree(BankCardThreeRequestDTO bankCardThreeRequestDto) { + return this.check(bankCardThreeRequestDto, chuangLanProperties.getBankCard3()); + } + + @Override + @CheckAndMock(mockClass = MockChuangLanServiceImpl.class, + propertyPrefix = ChuangLanProperties.BANK_CARD_FOUR_PREFIX) + public AlitaResult checkBankCardFour(BankCardFourRequestDTO bankCardFourRequestDto) { + return this.check(bankCardFourRequestDto, chuangLanProperties.getBankCard4()); + } + + @Override + @CheckAndMock(mockClass = MockChuangLanServiceImpl.class, + propertyPrefix = ChuangLanProperties.REAL_NAME_TWO_PREFIX) + public AlitaResult realNameTwoAuthentication(RealNameTwoRequestDTO realNameTwoRequestDTO){ + return this.check(realNameTwoRequestDTO, chuangLanProperties.getRealName2()); + } + + /** + * 父类dto 添加请求父类,可以指定appId,appSecret调用接口 + * @param requestDto + * @param commonProperties + * @return + */ + private AlitaResult check(ChuangLanRequestDTO requestDto, ChuangLanCommonProperties commonProperties) { + // 校验部分 + if (commonProperties == null || chuangLanProperties == null) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, + ChuangLanConstants.PROPERTIES_NOT_SET); + } + if (!Boolean.TRUE.equals(chuangLanProperties.getEnable())) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, + "暂不支持要素认证"); + } + if (!ChuangLanUtils.dealAppIdAndSecret(commonProperties, requestDto, chuangLanProperties)) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, + ChuangLanConstants.ID_SECRET_NOT_ENOUGH); + } + // 执行 + ChuangLanResponseDTO responseDto = HttpUtilCl.execute(chuangLanProperties.getDomain().concat(commonProperties.getUrl()), requestDto); + + // 返回结果校验 + if (!ChuangLanConstants.SUC_CODE.equals(responseDto.getCode())) { + // 返回结果验证错误 + return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_RESPONSE_FAIL_CODE, responseDto.getMessage() ); + } + + return BankCardVerifyStateEnum.dealState(responseDto); + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/chuanglan/service/impl/MockChuangLanServiceImpl.java b/backend/src/main/java/com/senmesh/sdk/chuanglan/service/impl/MockChuangLanServiceImpl.java new file mode 100644 index 0000000..dfcf22b --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/chuanglan/service/impl/MockChuangLanServiceImpl.java @@ -0,0 +1,75 @@ +package com.senmesh.sdk.chuanglan.service.impl; + +import com.senmesh.common.AlitaResult; +import com.senmesh.sdk.chuanglan.config.ChuangLanProperties; +import com.senmesh.sdk.chuanglan.dto.*; +import com.senmesh.sdk.chuanglan.service.ChuangLanService; +import com.senmesh.sdk.common.constant.SdkConstants; + +import lombok.extern.slf4j.Slf4j; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +/** + * @author sr on 2020-04-09 + */ +@Service(ChuangLanService.MOCK_BEAN_ID) +@Slf4j +public class MockChuangLanServiceImpl implements ChuangLanService { + + private final static ChuangLanResultDTO result = + ChuangLanResultDTO.builder().status(Boolean.TRUE).build(); + + @Autowired + private ChuangLanProperties chuangLanProperties; + + private AlitaResult check() { + // 校验部分 + if (chuangLanProperties == null || !Boolean.TRUE.equals(chuangLanProperties.getEnable())) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, + "暂不支持要素认证"); + } + return AlitaResult.success(result); + } + + @Override + public AlitaResult checkRealNameTwoBase( + RealNameTwoBaseRequestDTO requestDTO) { + log.info("chuanglan checkRealNameTwoBase mock..."); + return check(); + } + + @Override + public AlitaResult checkPhoneThree( + PhoneThreeRequestDTO phoneThreeRequestDTO) { + log.info("chuanglan checkPhoneThree mock..."); + return check(); + } + + @Override + public AlitaResult checkBankCardThree( + @NotNull @Valid BankCardThreeRequestDTO bankCardThreeRequestDto) { + log.info("chuanglan checkBankCardThree mock..."); + return check(); + } + + + @Override + public AlitaResult checkBankCardFour( + @NotNull @Valid BankCardFourRequestDTO bankCardFourRequestDto) { + log.info("chuanglan checkBankCardFour mock..."); + return check(); + } + + @Override + public AlitaResult realNameTwoAuthentication( + RealNameTwoRequestDTO realNameTwoRequestDTO) { + log.info("chuanglan checkRealNameTwo mock..."); + return check(); + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/chuanglan/util/ChuangLanUtils.java b/backend/src/main/java/com/senmesh/sdk/chuanglan/util/ChuangLanUtils.java new file mode 100644 index 0000000..c0d7e61 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/chuanglan/util/ChuangLanUtils.java @@ -0,0 +1,52 @@ +package com.senmesh.sdk.chuanglan.util; + +import com.senmesh.sdk.chuanglan.config.ChuangLanCommonProperties; +import com.senmesh.sdk.chuanglan.config.ChuangLanProperties; +import com.senmesh.sdk.chuanglan.dto.ChuangLanRequestDTO; +import org.apache.commons.lang3.StringUtils; + +/** + * 工具类 + * + * @author fzp on 2021年6月15日14:22:18 + */ +public final class ChuangLanUtils { + + /** + * 私有 + */ + private ChuangLanUtils() { + throw new IllegalStateException("Utility class"); + } + + /** + * 处理appId和appSecret参数 + * + * @param + * @param commonProperties + * @param requestDto + * @author fzp on 2021年6月15日16:20:49 + */ + public static boolean dealAppIdAndSecret(ChuangLanCommonProperties commonProperties, + T requestDto, ChuangLanProperties chuangLanProperties) { + + String appId = requestDto.getAppId(); + String appKey = requestDto.getAppKey(); + + // 如果appId为空,则从nacos配置文件读取 + if (StringUtils.isBlank(appId) && commonProperties.getEnable()) { + appId = chuangLanProperties.getAppId(); + } + if (StringUtils.isBlank(appKey) && commonProperties.getEnable()) { + appKey = chuangLanProperties.getAppSecret(); + } + if (StringUtils.isBlank(appId) || StringUtils.isBlank(appKey)) { + return false; + } + + requestDto.setAppId(appId); + requestDto.setAppKey(appKey); + return true; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/chuanglan/util/HttpUtilCl.java b/backend/src/main/java/com/senmesh/sdk/chuanglan/util/HttpUtilCl.java new file mode 100644 index 0000000..9f140f5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/chuanglan/util/HttpUtilCl.java @@ -0,0 +1,98 @@ +package com.senmesh.sdk.chuanglan.util; + +import com.senmesh.common.util.JsonUtils; +import com.senmesh.sdk.chuanglan.constant.ChuangLanConstants; +import com.senmesh.sdk.chuanglan.dto.ChuangLanResponseDTO; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.util.StopWatch; +import org.springframework.web.client.RestTemplate; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; + +@Slf4j +@Component +public class HttpUtilCl { + + private static RestTemplate restTemplate; + + @Autowired + public HttpUtilCl() { + this.restTemplate = new RestTemplate(); + } + + /** + * Http 通用请求封装 + * + * @param url 请求地址 + * @param requestDto 请求实体 + * @param + * @param + * @return + */ + public static ChuangLanResponseDTO execute(String url, T requestDto) { + ChuangLanResponseDTO result; + + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + try { + String reqJson = JsonUtils.toJsonString(requestDto); + log.info("chuanglan request url :{}", url); + log.info("chuanglan request requestDto :{}", reqJson); + + MultiValueMap requestBody = new LinkedMultiValueMap(); + Map paramMap = JsonUtils.toMap(reqJson); + paramMap.forEach((k,v) -> { + if(Objects.nonNull(v)){ + requestBody.add(k,v); + } + }); + + // 设置请求头 + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + HttpEntity request = new HttpEntity(requestBody, headers); + String response = restTemplate.postForObject(url, request, String.class); + log.info("chuanglan 响应结果 :{}", response); + + result = formatDto(response); + + } catch (Exception e) { + log.error("chuanglan {} invoke error:{}", requestDto.getClass().getName(), e); + stopWatch.stop(); + return ChuangLanResponseDTO.buildCommonError(); + } + stopWatch.stop(); + log.info("chuanglan consuming {} s", stopWatch.getTotalTimeSeconds()); + + return result; + } + + private static ChuangLanResponseDTO formatDto(String json){ + if(StringUtils.isBlank(json)){ + return ChuangLanResponseDTO.buildCommonError(); + } + ChuangLanResponseDTO result = JsonUtils.toObject(json,ChuangLanResponseDTO.class); + Map map = JsonUtils.toMap(json); + if(map.get("data") != null){ + LinkedHashMap data = (LinkedHashMap) map.get("data"); + // 创蓝接口验证失败 + if(!ChuangLanConstants.IMPL_CODE.equals(data.get("result"))){ + result.setMsg(data.get("remark") + ""); + result.setMessage(data.get("remark") + ""); +// result.setCode(data.get("result") + ""); + } + } + return result; + } + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/sdk/common/config/ApiConfig.java b/backend/src/main/java/com/senmesh/sdk/common/config/ApiConfig.java new file mode 100644 index 0000000..b116f0f --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/common/config/ApiConfig.java @@ -0,0 +1,73 @@ +package com.senmesh.sdk.common.config; + +import java.util.List; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.client.RestTemplate; + +import com.google.common.collect.Lists; + +/** + * @author sr on 2020-04-16 + */ +@Configuration +public class ApiConfig { + + /** + * 读取超时 + **/ + public static final int READ_TIME_OUT = 60000; + /** + * 连接超时 + **/ + public static final int CONNECT_TIME_OUT = 60000; + + @Bean + @ConditionalOnMissingBean + public RestTemplate restTemplate(ClientHttpRequestFactory factory) { + RestTemplate restTemplate = new RestTemplate(factory); + MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); + List mediaTypes = Lists.newArrayList(MediaType.APPLICATION_ATOM_XML, + MediaType.APPLICATION_FORM_URLENCODED, + MediaType.APPLICATION_JSON, + MediaType.APPLICATION_JSON_UTF8, + MediaType.APPLICATION_OCTET_STREAM, + MediaType.APPLICATION_PDF, + MediaType.APPLICATION_PROBLEM_JSON, + MediaType.APPLICATION_PROBLEM_JSON_UTF8, + MediaType.APPLICATION_PROBLEM_XML, + MediaType.APPLICATION_RSS_XML, + MediaType.APPLICATION_STREAM_JSON, + MediaType.APPLICATION_XHTML_XML, + MediaType.APPLICATION_XML, + MediaType.IMAGE_GIF, + MediaType.IMAGE_JPEG, + MediaType.IMAGE_PNG, + MediaType.MULTIPART_FORM_DATA, + MediaType.TEXT_EVENT_STREAM, + MediaType.TEXT_HTML, + MediaType.TEXT_MARKDOWN, + MediaType.TEXT_PLAIN, + MediaType.TEXT_XML); + converter.setSupportedMediaTypes(mediaTypes); + restTemplate.getMessageConverters().add(converter); + return restTemplate; + } + + @Bean + @ConditionalOnMissingBean + public ClientHttpRequestFactory simpleClientHttpRequestFactory() { + SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); + // 单位为ms + factory.setReadTimeout(READ_TIME_OUT); + factory.setConnectTimeout(CONNECT_TIME_OUT); + return factory; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/common/config/ValidConfig.java b/backend/src/main/java/com/senmesh/sdk/common/config/ValidConfig.java new file mode 100644 index 0000000..d25d96d --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/common/config/ValidConfig.java @@ -0,0 +1,18 @@ +package com.senmesh.sdk.common.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.validation.beanvalidation.MethodValidationPostProcessor; + +import javax.validation.Validator; + +@Configuration +public class ValidConfig { + + public MethodValidationPostProcessor methodValidationPostProcessor(Validator validator) { + MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor(); + if (validator != null) { + methodValidationPostProcessor.setValidator(validator); + } + return methodValidationPostProcessor; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/common/constant/SdkConstants.java b/backend/src/main/java/com/senmesh/sdk/common/constant/SdkConstants.java new file mode 100644 index 0000000..97fa9e9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/common/constant/SdkConstants.java @@ -0,0 +1,39 @@ +package com.senmesh.sdk.common.constant; + +/** + * @author sr on 2020-04-10 + */ +public interface SdkConstants { + + String INVOKE_FAIL = "第三方接口调用异常:"; + + /** ()代表错误码中间两位,如060101是放心签错误码 **/ + /** 标识:放心签(01) **/ + String FXQ_CODE = "fxq"; + /** 标识:短信(02) **/ + String SMS_CODE = "sms"; + /** 标识:支付宝(03) **/ + String ALIPAY_CODE = "alipay"; + /** 标识:微信(04) **/ + String WECHAT_CODE = "wechat"; + /** 标识:创蓝(05) **/ + String CL_CODE = "chuanglan"; + + + /** ================ sdk通用异常code ================= **/ + /** 调用异常,未调起第三方 **/ + String SDK_INVOKE_NOT_REACH_CODE = "060000"; + /** 调用异常,http调起第三方异常 **/ + String SDK_HTTP_INVOKE_ERROR_CODE = "060001"; + /** 调用失败,http调起第三方结果返回,非成功码 **/ + String SDK_HTTP_INVOKE_RESPONSE_FAIL_CODE = "060002"; + /** 调用失败(业务),http调起第三方结果返回成功,根据业务判断非成功状态 **/ + String SDK_HTTP_INVOKE_BUSINESS_FAIL_CODE = "060003"; + /** 请求参数异常 **/ + String SDK_REQUEST_PARAM_ERROR_CODE = "060004"; + /** 结果转换失败 **/ + String SDK_RESPONSE_CONVERT_ERROR_CODE = "060005"; + + /** ================ sdk通用异常code ================= **/ + +} diff --git a/backend/src/main/java/com/senmesh/sdk/common/dto/AbstractSdkInvokeLogDTO.java b/backend/src/main/java/com/senmesh/sdk/common/dto/AbstractSdkInvokeLogDTO.java new file mode 100644 index 0000000..cc976f0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/common/dto/AbstractSdkInvokeLogDTO.java @@ -0,0 +1,51 @@ +package com.senmesh.sdk.common.dto; + +import java.io.Serializable; +import java.util.Date; + +import com.senmesh.common.util.RandomUtils; + +import lombok.AllArgsConstructor; +import lombok.Builder.Default; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * sdk 调用日志对象 + * + * @author sr on 2021-01-27 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class AbstractSdkInvokeLogDTO implements Serializable { + + /** **/ + private static final long serialVersionUID = 4230907893212819576L; + + /** 请求对象 **/ + private Object requestData; + /** 结果对象 **/ + private Object responseData; + /** 请求时间 **/ + @Default + private Date requestDate = new Date(); + /** 请求标识 **/ + @Default + private String requestId = RandomUtils.generateUUID(); + /** 具体方法类型 **/ + private String methodType; + /** 调用耗时(单位毫秒) **/ + private Long useTime; + + public String getMethodType() { + if (methodType == null && requestData != null) { + methodType = requestData instanceof ISdkRequest ? ((ISdkRequest) requestData).getMethodName() + : requestData.getClass().getSimpleName(); + } + return methodType; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/common/dto/DefaultSdkInvokeLogDTO.java b/backend/src/main/java/com/senmesh/sdk/common/dto/DefaultSdkInvokeLogDTO.java new file mode 100644 index 0000000..90489f3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/common/dto/DefaultSdkInvokeLogDTO.java @@ -0,0 +1,29 @@ +package com.senmesh.sdk.common.dto; + +import org.springframework.data.annotation.Transient; + +import lombok.AllArgsConstructor; +import lombok.Builder.Default; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 默认sdk调用日志对象 + * @author sr on 2021-03-18 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class DefaultSdkInvokeLogDTO extends AbstractSdkInvokeLogDTO{ + + /** **/ + private static final long serialVersionUID = -7870863791739331150L; + + /** 分类集合名称(mongo使用) **/ + @Transient + @Default + private String collectionName = "default_sdk_invoke_log"; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/common/dto/ISdkRequest.java b/backend/src/main/java/com/senmesh/sdk/common/dto/ISdkRequest.java new file mode 100644 index 0000000..bcab465 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/common/dto/ISdkRequest.java @@ -0,0 +1,55 @@ +package com.senmesh.sdk.common.dto; + +import java.io.Serializable; + +import org.springframework.core.ParameterizedTypeReference; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +/** + * 请求对象 + * @author sr on 2021-03-18 + */ +public interface ISdkRequest extends Serializable{ + + /** + * 方法名 + * @return + * @author sr on 2021-12-27 + */ + @JsonIgnore + default String getMethodName() { + return this.getClass().getSimpleName(); + } + + /** + * 调用uri + * @return + * @author sr on 2021-12-27 + */ + @JsonIgnore + default String getUri() { + return null; + } + + /** + * 结果集普通类型 + * @return + * @author sr on 2021-12-20 + */ + @JsonIgnore + default Class getResponseClass() { + return null; + } + + /** + * 结果集带范性类型 + * @return + * @author sr on 2021-12-20 + */ + @JsonIgnore + default ParameterizedTypeReference getResponseType() { + return null; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/common/dto/ISdkResponse.java b/backend/src/main/java/com/senmesh/sdk/common/dto/ISdkResponse.java new file mode 100644 index 0000000..5e8c410 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/common/dto/ISdkResponse.java @@ -0,0 +1,11 @@ +package com.senmesh.sdk.common.dto; + +import java.io.Serializable; + +/** + * 结果 + * @author sr on 2021-11-24 + */ +public interface ISdkResponse extends Serializable{ + +} diff --git a/backend/src/main/java/com/senmesh/sdk/common/dto/LiteUserPhoneDTO.java b/backend/src/main/java/com/senmesh/sdk/common/dto/LiteUserPhoneDTO.java new file mode 100644 index 0000000..87b8938 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/common/dto/LiteUserPhoneDTO.java @@ -0,0 +1,32 @@ +package com.senmesh.sdk.common.dto; + +import java.io.Serializable; + +import com.senmesh.sdk.wechat.model.Watermark; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 小程序用户手机号信息 + * @author sr on 2021-11-25 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class LiteUserPhoneDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 4564606626820175506L; + + /** 用户绑定的手机号(国外手机号会有区号) **/ + private String phoneNumber; + /** 没有区号的手机号 **/ + private String purePhoneNumber; + /** 区号 **/ + private String countryCode; + /** 数据水印 **/ + private Watermark watermark; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/common/exception/SdkException.java b/backend/src/main/java/com/senmesh/sdk/common/exception/SdkException.java new file mode 100644 index 0000000..025e540 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/common/exception/SdkException.java @@ -0,0 +1,34 @@ +package com.senmesh.sdk.common.exception; + +/** + * @author sr on 2020-04-09 + */ +public class SdkException extends RuntimeException { + + /** **/ + private static final long serialVersionUID = 1139970958567895252L; + + public SdkException() { + super(); + } + + public SdkException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + public SdkException(String message, Throwable cause) { + super(message, cause); + } + + public SdkException(String message) { + super(message); + } + + public SdkException(Throwable cause) { + super(cause); + } + + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/common/util/HttpUtils.java b/backend/src/main/java/com/senmesh/sdk/common/util/HttpUtils.java new file mode 100644 index 0000000..a1078fb --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/common/util/HttpUtils.java @@ -0,0 +1,97 @@ +package com.senmesh.sdk.common.util; + +import java.util.List; + +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.util.StopWatch; +import org.springframework.web.client.RestTemplate; + +import com.google.common.collect.Lists; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.sdk.common.dto.DefaultSdkInvokeLogDTO; +import com.senmesh.sdk.common.dto.ISdkRequest; +import com.senmesh.sdk.common.dto.ISdkResponse; +import com.senmesh.sdk.common.exception.SdkException; + +import lombok.extern.slf4j.Slf4j; + + +/** + * sdk,http调用工具类 + * @author sr on 2022-07-26 + */ +@Slf4j +public class HttpUtils { + + public static RestTemplate restTemplate = new RestTemplate(); + static { + MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); + List mediaTypes = Lists.newArrayList(MediaType.APPLICATION_ATOM_XML, + MediaType.APPLICATION_FORM_URLENCODED, + MediaType.APPLICATION_JSON, + MediaType.APPLICATION_JSON_UTF8, + MediaType.APPLICATION_OCTET_STREAM, + MediaType.APPLICATION_PDF, + MediaType.APPLICATION_PROBLEM_JSON, + MediaType.APPLICATION_PROBLEM_JSON_UTF8, + MediaType.APPLICATION_PROBLEM_XML, + MediaType.APPLICATION_RSS_XML, + MediaType.APPLICATION_STREAM_JSON, + MediaType.APPLICATION_XHTML_XML, + MediaType.APPLICATION_XML, + MediaType.IMAGE_GIF, + MediaType.IMAGE_JPEG, + MediaType.IMAGE_PNG, + MediaType.MULTIPART_FORM_DATA, + MediaType.TEXT_EVENT_STREAM, + MediaType.TEXT_HTML, + MediaType.TEXT_MARKDOWN, + MediaType.TEXT_PLAIN, + MediaType.TEXT_XML); + converter.setSupportedMediaTypes(mediaTypes); + restTemplate.getMessageConverters().add(converter); + } + + public static RES post(ISdkRequest req) throws SdkException { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity httpEntity = new HttpEntity<>(req, headers); + return exchange(req, req.getUri(), httpEntity, HttpMethod.POST); + } + + public static RES exchange(ISdkRequest req, String url, HttpEntity httpEntity, + HttpMethod method) throws SdkException { + Class responseClass = req.getResponseClass(); + ParameterizedTypeReference responseType = req.getResponseType(); + Object requestData = httpEntity.getBody(); + try { + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + ResponseEntity response = null; + if (responseClass != null) { + response = restTemplate.exchange(url, method, httpEntity, responseClass); + } else { + response = + restTemplate.exchange(url, method, httpEntity, + responseType); + } + Object body = response.getBody(); + stopWatch.stop(); + log.info("req:{} invoke:{}, ", req.getClass(), JsonUtils + .toJsonString(DefaultSdkInvokeLogDTO.builder().requestData(requestData).responseData(body) + .useTime(stopWatch.getTotalTimeMillis()) + .methodType(req.getMethodName()) + .build())); + return (RES) body; + } catch (Exception e) { + log.error("req:{}, :{},{}", req.getClass(), JsonUtils.toJsonString(requestData), e); + throw new SdkException(e); + } + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/common/util/LiteEncryptor.java b/backend/src/main/java/com/senmesh/sdk/common/util/LiteEncryptor.java new file mode 100644 index 0000000..78808a4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/common/util/LiteEncryptor.java @@ -0,0 +1,46 @@ +package com.senmesh.sdk.common.util; + +import java.nio.charset.StandardCharsets; +import java.security.AlgorithmParameters; +import java.util.Base64; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.util.JsonUtils; + +import lombok.extern.slf4j.Slf4j; + +/** + * 加密器 + * @author sr on 2021-11-23 + */ +@Slf4j +public class LiteEncryptor { + + public static T decrypt(String encryptData, String iv, String sessionKey, Class clazz) { + String decryptStr ; + try { + AlgorithmParameters algorithmParameters = AlgorithmParameters.getInstance("AES"); + algorithmParameters.init(new IvParameterSpec(Base64.getDecoder().decode(iv))); + Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); + cipher.init(Cipher.DECRYPT_MODE, + new SecretKeySpec(Base64.getDecoder().decode(sessionKey), "AES"), algorithmParameters); + byte[] decode = PKCS7Encoder.decode(cipher.doFinal(Base64.getDecoder().decode(encryptData))); + decryptStr = new String(decode, StandardCharsets.US_ASCII); + } catch (Exception e) { + log.error("微信解密失败:", e); + throw new BusinessException("微信解密失败"); + } + try { + return JsonUtils.toObject(decryptStr, clazz); + } catch (Exception e) { + log.debug(decryptStr); + throw new BusinessException("微信解密失败(可能小程序session_key过期)"); + } + + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/common/util/PKCS7Encoder.java b/backend/src/main/java/com/senmesh/sdk/common/util/PKCS7Encoder.java new file mode 100644 index 0000000..0161fef --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/common/util/PKCS7Encoder.java @@ -0,0 +1,67 @@ +/** + * 对企业微信发送给企业后台的消息加解密示例代码. + * + * @copyright Copyright (c) 1998-2014 Tencent Inc. + */ + +// ------------------------------------------------------------------------ + +package com.senmesh.sdk.common.util; + +import java.nio.charset.Charset; +import java.util.Arrays; + +/** + * 提供基于PKCS7算法的加解密接口. + */ +class PKCS7Encoder { + static Charset CHARSET = Charset.forName("utf-8"); + static int BLOCK_SIZE = 32; + + /** + * 获得对明文进行补位填充的字节. + * + * @param count 需要进行填充补位操作的明文字节个数 + * @return 补齐用的字节数组 + */ + static byte[] encode(int count) { + // 计算需要填充的位数 + int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE); + if (amountToPad == 0) { + amountToPad = BLOCK_SIZE; + } + // 获得补位所用的字符 + char padChr = chr(amountToPad); + String tmp = new String(); + for (int index = 0; index < amountToPad; index++) { + tmp += padChr; + } + return tmp.getBytes(CHARSET); + } + + /** + * 删除解密后明文的补位字符 + * + * @param decrypted 解密后的明文 + * @return 删除补位字符后的明文 + */ + static byte[] decode(byte[] decrypted) { + int pad = (int) decrypted[decrypted.length - 1]; + if (pad < 1 || pad > 32) { + pad = 0; + } + return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad); + } + + /** + * 将数字转化成ASCII码对应的字符,用于对明文进行补码 + * + * @param a 需要转化的数字 + * @return 转化得到的字符 + */ + static char chr(int a) { + byte target = (byte) (a & 0xFF); + return (char) target; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/deepseek/config/DeepSeekProperties.java b/backend/src/main/java/com/senmesh/sdk/deepseek/config/DeepSeekProperties.java new file mode 100644 index 0000000..3740b78 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/deepseek/config/DeepSeekProperties.java @@ -0,0 +1,29 @@ +package com.senmesh.sdk.deepseek.config; + +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@ConfigurationProperties(prefix = DeepSeekProperties.PREFIX) +@Data +@Component +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class DeepSeekProperties implements Serializable{ + + /** **/ + private static final long serialVersionUID = 6362606996602121889L; + + public static final String PREFIX = "deepseek"; + + /** 控制台获取http服务接口认证信息中的APIPassword **/ + private String httpAPIPassword; + + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/deepseek/service/DeepSeekProvider.java b/backend/src/main/java/com/senmesh/sdk/deepseek/service/DeepSeekProvider.java new file mode 100644 index 0000000..0f2a74b --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/deepseek/service/DeepSeekProvider.java @@ -0,0 +1,65 @@ +package com.senmesh.sdk.deepseek.service; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.sdk.common.constant.SdkConstants; +import com.senmesh.sdk.common.dto.DefaultSdkInvokeLogDTO; +import com.senmesh.sdk.common.util.HttpUtils; +import com.senmesh.sdk.deepseek.config.DeepSeekProperties; +import com.senmesh.sdk.xf.model.ChatReq; +import com.senmesh.sdk.xf.model.ChatRes; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class DeepSeekProvider { + + private static DeepSeekProperties deepSeekProperties; + + private DeepSeekProvider(DeepSeekProperties deepSeekProperties) { + DeepSeekProvider.deepSeekProperties = deepSeekProperties; + } + + public static AlitaResult httpChat(ChatReq req) { + return httpChat(req, deepSeekProperties.getHttpAPIPassword()); + } + + + public static AlitaResult httpChat(ChatReq req, String httpAPIPassword) { + ResponseEntity response = null; + try { + try { + HttpHeaders header = new HttpHeaders(); + header.add("Authorization", "Bearer " + httpAPIPassword); + header.add("Content-Type", "application/json"); + // 发送请求 + HttpEntity requestEntity = new HttpEntity(req, header); + response = + HttpUtils.restTemplate.exchange("https://api.deepseek.com/chat/completions", + HttpMethod.POST, requestEntity, ChatRes.class); + } catch (Exception e) { + log.error("http error:{}", e.getMessage()); + return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_ERROR_CODE, e.getMessage()); + } + try { + String content = response.getBody().getChoices().get(0).getMessage().getContent(); + return AlitaResult.success(content); + } catch (Exception e) { + return AlitaResult.error(SdkConstants.SDK_RESPONSE_CONVERT_ERROR_CODE, "返回结果获取content失败"); + } + + } finally { + log.info("invoke:{}", + JsonUtils + .toJsonString( + DefaultSdkInvokeLogDTO.builder().requestData(req).responseData(response) + .build())); + } + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/dify/config/DifyConfig.java b/backend/src/main/java/com/senmesh/sdk/dify/config/DifyConfig.java new file mode 100644 index 0000000..fbe48ed --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/dify/config/DifyConfig.java @@ -0,0 +1,23 @@ +package com.senmesh.sdk.dify.config; + +import lombok.Data; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +/** + * Dify配置 + * + * @author sr + */ +@Data +@Configuration +@EnableConfigurationProperties(DifyProperties.class) +@ConditionalOnProperty(name = DifyConfig.DIFY_ENABLE, havingValue = "true") +public class DifyConfig { + + static final String DIFY_ENABLE = "dify.enable"; + +} + diff --git a/backend/src/main/java/com/senmesh/sdk/dify/config/DifyProperties.java b/backend/src/main/java/com/senmesh/sdk/dify/config/DifyProperties.java new file mode 100644 index 0000000..5716f90 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/dify/config/DifyProperties.java @@ -0,0 +1,32 @@ +package com.senmesh.sdk.dify.config; + +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * Dify配置属性 + * + * @author sr + */ +@ConfigurationProperties(prefix = DifyProperties.PREFIX) +@Data +@Component +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class DifyProperties implements Serializable { + + private static final long serialVersionUID = 1L; + + public static final String PREFIX = "dify"; + + /** Dify服务地址 */ + private String host; + +} + diff --git a/backend/src/main/java/com/senmesh/sdk/dify/dto/DifyChatRequest.java b/backend/src/main/java/com/senmesh/sdk/dify/dto/DifyChatRequest.java new file mode 100644 index 0000000..9b8a702 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/dify/dto/DifyChatRequest.java @@ -0,0 +1,74 @@ +package com.senmesh.sdk.dify.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Dify对话请求 + * + * @author sr + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class DifyChatRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 输入参数 */ + private Map inputs; + + /** 查询内容 */ + private String query; + + /** 响应模式: blocking/streaming */ + @JsonProperty("response_mode") + @Builder.Default + private String responseMode = "blocking"; + + /** 会话ID */ + @JsonProperty("conversation_id") + private String conversationId; + + /** 用户标识 */ + private String user; + + /** 文件列表 */ + private List files; + + /** + * 文件信息 + */ + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class DifyFileInfo implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 文件类型: image/document */ + private String type; + + /** 传输方式: remote_url/local_file */ + @JsonProperty("transfer_method") + @Builder.Default + private String transferMethod = "local_file"; + + /** 远程URL */ + private String url; + + /** 上传文件ID */ + @JsonProperty("upload_file_id") + private String uploadFileId; + } + +} + diff --git a/backend/src/main/java/com/senmesh/sdk/dify/dto/DifyChatResponse.java b/backend/src/main/java/com/senmesh/sdk/dify/dto/DifyChatResponse.java new file mode 100644 index 0000000..00a9552 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/dify/dto/DifyChatResponse.java @@ -0,0 +1,164 @@ +package com.senmesh.sdk.dify.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Dify对话响应 + * + * @author sr + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class DifyChatResponse implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 消息ID */ + @JsonProperty("message_id") + private String messageId; + + /** 会话ID */ + @JsonProperty("conversation_id") + private String conversationId; + + /** 模式 */ + private String mode; + + /** 回答内容 */ + private String answer; + + /** 元数据 */ + private Metadata metadata; + + /** 创建时间 */ + @JsonProperty("created_at") + private Long createdAt; + + /** + * 元数据 + */ + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class Metadata implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 使用量 */ + private Usage usage; + + /** 检索器资源 */ + @JsonProperty("retriever_resources") + private List retrieverResources; + } + + /** + * 使用量 + */ + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class Usage implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 提示词token数 */ + @JsonProperty("prompt_tokens") + private Integer promptTokens; + + /** 提示词单位价格 */ + @JsonProperty("prompt_unit_price") + private String promptUnitPrice; + + /** 提示词价格单位 */ + @JsonProperty("prompt_price_unit") + private String promptPriceUnit; + + /** 提示词价格 */ + @JsonProperty("prompt_price") + private String promptPrice; + + /** 完成token数 */ + @JsonProperty("completion_tokens") + private Integer completionTokens; + + /** 完成单位价格 */ + @JsonProperty("completion_unit_price") + private String completionUnitPrice; + + /** 完成价格单位 */ + @JsonProperty("completion_price_unit") + private String completionPriceUnit; + + /** 完成价格 */ + @JsonProperty("completion_price") + private String completionPrice; + + /** 总token数 */ + @JsonProperty("total_tokens") + private Integer totalTokens; + + /** 总价格 */ + @JsonProperty("total_price") + private String totalPrice; + + /** 货币 */ + private String currency; + + /** 延迟(毫秒) */ + private Double latency; + } + + /** + * 检索器资源 + */ + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class RetrieverResource implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 位置 */ + private Integer position; + + /** 数据集ID */ + @JsonProperty("dataset_id") + private String datasetId; + + /** 数据集名称 */ + @JsonProperty("dataset_name") + private String datasetName; + + /** 文档ID */ + @JsonProperty("document_id") + private String documentId; + + /** 文档名称 */ + @JsonProperty("document_name") + private String documentName; + + /** 分段ID */ + @JsonProperty("segment_id") + private String segmentId; + + /** 分数 */ + private Double score; + + /** 内容 */ + private String content; + } + +} + diff --git a/backend/src/main/java/com/senmesh/sdk/dify/dto/DifyFileUploadRequest.java b/backend/src/main/java/com/senmesh/sdk/dify/dto/DifyFileUploadRequest.java new file mode 100644 index 0000000..49dd798 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/dify/dto/DifyFileUploadRequest.java @@ -0,0 +1,36 @@ +package com.senmesh.sdk.dify.dto; + +import java.io.InputStream; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Dify文件上传请求 + * + * @author sr + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class DifyFileUploadRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 文件输入流 */ + private InputStream inputStream; + + /** 文件名 */ + private String fileName; + + /** 文件MIME类型 */ + private String contentType; + + /** 用户标识 */ + private String user; + +} + diff --git a/backend/src/main/java/com/senmesh/sdk/dify/dto/DifyFileUploadResponse.java b/backend/src/main/java/com/senmesh/sdk/dify/dto/DifyFileUploadResponse.java new file mode 100644 index 0000000..4975a50 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/dify/dto/DifyFileUploadResponse.java @@ -0,0 +1,47 @@ +package com.senmesh.sdk.dify.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Dify文件上传响应 + * + * @author sr + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class DifyFileUploadResponse implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 文件ID */ + private String id; + + /** 文件名 */ + private String name; + + /** 文件大小 */ + private Long size; + + /** 文件扩展名 */ + private String extension; + + /** MIME类型 */ + @JsonProperty("mime_type") + private String mimeType; + + /** 创建者 */ + @JsonProperty("created_by") + private String createdBy; + + /** 创建时间 */ + @JsonProperty("created_at") + private Long createdAt; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/sdk/dify/service/DifyClient.java b/backend/src/main/java/com/senmesh/sdk/dify/service/DifyClient.java new file mode 100644 index 0000000..602f7e6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/dify/service/DifyClient.java @@ -0,0 +1,215 @@ +package com.senmesh.sdk.dify.service; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.sdk.common.constant.SdkConstants; +import com.senmesh.sdk.common.util.HttpUtils; +import com.senmesh.sdk.dify.config.DifyProperties; +import com.senmesh.sdk.dify.dto.DifyChatRequest; +import com.senmesh.sdk.dify.dto.DifyChatResponse; +import com.senmesh.sdk.dify.dto.DifyFileUploadRequest; +import com.senmesh.sdk.dify.dto.DifyFileUploadResponse; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +/** + * Dify客户端 + * + * @author sr + */ +@Slf4j +@Component +public class DifyClient { + + private static DifyProperties difyProperties; + + private static final String FILE_UPLOAD_URI = "/v1/files/upload"; + private static final String CHAT_MESSAGES_URI = "/v1/chat-messages"; + + /** + * 构造方法 - 用于Spring注入,同时设置静态变量 + */ + @Autowired + public DifyClient(DifyProperties difyProperties) { + DifyClient.difyProperties = difyProperties; + } + + /** + * 上传文件到Dify(静态方法 - 只传apiKey) + * + * @param apiKey API密钥 + * @param request 文件上传请求 + * @return 上传结果 + */ + public static AlitaResult uploadFile(String apiKey, DifyFileUploadRequest request) { + if (difyProperties == null) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "DifyProperties未初始化"); + } + return uploadFile(difyProperties.getHost(), apiKey, request); + } + + /** + * 上传文件到Dify(静态方法) + * + * @param host Dify服务地址 + * @param apiKey API密钥 + * @param request 文件上传请求 + * @return 上传结果 + */ + public static AlitaResult uploadFile(String host, String apiKey, DifyFileUploadRequest request) { + try { + // 参数校验 + if (StringUtils.isBlank(host)) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "Dify服务地址不能为空"); + } + if (StringUtils.isBlank(apiKey)) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "API密钥不能为空"); + } + if (request == null || request.getInputStream() == null) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "文件输入流不能为空"); + } + if (StringUtils.isBlank(request.getFileName())) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "文件名不能为空"); + } + if (StringUtils.isBlank(request.getUser())) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "用户标识不能为空"); + } + + String url = host + FILE_UPLOAD_URI; + + // 构建请求头 + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.MULTIPART_FORM_DATA); + headers.set("Authorization", "Bearer " + apiKey); + + // 构建请求体 + MultiValueMap body = new LinkedMultiValueMap<>(); + + // 将InputStream转换为ByteArrayResource + byte[] fileBytes = org.springframework.util.StreamUtils.copyToByteArray(request.getInputStream()); + ByteArrayResource fileResource = new ByteArrayResource(fileBytes) { + @Override + public String getFilename() { + return request.getFileName(); + } + + /* @Override + public String getDescription() { + try { + return HttpURLConnection.guessContentTypeFromStream(request.getInputStream()); + } catch (IOException e) { + return null; + } + }*/ + }; + + body.add("file", fileResource); + body.add("user", request.getUser()); + + HttpEntity> requestEntity = new HttpEntity<>(body, headers); + + log.info("dify uploadFile request url:{}, user:{}, fileName:{}", + url, request.getUser(), request.getFileName()); + + // 发送请求 + ResponseEntity response = HttpUtils.restTemplate.exchange( + url, + HttpMethod.POST, + requestEntity, + DifyFileUploadResponse.class + ); + + DifyFileUploadResponse result = response.getBody(); + log.info("dify uploadFile response:{}", JsonUtils.toJsonString(result)); + + return AlitaResult.success(result); + + } catch (Exception e) { + log.error("dify uploadFile error:", e); + return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_ERROR_CODE, e.getMessage()); + } + } + + /** + * 发送对话消息(静态方法 - 只传apiKey) + * + * @param apiKey API密钥 + * @param request 对话请求 + * @return 对话结果 + */ + public static AlitaResult chatMessages(String apiKey, DifyChatRequest request) { + if (difyProperties == null) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "DifyProperties未初始化"); + } + return chatMessages(difyProperties.getHost(), apiKey, request); + } + + /** + * 发送对话消息(静态方法) + * + * @param host Dify服务地址 + * @param apiKey API密钥 + * @param request 对话请求 + * @return 对话结果 + */ + public static AlitaResult chatMessages(String host, String apiKey, DifyChatRequest request) { + try { + // 参数校验 + if (StringUtils.isBlank(host)) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "Dify服务地址不能为空"); + } + if (StringUtils.isBlank(apiKey)) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "API密钥不能为空"); + } + if (request == null) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "请求参数不能为空"); + } + if (StringUtils.isBlank(request.getQuery())) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "查询内容不能为空"); + } + if (StringUtils.isBlank(request.getUser())) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "用户标识不能为空"); + } + + String url = host + CHAT_MESSAGES_URI; + + // 构建请求头 + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.set("Authorization", "Bearer " + apiKey); + + HttpEntity requestEntity = new HttpEntity<>(request, headers); + + log.info("dify chatMessages request url:{}, body:{}", url, JsonUtils.toJsonString(request)); + + // 发送请求 + ResponseEntity response = HttpUtils.restTemplate.exchange( + url, + HttpMethod.POST, + requestEntity, + DifyChatResponse.class + ); + + DifyChatResponse result = response.getBody(); + log.info("dify chatMessages response:{}", JsonUtils.toJsonString(result)); + + return AlitaResult.success(result); + + } catch (Exception e) { + log.error("dify chatMessages error:", e); + return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_ERROR_CODE, e.getMessage()); + } + } + +} + diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/config/FxqCommonProperties.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/config/FxqCommonProperties.java new file mode 100644 index 0000000..cf93715 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/config/FxqCommonProperties.java @@ -0,0 +1,24 @@ +package com.senmesh.sdk.fangxinqian.config; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-04-09 + */ +@Data +@NoArgsConstructor +public class FxqCommonProperties{ + + /** 是否启用 **/ + private Boolean enable = Boolean.FALSE; + /** id **/ + private String appId; + /** secret **/ + private String appSecret; + /** 接口地址 **/ + private String url; + /** 次数限制 **/ + private Long numLimit; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/config/FxqContractExtensionProperties.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/config/FxqContractExtensionProperties.java new file mode 100644 index 0000000..cf3a441 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/config/FxqContractExtensionProperties.java @@ -0,0 +1,24 @@ +package com.senmesh.sdk.fangxinqian.config; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 合同相关配置 + */ +@Data +@NoArgsConstructor +public class FxqContractExtensionProperties { + /** + * 是否启用 + **/ + private Boolean enable = Boolean.FALSE; + /** + * 接口地址 + **/ + private String url; + /** + * 次数限制 + **/ + private Long numLimit; +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/config/FxqContractProperties.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/config/FxqContractProperties.java new file mode 100644 index 0000000..ee5af9c --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/config/FxqContractProperties.java @@ -0,0 +1,39 @@ +package com.senmesh.sdk.fangxinqian.config; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 合同相关配置 + */ +@Data +@NoArgsConstructor +public class FxqContractProperties extends FxqCommonProperties { + + /** + * 普通签署 + */ + private FxqContractExtensionProperties commonSign; + /** + * 关键字签署 + */ + private FxqContractExtensionProperties keySign; + /** + * 存证 + */ + private FxqContractExtensionProperties evidenceSave; + /** + * 出证 + */ + private FxqContractExtensionProperties evidenceGet; + + public FxqCommonProperties build(FxqContractExtensionProperties properties) { + FxqCommonProperties result = new FxqCommonProperties(); + result.setAppId(this.getAppId()); + result.setAppSecret(this.getAppSecret()); + result.setEnable(properties.getEnable()); + result.setNumLimit(properties.getNumLimit()); + result.setUrl(properties.getUrl()); + return result; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/config/FxqProperties.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/config/FxqProperties.java new file mode 100644 index 0000000..a2d4586 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/config/FxqProperties.java @@ -0,0 +1,112 @@ +package com.senmesh.sdk.fangxinqian.config; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 放心签配置 + * + * @author sr on 2020-04-09 + */ +@ConfigurationProperties(prefix = FxqProperties.PREFIX, ignoreUnknownFields = false) +@Data +@Component +@NoArgsConstructor +public class FxqProperties { + + /** + * 放心签配置前缀 + **/ + public static final String PREFIX = "fangxinqian"; + /** + * 放心签三要素配置前缀 + **/ + public static final String BANK_CARD_THREE_PREFIX = PREFIX + ".bankCard3"; + /** + * 放心签四要素配置前缀 + **/ + public static final String BANK_CARD_FOUR_PREFIX = PREFIX + ".bankCard4"; + + /** + * 实名认证配置前缀 + */ + public static final String REALNAME_AUTH_PREFIX = PREFIX + ".realname"; + + /** + * 工商核验 + */ + public static final String GOVERNMENT_AUTH_PREFIX = PREFIX + ".government"; + + /** + * 普通签署 + */ + public static final String COMMON_SIGN_PREFIX = PREFIX + ".contract.commonSign"; + + /** + * 关键字签署 + */ + public static final String KEY_SIGN_PREFIX = PREFIX + ".contract.keySign"; + /** + * 存证 + */ + public static final String EVIDENCE_SAVE_PREFIX = PREFIX + ".contract.evidenceSave"; + + /** + * 出证 + */ + public static final String EVIDENCE_GET_PREFIX = PREFIX + ".contract.evidenceGet"; + + + /** + * https://api.fangxinqian.cn + */ + private String domain; + + /** + * 系统预留手机号 + */ + private String phone; + + /** + * 公章uri + */ + private String officialSealUri; + + /** + * 个人章uri + */ + private String personalSealUri; + + /** + * 合同关键字替换 + */ + private String textReplaceUri; + + /** + * 银行卡三要素配置 + **/ + private FxqCommonProperties bankCard3; + + /** + * 银行卡四要素配置 + **/ + private FxqCommonProperties bankCard4; + + /** + * 实名认证配置 + */ + private FxqCommonProperties realName; + + /** + * 工商信息核验配置 + */ + private FxqCommonProperties government; + + /** + * 合同 + */ + private FxqContractProperties contract; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/constant/BankCardFourStateEnum.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/constant/BankCardFourStateEnum.java new file mode 100644 index 0000000..4de5719 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/constant/BankCardFourStateEnum.java @@ -0,0 +1,66 @@ +package com.senmesh.sdk.fangxinqian.constant; + +import java.util.Map; + +import com.google.common.collect.Maps; +import com.senmesh.common.AlitaResult; + +/** + * 银行三要素验证结果枚举 + * + * @author sr on 2020-04-10 + */ +public enum BankCardFourStateEnum { + /** 验证一致 **/ + SUC("1", "验证一致"), + /** 验证不一致 **/ + FAIL("2", "验证不一致"); + + private static Map stateMap; + /** 验证结果 **/ + private String state; + /** 说明 **/ + private String msg; + + + BankCardFourStateEnum(String state, String msg) { + this.state = state; + this.msg = msg; + } + + static { + BankCardFourStateEnum[] array = BankCardFourStateEnum.values(); + stateMap = Maps.newHashMapWithExpectedSize(array.length); + for (BankCardFourStateEnum stateEnum : array) { + stateMap.put(stateEnum.getState(), stateEnum); + } + } + + public String getState() { + return state; + } + + public String getMsg() { + return msg; + } + + /** + * 处理验证结果 + * + * @param state + * @return + * @author sr on 2020-04-10 + */ + public static AlitaResult dealState(String state) { + BankCardFourStateEnum stateEnum = stateMap.get(state); + if (stateEnum == null) { + return AlitaResult.success("state not available...", false); + } + if (stateEnum == SUC) { + return AlitaResult.success(true); + } + return AlitaResult.success(stateEnum.getMsg(), false); + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/constant/BankCardThreeStateEnum.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/constant/BankCardThreeStateEnum.java new file mode 100644 index 0000000..75d3910 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/constant/BankCardThreeStateEnum.java @@ -0,0 +1,68 @@ +package com.senmesh.sdk.fangxinqian.constant; + +import java.util.Map; + +import com.google.common.collect.Maps; +import com.senmesh.common.AlitaResult; + +/** + * 银行三要素验证结果枚举 + * + * @author sr on 2020-04-10 + */ +public enum BankCardThreeStateEnum { + /** 验证一致 **/ + SUC("1", "验证一致"), + /** 验证不一致 **/ + FAIL("2", "验证不一致"), + /** 异常情况 **/ + UNKNOWN("3", "异常情况"); + + private static Map stateMap; + /** 验证结果 **/ + private String state; + /** 说明 **/ + private String msg; + + + BankCardThreeStateEnum(String state, String msg) { + this.state = state; + this.msg = msg; + } + + static { + BankCardThreeStateEnum[] array = BankCardThreeStateEnum.values(); + stateMap = Maps.newHashMapWithExpectedSize(array.length); + for (BankCardThreeStateEnum stateEnum : array) { + stateMap.put(stateEnum.getState(), stateEnum); + } + } + + public String getState() { + return state; + } + + public String getMsg() { + return msg; + } + + /** + * 处理验证结果 + * + * @param state + * @return + * @author sr on 2020-04-10 + */ + public static AlitaResult dealState(String state) { + BankCardThreeStateEnum stateEnum = stateMap.get(state); + if (stateEnum == null) { + return AlitaResult.success("state not available...", false); + } + if (stateEnum == SUC) { + return AlitaResult.success(true); + } + return AlitaResult.success(stateEnum.getMsg(), false); + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/constant/FxqConstants.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/constant/FxqConstants.java new file mode 100644 index 0000000..d85fdb9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/constant/FxqConstants.java @@ -0,0 +1,19 @@ +package com.senmesh.sdk.fangxinqian.constant; + +import com.senmesh.sdk.common.constant.SdkConstants; + +/** + * @author sr on 2020-04-10 + */ +public interface FxqConstants { + + /** 成功码 **/ + String SUC_CODE = "10000"; + + /** ================ fxq 调起真实服务前异常msg ================= **/ + String PROPERTIES_NOT_SET = SdkConstants.FXQ_CODE + ":配置文件未配置"; + String ID_SECRET_NOT_ENOUGH = SdkConstants.FXQ_CODE + ":参数appId或appSecret缺失"; + /** ================ fxq 调起真实服务前异常msq ================= **/ + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/constant/FxqErrorCodeEnum.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/constant/FxqErrorCodeEnum.java new file mode 100644 index 0000000..51995ad --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/constant/FxqErrorCodeEnum.java @@ -0,0 +1,33 @@ +package com.senmesh.sdk.fangxinqian.constant; + +/** + * sdk放心签错误码枚举;标识:放心签(01) + * @author sr on 2020-05-22 + */ +public enum FxqErrorCodeEnum { + + /** 放心签调用返回错误码 **/ + INVOKE_RETURN_ERROR("060101", "放心签接口调用失败,返回错误码"), + /** 放心签调用成功,但信息不匹配 **/ + NOT_EQUAL("060102", "不匹配"); + + /** 错误码 **/ + private String code; + /** 错误信息 **/ + private String msg; + + FxqErrorCodeEnum(String code, String msg){ + this.code = code; + this.msg = msg; + } + + public String getCode() { + return code; + } + + public String getMsg() { + return msg; + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/BankCardFourRequestDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/BankCardFourRequestDTO.java new file mode 100644 index 0000000..446ea8c --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/BankCardFourRequestDTO.java @@ -0,0 +1,40 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 银行卡四要素请求 + * + * @author sr on 2020-04-09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class BankCardFourRequestDTO extends FxqRequestDTO implements Serializable { + + /** **/ + private static final long serialVersionUID = 3807618123977056991L; + + /** 姓名 **/ + @NotBlank(message = "姓名不能为空") + private String name; + /** 身份证号 **/ + @NotBlank(message = "身份证号不能为空") + private String identityCode; + /** 银行卡号 **/ + @NotBlank(message = "银行卡号不能为空") + private String bankcardNumber; + @NotBlank(message = "手机号码不能为空") + private String phoneNumber; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/BankCardFourResponseDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/BankCardFourResponseDTO.java new file mode 100644 index 0000000..a4705ff --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/BankCardFourResponseDTO.java @@ -0,0 +1,29 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.ToString; + +/** + * 银行卡四要素请求 + * + * @author sr on 2020-04-09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ToString(callSuper = true) +public class BankCardFourResponseDTO extends FxqResponseDTO { + + /** **/ + private static final long serialVersionUID = 3188936116187424875L; + + /** 结果data **/ + private StateDataDTO data; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/BankCardThreeRequestDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/BankCardThreeRequestDTO.java new file mode 100644 index 0000000..ba156ae --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/BankCardThreeRequestDTO.java @@ -0,0 +1,38 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 银行卡三要素请求 + * + * @author sr on 2020-04-09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class BankCardThreeRequestDTO extends FxqRequestDTO implements Serializable { + + /** **/ + private static final long serialVersionUID = -6539738426193243916L; + + /** 姓名 **/ + @NotBlank(message = "姓名不能为空") + private String name; + /** 身份证号 **/ + @NotBlank(message = "身份证号不能为空") + private String identityCode; + /** 银行卡号 **/ + @NotBlank(message = "银行卡号不能为空") + private String bankcardNumber; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/BankCardThreeResponseDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/BankCardThreeResponseDTO.java new file mode 100644 index 0000000..c63e596 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/BankCardThreeResponseDTO.java @@ -0,0 +1,29 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.ToString; + +/** + * 银行卡三要素请求 + * + * @author sr on 2020-04-09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ToString(callSuper = true) +public class BankCardThreeResponseDTO extends FxqResponseDTO { + + /** **/ + private static final long serialVersionUID = 3188936116187424875L; + + /** 结果data **/ + private StateDataDTO data; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/ContractRequestDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/ContractRequestDTO.java new file mode 100644 index 0000000..15b8464 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/ContractRequestDTO.java @@ -0,0 +1,113 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import lombok.*; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 合同签署请求DTO + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ContractRequestDTO extends FxqRequestDTO { + private static final long serialVersionUID = 7354207669664708465L; + + /** + * 合同⽂件(base64/云存储⽂件链接) + */ + @NotBlank(message = "合同⽂件不能为空") + private String contract; + + /** + * 合同文件名 + */ + @NotBlank(message = "合同⽂件名不能为空") + private String title; + + /** + * 0.返回签署完成的base64 1.返回云存储⽂件链接 不填默认 0 + */ + private String returnType; + + /** + * 签署⼈信息 + */ + @Valid + @NotNull(message = "签署⼈信息不能为空") + private List signers; + + /** + * 签署人信息 + */ + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class CommonSignSigner { + /** + * 真实姓名/公司名称 + */ + @NotBlank(message = "签署人名称不能为空") + private String name; + + /** + * 身份证号码/统⼀信⽤代码 + */ + @NotBlank(message = "签署人证件信息不能为空") + private String idcard; + + /** + * 签章图⽚⽂件 + */ + @NotBlank(message = "签章图⽚⽂件信息不能为空") + private String img; + + /** + * 个⼈传⼿机号码,企业传法⼈⼿机号码/公司简称的拼⾳⾸字⺟ 如葫芦娃:hlw + */ + @NotBlank(message = "手机号不能为空") + private String phone; + + /** + * 该值控制骑缝章位置 ⼤于100 表示需要签署骑缝章 双⽅骑缝章 位置间隔建议⼤于100 最⼤不能超过650 + */ + private Integer gapMargin; + + /** + * 签署区域 (普通签署方式) + */ + private List areas; + + /** + * 签署关键字 (关键字签署方式) + */ + private String key; + /** + * 签章签署在距离关键字距离 正数(往右)负数(往左) (关键字签署方式) + */ + private Integer marginLeft; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class Area { + @NotNull(message = "签署区域左下⻆点X坐标不能为空") + private Integer x1; + @NotNull(message = "签署区域左下⻆点Y坐标不能为空") + private Integer y1; + @NotNull(message = "签署区域右上⻆点X坐标不能为空") + private Integer x2; + @NotNull(message = "签署区域右上⻆点Y坐标不能为空") + private Integer y2; + @NotNull(message = "签署⻚数不能为空") + private Integer page; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/ContractResponseDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/ContractResponseDTO.java new file mode 100644 index 0000000..a674b2d --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/ContractResponseDTO.java @@ -0,0 +1,17 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import lombok.Data; + +@Data +public class ContractResponseDTO extends FxqResponseDTO { + + /** + * 文件base64或云链接 + */ + private String data; + + @Override + protected String handleData() { + return this.data; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/EvidenceGetRequestDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/EvidenceGetRequestDTO.java new file mode 100644 index 0000000..61cdc34 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/EvidenceGetRequestDTO.java @@ -0,0 +1,23 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import lombok.*; + +import javax.validation.constraints.NotNull; + +/** + * 区块链出证请求DTO + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class EvidenceGetRequestDTO extends FxqRequestDTO { + private static final long serialVersionUID = 7354207669664708465L; + + /** + * 合同区块链存证时的回执 + */ + @NotNull(message = "回执不能为空") + private String evidenceID; +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/EvidenceGetResponseDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/EvidenceGetResponseDTO.java new file mode 100644 index 0000000..b4c48b1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/EvidenceGetResponseDTO.java @@ -0,0 +1,17 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import lombok.Data; + +@Data +public class EvidenceGetResponseDTO extends FxqResponseDTO { + + /** + * 证据链上地址 + */ + private String data; + + @Override + protected String handleData() { + return this.data; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/EvidenceSaveRequestDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/EvidenceSaveRequestDTO.java new file mode 100644 index 0000000..5cf0f18 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/EvidenceSaveRequestDTO.java @@ -0,0 +1,96 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import lombok.*; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 区块链存证请求DTO + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class EvidenceSaveRequestDTO extends FxqRequestDTO { + private static final long serialVersionUID = 7354207669664708465L; + + /** + * 合同⽂件(base64/云存储⽂件链接) + */ + @NotBlank(message = "合同⽂件不能为空") + private String contract; + + /** + * 合同名称 + */ + @NotBlank(message = "合同名称不能为空") + private String title; + + /** + * ⾏业类型 + * 1 政务⺠⽣ + * 2 保险 + * 3 银⾏ + * 4 消费⾦融-资产 + * 5 消费⾦融-资⾦ + * 6 持牌⼩贷 + * 7 医疗 + * 8 教育 + * 9 出⾏与交通 + * 10 ⽣活服务 + * 11 通信与运营商 + * 12 旅游与酒店 + * 13 快递与邮政 + * 99 其他 + */ + @NotBlank(message = "⾏业类型不能为空") + private String industry; + + /** + * 签署⼈信息 + */ + @NotNull(message = "签署⼈列表") + private List userInfos; + + /** + * 合同签署⼈列表 + */ + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class UserInfo { + /** + * 真实姓名/公司名称 + */ + @NotBlank(message = "签署人姓名不能为空") + private String userName; + + /** + * ⽤户类型 0.个⼈ 1.企业 + */ + @NotBlank(message = "⽤户类型不能为空") + private String customerType; + + /** + * 证件类型 具体参考类型列表 + * 0 居⺠身份证 + * 1 护照 + * 3 ⼯商登记证 + * C 台湾居⺠来往⼤陆通⾏证 + * P 外国⼈永久居留证 + * Z 其它 + */ + @NotBlank(message = "证件类型不能为空") + private String identificationType; + + /** + * 证件号码 + */ + @NotBlank(message = "证件号码不能为空") + private String identificationNo; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/EvidenceSaveResponseDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/EvidenceSaveResponseDTO.java new file mode 100644 index 0000000..3de48ff --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/EvidenceSaveResponseDTO.java @@ -0,0 +1,17 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import lombok.Data; + +@Data +public class EvidenceSaveResponseDTO extends FxqResponseDTO { + + /** + * 区块链存证业务回执 这个需要⾃⾏保存 出证需要⽤到 + */ + private String data; + + @Override + protected String handleData() { + return this.data; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/FxqRequestDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/FxqRequestDTO.java new file mode 100644 index 0000000..7aa43ff --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/FxqRequestDTO.java @@ -0,0 +1,27 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 放心签请求父类dto + * + * @author sr on 2020-04-09 + */ +@Data +@NoArgsConstructor +public class FxqRequestDTO implements Serializable { + + private static final long serialVersionUID = 3960499271644654446L; + /** + * id + **/ + private String appId; + /** + * secret + **/ + private String appSecret; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/FxqResponseDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/FxqResponseDTO.java new file mode 100644 index 0000000..8eed6a9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/FxqResponseDTO.java @@ -0,0 +1,76 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import com.senmesh.common.AlitaResult; +import com.senmesh.sdk.fangxinqian.constant.FxqConstants; +import com.senmesh.sdk.fangxinqian.constant.FxqErrorCodeEnum; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.util.StringUtils; + +import java.io.Serializable; + +/** + * 放心签返回 + * + * @param + * @author sr on 2020-04-09 + */ +@Data +@NoArgsConstructor +public class FxqResponseDTO implements Serializable { + + /** + * + **/ + private static final long serialVersionUID = -4576000729533850612L; + /** + * 错误码 + **/ + private String code; + /** + * 序列号(每次调用接口返回的唯一值,seqNo 如有接口问题,请提供此值) + **/ + private String seqNo; + /** + * 错误信息 1 + **/ + private String message; + + /** + * 错误信息 2 + */ + private String msg; + + + public static FxqResponseDTO buildCommonError() { + FxqResponseDTO fxqResponseDTO = new FxqResponseDTO(); + fxqResponseDTO.setCode("999"); + return fxqResponseDTO; + } + + /** + * 返回结果处理 + * + * @return + */ + public AlitaResult handleResult() { + if (FxqConstants.SUC_CODE.equals(this.getCode())) { + return AlitaResult.success(handleData()); + } else { + return AlitaResult.error(FxqErrorCodeEnum.INVOKE_RETURN_ERROR.getCode(), + StringUtils.isEmpty(this.getMsg()) ? + StringUtils.isEmpty(this.getMessage()) ? FxqErrorCodeEnum.INVOKE_RETURN_ERROR.getMsg() : this.getMessage() + : this.getMsg()); + } + } + + /** + * 子类DTO实现 转换为AlitaResult时 + * 通过 handleData()决定转换为AlitaResult的data返回什么 + * + * @return + */ + protected T handleData() { + return null; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/GovernmentAuthRequestDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/GovernmentAuthRequestDTO.java new file mode 100644 index 0000000..e5d3146 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/GovernmentAuthRequestDTO.java @@ -0,0 +1,34 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * @author chenyun + * @description [ 放心签 ] 公章生成请求DTO + * @date 2020/8/14 11:33 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class GovernmentAuthRequestDTO extends FxqRequestDTO { + + private static final long serialVersionUID = -5777141264861824696L; + + /** + * 企业名称 + */ + @NotNull(message = "企业名称不能为空") + private String companyName; + + /** + * 企业类型 0.企业 1.个体⼯商户 + */ + @NotNull(message = "企业类型不能为空") + private String companyType; +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/GovernmentAuthResponseDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/GovernmentAuthResponseDTO.java new file mode 100644 index 0000000..f5765dd --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/GovernmentAuthResponseDTO.java @@ -0,0 +1,123 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import lombok.Data; + +import java.io.Serializable; +import java.util.Map; +import java.util.Optional; + +@Data +public class GovernmentAuthResponseDTO extends FxqResponseDTO { + + private String status; + + /** + * 返回实体 + */ + private Map data; + + @Override + protected GovernmentAuthResponseDataDTO handleData() { + return Optional.ofNullable(this.getData()) + .map(result -> Optional.ofNullable(result.get("basic")).orElse(null)) + .orElse(null); + } + + @Data + public static class GovernmentAuthResponseDataDTO implements Serializable { + private static final long serialVersionUID = -3235649555399151281L; + private String esdate; + /** + * 原注册号 + */ + private String regno; + /** + * 统一信用代码 + */ + private String creditcode; + /** + * 地址 + */ + private String dom; + /** + * 经营业务范围 + */ + private String zsopscope; + /** + * 实收资本 + */ + private String reccap; + /** + * 原注册号 + */ + private String oriregno; + /** + * 企业英文名 + */ + private String entnameeng; + /** + * 企业类型 + */ + private String enttype; + /** + * 最后年检度 + */ + private String ancheyear; + /** + * 经营期限至 + */ + private String opto; + /** + * 经营企业自 + */ + private String opfrom; + /** + * 注册资本币种 + */ + private String regcapcur; + /** + * 组织机构代码 + */ + private String orgcodes; + /** + * 注销日期 + */ + private String candate; + /** + * 企业名称 + */ + private String entname; + /** + * 实收资本 + */ + private String regcap; + /** + * 登记机关 + */ + private String regorg; + /** + * 吊销日期 + */ + private String revdate; + /** + * 经营状态 + */ + private String entstatus; + /** + * 许可经营项目 + */ + private String abuitem; + /** + * 注册地址编码 + */ + private String regorgcode; + /** + * 法人姓名 + */ + private String frname; + /** + * + */ + private String apprdate; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/OfficialSealGenerateRequestDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/OfficialSealGenerateRequestDTO.java new file mode 100644 index 0000000..ef8e525 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/OfficialSealGenerateRequestDTO.java @@ -0,0 +1,60 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + * @author chenyun + * @description [ 放心签 ] 公章生成请求DTO + * @date 2020/8/14 11:33 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OfficialSealGenerateRequestDTO implements Serializable { + + private static final long serialVersionUID = -4020535227323920801L; + + /** + * 系统预留⼿机号 + */ + private String phone; + + /** + * 公司名称 + */ + @NotNull(message = "公司名称不能为空") + private String companyName; + + /** + * 公章类型 默认圆形 0:圆形 ,1:椭圆形 + */ + @NotNull(message = "公章类型不能为空") + private String serviceType; + + /** + * 公章颜⾊ , 默认红⾊ ,0:红⾊ ,1:蓝⾊ ,2:⿊⾊ + */ + private String color; + + /** + * 公章字体 , 默认宋体 ,0:宋体 ,1:楷体 ,2:正⽅⿊体 + */ + private String font; + + /** + * 公章下弦⽂ + */ + private String serNo; + + /** + * 公章副标题 + */ + private String title; +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/PersonalSealGenerateRequestDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/PersonalSealGenerateRequestDTO.java new file mode 100644 index 0000000..2789dd1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/PersonalSealGenerateRequestDTO.java @@ -0,0 +1,49 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + * @author chenyun + * @description [ 放心签 ] 个人章生成请求DTO + * @date 2020/8/17 10:41 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PersonalSealGenerateRequestDTO implements Serializable { + + private static final long serialVersionUID = -4020535227323920801L; + + /** + * 系统预留⼿机号 + */ + private String phone; + + /** + * 个⼈签章名称 + */ + @NotNull(message = "个⼈签章名称不能为空") + private String fontText; + + /** + * 签章颜⾊ , 默认红⾊ ,1: 红⾊ ,2: ⿊⾊ ,3: 蓝⾊ + */ + private Integer colorTag; + + /** + * 签章字体 , 默认⽅正⿊体 ,1: ⽅正⿊体 ,2: 仿宋 ,3: 楷体 + */ + private Integer fontFamilyTag; + + /** + * 签章类型 , 默认⻓⽅形 ; 1: ⻓⽅形 , 2 正⽅形 + */ + private Integer shape; +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/PersonalSealGenerateResponseDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/PersonalSealGenerateResponseDTO.java new file mode 100644 index 0000000..83e6039 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/PersonalSealGenerateResponseDTO.java @@ -0,0 +1,19 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import com.senmesh.common.annotation.Mask; +import lombok.Data; + +@Data +public class PersonalSealGenerateResponseDTO extends FxqResponseDTO { + + /** + * 公章/个人章 图片 base64 + */ + @Mask + private String data; + + @Override + protected String handleData() { + return this.data; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/RealnameAuthRequestDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/RealnameAuthRequestDTO.java new file mode 100644 index 0000000..7684903 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/RealnameAuthRequestDTO.java @@ -0,0 +1,34 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * @author chenyun + * @description [ 放心签 ] 公章生成请求DTO + * @date 2020/8/14 11:33 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RealnameAuthRequestDTO extends FxqRequestDTO { + + private static final long serialVersionUID = -5777141264861824696L; + + /** + * 系统预留⼿机号 + */ + @NotNull(message = "姓名不能为空") + private String name; + + /** + * 公司名称 + */ + @NotNull(message = "身份证号码不能为空") + private String identityNumber; +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/RealnameAuthResponseDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/RealnameAuthResponseDTO.java new file mode 100644 index 0000000..8c632e9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/RealnameAuthResponseDTO.java @@ -0,0 +1,31 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import com.senmesh.sdk.fangxinqian.enums.RealnameResultEnum; +import lombok.Data; + +import java.io.Serializable; +import java.util.Optional; + +@Data +public class RealnameAuthResponseDTO extends FxqResponseDTO { + + private String status; + + /** + * 实名认证结果 1:实名通过 2:实名不通过 + */ + private RealnameAuthResponseDataDTO data; + + @Override + protected Boolean handleData() { + return Optional.ofNullable(this.getData()) + .map(result -> Optional.ofNullable(result.getResult()).orElse("").equals(RealnameResultEnum.SUC.getResult())) + .orElse(false); + } + + @Data + public static class RealnameAuthResponseDataDTO implements Serializable { + private static final long serialVersionUID = -3235649555399151281L; + private String result; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/SealGenerateResponseDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/SealGenerateResponseDTO.java new file mode 100644 index 0000000..bea8ba4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/SealGenerateResponseDTO.java @@ -0,0 +1,17 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import lombok.Data; + +@Data +public class SealGenerateResponseDTO extends FxqResponseDTO { + + /** + * 公章/个人章 图片 base64 + */ + private String baseStr; + + @Override + protected String handleData() { + return this.baseStr; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/StateDataDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/StateDataDTO.java new file mode 100644 index 0000000..3dd30ee --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/StateDataDTO.java @@ -0,0 +1,21 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import java.io.Serializable; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-04-09 + */ +@Data +@NoArgsConstructor +public class StateDataDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = -4608569342053995450L; + + /** 状态 **/ + private String state; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/TextReplaceRequestDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/TextReplaceRequestDTO.java new file mode 100644 index 0000000..d0d2133 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/TextReplaceRequestDTO.java @@ -0,0 +1,64 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import com.senmesh.common.annotation.Mask; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.List; + +/** + * @author chenyun + * @description [ 放心签 ] 合同替换关键字请求DTO + * @date 2020/8/17 11:15 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TextReplaceRequestDTO implements Serializable { + + private static final long serialVersionUID = -4020535227323920801L; + + /** + * 系统预留⼿机号 + */ + private String phone; + + /** + * 待替换的 base64 ⽂档 + */ + @Mask + @NotNull(message = "个⼈签章名称不能为空") + private String fileBase64; + + /** + * ⽂件类型暂时只⽀持以下三种 + * 1:pdf 2:doc 3.docx + * 不传默认1 + */ + private String fileType; + + /** 待替换内容集合 **/ + private List keyValues; + + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class KeyValueBO { + /** + * 关键字key + */ + private String oldText; + + /** + * 关键字value + */ + private String newText; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/TextReplaceResponseDTO.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/TextReplaceResponseDTO.java new file mode 100644 index 0000000..d1dc827 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/dto/TextReplaceResponseDTO.java @@ -0,0 +1,19 @@ +package com.senmesh.sdk.fangxinqian.dto; + +import com.senmesh.common.annotation.Mask; +import lombok.Data; + +@Data +public class TextReplaceResponseDTO extends FxqResponseDTO { + + /** + * 文档 base64 + */ + @Mask + private String data; + + @Override + protected String handleData() { + return this.data; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/enums/RealnameResultEnum.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/enums/RealnameResultEnum.java new file mode 100644 index 0000000..a16b621 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/enums/RealnameResultEnum.java @@ -0,0 +1,26 @@ +package com.senmesh.sdk.fangxinqian.enums; + +/** + * 实名认证状态枚举类 + */ +public enum RealnameResultEnum { + + SUC("1", "实名通过"), + FAIL("2", "实名不通过"); + + private String result; + private String message; + + RealnameResultEnum(String result, String message) { + this.result = result; + this.message = message; + } + + public String getResult() { + return result; + } + + public String getMessage() { + return message; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/service/FangXinQianService.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/service/FangXinQianService.java new file mode 100644 index 0000000..8227544 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/service/FangXinQianService.java @@ -0,0 +1,116 @@ +package com.senmesh.sdk.fangxinqian.service; + +import com.senmesh.common.AlitaResult; +import com.senmesh.sdk.fangxinqian.dto.*; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.groups.Default; + +/** + * 放心签 + * + * @author sr on 2020-04-09 + */ +@Validated(Default.class) +public interface FangXinQianService { + + String BEAN_ID = "sdk.fangXinQianService"; + String MOCK_BEAN_ID = "mock.fangXinQianService"; + + /** + * 银行卡三要素 + * + * @param bankCardThreeRequestDto + * @return success-false真实调用第三方未成功,未拿到返回值; + * success-true获取到第三方返回,data-true校验成功,data-false校验不一致并返回失败原因(msg) + * @author sr on 2020-04-10 + */ + AlitaResult checkBankCardThree(@NotNull @Valid BankCardThreeRequestDTO bankCardThreeRequestDto); + + /** + * 银行卡四要素 + * + * @param bankCardFourRequestDto + * @return success-false真实调用第三方未成功,未拿到返回值; + * success-true获取到第三方返回,data-true校验成功,data-false校验不一致并返回失败原因(msg) + * @author sr on 2020-05-22 + */ + AlitaResult checkBankCardFour(@NotNull @Valid BankCardFourRequestDTO bankCardFourRequestDto); + + /** + * 公章生成 + * + * @param officialSealGenerateRequestDTO + * @return base64 + */ + AlitaResult generateOfficialSeal(@NotNull @Valid OfficialSealGenerateRequestDTO officialSealGenerateRequestDTO); + + /** + * 个人章生成 + * + * @param personalSealGenerateRequestDTO + * @return + */ + AlitaResult generatePersonalSeal(@NotNull @Valid PersonalSealGenerateRequestDTO personalSealGenerateRequestDTO); + + + /** + * 文档关键字替换 + * + * @param textReplaceRequestDTO + * @return + */ + AlitaResult textReplace(@NotNull @Valid TextReplaceRequestDTO textReplaceRequestDTO); + + /** + * 实名认证 + * + * @param realnameAuthRequestDTO + * @return + */ + AlitaResult realnameAuth(@NotNull @Valid RealnameAuthRequestDTO realnameAuthRequestDTO); + + /** + * 工商信息核验 + * + * @param governmentAuthRequestDTO + * @return + */ + AlitaResult governmentAuth(@NotNull @Valid GovernmentAuthRequestDTO governmentAuthRequestDTO); + + /** + * 合同签署 (普通签署) + * + * @param contractRequestDTO + * @return + */ + AlitaResult contractCommonSign(@NotNull @Valid ContractRequestDTO contractRequestDTO); + + /** + * 合同签署 (关键字签署) + * + * @param contractRequestDTO + * @return + */ + AlitaResult contractKeySign(@NotNull @Valid ContractRequestDTO contractRequestDTO); + + + /** + * 存证接⼝ + * 存证成功的合同默认30s以后才能出证,如果太早出证会提示证据不存在 + * + * @param evidenceSaveRequestDTO + * @return + */ + AlitaResult evidenceSave(@NotNull @Valid EvidenceSaveRequestDTO evidenceSaveRequestDTO); + + /** + * 出证接口 + * + * @param evidenceGetRequestDTO + * @return + */ + AlitaResult evidenceGet(@NotNull @Valid EvidenceGetRequestDTO evidenceGetRequestDTO); +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/service/impl/FangXinQianServiceImpl.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/service/impl/FangXinQianServiceImpl.java new file mode 100644 index 0000000..7ef9449 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/service/impl/FangXinQianServiceImpl.java @@ -0,0 +1,247 @@ +package com.senmesh.sdk.fangxinqian.service.impl; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.annotation.CheckAndMock; +import com.senmesh.sdk.common.constant.SdkConstants; +import com.senmesh.sdk.fangxinqian.config.FxqCommonProperties; +import com.senmesh.sdk.fangxinqian.config.FxqContractProperties; +import com.senmesh.sdk.fangxinqian.config.FxqProperties; +import com.senmesh.sdk.fangxinqian.constant.BankCardFourStateEnum; +import com.senmesh.sdk.fangxinqian.constant.BankCardThreeStateEnum; +import com.senmesh.sdk.fangxinqian.constant.FxqConstants; +import com.senmesh.sdk.fangxinqian.constant.FxqErrorCodeEnum; +import com.senmesh.sdk.fangxinqian.dto.*; +import com.senmesh.sdk.fangxinqian.service.FangXinQianService; +import com.senmesh.sdk.fangxinqian.util.FxqUtils; +import com.senmesh.sdk.fangxinqian.util.HttpUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * @author sr on 2020-04-09 + */ +@Slf4j +@Service(FangXinQianService.BEAN_ID) +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class FangXinQianServiceImpl implements FangXinQianService { + + private final FxqProperties fxqProperties; + + @Override + public AlitaResult generateOfficialSeal(OfficialSealGenerateRequestDTO officialSealGenerateRequestDTO) { + if (StringUtils.isEmpty(officialSealGenerateRequestDTO.getPhone())) { + officialSealGenerateRequestDTO.setPhone(fxqProperties.getPhone()); + } + return HttpUtil + .execute(fxqProperties.getDomain().concat(fxqProperties.getOfficialSealUri()), + officialSealGenerateRequestDTO, SealGenerateResponseDTO.class) + .handleResult(); + } + + @Override + public AlitaResult generatePersonalSeal(PersonalSealGenerateRequestDTO personalSealGenerateRequestDTO) { + if (StringUtils.isEmpty(personalSealGenerateRequestDTO.getPhone())) { + personalSealGenerateRequestDTO.setPhone(fxqProperties.getPhone()); + } + return HttpUtil + .execute(fxqProperties.getDomain().concat(fxqProperties.getPersonalSealUri()), + personalSealGenerateRequestDTO, PersonalSealGenerateResponseDTO.class) + .handleResult(); + } + + @Override + public AlitaResult textReplace(TextReplaceRequestDTO textReplaceRequestDTO) { + if (StringUtils.isEmpty(textReplaceRequestDTO.getPhone())) { + textReplaceRequestDTO.setPhone(fxqProperties.getPhone()); + } + return HttpUtil + .execute(fxqProperties.getDomain().concat(fxqProperties.getTextReplaceUri()), + textReplaceRequestDTO, TextReplaceResponseDTO.class) + .handleResult(); + } + + @Override + @CheckAndMock(mockClass = MockFangXinQianServiceImpl.class, + propertyPrefix = FxqProperties.REALNAME_AUTH_PREFIX) + public AlitaResult realnameAuth(RealnameAuthRequestDTO realnameAuthRequestDTO) { + FxqCommonProperties fxqCommonProperties = fxqProperties.getRealName(); + // 校验部分 + if (fxqCommonProperties == null) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, + FxqConstants.PROPERTIES_NOT_SET); + } + if (!FxqUtils.dealAppIdAndSecret(fxqCommonProperties, realnameAuthRequestDTO)) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, + FxqConstants.ID_SECRET_NOT_ENOUGH); + } + //执行 + return HttpUtil + .execute(fxqProperties.getDomain().concat(fxqCommonProperties.getUrl()), + realnameAuthRequestDTO, RealnameAuthResponseDTO.class) + .handleResult(); + } + + @Override + @CheckAndMock(mockClass = MockFangXinQianServiceImpl.class, + propertyPrefix = FxqProperties.GOVERNMENT_AUTH_PREFIX) + public AlitaResult governmentAuth(GovernmentAuthRequestDTO governmentAuthRequestDTO) { + FxqCommonProperties fxqCommonProperties = fxqProperties.getGovernment(); + // 校验部分 + if (fxqCommonProperties == null) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, + FxqConstants.PROPERTIES_NOT_SET); + } + if (!FxqUtils.dealAppIdAndSecret(fxqCommonProperties, governmentAuthRequestDTO)) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, + FxqConstants.ID_SECRET_NOT_ENOUGH); + } + //执行 + return HttpUtil + .execute(fxqProperties.getDomain().concat(fxqCommonProperties.getUrl()), + governmentAuthRequestDTO, GovernmentAuthResponseDTO.class) + .handleResult(); + } + + @Override + @CheckAndMock(mockClass = MockFangXinQianServiceImpl.class, + propertyPrefix = FxqProperties.COMMON_SIGN_PREFIX) + public AlitaResult contractCommonSign(ContractRequestDTO contractRequestDTO) { + FxqContractProperties contract = fxqProperties.getContract(); + FxqCommonProperties fxqCommonProperties = contract.build(contract.getCommonSign()); + // 校验部分 + if (fxqCommonProperties == null) { + return AlitaResult.error( + SdkConstants.SDK_INVOKE_NOT_REACH_CODE, FxqConstants.PROPERTIES_NOT_SET); + } + if (!FxqUtils.dealAppIdAndSecret(fxqCommonProperties, contractRequestDTO)) { + return AlitaResult.error( + SdkConstants.SDK_INVOKE_NOT_REACH_CODE, FxqConstants.ID_SECRET_NOT_ENOUGH); + } + // 执行 + return HttpUtil + .execute(fxqProperties.getDomain().concat(fxqCommonProperties.getUrl()), + contractRequestDTO, ContractResponseDTO.class) + .handleResult(); + } + + @Override + @CheckAndMock(mockClass = MockFangXinQianServiceImpl.class, + propertyPrefix = FxqProperties.KEY_SIGN_PREFIX) + public AlitaResult contractKeySign(ContractRequestDTO contractRequestDTO) { + FxqContractProperties contract = fxqProperties.getContract(); + FxqCommonProperties fxqCommonProperties = contract.build(contract.getKeySign()); + // 校验部分 + if (fxqCommonProperties == null) { + return AlitaResult.error( + SdkConstants.SDK_INVOKE_NOT_REACH_CODE, FxqConstants.PROPERTIES_NOT_SET); + } + if (!FxqUtils.dealAppIdAndSecret(fxqCommonProperties, contractRequestDTO)) { + return AlitaResult.error( + SdkConstants.SDK_INVOKE_NOT_REACH_CODE, FxqConstants.ID_SECRET_NOT_ENOUGH); + } + // 执行 + return HttpUtil + .execute( + fxqProperties.getDomain().concat(fxqCommonProperties.getUrl()), + contractRequestDTO, ContractResponseDTO.class) + .handleResult(); + } + + @Override + @CheckAndMock(mockClass = MockFangXinQianServiceImpl.class, + propertyPrefix = FxqProperties.EVIDENCE_SAVE_PREFIX) + public AlitaResult evidenceSave(EvidenceSaveRequestDTO evidenceSaveRequestDTO) { + FxqContractProperties contract = fxqProperties.getContract(); + FxqCommonProperties fxqCommonProperties = contract.build(contract.getEvidenceSave()); + // 校验部分 + if (fxqCommonProperties == null) { + return AlitaResult.error( + SdkConstants.SDK_INVOKE_NOT_REACH_CODE, FxqConstants.PROPERTIES_NOT_SET); + } + if (!FxqUtils.dealAppIdAndSecret(fxqCommonProperties, evidenceSaveRequestDTO)) { + return AlitaResult.error( + SdkConstants.SDK_INVOKE_NOT_REACH_CODE, FxqConstants.ID_SECRET_NOT_ENOUGH); + } + // 执行 + return HttpUtil + .execute( + fxqProperties.getDomain().concat(fxqCommonProperties.getUrl()), + evidenceSaveRequestDTO, ContractResponseDTO.class) + .handleResult(); + } + + @Override + @CheckAndMock(mockClass = MockFangXinQianServiceImpl.class, + propertyPrefix = FxqProperties.EVIDENCE_GET_PREFIX) + public AlitaResult evidenceGet(EvidenceGetRequestDTO evidenceGetRequestDTO) { + FxqContractProperties contract = fxqProperties.getContract(); + FxqCommonProperties fxqCommonProperties = contract.build(contract.getEvidenceGet()); + // 校验部分 + if (fxqCommonProperties == null) { + return AlitaResult.error( + SdkConstants.SDK_INVOKE_NOT_REACH_CODE, FxqConstants.PROPERTIES_NOT_SET); + } + if (!FxqUtils.dealAppIdAndSecret(fxqCommonProperties, evidenceGetRequestDTO)) { + return AlitaResult.error( + SdkConstants.SDK_INVOKE_NOT_REACH_CODE, FxqConstants.ID_SECRET_NOT_ENOUGH); + } + // 执行 + return HttpUtil + .execute( + fxqProperties.getDomain().concat(fxqCommonProperties.getUrl()), + evidenceGetRequestDTO, ContractResponseDTO.class) + .handleResult(); + } + + @Override + @CheckAndMock(mockClass = MockFangXinQianServiceImpl.class, + propertyPrefix = FxqProperties.BANK_CARD_THREE_PREFIX) + public AlitaResult checkBankCardThree(BankCardThreeRequestDTO bankCardThreeRequestDto) { + return this.check(bankCardThreeRequestDto, fxqProperties.getBankCard3(), + BankCardThreeResponseDTO.class); + } + + @Override + @CheckAndMock(mockClass = MockFangXinQianServiceImpl.class, + propertyPrefix = FxqProperties.BANK_CARD_FOUR_PREFIX) + public AlitaResult checkBankCardFour(BankCardFourRequestDTO bankCardFourRequestDto) { + return this.check(bankCardFourRequestDto, fxqProperties.getBankCard4(), + BankCardFourResponseDTO.class); + } + + + private AlitaResult check(FxqRequestDTO fxqRequestDto, + FxqCommonProperties fxqCommonProperties, + Class responseClazz) { + // 校验部分 + if (fxqCommonProperties == null) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, + FxqConstants.PROPERTIES_NOT_SET); + } + if (!FxqUtils.dealAppIdAndSecret(fxqCommonProperties, fxqRequestDto)) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, + FxqConstants.ID_SECRET_NOT_ENOUGH); + } + // 执行 + FxqResponseDTO responseDto = HttpUtil.execute(fxqProperties.getDomain().concat(fxqCommonProperties.getUrl()), + fxqRequestDto, responseClazz); + + // 返回结果校验 + if (!FxqConstants.SUC_CODE.equals(responseDto.getCode())) { + return AlitaResult.success(StringUtils.join(FxqErrorCodeEnum.INVOKE_RETURN_ERROR.getMsg(), + responseDto.getMessage()), false); + } + if (responseClazz == BankCardThreeResponseDTO.class) { + String state = ((BankCardThreeResponseDTO) responseDto).getData().getState(); + return BankCardThreeStateEnum.dealState(state); + } + + // 处理验证结果 + return BankCardFourStateEnum.dealState(((BankCardFourResponseDTO) responseDto).getData().getState()); + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/service/impl/MockFangXinQianServiceImpl.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/service/impl/MockFangXinQianServiceImpl.java new file mode 100644 index 0000000..e7b00ce --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/service/impl/MockFangXinQianServiceImpl.java @@ -0,0 +1,86 @@ +package com.senmesh.sdk.fangxinqian.service.impl; + +import com.senmesh.common.AlitaResult; +import com.senmesh.sdk.fangxinqian.dto.*; +import com.senmesh.sdk.fangxinqian.service.FangXinQianService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +/** + * @author sr on 2020-04-09 + */ +@Service(FangXinQianService.MOCK_BEAN_ID) +@Slf4j +public class MockFangXinQianServiceImpl implements FangXinQianService { + + @Override + public AlitaResult checkBankCardThree( + @NotNull @Valid BankCardThreeRequestDTO bankCardThreeRequestDto) { + log.info("fxq checkBankCardThree mock..."); + return AlitaResult.success(true); + } + + + @Override + public AlitaResult checkBankCardFour(@NotNull @Valid BankCardFourRequestDTO bankCardFourRequestDto) { + log.info("fxq checkBankCardFour mock..."); + return AlitaResult.success(true); + } + + @Override + public AlitaResult generateOfficialSeal(@NotNull @Valid OfficialSealGenerateRequestDTO officialSealGenerateRequestDTO) { + log.info("fxq generateOfficialSeal mock..."); + return AlitaResult.success(""); + } + + @Override + public AlitaResult generatePersonalSeal(@NotNull @Valid PersonalSealGenerateRequestDTO personalSealGenerateRequestDTO) { + log.info("fxq generatePersonalSeal mock..."); + return AlitaResult.success(""); + } + + @Override + public AlitaResult textReplace(@NotNull @Valid TextReplaceRequestDTO textReplaceRequestDTO) { + log.info("fxq textReplace mock..."); + return AlitaResult.success(""); + } + + @Override + public AlitaResult realnameAuth(@NotNull @Valid RealnameAuthRequestDTO realnameAuthRequestDTO) { + log.info("fxq realnameAuth mock..."); + return AlitaResult.success(true); + } + + @Override + public AlitaResult governmentAuth(@NotNull @Valid GovernmentAuthRequestDTO governmentAuthRequestDTO) { + log.info("fxq governmentAuth mock..."); + return AlitaResult.success(new GovernmentAuthResponseDTO.GovernmentAuthResponseDataDTO()); + } + + @Override + public AlitaResult contractCommonSign(@NotNull @Valid ContractRequestDTO contractRequestDTO) { + log.info("fxq contractCommonSign mock..."); + return AlitaResult.success("https://huluwa-ec.oss-accelerate.aliyuncs.com/20200825/20200825174051_2913.pdf?Expires=4751948451&OSSAccessKeyId=HLUmOSIDpYentPOt&Signature=RB%2FFQgM7dJyBac4DMSG0YZYz3ao%3D"); + } + + @Override + public AlitaResult contractKeySign(@NotNull @Valid ContractRequestDTO contractRequestDTO) { + log.info("fxq contractKeySign mock..."); + return AlitaResult.success("https://huluwa-ec.oss-accelerate.aliyuncs.com/20200825/20200825174051_2913.pdf?Expires=4751948451&OSSAccessKeyId=HLUmOSIDpYentPOt&Signature=RB%2FFQgM7dJyBac4DMSG0YZYz3ao%3D"); + } + + @Override + public AlitaResult evidenceSave(@NotNull @Valid EvidenceSaveRequestDTO evidenceSaveRequestDTO) { + log.info("fxq evidenceSave mock..."); + return AlitaResult.success(""); + } + + @Override + public AlitaResult evidenceGet(@NotNull @Valid EvidenceGetRequestDTO evidenceGetRequestDTO) { + log.info("fxq evidenceGet mock..."); + return AlitaResult.success(""); + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/util/FxqUtils.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/util/FxqUtils.java new file mode 100644 index 0000000..241a643 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/util/FxqUtils.java @@ -0,0 +1,62 @@ +package com.senmesh.sdk.fangxinqian.util; + +import org.apache.commons.lang3.StringUtils; + +import com.senmesh.sdk.fangxinqian.config.FxqCommonProperties; +import com.senmesh.sdk.fangxinqian.dto.FxqRequestDTO; + +/** + * 工具类 + * + * @author sr on 2020-04-09 + */ +public final class FxqUtils { + + /** + * 私有 + */ + private FxqUtils() { + throw new IllegalStateException("Utility class"); + } + + /** + * 处理appId和appSecret参数 + * + * @param + * @param fxqCommonProperties + * @param fxqRequestDto + * @author sr on 2020-04-09 + */ + public static boolean dealAppIdAndSecret(FxqCommonProperties fxqCommonProperties, + T fxqRequestDto) { + + String appId = fxqRequestDto.getAppId(); + String appSecret = fxqRequestDto.getAppSecret(); + boolean enable = enableFxq(fxqCommonProperties); + if (StringUtils.isBlank(appId) && enable) { + appId = fxqCommonProperties.getAppId(); + } + if (StringUtils.isBlank(appSecret) && enable) { + appSecret = fxqCommonProperties.getAppSecret(); + } + if (StringUtils.isBlank(appId) || StringUtils.isBlank(appSecret)) { + return false; + } + + fxqRequestDto.setAppId(appId); + fxqRequestDto.setAppSecret(appSecret); + return true; + } + + /** + * 是否开启放心签接口 + * + * @param fxqCommonProperties + * @return + * @author sr on 2020-04-21 + */ + public static boolean enableFxq(FxqCommonProperties fxqCommonProperties) { + return fxqCommonProperties != null && fxqCommonProperties.getEnable(); + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/fangxinqian/util/HttpUtil.java b/backend/src/main/java/com/senmesh/sdk/fangxinqian/util/HttpUtil.java new file mode 100644 index 0000000..5021428 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/fangxinqian/util/HttpUtil.java @@ -0,0 +1,58 @@ +package com.senmesh.sdk.fangxinqian.util; + +import com.senmesh.common.util.JsonUtils; +import com.senmesh.sdk.fangxinqian.dto.FxqResponseDTO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.util.StopWatch; +import org.springframework.web.client.RestTemplate; + +@Slf4j +@Component +public class HttpUtil { + + private static RestTemplate restTemplate; + + @Autowired + public HttpUtil(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + /** + * Http 通用请求封装 + * + * @param url 请求地址 + * @param requestDto 请求实体 + * @param responseClazz 返回实体Class + * @param + * @param + * @return + */ + public static FxqResponseDTO execute(String url, T requestDto, Class responseClazz) { + ResponseEntity response; + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + try { + log.debug("fangxinqian request url :{}", url); + log.info("fangxinqian request requestDto :{}", JsonUtils.toJsonString(requestDto)); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity request = new HttpEntity<>(requestDto, headers); + response = restTemplate.postForEntity(url, request, responseClazz); + log.info("fangxinqian {}:{}", responseClazz.getName(), JsonUtils.toJsonString(response)); + } catch (Exception e) { + log.error("fangxinqian {} invoke error:{}", requestDto.getClass().getName(), + e); + stopWatch.stop(); + return FxqResponseDTO.buildCommonError(); + } + stopWatch.stop(); + log.info("fangxinqian consuming {} s", stopWatch.getTotalTimeSeconds()); + return JsonUtils.objToClassObj(response.getBody(), responseClazz); + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/mbti/config/MbtiProperties.java b/backend/src/main/java/com/senmesh/sdk/mbti/config/MbtiProperties.java new file mode 100644 index 0000000..72666c7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/mbti/config/MbtiProperties.java @@ -0,0 +1,25 @@ +package com.senmesh.sdk.mbti.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@ConfigurationProperties(prefix = MbtiProperties.PREFIX) +@Data +@Component +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class MbtiProperties { + + public static final String PREFIX = "mbti"; + + private String urlPrefix; + private String appId; + private String appKey; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/mbti/mobel/AnswerReq.java b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/AnswerReq.java new file mode 100644 index 0000000..74c4396 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/AnswerReq.java @@ -0,0 +1,39 @@ +package com.senmesh.sdk.mbti.mobel; + +import org.springframework.core.ParameterizedTypeReference; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AnswerReq extends MbtiTokenReq>{ + + /** **/ + private static final long serialVersionUID = 1L; + + private static ParameterizedTypeReference> type = + new ParameterizedTypeReference>() {}; + + private String liangbiaoId; + private String userName; + private String userEmail; + private AnswerReqDTO answerData; + + @Override + public String getUri() { + return "submit"; + } + + @Override + public ParameterizedTypeReference> getResponseType() { + return type; + } + + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/mbti/mobel/AnswerReqDTO.java b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/AnswerReqDTO.java new file mode 100644 index 0000000..da44950 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/AnswerReqDTO.java @@ -0,0 +1,32 @@ +package com.senmesh.sdk.mbti.mobel; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.io.Serializable; +import java.util.Map; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Builder.Default; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AnswerReqDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + @Default + private String liangbiaoId = "MBTI-STEP-II"; + @JsonProperty(value="Answers") + private Map Answers; + @Default + private String checkcode = "I194H5LAHLJR2DIJ"; + + private String test_name; + + private String test_email; +} diff --git a/backend/src/main/java/com/senmesh/sdk/mbti/mobel/AnswerRes.java b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/AnswerRes.java new file mode 100644 index 0000000..823615f --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/AnswerRes.java @@ -0,0 +1,21 @@ +package com.senmesh.sdk.mbti.mobel; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AnswerRes implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + private String liangbiaoId; + private String orderId; +} diff --git a/backend/src/main/java/com/senmesh/sdk/mbti/mobel/AnwserDTO.java b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/AnwserDTO.java new file mode 100644 index 0000000..47a0217 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/AnwserDTO.java @@ -0,0 +1,27 @@ +package com.senmesh.sdk.mbti.mobel; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AnwserDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + public String code; + public String content; + public String createTime; + public String deleteFlag; + public String id; + public String liangbiaoId; + public String questionId; + public String updateTime; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/mbti/mobel/MbtiRes.java b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/MbtiRes.java new file mode 100644 index 0000000..9aa989a --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/MbtiRes.java @@ -0,0 +1,23 @@ +package com.senmesh.sdk.mbti.mobel; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class MbtiRes implements Serializable{ + + public static final String SUC_STATUS = "success"; + + private T data; + private String message; + private String redirect; + private String status; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/mbti/mobel/MbtiTokenReq.java b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/MbtiTokenReq.java new file mode 100644 index 0000000..2a30ca9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/MbtiTokenReq.java @@ -0,0 +1,18 @@ +package com.senmesh.sdk.mbti.mobel; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.senmesh.sdk.common.dto.ISdkRequest; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public abstract class MbtiTokenReq implements ISdkRequest{ + + @JsonIgnore + private String token; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/mbti/mobel/OrderQueryReq.java b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/OrderQueryReq.java new file mode 100644 index 0000000..5bb133d --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/OrderQueryReq.java @@ -0,0 +1,37 @@ +package com.senmesh.sdk.mbti.mobel; + +import org.springframework.core.ParameterizedTypeReference; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class OrderQueryReq extends MbtiTokenReq>{ + + /** **/ + private static final long serialVersionUID = 1L; + + private static ParameterizedTypeReference> type = + new ParameterizedTypeReference>() {}; + + private String liangbiaoId; + private String orderId; + + @Override + public String getUri() { + return "query"; + } + + @Override + public ParameterizedTypeReference> getResponseType() { + return type; + } + + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/mbti/mobel/OrderQueryRes.java b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/OrderQueryRes.java new file mode 100644 index 0000000..1a284e9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/OrderQueryRes.java @@ -0,0 +1,21 @@ +package com.senmesh.sdk.mbti.mobel; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class OrderQueryRes implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + private String reportId; + private String orderId; +} diff --git a/backend/src/main/java/com/senmesh/sdk/mbti/mobel/QuestionReq.java b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/QuestionReq.java new file mode 100644 index 0000000..c567eaa --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/QuestionReq.java @@ -0,0 +1,38 @@ +package com.senmesh.sdk.mbti.mobel; + +import java.util.List; + +import org.springframework.core.ParameterizedTypeReference; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class QuestionReq extends MbtiTokenReq>>{ + + /** **/ + private static final long serialVersionUID = 1L; + + private static ParameterizedTypeReference>> type = + new ParameterizedTypeReference>>() {}; + + private String liangbiaoId; + + @Override + public String getUri() { + return "getQuestions"; + } + + @Override + public ParameterizedTypeReference>> getResponseType() { + return type; + } + + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/mbti/mobel/QuestionRes.java b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/QuestionRes.java new file mode 100644 index 0000000..f72f008 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/QuestionRes.java @@ -0,0 +1,25 @@ +package com.senmesh.sdk.mbti.mobel; + +import java.io.Serializable; +import java.util.List; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class QuestionRes implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + private String anwType; + private List anwserList; + private String id; + private String liangbiaoId; + private String part; + private String title; +} diff --git a/backend/src/main/java/com/senmesh/sdk/mbti/mobel/ReportReq.java b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/ReportReq.java new file mode 100644 index 0000000..c0701c5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/ReportReq.java @@ -0,0 +1,37 @@ +package com.senmesh.sdk.mbti.mobel; + +import org.springframework.core.ParameterizedTypeReference; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ReportReq extends MbtiTokenReq>{ + + /** **/ + private static final long serialVersionUID = 1L; + + private static ParameterizedTypeReference> type = + new ParameterizedTypeReference>() {}; + + private String liangbiaoId; + private String reportId; + + @Override + public String getUri() { + return "getReport"; + } + + @Override + public ParameterizedTypeReference> getResponseType() { + return type; + } + + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/mbti/mobel/ReportRes.java b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/ReportRes.java new file mode 100644 index 0000000..a247a74 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/ReportRes.java @@ -0,0 +1,22 @@ +package com.senmesh.sdk.mbti.mobel; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ReportRes implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + private String liangbiaoId; + private String reportId; + private String content; +} diff --git a/backend/src/main/java/com/senmesh/sdk/mbti/mobel/TokenReq.java b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/TokenReq.java new file mode 100644 index 0000000..9442433 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/TokenReq.java @@ -0,0 +1,39 @@ +package com.senmesh.sdk.mbti.mobel; + +import org.springframework.core.ParameterizedTypeReference; + +import com.senmesh.sdk.common.dto.ISdkRequest; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class TokenReq implements ISdkRequest>{ + + /** **/ + private static final long serialVersionUID = 1L; + + private static ParameterizedTypeReference> type = + new ParameterizedTypeReference>() {}; + + private String appId; + private String appKey; + + @Override + public String getUri() { + return "getToken"; + } + + @Override + public ParameterizedTypeReference> getResponseType() { + return type; + } + + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/mbti/mobel/TokenRes.java b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/TokenRes.java new file mode 100644 index 0000000..a6aa62d --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/mbti/mobel/TokenRes.java @@ -0,0 +1,22 @@ +package com.senmesh.sdk.mbti.mobel; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class TokenRes implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + private String expiresIn; + private String appId; + private String token; +} diff --git a/backend/src/main/java/com/senmesh/sdk/mbti/service/MbtiProvider.java b/backend/src/main/java/com/senmesh/sdk/mbti/service/MbtiProvider.java new file mode 100644 index 0000000..99a8924 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/mbti/service/MbtiProvider.java @@ -0,0 +1,80 @@ +package com.senmesh.sdk.mbti.service; + +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.sdk.common.constant.SdkConstants; +import com.senmesh.sdk.common.dto.DefaultSdkInvokeLogDTO; +import com.senmesh.sdk.common.dto.ISdkRequest; +import com.senmesh.sdk.common.util.HttpUtils; +import com.senmesh.sdk.mbti.config.MbtiProperties; +import com.senmesh.sdk.mbti.mobel.MbtiRes; +import com.senmesh.sdk.mbti.mobel.MbtiTokenReq; +import com.senmesh.sdk.mbti.mobel.TokenReq; +import com.senmesh.sdk.mbti.mobel.TokenRes; + +import io.jsonwebtoken.lang.Assert; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class MbtiProvider { + + private static MbtiProperties mbtiProperties; + + private MbtiProvider(MbtiProperties mbtiProperties) { + MbtiProvider.mbtiProperties = mbtiProperties; + } + + public static String getToken() { + AlitaResult res = http(TokenReq.builder().appId(mbtiProperties.getAppId()).appKey(mbtiProperties.getAppKey()).build()); + Assert.isTrue(res.getSuccess(), res.getMsg()); + return res.getData().getToken(); + } + + + public static AlitaResult http(ISdkRequest> req) { + MbtiRes res = null; + try { + try { + HttpHeaders header = new HttpHeaders(); + if (req instanceof MbtiTokenReq) { + header.add("Authentication", getToken()); + header.add("appId", mbtiProperties.getAppId()); + } + // 发送请求 + HttpEntity requestEntity = new HttpEntity(req, header); + ResponseEntity> response = HttpUtils.restTemplate.exchange(mbtiProperties.getUrlPrefix() + req.getUri(), + HttpMethod.POST, requestEntity, req.getResponseType()); + res = response.getBody(); + } catch (Exception e) { + log.error("mbti http error:{}", e.getMessage()); + return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_ERROR_CODE, e.getMessage()); + } + try { + if (MbtiRes.SUC_STATUS.equals(res.getStatus())) { + return AlitaResult.success(res.getData()); + } + return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_RESPONSE_FAIL_CODE, + res.getMessage()); + } catch (Exception e) { + return AlitaResult.error(SdkConstants.SDK_RESPONSE_CONVERT_ERROR_CODE, + e.getMessage()); + } + + } finally { + log.info("mbti invoke:{}", + JsonUtils + .toJsonString( + DefaultSdkInvokeLogDTO.builder().requestData(req).responseData(res) + .build())); + } + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/robot/constant/DingTalkMsgTypeEnum.java b/backend/src/main/java/com/senmesh/sdk/robot/constant/DingTalkMsgTypeEnum.java new file mode 100644 index 0000000..d8e6bf3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/robot/constant/DingTalkMsgTypeEnum.java @@ -0,0 +1,28 @@ +package com.senmesh.sdk.robot.constant; + +/** + * @author sr on 2020-09-30 + */ +public enum DingTalkMsgTypeEnum { + /** **/ + TEXT("text"), + /** **/ + LINK("link"), + /** **/ + MARKDOWN("markdown"), + /** **/ + ACTIONCARD("actionCard"), + /** **/ + FEEDCARD("feedCard") + ; + + private String msgType; + + DingTalkMsgTypeEnum(String msgType){ + this.msgType = msgType; + } + + public String getMsgType() { + return this.msgType; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/robot/constant/RobotTypeEnum.java b/backend/src/main/java/com/senmesh/sdk/robot/constant/RobotTypeEnum.java new file mode 100644 index 0000000..4132971 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/robot/constant/RobotTypeEnum.java @@ -0,0 +1,13 @@ +package com.senmesh.sdk.robot.constant; + +/** + * @author sr on 2020-09-30 + */ +public enum RobotTypeEnum { + + /** 企业微信 **/ + WORK_WECHAT, + /** 钉钉 **/ + DING_TALK; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/robot/constant/WorkWechatMsgTypeEnum.java b/backend/src/main/java/com/senmesh/sdk/robot/constant/WorkWechatMsgTypeEnum.java new file mode 100644 index 0000000..1179b14 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/robot/constant/WorkWechatMsgTypeEnum.java @@ -0,0 +1,26 @@ +package com.senmesh.sdk.robot.constant; + +/** + * @author sr on 2020-09-30 + */ +public enum WorkWechatMsgTypeEnum { + /** **/ + TEXT("text"), + /** **/ + MARKDOWN("markdown"), + /** **/ + NEWS("news"), + /** **/ + IMAGE("image"); + + private String type; + + WorkWechatMsgTypeEnum(String msgType){ + this.type = msgType; + } + + public String getType() { + return this.type; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/robot/model/IDingTalkMsg.java b/backend/src/main/java/com/senmesh/sdk/robot/model/IDingTalkMsg.java new file mode 100644 index 0000000..a7cfd79 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/robot/model/IDingTalkMsg.java @@ -0,0 +1,19 @@ +package com.senmesh.sdk.robot.model; + +import com.senmesh.sdk.robot.constant.RobotTypeEnum; + +import lombok.Data; + +/** + * @author sr on 2020-07-06 + */ +@Data +public abstract class IDingTalkMsg implements IMsg{ + + private String robotKey; + + public RobotTypeEnum getRobotType() { + return RobotTypeEnum.DING_TALK; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/robot/model/IMsg.java b/backend/src/main/java/com/senmesh/sdk/robot/model/IMsg.java new file mode 100644 index 0000000..d531a17 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/robot/model/IMsg.java @@ -0,0 +1,35 @@ +package com.senmesh.sdk.robot.model; + +import com.senmesh.sdk.robot.constant.RobotTypeEnum; + +/** + * @author sr on 2020-09-30 + */ +public interface IMsg { + + /** + * 机器人类型 + * + * @return + * @author sr on 2020-09-30 + */ + RobotTypeEnum getRobotType(); + + /** + * 机器人标识 + * + * @return + * @author sr on 2020-09-30 + */ + String getRobotKey(); + + /** + * 消息类型 + * @return + * @author sr on 2020-09-30 + */ + String getMsgType(); + + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/robot/model/IRobot.java b/backend/src/main/java/com/senmesh/sdk/robot/model/IRobot.java new file mode 100644 index 0000000..bc1d383 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/robot/model/IRobot.java @@ -0,0 +1,26 @@ +package com.senmesh.sdk.robot.model; + +import com.senmesh.sdk.robot.constant.RobotTypeEnum; + +/** + * @author sr on 2020-09-30 + */ +public interface IRobot { + + /** + * 机器人标识 + * + * @return + * @author sr on 2020-09-30 + */ + String getRobotKey(); + + /** + * 机器人类型 + * + * @return + * @author sr on 2020-09-30 + */ + RobotTypeEnum getRobotType(); + +} diff --git a/backend/src/main/java/com/senmesh/sdk/robot/model/IWorkWechatMsg.java b/backend/src/main/java/com/senmesh/sdk/robot/model/IWorkWechatMsg.java new file mode 100644 index 0000000..c55fd09 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/robot/model/IWorkWechatMsg.java @@ -0,0 +1,19 @@ +package com.senmesh.sdk.robot.model; + +import com.senmesh.sdk.robot.constant.RobotTypeEnum; + +import lombok.Data; + +/** + * @author sr on 2020-07-06 + */ +@Data +public abstract class IWorkWechatMsg implements IMsg{ + + private String robotKey; + + public RobotTypeEnum getRobotType() { + return RobotTypeEnum.WORK_WECHAT; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/robot/model/MarkdownMsg.java b/backend/src/main/java/com/senmesh/sdk/robot/model/MarkdownMsg.java new file mode 100644 index 0000000..0bb1e03 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/robot/model/MarkdownMsg.java @@ -0,0 +1,51 @@ +package com.senmesh.sdk.robot.model; + +import com.google.common.collect.Lists; +import com.senmesh.sdk.robot.constant.DingTalkMsgTypeEnum; +import com.senmesh.sdk.robot.constant.RobotTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Builder.Default; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; + + +/** + * markdown类型 消息 + * + * @author Carlye + * @date 2021/10/08 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class MarkdownMsg implements Serializable, IMsg{ + + /** **/ + private String title; + /** 消息内容 **/ + private String text; + + /** @ 手机号列表 **/ + @Default + private List atMobiles = Lists.newArrayList(); + + /** 是否@全部 **/ + private boolean atAll; + + @Default + private RobotTypeEnum robotType = RobotTypeEnum.DING_TALK; + + private String robotKey; + + @Override + public String getMsgType() { + return DingTalkMsgTypeEnum.MARKDOWN.getMsgType(); + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/robot/model/TextMsg.java b/backend/src/main/java/com/senmesh/sdk/robot/model/TextMsg.java new file mode 100644 index 0000000..d8b1204 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/robot/model/TextMsg.java @@ -0,0 +1,50 @@ +package com.senmesh.sdk.robot.model; + +import java.io.Serializable; +import java.util.List; + +import com.google.common.collect.Lists; +import com.senmesh.sdk.robot.constant.DingTalkMsgTypeEnum; +import com.senmesh.sdk.robot.constant.RobotTypeEnum; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Builder.Default; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 机器人消息 + * @author sr on 2020-09-30 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class TextMsg implements Serializable, IMsg{ + + /** **/ + private static final long serialVersionUID = -947405425579179554L; + + /** 消息内容 **/ + private String content; + + /** @ 手机号列表 **/ + @Default + private List atMobiles = Lists.newArrayList(); + + /** 是否@全部 **/ + private boolean atAll; + + @Default + private RobotTypeEnum robotType = RobotTypeEnum.DING_TALK; + + private String robotKey; + + @Override + public String getMsgType() { + return DingTalkMsgTypeEnum.TEXT.getMsgType(); + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/robot/service/IRobotService.java b/backend/src/main/java/com/senmesh/sdk/robot/service/IRobotService.java new file mode 100644 index 0000000..72a81a7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/robot/service/IRobotService.java @@ -0,0 +1,41 @@ +package com.senmesh.sdk.robot.service; + +import com.senmesh.sdk.robot.model.IDingTalkMsg; +import com.senmesh.sdk.robot.model.IWorkWechatMsg; +import com.senmesh.sdk.robot.model.MarkdownMsg; +import com.senmesh.sdk.robot.model.TextMsg; + +/** + * @author sr on 2020-09-30 + */ +public interface IRobotService { + + /** + * @param msg + * @return + * @author sr on 2020-10-09 + */ + boolean sendWorkWechat(IWorkWechatMsg msg); + + /** + * @param msg + * @return + * @author sr on 2020-10-09 + */ + boolean sendDingTalk(IDingTalkMsg msg); + + /** + * @param msg + * @return + * @author sr on 2020-10-09 + */ + boolean sendText(TextMsg msg); + + /** + * 发送 markdown 消息 + * + * @param msg 味精 + * @return boolean + */ + boolean sendMarkdown(MarkdownMsg msg); +} diff --git a/backend/src/main/java/com/senmesh/sdk/robot/service/impl/RobotDevopsProvider.java b/backend/src/main/java/com/senmesh/sdk/robot/service/impl/RobotDevopsProvider.java new file mode 100644 index 0000000..dc8d14f --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/robot/service/impl/RobotDevopsProvider.java @@ -0,0 +1,20 @@ +package com.senmesh.sdk.robot.service.impl; + +import org.springframework.stereotype.Service; + +import com.senmesh.common.exception.IDevopsProvider; +import com.senmesh.sdk.robot.util.RobotUtils; + +/** + * 机器人运维工具类 + * @author sr on 2022-03-01 + */ +@Service +public class RobotDevopsProvider implements IDevopsProvider{ + + @Override + public void deal(String msg) { + RobotUtils.sendDevops(msg); + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/robot/service/impl/RobotServiceImpl.java b/backend/src/main/java/com/senmesh/sdk/robot/service/impl/RobotServiceImpl.java new file mode 100644 index 0000000..4862c03 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/robot/service/impl/RobotServiceImpl.java @@ -0,0 +1,117 @@ +package com.senmesh.sdk.robot.service.impl; + +import com.senmesh.sdk.robot.model.MarkdownMsg; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import com.dingtalk.api.DefaultDingTalkClient; +import com.dingtalk.api.DingTalkClient; +import com.dingtalk.api.request.OapiRobotSendRequest; +import com.dingtalk.api.response.OapiRobotSendResponse; +import com.senmesh.sdk.robot.constant.RobotTypeEnum; +import com.senmesh.sdk.robot.model.IDingTalkMsg; +import com.senmesh.sdk.robot.model.IWorkWechatMsg; +import com.senmesh.sdk.robot.model.TextMsg; +import com.senmesh.sdk.robot.service.IRobotService; +import com.senmesh.sdk.workwechat.constant.WorkWechatConstants; +import com.senmesh.sdk.workwechat.model.WwrTextMsg; +import com.senmesh.sdk.workwechat.util.WorkWechatUtils; +import com.taobao.api.ApiException; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author sr on 2020-09-30 + */ +@Service +@Slf4j +public class RobotServiceImpl implements IRobotService { + + private static final String WORK_WECHAT_URL_PREFIX = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key="; + private static final String DING_TALK_URL_PREFIX = "https://oapi.dingtalk.com/robot/send?access_token="; + + private static final Long DING_TALK_SUC_CODE = 0L; + + @Autowired + private RestTemplate restTemplate; + + @Override + public boolean sendMarkdown(MarkdownMsg msg) { + if (msg.getRobotType() == RobotTypeEnum.DING_TALK) { + OapiRobotSendRequest request = new OapiRobotSendRequest(); + request.setMsgtype(msg.getMsgType()); + + OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown(); + markdown.setText(msg.getText()); + markdown.setTitle(msg.getTitle()); + request.setMarkdown(markdown); + + OapiRobotSendRequest.At at = new OapiRobotSendRequest.At(); + at.setAtMobiles(msg.getAtMobiles()); + // isAtAll类型如果不为Boolean,请升级至最新SDK + at.setIsAtAll(msg.isAtAll()); + request.setAt(at); + this.sendDingTalk(msg.getRobotKey(), request); + } + return false; + } + + @Override + public boolean sendText(TextMsg msg) { + if (msg.getRobotType() == RobotTypeEnum.DING_TALK) { + OapiRobotSendRequest request = new OapiRobotSendRequest(); + request.setMsgtype(msg.getMsgType()); + OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text(); + text.setContent(msg.getContent()); + request.setText(text); + OapiRobotSendRequest.At at = new OapiRobotSendRequest.At(); + at.setAtMobiles(msg.getAtMobiles()); + // isAtAll类型如果不为Boolean,请升级至最新SDK + at.setIsAtAll(msg.isAtAll()); + request.setAt(at); + this.sendDingTalk(msg.getRobotKey(), request); + } else { + WwrTextMsg wwrMsg = WwrTextMsg.builder().content(msg.getContent()) + .mentionedMobileList(msg.getAtMobiles()).build(); + wwrMsg.setRobotKey(msg.getRobotKey()); + if (msg.isAtAll()) { + wwrMsg.getMentionedMobileList().add(WorkWechatConstants.AT_ALL); + } + return this.sendWorkWechat(wwrMsg); + } + return false; + } + + @Override + public boolean sendWorkWechat(IWorkWechatMsg msg) { + try { + restTemplate.postForEntity(WORK_WECHAT_URL_PREFIX + msg.getRobotKey(), WorkWechatUtils.parsePostData(msg), + Object.class); + return true; + } catch (Exception e) { + log.info("WorkWechatRobot send error:{}", e.getMessage(), e); + return false; + } + } + + @Override + public boolean sendDingTalk(IDingTalkMsg msg) { + // TODO 待实现其他类型 + return false; + } + + private boolean sendDingTalk(String robotKey, OapiRobotSendRequest request) { + DingTalkClient client = + new DefaultDingTalkClient(DING_TALK_URL_PREFIX + robotKey); + try { + OapiRobotSendResponse response = client.execute(request); + log.info("DingTalkRobot response,code:{},msg:{}", response.getErrcode(), response.getErrmsg()); + return DING_TALK_SUC_CODE.equals(response.getErrcode()); + } catch (ApiException e) { + log.info("DingTalkRobot send error:{}", e.getMessage()); + return false; + } + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/robot/util/MarkdownMsgUtils.java b/backend/src/main/java/com/senmesh/sdk/robot/util/MarkdownMsgUtils.java new file mode 100644 index 0000000..24ae8d9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/robot/util/MarkdownMsgUtils.java @@ -0,0 +1,87 @@ +package com.senmesh.sdk.robot.util; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.sdk.robot.constant.RobotTypeEnum; +import com.senmesh.sdk.robot.model.MarkdownMsg; +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; +import java.util.List; + + +/** + * Markdown + * + * @author Carlye + * @date 2021/10/08 + */ +public class MarkdownMsgUtils { + + public static MarkdownMsg build(String robotKey, String title, String msg) { + return MarkdownMsg.builder().robotKey(robotKey).title(title).text(msg).build(); + } + + public static MarkdownMsg setAtMobiles(MarkdownMsg markdownMsg, List atMobileList) { + if (markdownMsg == null) { + return markdownMsg; + } + markdownMsg.setAtMobiles(atMobileList); + return markdownMsg; + } + + + /** + * 根据传入类型创建文本消息 + * + * @param robotTypeKey 机器人类型关键 + * @param title 标题 + * @param msg 味精 + * @return {@link MarkdownMsg} + */ + public static MarkdownMsg createMsg(String robotTypeKey, String title, String msg) { + String[] typeKey = robotTypeKey.split(CommonConstants.COLON); + RobotTypeEnum robotType = RobotTypeEnum.valueOf(typeKey[0]); + String robotKey = typeKey[1]; + MarkdownMsg markdownMsg = null; + if (robotType == RobotTypeEnum.WORK_WECHAT) { +// markdownMsg = build(robotKey, title, msg); +// markdownMsg.setRobotType(RobotTypeEnum.WORK_WECHAT); + } else if (robotType == RobotTypeEnum.DING_TALK) { + markdownMsg = build(robotKey, title, msg); + } + return markdownMsg; + } + + + /** + * 根据传入类型创建文本消息 + * + * @param robotTypeKey 机器人类型关键 + * @param atMobiles 在手机 + * @param title 标题 + * @param msg 味精 + * @return {@link MarkdownMsg} + */ + public static MarkdownMsg createMsg(String robotTypeKey, String atMobiles, String title, String msg) { + List atMobileList = + StringUtils.isNotBlank(atMobiles) ? Arrays.asList(atMobiles.split(",")) : null; + return createMsg(robotTypeKey, atMobileList, title, msg); + } + + + /** + * 根据传入类型创建文本消息 + * + * @param robotTypeKey 机器人类型关键 + * @param atMobileList 在移动列表 + * @param title 标题 + * @param msg 味精 + * @return {@link MarkdownMsg} + */ + public static MarkdownMsg createMsg(String robotTypeKey, List atMobileList, String title, String msg) { + MarkdownMsg markdownMsg = createMsg(robotTypeKey, title, msg); + return setAtMobiles(markdownMsg, atMobileList); + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/robot/util/RobotUtils.java b/backend/src/main/java/com/senmesh/sdk/robot/util/RobotUtils.java new file mode 100644 index 0000000..91a1b34 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/robot/util/RobotUtils.java @@ -0,0 +1,168 @@ +package com.senmesh.sdk.robot.util; + +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.sdk.robot.model.MarkdownMsg; +import com.senmesh.sdk.robot.model.TextMsg; +import com.senmesh.sdk.robot.service.IRobotService; + +import lombok.extern.slf4j.Slf4j; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author sr on 2020-10-12 + */ +@Component +@Slf4j +public class RobotUtils { + + private static IRobotService robotService; + + /** + * 运维机器人配置键 + **/ + public static final String DEVOPS_KEY = "robot.devops.typeKey"; + + @Autowired + public void setRobotService(IRobotService robotService) { + RobotUtils.robotService = robotService; + } + + + /** + * 发送文本消息,@指定手机号 + * + * @param robotTypeKey 机器人类型关键 + * @param atMobiles 在手机 + * @param title 标题 + * @param msg 味精 + */ + public static void sendMarkdownMsg(String robotTypeKey, String atMobiles, String title, + String msg) { + try { + MarkdownMsg markdownMsg = MarkdownMsgUtils.createMsg(robotTypeKey, atMobiles, title, msg); + robotService.sendMarkdown(markdownMsg); + } catch (BusinessException be) { + log.info("执行失败:{}", be.getMessage()); + } catch (Exception e) { + log.info("robot error", e); + } + } + + /** + * 发送文本消息,@指定手机号 + * + * @param robotTypeKey 机器人类型关键 + * @param atMobileList 在移动列表 + * @param title 标题 + * @param msg 味精 + */ + public static void sendMarkdownMsg(String robotTypeKey, List atMobileList, String title, + String msg) { + try { + MarkdownMsg markdownMsg = MarkdownMsgUtils.createMsg(robotTypeKey, atMobileList, title, msg); + robotService.sendMarkdown(markdownMsg); + } catch (BusinessException be) { + log.info("执行失败:{}", be.getMessage()); + } catch (Exception e) { + log.info("robot error", e); + } + } + + + /** + * 发送文本消息,@所有人 + * + * @param robotTypeKey 机器人类型关键 + * @param title 标题 + * @param msg 味精 + */ + public static void sendMarkdownMsgAtAll(String robotTypeKey, String title, String msg) { + try { + MarkdownMsg markdownMsg = MarkdownMsgUtils.createMsg(robotTypeKey, title, msg); + markdownMsg.setAtAll(true); + robotService.sendMarkdown(markdownMsg); + } catch (BusinessException be) { + log.info("执行失败:{}", be.getMessage()); + } catch (Exception e) { + log.info("robot error", e); + } + } + + /** + * 发送文本消息,@指定手机号 + * + * @param robotTypeKey + * @param atMobiles 手机号逗号拼接 + * @param msg + * @author sr on 2020-10-12 + */ + public static void sendTextMsg(String robotTypeKey, String atMobiles, String msg) { + try { + TextMsg textMsg = TextMsgUtils.createMsg(robotTypeKey, atMobiles, msg); + robotService.sendText(textMsg); + } catch (BusinessException be) { + log.info("执行失败:{}", be.getMessage()); + } catch (Exception e) { + log.info("robot error", e); + } + } + + /** + * 发送文本消息,@指定手机号 + * + * @param robotTypeKey + * @param atMobileList 手机号集合 + * @param msg + * @author sr on 2020-10-12 + */ + public static void sendTextMsg(String robotTypeKey, List atMobileList, String msg) { + try { + TextMsg textMsg = TextMsgUtils.createMsg(robotTypeKey, atMobileList, msg); + robotService.sendText(textMsg); + } catch (BusinessException be) { + log.info("执行失败:{}", be.getMessage()); + }catch (Exception e) { + log.info("robot error", e); + } + } + + /** + * 发送文本消息,@所有人 + * + * @param robotTypeKey + * @param msg + * @author sr on 2020-10-12 + */ + public static void sendTextMsgAtAll(String robotTypeKey, String msg) { + try { + TextMsg textMsg = TextMsgUtils.createMsg(robotTypeKey, msg); + textMsg.setAtAll(true); + robotService.sendText(textMsg); + } catch (BusinessException be) { + log.info("执行失败:{}", be.getMessage()); + } catch (Exception e) { + log.info("robot error", e); + } + } + + + + /** + * 发送运维人员消息 + * + * @param msg 消息体 + * @author sr on 2021-04-13 + */ + public static void sendDevops(String msg) { + try { + sendTextMsgAtAll(EnvironmentUtils.getProperty(DEVOPS_KEY), msg); + } catch (Exception e) { + log.info("robot error", e); + } + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/robot/util/TextMsgUtils.java b/backend/src/main/java/com/senmesh/sdk/robot/util/TextMsgUtils.java new file mode 100644 index 0000000..390c101 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/robot/util/TextMsgUtils.java @@ -0,0 +1,86 @@ +package com.senmesh.sdk.robot.util; + +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.sdk.robot.constant.RobotTypeEnum; +import com.senmesh.sdk.robot.model.TextMsg; + +/** + * @author sr on 2020-10-12 + */ +public class TextMsgUtils { + + public static TextMsg build(String robotKey, String msg){ + return TextMsg.builder().robotKey(robotKey).content(msg).build(); + } + + public static TextMsg setAtMobiles(TextMsg textMsg, List atMobileList) { + if (textMsg == null) { + return textMsg; + } + textMsg.setAtMobiles(atMobileList); + return textMsg; + } + + /** + * 根据传入类型创建文本消息 + * + * @param robotTypeKey + * @param msg + * @return + * @author sr on 2020-10-12 + */ + public static TextMsg createMsg(String robotTypeKey, String msg) { + Assert.isTrue( + StringUtils.isNotBlank(robotTypeKey) && robotTypeKey.contains(CommonConstants.COLON), + "机器人类型有误:" + robotTypeKey); + String[] typeKey = robotTypeKey.split(CommonConstants.COLON); + String robotTypeStr = typeKey[0]; + RobotTypeEnum robotType = RobotTypeEnum.valueOf(robotTypeStr); + String robotKey = typeKey[1]; + TextMsg textMsg = null; + if (robotType == RobotTypeEnum.WORK_WECHAT) { + textMsg = build(robotKey, msg); + textMsg.setRobotType(RobotTypeEnum.WORK_WECHAT); + } else if (robotType == RobotTypeEnum.DING_TALK) { + textMsg = build(robotKey, msg); + } + return textMsg; + } + + /** + * 根据传入类型创建文本消息 + * + * @param robotTypeKey 机器人类型和标识,type:key + * @param atMobiles + * @param msg + * @return + * @author sr on 2020-10-12 + */ + public static TextMsg createMsg(String robotTypeKey, String atMobiles, String msg) { + List atMobileList = + StringUtils.isNotBlank(atMobiles) ? Arrays.asList(atMobiles.split(",")) : null; + return createMsg(robotTypeKey, atMobileList, msg); + } + + /** + * 根据传入类型创建文本消息 + * + * @param robotTypeKey + * @param atMobileList + * @param msg + * @return + * @author sr on 2020-10-12 + */ + public static TextMsg createMsg(String robotTypeKey, List atMobileList, String msg) { + TextMsg textMsg = createMsg(robotTypeKey, msg); + return setAtMobiles(textMsg, atMobileList); + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/config/SmsConfig.java b/backend/src/main/java/com/senmesh/sdk/sms/config/SmsConfig.java new file mode 100644 index 0000000..abce16c --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/config/SmsConfig.java @@ -0,0 +1,49 @@ +package com.senmesh.sdk.sms.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +import com.aliyuncs.DefaultAcsClient; +import com.aliyuncs.IAcsClient; +import com.aliyuncs.profile.DefaultProfile; + +import lombok.Data; + +/** + * 短信sms配置 + * + * @author on 2019-11-05 + */ +@ConfigurationProperties(prefix = SmsConfig.PREFIX) +@Data +@Component +public class SmsConfig { + + public static final String PREFIX = "sms"; + + private Boolean enable; + + /** 次数限制 **/ + private Long numLimit; + + private String domain; + + private String accessKeyId; + + private String accessSecret; + + private String regionId; + + private String version; + + /** 签名 **/ + private String signName; + + + @Bean + public IAcsClient defaultProfile() { + DefaultProfile defaultProfile = DefaultProfile.getProfile(regionId, accessKeyId, accessSecret); + return new DefaultAcsClient(defaultProfile); + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/constant/AliSmsActionEnum.java b/backend/src/main/java/com/senmesh/sdk/sms/constant/AliSmsActionEnum.java new file mode 100644 index 0000000..10f9cb3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/constant/AliSmsActionEnum.java @@ -0,0 +1,44 @@ +package com.senmesh.sdk.sms.constant; + +/** + * 阿里云action + * + * @author sr on 2020-07-03 + */ +public enum AliSmsActionEnum { + + /** 发送短信 **/ + SEND_SMS("SendSms"), + /** 批量发送短信 **/ + SEND_BATCH_SMS("SendBatchSms"), + /** 查询短信发送的状态 **/ + QUERY_SEND_DETAILS("QuerySendDetails"), + /** 申请短信签名 **/ + ADD_SMS_SIGN("AddSmsSign"), + /** 删除短信签名 **/ + DELETE_SMS_SIGN("DeleteSmsSign"), + /** 查询短信签名申请状态 **/ + QUERY_SMS_SIGN("QuerySmsSign"), + /** 修改未审核通过的短信签名,并重新提交审核 **/ + MODIFY_SMS_SIGN("ModifySmsSign"), + /** 修改未通过审核的短信模板 **/ + MODIFY_SMS_TEMPLATE("ModifySmsTemplate"), + /** 查询短信模板的审核状态 **/ + QUERY_SMS_TEMPLATE("QuerySmsTemplate"), + /** 申请短信模板 **/ + ADD_SMS_TEMPLATE("AddSmsTemplate"), + /** 删除短信模板 **/ + DELETE_SMS_TEMPLATE("DeleteSmsTemplate"); + + private String value; + + private AliSmsActionEnum(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/constant/SmsConstants.java b/backend/src/main/java/com/senmesh/sdk/sms/constant/SmsConstants.java new file mode 100644 index 0000000..4c75783 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/constant/SmsConstants.java @@ -0,0 +1,18 @@ +package com.senmesh.sdk.sms.constant; + +/** + * 短信常量类 + * + * @author sr on 2019-09-16 + */ +public interface SmsConstants { + + /** 成功码 **/ + String SUCCESS_CODE = "OK"; + + /** ================ sms 调起真实服务前异常msg ================= **/ + String TEMPLATE_CODE_KEY_EMPTY = "sms短信模版配置健为空"; + String TEMPLATE_CODE_EMPTY = "sms短信模版为空"; + /** ================ sms 调起真实服务前异常msg ================= **/ + +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/constant/SmsProviderEnum.java b/backend/src/main/java/com/senmesh/sdk/sms/constant/SmsProviderEnum.java new file mode 100644 index 0000000..98ce908 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/constant/SmsProviderEnum.java @@ -0,0 +1,22 @@ +package com.senmesh.sdk.sms.constant; + +/** + * 短信服务提供者 + * @author sr on 2020-07-03 + */ +public enum SmsProviderEnum { + + /** 阿里云 **/ + ALIYAN("aliyun"); + + private String providerName; + + SmsProviderEnum(String providerName){ + this.providerName = providerName; + } + + public String getProviderName() { + return this.providerName; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/dto/ISendDTO.java b/backend/src/main/java/com/senmesh/sdk/sms/dto/ISendDTO.java new file mode 100644 index 0000000..a444fc3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/dto/ISendDTO.java @@ -0,0 +1,64 @@ +package com.senmesh.sdk.sms.dto; + +import com.senmesh.sdk.sms.constant.SmsProviderEnum; + +/** + * 发送短信对象接口 + * + * @author sr on 2020-07-02 + * @param + */ +public interface ISendDTO { + + /** + * 短信服务商提供者,默认阿里云 + * + * @return + * @author sr on 2020-07-03 + */ + default SmsProviderEnum getSmsProvider() { + return SmsProviderEnum.ALIYAN; + } + + /** + * 短信模版配置key,获取配置时内部会自动加上(sms)前缀, 如配置文件中添加sms.someTemplateCode,此处配置someTemplateCode + * + * @return + * @author sr on 2020-07-02 + */ + String getTemplateCodeKey(); + + /** + * 阿里云模版code,如SMS_19522**** + * + * @return + * @author sr on 2020-07-03 + */ + default String getTemplateCode() { + return null; + } + + /** + * 手机号 + * + * @return + * @author sr on 2020-07-02 + */ + String getPhone(); + + /** + * 短信模版参数 + * + * @return + * @author sr on 2020-07-02 + */ + T getParameters(); + + /** + * 获取签名 + * + * @return + */ + String getSignName(); + +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/dto/ITemplateCode.java b/backend/src/main/java/com/senmesh/sdk/sms/dto/ITemplateCode.java new file mode 100644 index 0000000..d78e0e9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/dto/ITemplateCode.java @@ -0,0 +1,18 @@ +package com.senmesh.sdk.sms.dto; + +/** + * 短信模版对象 + * + * @author sr on 2020-07-03 + */ +public interface ITemplateCode { + + /** + * 模版属性配置键,不带sms.前缀 + * + * @return + * @author sr on 2020-07-03 + */ + String getTemplateCodeKey(); + +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/dto/SimpleSendDTO.java b/backend/src/main/java/com/senmesh/sdk/sms/dto/SimpleSendDTO.java new file mode 100644 index 0000000..5453c8f --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/dto/SimpleSendDTO.java @@ -0,0 +1,31 @@ +package com.senmesh.sdk.sms.dto; + +import java.util.Map; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 发送sms对象,模版参数对象为map + * + * @author sr on 2020-07-02 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class SimpleSendDTO implements ISendDTO> { + + private String templateCodeKey; + + private String templateCode; + + private String phone; + + private Map parameters; + + private String signName; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/dto/VerificationCodeParamDTO.java b/backend/src/main/java/com/senmesh/sdk/sms/dto/VerificationCodeParamDTO.java new file mode 100644 index 0000000..10914f0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/dto/VerificationCodeParamDTO.java @@ -0,0 +1,26 @@ +package com.senmesh.sdk.sms.dto; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 验证码短信参数对象 + * + * @author sr on 2020-07-02 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class VerificationCodeParamDTO implements Serializable { + + /** **/ + private static final long serialVersionUID = 2431795846055282684L; + + private String code; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/dto/VerificationCodeSendDTO.java b/backend/src/main/java/com/senmesh/sdk/sms/dto/VerificationCodeSendDTO.java new file mode 100644 index 0000000..dc93eba --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/dto/VerificationCodeSendDTO.java @@ -0,0 +1,54 @@ +package com.senmesh.sdk.sms.dto; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 发送验证码sms对象 + * + * @author sr on 2020-07-02 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class VerificationCodeSendDTO implements ISendDTO { + + /** 短信模版配置key **/ + private String templateCodeKey; + + /** 短信模版号 **/ + private String templateCode; + + /** 手机号 **/ + private String phone; + + /** 验证码参数 **/ + private VerificationCodeParamDTO parameters; + + private String signName; + + /** 验证码 **/ + @JsonIgnore + private String code; + + @Override + public String getSignName() { + return signName; + } + + public VerificationCodeParamDTO getParameters() { + if (parameters != null) { + return parameters; + } + if (code != null) { + parameters = VerificationCodeParamDTO.builder().code(code).build(); + } + return parameters; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/model/AddSmsSign.java b/backend/src/main/java/com/senmesh/sdk/sms/model/AddSmsSign.java new file mode 100644 index 0000000..d2b64c2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/model/AddSmsSign.java @@ -0,0 +1,61 @@ +package com.senmesh.sdk.sms.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; + + +/** + * 短信签名 + * + */ +public class AddSmsSign implements Serializable { + + /** + * + */ + private static final long serialVersionUID = -5401737524288272902L; + + /** + * 是否必填:是
+ * 事例:阿里云
+ * 描述:签名名称。 **说明** + * 签名必须符合[个人用户签名规范](https://help.aliyun.com/document_detail/108076.html)或[企业用户签名规范](https://help.aliyun.com/document_detail/108254.html)。
+ */ + @JsonProperty("SignName") + private String signName; + + /** + * 是否必填:是
+ * 事例:1
+ * 描述:签名来源。其中: - 0:企事业单位的全称或简称。 - 1:工信部备案网站的全称或简称。 - 2:APP 应用的全称或简称。 - 3:公众号或小程序的全称或简称。 - + * 4:电商平台店铺名的全称或简称。 - 5:商标名的全称或简称 说明** 签名来源为 1 时,请在申请说明中添加网站域名,加快审核速度。
+ */ + @JsonProperty("SignSource") + private Integer signSource; + + /** + * 是否必填:是
+ * 事例:当前的短信签名应用于双 11 大促推广营销
+ * 描述:短信签名申请说明。请在申请说明中详细描述您的业务使用场景,申请工信部备案网站的全称或简称请在此处填写域名,长度不超过 200 个字符。
+ */ + @JsonProperty("Remark") + private String remark; + + /** + * 是否必填:否
+ * 事例:jpg
+ * 描述:签名的证明文件格式,支持上传多张图片。当前支持 jpg、png、gif 或 jpeg + * 格式的图片。个别场景下,申请签名需要上传证明文件。详细说明请参考[个人用户签名规范](https://help.aliyun.com/document_detail/108076.html)和[企业用户签名规范](https://help.aliyun.com/document_detail/108254.html)。
+ */ + @JsonProperty("SignFileList.N.FileSuffix") + private String fileSuffix; + + /** + * 是否必填:否
+ * 事例:R0lGODlhHAAmAKIHAKqqqsvLy0hISObm5vf394uLiwAA
+ * 描述:签名的资质证明文件经 base64 编码后的字符串。图片不超过 2 + * MB。个别场景下,申请签名需要上传证明文件。详细说明请参考[个人用户签名规范](https://help.aliyun.com/document_detail/108076.html)和[企业用户签名规范](https://help.aliyun.com/document_detail/108254.html)。
+ */ + @JsonProperty("SignFileList.N.FileContents") + private String fileContents; +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/model/AddSmsSignResponse.java b/backend/src/main/java/com/senmesh/sdk/sms/model/AddSmsSignResponse.java new file mode 100644 index 0000000..4564b26 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/model/AddSmsSignResponse.java @@ -0,0 +1,45 @@ +package com.senmesh.sdk.sms.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; + +/** + * 短信签名 + * + */ +public class AddSmsSignResponse implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 4121769016752821993L; + + /** + * 事例:阿里云
+ * 描述:签名名称。
+ */ + @JsonProperty("SignName") + private String signName; + + /** + * 事例:OK
+ * 描述:状态码的描述。
+ */ + @JsonProperty("Message") + private String message; + + /** + * 事例:F655A8D5-B967-440B-8683-DAD6FF8DE990
+ * 描述:请求 ID。
+ */ + @JsonProperty("RequestId") + private String requestId; + + /** + * 事例:OK
+ * 描述:请求状态码。 - 返回 OK 代表请求成功。 - + * 其他错误码详见[错误码列表](https://help.aliyun.com/document_detail/101346.html)。
+ */ + @JsonProperty("Code") + private String code; +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/model/AddSmsTemplate.java b/backend/src/main/java/com/senmesh/sdk/sms/model/AddSmsTemplate.java new file mode 100644 index 0000000..2f0d755 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/model/AddSmsTemplate.java @@ -0,0 +1,50 @@ +package com.senmesh.sdk.sms.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; + +/** + * 短信模板 + * + */ +public class AddSmsTemplate implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 5868722985393802890L; + + /** + * 是否必填:是
+ * 事例:1
+ * 描述:短信类型。其中: - 0:验证码。 - 1:短信通知。 - 2:推广短信。 - 3:国际 / 港澳台消息。
+ */ + @JsonProperty("TemplateType") + private Integer templateType; + + /** + * 是否必填:是
+ * 事例:阿里云短信测试模板
+ * 描述:模板名称,长度为 1~30 个字符。
+ */ + @JsonProperty("TemplateName") + private String templateName; + + /** + * 是否必填:是
+ * 事例:您正在申请手机注册,验证码为:${code},5 分钟内有效!
+ * 描述:模板内容,长度为 1~500 + * 个字符。模板内容需要符合[文本短信模板规范](https://help.aliyun.com/document_detail/108253.html)或[国际 / + * 港澳台短信模板规范](https://help.aliyun.com/document_detail/108254.html)。
+ */ + @JsonProperty("TemplateContent") + private String templateContent; + + /** + * 是否必填:是
+ * 事例:当前的短信模板应用于双 11 大促推广营销
+ * 描述:短信模板申请说明。请在申请说明中描述您的业务使用场景,长度为 1~100 个字符。
+ */ + @JsonProperty("Remark") + private String remark; +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/model/DeleteSmsSign.java b/backend/src/main/java/com/senmesh/sdk/sms/model/DeleteSmsSign.java new file mode 100644 index 0000000..2aa8284 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/model/DeleteSmsSign.java @@ -0,0 +1,24 @@ +package com.senmesh.sdk.sms.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; + +/** + * 短信签名 + * + */ +public class DeleteSmsSign implements Serializable { + + /** + * + */ + private static final long serialVersionUID = -6841147861661592533L; + + /** + * 是否必填:是
+ * 事例:阿里云
+ * 描述:短信签名。 **说明** 必须是本账号已申请的短信签名。
+ */ + @JsonProperty("SignName") + private String signName; +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/model/DeleteSmsSignResponse.java b/backend/src/main/java/com/senmesh/sdk/sms/model/DeleteSmsSignResponse.java new file mode 100644 index 0000000..65764c1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/model/DeleteSmsSignResponse.java @@ -0,0 +1,45 @@ +package com.senmesh.sdk.sms.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; + +/** + * 短信签名 + * + */ +public class DeleteSmsSignResponse implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 8836559705606969786L; + + /** + * 事例:OK
+ * 描述:请求状态码。 - 返回 OK 代表请求成功。 - + * 其他错误码详见[错误码列表](https://help.aliyun.com/document_detail/101346.html)。
+ */ + @JsonProperty("Code") + private String code; + + /** + * 事例:OK
+ * 描述:状态码的描述。
+ */ + @JsonProperty("Message") + private String message; + + /** + * 事例:F655A8D5-B967-440B-8683-DAD6FF8DE990
+ * 描述:请求 ID。
+ */ + @JsonProperty("RequestId") + private String requestId; + + /** + * 事例:阿里云
+ * 描述:签名名称。
+ */ + @JsonProperty("SignName") + private String signName; +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/model/DeleteSmsTemplate.java b/backend/src/main/java/com/senmesh/sdk/sms/model/DeleteSmsTemplate.java new file mode 100644 index 0000000..891507e --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/model/DeleteSmsTemplate.java @@ -0,0 +1,24 @@ +package com.senmesh.sdk.sms.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; + +/** + * 短信模板 + * + */ +public class DeleteSmsTemplate implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 3423181148483950846L; + + /** + * 是否必填:是
+ * 事例:SMS\_152550005
+ * 描述:短信模板 CODE。您可以在控制台 **模板管理** 页面或 API 接口 ** AddSmsTemplate** 的返回参数中获取短信模板 CODE。
+ */ + @JsonProperty("TemplateCode") + private String templateCode; +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/model/ModifySmsSign.java b/backend/src/main/java/com/senmesh/sdk/sms/model/ModifySmsSign.java new file mode 100644 index 0000000..1b423b8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/model/ModifySmsSign.java @@ -0,0 +1,60 @@ +package com.senmesh.sdk.sms.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; + +/** + * 短信签名 + * + */ +public class ModifySmsSign implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 7033519742117645850L; + + /** + * 是否必填:是
+ * 事例:阿里云
+ * 描述:签名内容。 **说明** + * 签名内容必须符合[个人用户签名规范](https://help.aliyun.com/document_detail/108076.html)或[企业用户签名规范](https://help.aliyun.com/document_detail/108254.html)。
+ */ + @JsonProperty("SignName") + private String signName; + + /** + * 是否必填:是
+ * 事例:1
+ * 描述:签名来源。其中: - 0:企事业单位的全称或简称。 - 1:工信部备案网站的全称或简称。 - 2:APP 应用的全称或简称。 - 3:公众号或小程序的全称或简称。 - + * 4:电商平台店铺名的全称或简称。 - 5:商标名的全称或简称 说明** 签名来源为 1 时,请在申请说明中添加网站域名,加快审核速度。
+ */ + @JsonProperty("SignSource") + private Integer signSource; + + /** + * 是否必填:是
+ * 事例:当前的短信签名应用于双 11 大促推广营销
+ * 描述:短信签名申请说明。请在申请说明中详细描述您的业务使用场景,申请工信部备案网站的全称或简称请在此处填写域名,长度不超过 200 个字符。
+ */ + @JsonProperty("Remark") + private String remark; + + /** + * 是否必填:否
+ * 事例:jpg
+ * 描述:签名的证明文件格式,支持上传多张图片。当前支持 jpg、png、gif 或 jpeg + * 格式的图片。个别场景下,申请签名需要上传证明文件。详细说明请参考[个人用户签名规范](https://help.aliyun.com/document_detail/108076.html)和[企业用户签名规范](https://help.aliyun.com/document_detail/108254.html)。
+ */ + @JsonProperty("SignFileList.N.FileSuffix") + private String fileSuffix; + + /** + * 是否必填:否
+ * 事例:R0lGODlhHAAmAKIHAKqqqsvLy0hISObm5vf394uLiwAA
+ * 描述:签名的质证明文件经 base64 编码后的字符串。图片不超过 2 + * MB。个别场景下,申请签名需要上传证明文件。详细说明请参考[个人用户签名规范](https://help.aliyun.com/document_detail/108076.html)和[企业用户签名规范](https://help.aliyun.com/document_detail/108254.html)。
+ */ + @JsonProperty("SignFileList.N.FileContents") + private String fileContents; +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/model/ModifySmsSignResponse.java b/backend/src/main/java/com/senmesh/sdk/sms/model/ModifySmsSignResponse.java new file mode 100644 index 0000000..caeb684 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/model/ModifySmsSignResponse.java @@ -0,0 +1,45 @@ +package com.senmesh.sdk.sms.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; + +/** + * 短信签名 + * + */ +public class ModifySmsSignResponse implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 2556874115950958951L; + + /** + * 事例:OK
+ * 描述:请求状态码。 - 返回 OK 代表请求成功。 - + * 其他错误码详见[错误码列表](https://help.aliyun.com/document_detail/101346.html)。
+ */ + @JsonProperty("Code") + private String code; + + /** + * 事例:OK
+ * 描述:状态码的描述。
+ */ + @JsonProperty("Message") + private String message; + + /** + * 事例:F655A8D5-B967-440B-8683-DAD6FF8DE990
+ * 描述:请求 ID。
+ */ + @JsonProperty("RequestId") + private String requestId; + + /** + * 事例:阿里云
+ * 描述:签名名称。
+ */ + @JsonProperty("SignName") + private String signName; +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/model/ModifySmsTemplate.java b/backend/src/main/java/com/senmesh/sdk/sms/model/ModifySmsTemplate.java new file mode 100644 index 0000000..311c1c6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/model/ModifySmsTemplate.java @@ -0,0 +1,59 @@ +package com.senmesh.sdk.sms.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; + +/** + * 短信模板 + * + */ +public class ModifySmsTemplate implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 4824423254878168505L; + + /** + * 是否必填:是
+ * 事例:1
+ * 描述:短信类型。其中: - 0 表示验证码。 - 1 表示短信通知。 - 2 表示推广短信。 - 3 国际 / 港澳台消息。
+ */ + @JsonProperty("TemplateType") + private Integer templateType; + + /** + * 是否必填:是
+ * 事例:阿里云短信测试模板
+ * 描述:模板名称,长度为 1~30 个字符。
+ */ + @JsonProperty("TemplateName") + private String templateName; + + /** + * 是否必填:是
+ * 事例:您正在申请手机注册,验证码为:${code},5 分钟内有效!
+ * 描述:模板内容,长度为 1~500 + * 个字符。模板内容需要符合[文本短信模板规范](https://help.aliyun.com/document_detail/108253.html)或[国际 / + * 港澳台短信模板规范](https://help.aliyun.com/document_detail/108254.html)。 **说明** + * 修改模板时,请针对审核意见合理设计模板内容。
+ */ + @JsonProperty("TemplateContent") + private String templateContent; + + /** + * 是否必填:是
+ * 事例:当前的短信模板应用于双 11 大促推广营销
+ * 描述:短信模板申请说明。请在申请说明中描述您的业务使用场景,长度为 1~100 个字符。
+ */ + @JsonProperty("Remark") + private String remark; + + /** + * 是否必填:是
+ * 事例:SMS\_152550005
+ * 描述:短信模板 CODE。您可以在控制台 **模板管理** 页面或 API 接口 ** AddSmsTemplate** 的返回参数中获取短信模板 CODE。
+ */ + @JsonProperty("TemplateCode") + private String templateCode; +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/model/QuerySendDetails.java b/backend/src/main/java/com/senmesh/sdk/sms/model/QuerySendDetails.java new file mode 100644 index 0000000..441e983 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/model/QuerySendDetails.java @@ -0,0 +1,56 @@ +package com.senmesh.sdk.sms.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; + +/** + * 查询发送记录 + * + */ +public class QuerySendDetails implements Serializable { + + /** + * + */ + private static final long serialVersionUID = -6796100129790552341L; + + /** + * 是否必填:是
+ * 事例:1
+ * 描述:分页查看发送记录,指定发送记录的的当前页码。
+ */ + @JsonProperty("CurrentPage") + private Long currentPage; + + /** + * 是否必填:是
+ * 事例:10
+ * 描述:分页查看发送记录,指定每页显示的短信记录数量。取值范围为 1~50。
+ */ + @JsonProperty("PageSize") + private Long pageSize; + + /** + * 是否必填:是
+ * 事例:15900000000
+ * 描述:接收短信的手机号码。格式: - 国内短信:11 位手机号码,例如 15900000000。 - 国际 / 港澳台消息:国际区号 + 号码,例如 85200000000。
+ */ + @JsonProperty("PhoneNumber") + private String phoneNumber; + + /** + * 是否必填:是
+ * 事例:20181228
+ * 描述:短信发送日期,支持查询最近 30 天的记录。格式为 yyyyMMdd,例如 20181225。
+ */ + @JsonProperty("SendDate") + private String sendDate; + + /** + * 是否必填:否
+ * 事例:134523^4351232
+ * 描述:发送回执 ID,即发送流水号。调用发送接口 SendSms 或 SendBatchSms 发送短信时,返回值中的 BizId 字段。
+ */ + @JsonProperty("BizId") + private String bizId; +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/model/QuerySmsSign.java b/backend/src/main/java/com/senmesh/sdk/sms/model/QuerySmsSign.java new file mode 100644 index 0000000..a638960 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/model/QuerySmsSign.java @@ -0,0 +1,25 @@ +package com.senmesh.sdk.sms.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; + +/** + * 短信签名 + * + */ +public class QuerySmsSign implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 7244896668246210132L; + + /** + * 是否必填:是
+ * 事例:阿里云
+ * 描述:签名名称。
+ */ + @JsonProperty("SignName") + private String signName; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/model/QuerySmsSignResponse.java b/backend/src/main/java/com/senmesh/sdk/sms/model/QuerySmsSignResponse.java new file mode 100644 index 0000000..6595c48 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/model/QuerySmsSignResponse.java @@ -0,0 +1,67 @@ +package com.senmesh.sdk.sms.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; + +/** + * 短信签名 + * + */ +public class QuerySmsSignResponse implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 3695802019215175700L; + + /** + * 事例:OK
+ * 描述:请求状态码。 - 返回 OK 代表请求成功。 - + * 其他错误码详见[错误码列表](https://help.aliyun.com/document_detail/101346.html)。
+ */ + @JsonProperty("Code") + private String code; + + /** + * 事例:2019-01-08 16:44:13
+ * 描述:短信签名的创建日期和时间。
+ */ + @JsonProperty("CreateDate") + private String createDate; + + /** + * 事例:OK
+ * 描述:状态码描述。
+ */ + @JsonProperty("Message") + private String message; + + /** + * 事例:文件不能证明信息真实性,请重新上传
+ * 描述:审核备注。 - 如果审核状态为 **审核通过** 或 **审核中** ,参数 Reason 显示为 "无审核备注"。 - 如果审核状态为 **审核未通过** ,参数 + * Reason 显示审核的具体原因。
+ */ + @JsonProperty("Reason") + private String reason; + + /** + * 事例:CC89A90C-978F-46AC-B80D-54738371E7CA
+ * 描述:请求 ID。
+ */ + @JsonProperty("RequestId") + private String requestId; + + /** + * 事例:阿里云
+ * 描述:短信签名。
+ */ + @JsonProperty("SignName") + private String signName; + + /** + * 事例:1
+ * 描述:签名审核状态。其中: - 0:审核中。 - 1:审核通过。 - 2:审核失败,请在返回参数 Reason 中查看审核失败原因。
+ */ + @JsonProperty("SignStatus") + private Integer signStatus; +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/model/QuerySmsTemplate.java b/backend/src/main/java/com/senmesh/sdk/sms/model/QuerySmsTemplate.java new file mode 100644 index 0000000..9176c71 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/model/QuerySmsTemplate.java @@ -0,0 +1,25 @@ +package com.senmesh.sdk.sms.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; + +/** + * 短信模板 + * + */ +public class QuerySmsTemplate implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 7787624013394982501L; + + /** + * 是否必填:是
+ * 事例:SMS\_152550005
+ * 描述:短信模板 CODE。您可以在控制台 **模板管理** 页面或 API 接口 ** AddSmsTemplate** 的返回参数中获取短信模板 CODE。
+ */ + @JsonProperty("TemplateCode") + private String templateCode; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/model/QuerySmsTemplateResponse.java b/backend/src/main/java/com/senmesh/sdk/sms/model/QuerySmsTemplateResponse.java new file mode 100644 index 0000000..fbeb5c1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/model/QuerySmsTemplateResponse.java @@ -0,0 +1,63 @@ +package com.senmesh.sdk.sms.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * 查询查询短信模板的审核状态响应体 + * + */ +public class QuerySmsTemplateResponse extends SmsResponse { + + /** **/ + private static final long serialVersionUID = 4855274472484572364L; + + /** + * 事例:2019-06-04 11:42:17
+ * 描述:短信模板的创建日期和时间。
+ */ + @JsonProperty("CreateDate") + private String createDate; + + /** + * 事例:非验证码类型短信,请选择短信通知类型为推广短信。
+ * 描述:审核备注。 - 如果审核状态为 **审核通过** 或 **审核中** ,参数 Reason 显示为 "无审核备注"。 - 如果审核状态为 **审核未通过** ,参数 + * Reason 显示审核的具体原因。
+ */ + @JsonProperty("Reason") + private String reason; + + /** + * 事例:SMS\_167035184
+ * 描述:短信模板 CODE。
+ */ + @JsonProperty("TemplateCode") + private String templateCode; + + /** + * 事例:亲爱的会员!阿里云短信服务祝您新年快乐!
+ * 描述:模板内容。
+ */ + @JsonProperty("TemplateContent") + private String templateContent; + + /** + * 事例:阿里云短信测试模板
+ * 描述:模板名称。
+ */ + @JsonProperty("TemplateName") + private String templateName; + + /** + * 事例:1
+ * 描述:模板审核状态。其中: - 0:审核中。 - 1:审核通过。 - 2:审核失败,请在返回参数 Reason 中查看审核失败原因。
+ */ + @JsonProperty("TemplateStatus") + private Integer templateStatus; + + /** + * 事例:1
+ * 描述:短信类型。其中: - 0:验证码。 - 1:短信通知。 - 2:推广短信。 - 3:国际 / 港澳台消息。
+ */ + @JsonProperty("TemplateType") + private Integer templateType; +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/model/SendBatchSms.java b/backend/src/main/java/com/senmesh/sdk/sms/model/SendBatchSms.java new file mode 100644 index 0000000..36e6342 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/model/SendBatchSms.java @@ -0,0 +1,69 @@ +package com.senmesh.sdk.sms.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 发送短信 + * + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SendBatchSms implements Serializable { + + /** + * + */ + private static final long serialVersionUID = -721415853051957784L; + + /** + * 是否必填:是
+ * 事例:["15900000000","13500000000"]
+ * 描述:接收短信的手机号码,JSON 数组格式。手机号码格式: - 国内短信:11 位手机号码,例如 15900000000。 - 国际 / 港澳台消息:国际区号 + 号码,例如 + * 85200000000。 说明** 验证码类型短信,建议使用接口 SendSms 单独发送。
+ */ + @JsonProperty("PhoneNumberJson") + private String phoneNumberJson; + + /** + * 是否必填:是
+ * 事例:["阿里云","阿里巴巴"]
+ * 描述:短信签名名称,JSON 数组格式。请在控制台 **签名管理** 页面 **签名名称** 一列查看。 **说明** + * 必须是已添加、并通过审核的短信签名;且短信签名的个数必须与手机号码的个数相同、内容一一对应。
+ */ + @JsonProperty("SignNameJson") + private String signNameJson; + + /** + * 是否必填:是
+ * 事例:SMS\_152550005
+ * 描述:短信模板 CODE。请在控制台 **模板管理** 页面 **模板 CODE** 一列查看。 **说明** 必须是已添加、并通过审核的模板 CODE;且发送国际 / + * 港澳台消息时,请使用国际 / 港澳台短信模版。
+ */ + @JsonProperty("TemplateCode") + private String templateCode; + + /** + * 是否必填:否
+ * 事例:["90999","90998"]
+ * 描述:上行短信扩展码,JSON 数组格式。无特殊需要此字段的用户请忽略此字段。
+ */ + @JsonProperty("SmsUpExtendCodeJson") + private String smsUpExtendCodeJson; + + /** + * 是否必填:否
+ * 事例:[{"name":"TemplateParamJson"},{"name":"TemplateParamJson"}]
+ * 描述:短信模板变量对应的实际值,JSON 格式。 **说明** 如果 JSON 中需要带换行符,请参照标准的 JSON + * 协议处理;且模板变量值的个数必须与手机号码、签名的个数相同、内容一一对应,表示向指定手机号码中发对应签名的短信,且短信模板中的变量参数替换为对应的值。
+ */ + @JsonProperty("TemplateParamJson") + private String templateParamJson; +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/model/SendSms.java b/backend/src/main/java/com/senmesh/sdk/sms/model/SendSms.java new file mode 100644 index 0000000..42ae712 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/model/SendSms.java @@ -0,0 +1,76 @@ +package com.senmesh.sdk.sms.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 发送短信 + * + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SendSms implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 4127513146153674808L; + + /** + * 是否必填:是
+ * 事例:15900000000
+ * 描述:接收短信的手机号码。格式: - 国内短信:11 位手机号码,例如 15951955195。 - 国际 / 港澳台消息:国际区号 + 号码,例如 85200000000。 + * 支持对多个手机号码发送短信,手机号码之间以英文逗号(,)分隔。上限为 1000 个手机号码。批量调用相对于单条调用及时性稍有延迟。 **说明** + * 验证码类型短信,建议使用单独发送的方式。
+ */ + @JsonProperty("PhoneNumbers") + private String phoneNumbers; + + /** + * 是否必填:是
+ * 事例:阿里云
+ * 描述:短信签名名称。请在控制台 **签名管理** 页面 **签名名称** 一列查看。 **说明** 必须是已添加、并通过审核的短信签名。
+ */ + @JsonProperty("SignName") + private String signName; + + /** + * 是否必填:是
+ * 事例:SMS\_153055065
+ * 描述:短信模板 ID。请在控制台 **模板管理** 页面 **模板 CODE** 一列查看。 **说明** 必须是已添加、并通过审核的短信签名;且发送国际 / 港澳台消息时,请使用国际 / + * 港澳台短信模版。
+ */ + @JsonProperty("TemplateCode") + private String templateCode; + + /** + * 是否必填:否
+ * 事例:abcdefgh
+ * 描述:外部流水扩展字段。
+ */ + @JsonProperty("OutId") + private String outId; + + /** + * 是否必填:否
+ * 事例:90999
+ * 描述:上行短信扩展码,无特殊需要此字段的用户请忽略此字段。
+ */ + @JsonProperty("SmsUpExtendCode") + private String smsUpExtendCode; + + /** + * 是否必填:否
+ * 事例:{"code":"1111"}
+ * 描述:短信模板变量对应的实际值,JSON 格式。 **说明** 如果 JSON 中需要带换行符,请参照标准的 JSON 协议处理。
+ */ + @JsonProperty("TemplateParam") + private String templateParam; +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/model/SendSmsResponse.java b/backend/src/main/java/com/senmesh/sdk/sms/model/SendSmsResponse.java new file mode 100644 index 0000000..b39a4e5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/model/SendSmsResponse.java @@ -0,0 +1,15 @@ +package com.senmesh.sdk.sms.model; + +import lombok.NoArgsConstructor; + +/** + * 发送短信(单个/批量)响应体 + * + */ +@NoArgsConstructor +public class SendSmsResponse extends SmsResponse { + + /** **/ + private static final long serialVersionUID = -1884360556092571210L; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/model/SmsResponse.java b/backend/src/main/java/com/senmesh/sdk/sms/model/SmsResponse.java new file mode 100644 index 0000000..ee862e2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/model/SmsResponse.java @@ -0,0 +1,39 @@ +package com.senmesh.sdk.sms.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.Data; + +import java.io.Serializable; + + +/** + * 短信响应体 + * + */ +@SuppressWarnings("serial") +@Data +public class SmsResponse implements Serializable{ + + /** + * 事例:OK
+ * 描述:请求状态码。 - 返回 OK 代表请求成功。 - + * 其他错误码详见[错误码列表](https://help.aliyun.com/document_detail/101346.html)。
+ */ + @JsonProperty("Code") + private String code; + + /** + * 事例:OK
+ * 描述:状态码的描述。
+ */ + @JsonProperty("Message") + private String message; + + /** + * 事例:F655A8D5-B967-440B-8683-DAD6FF8DE990
+ * 描述:请求 ID。
+ */ + @JsonProperty("RequestId") + private String requestId; +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/model/SmsSendDetailResponse.java b/backend/src/main/java/com/senmesh/sdk/sms/model/SmsSendDetailResponse.java new file mode 100644 index 0000000..570bc4a --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/model/SmsSendDetailResponse.java @@ -0,0 +1,73 @@ +package com.senmesh.sdk.sms.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; + +/** + * 短信发送明细 + * + */ +public class SmsSendDetailResponse implements Serializable { + + /** + * + */ + private static final long serialVersionUID = -4473285026346918644L; + + /** + * 事例:【阿里云】验证码为:123,您正在登录,若非本人操作,请勿泄露
+ * 描述:短信内容。
+ */ + @JsonProperty("Content") + private String content; + + /** + * 事例:DELIVRD
+ * 描述:运营商短信状态码。 - 短信发送成功:DELIVRD。 - + * 短信发送失败:失败错误码请参考[错误码文档](https://help.aliyun.com/document_detail/101347.html)。
+ */ + @JsonProperty("ErrCode") + private String errCode; + + /** + * 事例:123
+ * 描述:外部流水扩展字段。
+ */ + @JsonProperty("OutId") + private String outId; + + /** + * 事例:15200000000
+ * 描述:接收短信的手机号码。
+ */ + @JsonProperty("PhoneNum") + private String phoneNum; + + /** + * 事例:2019-01-08 16:44:13
+ * 描述:短信接收日期和时间。
+ */ + @JsonProperty("ReceiveDate") + private String receiveDate; + + /** + * 事例:2019-01-08 16:44:10
+ * 描述:短信发送日期和时间。
+ */ + @JsonProperty("SendDate") + private String sendDate; + + /** + * 事例:3
+ * 描述:短信发送状态,包括: - 1:等待回执。 - 2:发送失败。 - 3:发送成功。
+ */ + @JsonProperty("SendStatus") + private Long sendStatus; + + /** + * 事例:SMS\_122310183
+ * 描述:短信模板 ID。
+ */ + @JsonProperty("TemplateCode") + private String templateCode; +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/model/SmsTemplateResponse.java b/backend/src/main/java/com/senmesh/sdk/sms/model/SmsTemplateResponse.java new file mode 100644 index 0000000..185d725 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/model/SmsTemplateResponse.java @@ -0,0 +1,19 @@ +package com.senmesh.sdk.sms.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * 短信模板响应体 + * + */ + public class SmsTemplateResponse extends SmsResponse{ + + /** **/ + private static final long serialVersionUID = -8499116525368789422L; + /** + * 事例:SMS\_152550005
+ * 描述:短信模板 CODE。您可以使用模板 CODE 通过 API 接口 ** QuerySmsTemplate** 或在控制台查看模板申请状态和结果。
+ */ + @JsonProperty("TemplateCode") + private String templateCode; + } \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/sdk/sms/service/SdkSmsProvider.java b/backend/src/main/java/com/senmesh/sdk/sms/service/SdkSmsProvider.java new file mode 100644 index 0000000..5e36835 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/service/SdkSmsProvider.java @@ -0,0 +1,32 @@ +package com.senmesh.sdk.sms.service; + +import com.senmesh.common.AlitaResult; +import com.senmesh.sdk.sms.constant.SmsProviderEnum; +import com.senmesh.sdk.sms.dto.ISendDTO; + +/** + * 短信服务提供者 + * + * @author sr on 2020-07-03 + */ +public interface SdkSmsProvider { + + /** + * 提供者类型 + * + * @return + * @author sr on 2020-07-03 + */ + SmsProviderEnum getType(); + + /** + * 发送短信 + * + * @param + * @param iSendDTO + * @return + * @author sr on 2020-07-03 + */ + AlitaResult send(ISendDTO iSendDTO); + +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/service/SdkSmsService.java b/backend/src/main/java/com/senmesh/sdk/sms/service/SdkSmsService.java new file mode 100644 index 0000000..006ae80 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/service/SdkSmsService.java @@ -0,0 +1,90 @@ +package com.senmesh.sdk.sms.service; + +import com.senmesh.common.AlitaResult; +import com.senmesh.sdk.sms.dto.ISendDTO; +import com.senmesh.sdk.sms.dto.ITemplateCode; + +import java.util.Map; + +/** + * 短信 + * + * @author sr on 2020-07-02 + */ +public interface SdkSmsService { + + /** + * 发送短信(使用配置文件配置) + * + * @param + * @param iSendDTO 发送对象 + * @return success-false真实调用第三方未成功,未拿到返回值; + * success-true获取到第三方返回,data-true发送成功,data-false发送失败并返回失败原因(msg) + * @author sr on 2020-07-02 + */ + AlitaResult send(ISendDTO iSendDTO); + + /** + * 发送短信验证码 + * + * @param + * @param iTemplateCode 获取templateCodeKey 短信模版配置key,获取配置时内部会自动加上(sms)前缀;如配置文件中添加sms.someTemplate,此处配置someTemplate + * @param phone + * @param code 验证码 + * @return success-false真实调用第三方未成功,未拿到返回值; + * success-true获取到第三方返回,data-true发送成功,data-false发送失败并返回失败原因(msg) + * @author sr on 2020-07-02 + */ + AlitaResult sendVerificationCode(ITemplateCode iTemplateCode, String phone, String code); + + /** + * 发送短信验证码 + * + * @param + * @param iTemplateCode 获取templateCodeKey 短信模版配置key,获取配置时内部会自动加上(sms)前缀;如配置文件中添加sms.someTemplate,此处配置someTemplate + * @param phone + * @param code 验证码 + * @param signName 验证码签名 + * @return success-false真实调用第三方未成功,未拿到返回值; + * success-true获取到第三方返回,data-true发送成功,data-false发送失败并返回失败原因(msg) + * @author sr on 2020-07-02 + */ + AlitaResult sendVerificationCode(ITemplateCode iTemplateCode, String phone, String code, String signName); + + /** + * 发送短信验证码 + * + * @param + * @param templateCode 模版code + * @param phone + * @param code 验证码 + * @return success-false真实调用第三方未成功,未拿到返回值; + * success-true获取到第三方返回,data-true发送成功,data-false发送失败并返回失败原因(msg) + * @author sr on 2020-07-02 + */ + AlitaResult sendVerificationCode(String templateCode, String phone, String code); + + /** + * 发送短信 + * @param iTemplateCode 短信模版配置key,获取配置时内部会自动加上(sms)前缀;如配置文件中添加sms.someTemplate,此处配置someTemplate + * @param phone + * @param params + * @return success-false真实调用第三方未成功,未拿到返回值; + * success-true获取到第三方返回,data-true发送成功,data-false发送失败并返回失败原因(msg) + * @author sr on 2020-07-02 + */ + AlitaResult sendSimple(ITemplateCode iTemplateCode, String phone, Map params); + + /** + * 发送短信 + * @param templateCode 模版code + * @param phone + * @param params + * @return success-false真实调用第三方未成功,未拿到返回值; + * success-true获取到第三方返回,data-true发送成功,data-false发送失败并返回失败原因(msg) + * @author sr on 2020-07-02 + */ + AlitaResult sendSimple(String templateCode, String phone, Map params); + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/service/impl/SdkSmsServiceImpl.java b/backend/src/main/java/com/senmesh/sdk/sms/service/impl/SdkSmsServiceImpl.java new file mode 100644 index 0000000..c253757 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/service/impl/SdkSmsServiceImpl.java @@ -0,0 +1,88 @@ +package com.senmesh.sdk.sms.service.impl; + +import com.google.common.collect.Maps; +import com.senmesh.common.AlitaResult; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.sdk.sms.config.SmsConfig; +import com.senmesh.sdk.sms.constant.SmsProviderEnum; +import com.senmesh.sdk.sms.dto.*; +import com.senmesh.sdk.sms.service.SdkSmsProvider; +import com.senmesh.sdk.sms.service.SdkSmsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +/** + * @author sr on 2020-07-02 + */ +@Service +public class SdkSmsServiceImpl implements SdkSmsService { + @Autowired + private SmsConfig smsConfig; + + private final Map smsProviders = Maps.newHashMap(); + + @Autowired + SdkSmsServiceImpl(List providers) { + providers.forEach(provider -> smsProviders.put(provider.getType(), provider)); + } + + + @Override + public AlitaResult send(ISendDTO iSendDTO) { + Assert.isTrue(Boolean.TRUE.equals(smsConfig.getEnable()), "暂不支持短信功能"); + SdkSmsProvider sdkSmsProvider = smsProviders.get(iSendDTO.getSmsProvider()); + // 默认阿里云 + if (sdkSmsProvider == null) { + sdkSmsProvider = smsProviders.get(SmsProviderEnum.ALIYAN); + } + + return sdkSmsProvider.send(iSendDTO); + } + + @Override + public AlitaResult sendVerificationCode(ITemplateCode iTemplateCode, String phone, + String code) { + return this.sendVerificationCode(iTemplateCode, phone, code, null); + } + + @Override + public AlitaResult sendVerificationCode(ITemplateCode iTemplateCode, String phone, String code, String signName) { + VerificationCodeSendDTO sendDto = VerificationCodeSendDTO.builder().phone(phone) + .templateCodeKey(iTemplateCode.getTemplateCodeKey()) + .parameters(new VerificationCodeParamDTO(code)) + .signName(signName) + .build(); + return this.send(sendDto); + } + + @Override + public AlitaResult sendSimple(ITemplateCode iTemplateCode, String phone, + Map params) { + SimpleSendDTO sendDto = + SimpleSendDTO.builder().templateCodeKey(iTemplateCode.getTemplateCodeKey()).phone(phone) + .parameters(params).build(); + return this.send(sendDto); + } + + @Override + public AlitaResult sendVerificationCode(String templateCode, String phone, + String code) { + VerificationCodeSendDTO sendDto = VerificationCodeSendDTO.builder().phone(phone) + .templateCode(templateCode).parameters(new VerificationCodeParamDTO(code)) + .build(); + return this.send(sendDto); + } + + @Override + public AlitaResult sendSimple(String templateCode, String phone, + Map params) { + SimpleSendDTO sendDto = SimpleSendDTO.builder().templateCode(templateCode).phone(phone) + .parameters(params).build(); + return this.send(sendDto); + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/service/provider/AliyunSmsInvoker.java b/backend/src/main/java/com/senmesh/sdk/sms/service/provider/AliyunSmsInvoker.java new file mode 100644 index 0000000..e3039a4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/service/provider/AliyunSmsInvoker.java @@ -0,0 +1,67 @@ +package com.senmesh.sdk.sms.service.provider; + +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.aliyuncs.CommonRequest; +import com.aliyuncs.CommonResponse; +import com.aliyuncs.IAcsClient; +import com.aliyuncs.exceptions.ClientException; +import com.aliyuncs.http.MethodType; +import com.senmesh.common.AlitaResult; +import com.senmesh.common.annotation.CheckAndMock; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.sdk.common.constant.SdkConstants; +import com.senmesh.sdk.sms.config.SmsConfig; +import com.senmesh.sdk.sms.constant.AliSmsActionEnum; + +import lombok.extern.slf4j.Slf4j; + +/** + * 短信sms调用 + * + * @author on 2019-11-05 + */ +@Service +@Slf4j +public class AliyunSmsInvoker { + + @Autowired + private IAcsClient client; + + @SuppressWarnings("unchecked") + @CheckAndMock(mockClass = MockAliyunSmsInvoker.class, propertyPrefix = "sms") + public AlitaResult invoke(SmsConfig smsConfig, AliSmsActionEnum action, Object params, + Class responseClazz) { + + CommonRequest request = new CommonRequest(); + request.setMethod(MethodType.POST); + request.setDomain(smsConfig.getDomain()); + request.setVersion(smsConfig.getVersion()); + request.setAction(action.getValue()); + + if (params instanceof Map) { + ((Map) params).forEach(request::putQueryParameter); + } else { + Map paramMap = JsonUtils.objToClassObj(params, Map.class); + paramMap.forEach(request::putQueryParameter); + + } + try { + log.info("sendSms request:{}", params); + CommonResponse response = client.getCommonResponse(request); + String data = response.getData(); + log.info("sendSms reponse:{}", data); + return AlitaResult.success(JsonUtils.toObject(data, responseClazz)); + } catch (ClientException e) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, e.getMessage()); + } catch (Exception e) { + return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_ERROR_CODE, + StringUtils.join(SdkConstants.SMS_CODE, SdkConstants.INVOKE_FAIL, e.getMessage())); + } + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/service/provider/AliyunSmsProvider.java b/backend/src/main/java/com/senmesh/sdk/sms/service/provider/AliyunSmsProvider.java new file mode 100644 index 0000000..0f97bf0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/service/provider/AliyunSmsProvider.java @@ -0,0 +1,90 @@ +package com.senmesh.sdk.sms.service.provider; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.sdk.common.constant.SdkConstants; +import com.senmesh.sdk.sms.config.SmsConfig; +import com.senmesh.sdk.sms.constant.AliSmsActionEnum; +import com.senmesh.sdk.sms.constant.SmsConstants; +import com.senmesh.sdk.sms.constant.SmsProviderEnum; +import com.senmesh.sdk.sms.dto.ISendDTO; +import com.senmesh.sdk.sms.model.SendSms; +import com.senmesh.sdk.sms.model.SendSmsResponse; +import com.senmesh.sdk.sms.service.SdkSmsProvider; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 阿里云服务商提供者 + * + * @author sr on 2020-07-03 + */ +@Service +public class AliyunSmsProvider implements SdkSmsProvider { + + @Autowired + private SmsConfig smsConfig; + + @Autowired + private AliyunSmsInvoker aliyunSmsInvoker; + + @Override + public SmsProviderEnum getType() { + return SmsProviderEnum.ALIYAN; + } + + @Override + public AlitaResult send(ISendDTO iSendDTO) { + // 处理模版 + String templateCode = this.dealTemplateCode(iSendDTO); + if (templateCode == null) { + return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, + SmsConstants.TEMPLATE_CODE_EMPTY); + } + SendSms sendSms = + SendSms.builder().phoneNumbers(iSendDTO.getPhone()).templateCode(templateCode) + .templateParam(JsonUtils.toJsonString(iSendDTO.getParameters())) + .signName(StringUtils.isEmpty(iSendDTO.getSignName()) ? smsConfig.getSignName() + : iSendDTO.getSignName()) + .build(); + + AlitaResult result = + aliyunSmsInvoker.invoke(smsConfig, AliSmsActionEnum.SEND_SMS, sendSms, + SendSmsResponse.class); + // 失败,success-false + if (!result.getSuccess()) { + return AlitaResult.error(result.getCode(), result.getMsg()); + } + SendSmsResponse responseData = result.getData(); + // sms状态码成功,success-true,data-true + if (SmsConstants.SUCCESS_CODE.equals(responseData.getCode())) { + return AlitaResult.success(Boolean.TRUE); + } + // sms状态码失败,success-true,data-false + return AlitaResult.success(responseData.getMessage(), Boolean.FALSE); + } + + /** + * 处理短信发送模版 + * @param iSendDTO + * @return + * @author sr on 2021-06-16 + */ + private String dealTemplateCode(ISendDTO iSendDTO) { + String templateCode = iSendDTO.getTemplateCode(); + String templateCodeKey = iSendDTO.getTemplateCodeKey(); + // 模版为空 且 模版属性键不为空,去环境配置中获取模版 + if (StringUtils.isBlank(templateCode) && StringUtils.isNotBlank(templateCodeKey)) { + templateCode = EnvironmentUtils + .getProperty(String.join(CommonConstants.POINT, SmsConfig.PREFIX, templateCodeKey)); + } + if (StringUtils.isBlank(templateCode)) { + return null; + } + return templateCode; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/service/provider/MockAliyunSmsInvoker.java b/backend/src/main/java/com/senmesh/sdk/sms/service/provider/MockAliyunSmsInvoker.java new file mode 100644 index 0000000..811d8cf --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/service/provider/MockAliyunSmsInvoker.java @@ -0,0 +1,34 @@ +package com.senmesh.sdk.sms.service.provider; + +import org.springframework.stereotype.Service; + +import com.senmesh.common.AlitaResult; +import com.senmesh.sdk.sms.config.SmsConfig; +import com.senmesh.sdk.sms.constant.AliSmsActionEnum; +import com.senmesh.sdk.sms.constant.SmsConstants; +import com.senmesh.sdk.sms.model.SendSmsResponse; + +import lombok.extern.slf4j.Slf4j; + +/** + * 模拟短信调用 + * + * @author sr on 2020-05-28 + */ +@Service +@Slf4j +public class MockAliyunSmsInvoker { + + @SuppressWarnings("unchecked") + public AlitaResult invoke(SmsConfig smsConfig, AliSmsActionEnum action, Object params, + Class responseClazz) { + log.info("mock sms params:{}", params); + if (action == AliSmsActionEnum.SEND_SMS) { + SendSmsResponse response = new SendSmsResponse(); + response.setCode(SmsConstants.SUCCESS_CODE); + return (AlitaResult) AlitaResult.success(response); + } + return null; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/sms/util/SmsUtils.java b/backend/src/main/java/com/senmesh/sdk/sms/util/SmsUtils.java new file mode 100644 index 0000000..6547a31 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/sms/util/SmsUtils.java @@ -0,0 +1,26 @@ +package com.senmesh.sdk.sms.util; + +import org.springframework.stereotype.Component; + +import com.senmesh.sdk.sms.service.SdkSmsService; + +/** + * sms工具类 + * + * @author sr on 2020-07-03 + */ +@Component +public class SmsUtils { + + private static SdkSmsService sdkSmsService; + + private SmsUtils(SdkSmsService sdkSmsService) { + SmsUtils.sdkSmsService = sdkSmsService; + } + + public static SdkSmsService getService() { + return sdkSmsService; + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/tencent/map/IRequestPostProcess.java b/backend/src/main/java/com/senmesh/sdk/tencent/map/IRequestPostProcess.java new file mode 100644 index 0000000..2f922f4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tencent/map/IRequestPostProcess.java @@ -0,0 +1,15 @@ +package com.senmesh.sdk.tencent.map; + +/** + * 请求发布过程 + * + * @author Carlye + * @date 2022/04/15 + */ +public interface IRequestPostProcess { + + /** + * 请求前处理 + */ + void postProcessBeforeRequest(); +} diff --git a/backend/src/main/java/com/senmesh/sdk/tencent/map/TencentMapContext.java b/backend/src/main/java/com/senmesh/sdk/tencent/map/TencentMapContext.java new file mode 100644 index 0000000..379a562 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tencent/map/TencentMapContext.java @@ -0,0 +1,216 @@ +package com.senmesh.sdk.tencent.map; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.sdk.common.dto.DefaultSdkInvokeLogDTO; +import com.senmesh.sdk.common.util.HttpUtils; +import com.senmesh.sdk.tencent.map.config.TencentMapProperties; +import com.senmesh.sdk.tencent.map.dto.TencentMapBaseResDTO; +import com.senmesh.sdk.tencent.map.dto.TencentMapGcoderReqDTO; +import com.senmesh.sdk.tencent.map.dto.TencentMapGeocoderReqDTO; +import com.senmesh.sdk.tencent.map.dto.TencentMapGeocoderResDTO; +import com.senmesh.sdk.tencent.map.dto.TencentMapLocationV1IpResDTO; +import com.senmesh.sdk.tencent.map.dto.TencentMapPlaceSearchReqDTO; +import com.senmesh.sdk.tencent.map.dto.TencentMapPlaceSearchResDTO; +import com.senmesh.sdk.tencent.map.dto.TencentMapWsDistanceV1MatrixReqDTO; +import com.senmesh.sdk.tencent.map.dto.TencentMapWsLocationV1IpReqDTO; +import com.senmesh.sdk.tencent.map.dto.TencentWsDistanceV1MatrixResDTO; + +import java.util.Map; +import java.util.Objects; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +@Slf4j +@Component +public class TencentMapContext { + + @Autowired + private RestTemplate restTemplate; + + @Autowired + private TencentMapProperties properties; + + + /** + * @param reqDTO + * @return {@link AlitaResult}<{@link ?}> + */ + public AlitaResult webServiceGcoder(TencentMapGcoderReqDTO reqDTO){ + reqDTO.setKey(properties.getKey()); + String[] reqParam = new String[]{properties.getBaseUrl() + reqDTO.getUri() + "?key={key}","location={location}"}; + if (Objects.nonNull(reqDTO.getGet_poi())){ + reqParam[2] = "get_poi={get_poi}"; + } + if (Objects.nonNull(reqDTO.getPoi_options())){ + reqParam[3] = ("poi_options={poi_options}"); + } + String fullUrl = String.join("&",reqParam) ; + Map stringObjectMap = buildReq(reqDTO); + TencentMapBaseResDTO resDTO; + try { + resDTO = restTemplate.getForObject(fullUrl, + TencentMapBaseResDTO.class, + stringObjectMap); + } catch (Exception e) { + resDTO = null; + log.error("webServiceGcoder {} invoke error:{}",JsonUtils.toJsonString(reqDTO), + e); + } + if (Objects.isNull(resDTO)){ + return AlitaResult.error("网络异常"); + } + if (resDTO.isSuccess()){ + return AlitaResult.success(resDTO.getResult()); + } + return AlitaResult.error(resDTO.getMessage()); + } + + /** + * @param reqDTO + * @return {@link AlitaResult}<{@link ?}> + */ + public AlitaResult webServiceGeocoder(TencentMapGeocoderReqDTO reqDTO){ + reqDTO.setKey(properties.getKey()); + ParameterizedTypeReference> responseType = new ParameterizedTypeReference>() {}; + + ResponseEntity> result = null; + try { + UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(properties.getBaseUrl() + reqDTO.getUri()) + .queryParam("key",reqDTO.getKey() ) + .queryParam("address", reqDTO.getAddress()) + .queryParam("region", reqDTO.getRegion()); + + result = restTemplate.exchange(builder.toUriString(), HttpMethod.GET, null, responseType); + if (result.getBody().isSuccess()){ + return AlitaResult.success(result.getBody().getResult()); + }else { + log.error("webServiceGeocoder {} invoke error:{}",JsonUtils.toJsonString(reqDTO), + result.getBody().getMessage()); + return AlitaResult.error(result.getBody().getMessage()); + } + } catch (Exception e) { + log.error("webServiceGeocoder {} invoke error:{}",JsonUtils.toJsonString(reqDTO), + e); + return AlitaResult.error("网络异常"); + } finally { + log.info("webServiceGeocoder invoke:{}", + JsonUtils + .toJsonString( + DefaultSdkInvokeLogDTO.builder().requestData(reqDTO).responseData(result) + .build())); + } + } + + /** + * @param req + */ + public Map buildReq(Object req){ + if (Objects.isNull(req)){ + return null; + } + if (req instanceof IRequestPostProcess){ + IRequestPostProcess process = (IRequestPostProcess)req; + process.postProcessBeforeRequest(); + } + return JsonUtils.toMap(JsonUtils.toJsonString(req)); + } + + public AlitaResult webServiceWsLocationV1Ip(TencentMapWsLocationV1IpReqDTO reqDTO){ + reqDTO.setKey(properties.getKey()); + ParameterizedTypeReference> responseType = new ParameterizedTypeReference>() {}; + + ResponseEntity> result = null; + try { + UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(properties.getBaseUrl() + reqDTO.getUri()) + .queryParam("key",reqDTO.getKey() ) + .queryParam("ip", reqDTO.getIp()); + + result = restTemplate.exchange(builder.toUriString(), HttpMethod.GET, null, responseType); + if (result.getBody().isSuccess()){ + return AlitaResult.success(result.getBody().getResult()); + }else { + log.error("webServiceWsLocationV1Ip {} invoke error:{}",JsonUtils.toJsonString(reqDTO), + result.getBody().getMessage()); + return AlitaResult.error(result.getBody().getMessage()); + } + } catch (Exception e) { + log.error("webServiceWsLocationV1Ip {} invoke error:{}",JsonUtils.toJsonString(reqDTO), + e); + return AlitaResult.error("网络异常"); + } finally { + log.info("webServiceWsLocationV1Ip invoke:{}", + JsonUtils + .toJsonString( + DefaultSdkInvokeLogDTO.builder().requestData(reqDTO).responseData(result) + .build())); + } + } + + public AlitaResult wsDistanceV1MatrixReqDTO(TencentMapWsDistanceV1MatrixReqDTO reqDTO){ + reqDTO.setKey(properties.getKey()); + ParameterizedTypeReference> responseType = new ParameterizedTypeReference>() {}; + + ResponseEntity> result = null; + try { + HttpEntity requestEntity = new HttpEntity(reqDTO); + result = HttpUtils.restTemplate.exchange(properties.getBaseUrl() + reqDTO.getUri(), HttpMethod.POST, requestEntity, responseType); + if (result.getBody().isSuccess()){ + return AlitaResult.success(result.getBody().getResult()); + }else { + log.error("wsDistanceV1MatrixReqDTO {} invoke error:{}",JsonUtils.toJsonString(reqDTO), + result.getBody().getMessage()); + return AlitaResult.error(result.getBody().getMessage()); + } + } catch (Exception e) { + log.error("wsDistanceV1MatrixReqDTO {} invoke error:{}",JsonUtils.toJsonString(reqDTO), + e); + return AlitaResult.error("网络异常"); + } finally { + log.info("wsDistanceV1MatrixReqDTO invoke:{}", + JsonUtils + .toJsonString( + DefaultSdkInvokeLogDTO.builder().requestData(reqDTO).responseData(result) + .build())); + } + } + + public AlitaResult placeSearch(TencentMapPlaceSearchReqDTO reqDTO){ + reqDTO.setKey(properties.getKey()); + ParameterizedTypeReference> responseType = new ParameterizedTypeReference>() {}; + + ResponseEntity> result = null; + try { + UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(properties.getBaseUrl() + reqDTO.getUri()) + .queryParam("key",reqDTO.getKey() ) + .queryParam("keyword", reqDTO.getKeyword()) + .queryParam("boundary", reqDTO.getBoundary()); + + result = restTemplate.exchange(builder.toUriString(), HttpMethod.GET, null, responseType); + if (result.getBody().isSuccess()){ + return AlitaResult.success(result.getBody().getData()); + }else { + log.error("placeSearch {} invoke error:{}",JsonUtils.toJsonString(reqDTO), + result.getBody().getMessage()); + return AlitaResult.error(result.getBody().getMessage()); + } + } catch (Exception e) { + log.error("placeSearch {} invoke error:{}",JsonUtils.toJsonString(reqDTO), + e); + return AlitaResult.error("网络异常"); + } finally { + log.info("placeSearch invoke:{}", + JsonUtils + .toJsonString( + DefaultSdkInvokeLogDTO.builder().requestData(reqDTO).responseData(result) + .build())); + } + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/tencent/map/config/TencentMapProperties.java b/backend/src/main/java/com/senmesh/sdk/tencent/map/config/TencentMapProperties.java new file mode 100644 index 0000000..4cd7f4c --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tencent/map/config/TencentMapProperties.java @@ -0,0 +1,30 @@ +package com.senmesh.sdk.tencent.map.config; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * 腾讯地图配置 + * + * @author sr on 2020-08-11 + */ +@Data +@NoArgsConstructor +@Configuration +@ConfigurationProperties(prefix = TencentMapProperties.PREFIX) +public class TencentMapProperties { + + public static final String PREFIX = "tencent.map"; + + /** + * key + */ + private String key; + + /** + * url前缀 + */ + private String baseUrl; +} diff --git a/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapBaseReqDTO.java b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapBaseReqDTO.java new file mode 100644 index 0000000..fd01770 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapBaseReqDTO.java @@ -0,0 +1,31 @@ +package com.senmesh.sdk.tencent.map.dto; + +import java.io.Serializable; +import javax.validation.constraints.NotEmpty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public abstract class TencentMapBaseReqDTO implements Serializable { + + private static final long serialVersionUID = -6669699584755546491L; + + + /** + * 开发密钥(Key) + */ + @NotEmpty(message = "秘钥不能为空") + private String key; + + /** + * 获取uri + * + * @return {@link String} + */ + protected abstract String getUri(); +} diff --git a/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapBaseResDTO.java b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapBaseResDTO.java new file mode 100644 index 0000000..9c2d90e --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapBaseResDTO.java @@ -0,0 +1,30 @@ +package com.senmesh.sdk.tencent.map.dto; + +import java.io.Serializable; +import java.util.Objects; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public class TencentMapBaseResDTO implements Serializable { + + + private static final long serialVersionUID = -3285179468910345476L; + + private Integer status; + + private String message; + + private String request_id; + + private T result; + + public boolean isSuccess(){ + return Objects.nonNull(status) && status == 0; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapGcoderReqDTO.java b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapGcoderReqDTO.java new file mode 100644 index 0000000..1ab1c5b --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapGcoderReqDTO.java @@ -0,0 +1,54 @@ +package com.senmesh.sdk.tencent.map.dto; + +import javax.validation.constraints.NotEmpty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public class TencentMapGcoderReqDTO extends TencentMapBaseReqDTO { + + + private static final long serialVersionUID = 4494672021783484087L; + /** + * 经纬度(GCJ02坐标系),格式:location=lat<纬度>,lng<经度> + */ + @NotEmpty(message = "经纬度不能为空") + private String location; + + /** + * 是否返回周边地点(POI)列表,可选值: + * 0 不返回(默认) + * 1 返回 + */ + private String get_poi; + + + /** + * 周边POI列表控制参数: + * 1 poi_options=address_format=short + * 返回短地址,缺省时返回长地址 + * 2 poi_options=radius=5000 + * 半径,取值范围 1-5000(米) + * 3 poi_options=policy=1/2/3/4/5 + * 控制返回场景, + * policy=1[默认] 以地标+主要的路+近距离POI为主,着力描述当前位置; + * policy=2 到家场景:筛选合适收货的POI,并会细化收货地址,精确到楼栋; + * policy=3 出行场景:过滤掉车辆不易到达的POI(如一些景区内POI),增加道路出入口、交叉口、大区域出入口类POI,排序会根据真实API大用户的用户点击自动优化。 + * policy=4 社交签到场景,针对用户签到的热门 地点进行优先排序。 + * policy=5 位置共享场景,用户经常用于发送位置、位置分享等场景的热门地点优先排序 + * 4 注:policy=1/2/3最多返回10条周边POI,policy=4/5最多返回20条, + */ + private String poi_options; + + @Override + public String getUri() { + return "geocoder/v1"; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapGeocoderReqDTO.java b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapGeocoderReqDTO.java new file mode 100644 index 0000000..6923a5c --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapGeocoderReqDTO.java @@ -0,0 +1,46 @@ +package com.senmesh.sdk.tencent.map.dto; + +import java.net.URLEncoder; +import javax.validation.constraints.NotEmpty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.apache.commons.lang3.StringUtils; + +import com.senmesh.sdk.tencent.map.IRequestPostProcess; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public class TencentMapGeocoderReqDTO extends TencentMapBaseReqDTO implements IRequestPostProcess { + + private static final long serialVersionUID = -309616473226679969L; + + /** + * 地址(注:地址中请包含城市名称,以及需要对地址进行URL编码,否则会影响解析效果) + */ + @NotEmpty(message = "地址不能为空") + private String address; + + /** + * 地址所在城市(若地址中包含城市名称侧可不传) + */ + private String region; + + @Override + public void postProcessBeforeRequest() { + String address = getAddress(); + if (StringUtils.isNotEmpty(address)){ + setAddress(URLEncoder.encode(address)); + } + } + + @Override + public String getUri() { + return "/ws/geocoder/v1"; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapGeocoderResDTO.java b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapGeocoderResDTO.java new file mode 100644 index 0000000..e0d0612 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapGeocoderResDTO.java @@ -0,0 +1,46 @@ +package com.senmesh.sdk.tencent.map.dto; + +import java.io.Serializable; +import java.math.BigDecimal; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: + * @author: guixinman + * @create: 2025-01-14 17:23 + **/ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TencentMapGeocoderResDTO implements Serializable { + + private TencentMapGeocoderLocationResDTO location; + private TencentMapGeocoderAddressComponentsDTO address_components; + private TencentMapGeocoderAdInfo ad_info; + + @Data + public class TencentMapGeocoderLocationResDTO implements Serializable { + private BigDecimal lat; + private BigDecimal lng; + } + + @Data + public class TencentMapGeocoderAddressComponentsDTO implements Serializable { + private String province; + private String city; + private String district; + private String street; + private String street_number; + + } + + @Data + public class TencentMapGeocoderAdInfo implements Serializable { + private String adcode; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapLocationV1IpResDTO.java b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapLocationV1IpResDTO.java new file mode 100644 index 0000000..e0bf52f --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapLocationV1IpResDTO.java @@ -0,0 +1,46 @@ +package com.senmesh.sdk.tencent.map.dto; + +import java.io.Serializable; +import java.math.BigDecimal; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: + * @author: guixinman + * @create: 2025-01-15 09:56 + **/ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TencentMapLocationV1IpResDTO implements Serializable { + private String ip; + private TencentMapLocationDTO location; + private TencentMapLocationAdInfoDTO ad_info; + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class TencentMapLocationDTO implements Serializable{ + private BigDecimal lat; + private BigDecimal lng; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class TencentMapLocationAdInfoDTO implements Serializable{ + private String nation; + private String nation_code; + private String province; + private String city; + private String district; + private String adcode; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapPlaceSearchReqDTO.java b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapPlaceSearchReqDTO.java new file mode 100644 index 0000000..4e1a76b --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapPlaceSearchReqDTO.java @@ -0,0 +1,31 @@ +package com.senmesh.sdk.tencent.map.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @description: 地点搜索 + * @author: guixinman + * @create: 2025-01-15 15:00 + **/ +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public class TencentMapPlaceSearchReqDTO extends TencentMapBaseReqDTO{ + + private String keyword; + private String boundary; + + + @Override + public String getUri() { + return "/ws/place/v1/search"; + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapPlaceSearchResDTO.java b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapPlaceSearchResDTO.java new file mode 100644 index 0000000..4f2245f --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapPlaceSearchResDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.sdk.tencent.map.dto; + +import java.io.Serializable; +import java.util.Objects; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @description: + * @author: guixinman + * @create: 2025-01-15 15:22 + **/ +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public class TencentMapPlaceSearchResDTO implements Serializable { + + private Integer status; + + private String message; + + private String request_id; + + private T Data; + + private T region; + + public boolean isSuccess(){ + return Objects.nonNull(status) && status == 0; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapWsDistanceV1MatrixReqDTO.java b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapWsDistanceV1MatrixReqDTO.java new file mode 100644 index 0000000..83991fd --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapWsDistanceV1MatrixReqDTO.java @@ -0,0 +1,29 @@ +package com.senmesh.sdk.tencent.map.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @description: 距离矩阵 + * @author: guixinman + * @create: 2024-12-18 14:48 + **/ +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public class TencentMapWsDistanceV1MatrixReqDTO extends TencentMapBaseReqDTO{ + + private String from; + private String to; + private String mode; + + @Override + public String getUri() { + return "/ws/distance/v1/matrix"; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapWsLocationV1IpReqDTO.java b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapWsLocationV1IpReqDTO.java new file mode 100644 index 0000000..0a72865 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentMapWsLocationV1IpReqDTO.java @@ -0,0 +1,27 @@ +package com.senmesh.sdk.tencent.map.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @description: IP定位 + * @author: guixinman + * @create: 2024-12-18 13:54 + **/ +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public class TencentMapWsLocationV1IpReqDTO extends TencentMapBaseReqDTO{ + + private String ip; + + @Override + public String getUri() { + return "/ws/location/v1/ip"; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentWsDistanceV1MatrixElementsResDTO.java b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentWsDistanceV1MatrixElementsResDTO.java new file mode 100644 index 0000000..41353b4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentWsDistanceV1MatrixElementsResDTO.java @@ -0,0 +1,23 @@ +package com.senmesh.sdk.tencent.map.dto; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: + * @author: guixinman + * @create: 2024-12-19 09:12 + **/ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TencentWsDistanceV1MatrixElementsResDTO implements Serializable { + private long distance; + private long duration; + private long status; +} diff --git a/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentWsDistanceV1MatrixElementsRowResDTO.java b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentWsDistanceV1MatrixElementsRowResDTO.java new file mode 100644 index 0000000..9b53902 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentWsDistanceV1MatrixElementsRowResDTO.java @@ -0,0 +1,16 @@ +package com.senmesh.sdk.tencent.map.dto; + +import java.io.Serializable; +import java.util.List; + +import lombok.Data; + +/** + * @description: + * @author: guixinman + * @create: 2024-12-19 10:03 + **/ +@Data +public class TencentWsDistanceV1MatrixElementsRowResDTO implements Serializable { + private List elements; +} diff --git a/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentWsDistanceV1MatrixResDTO.java b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentWsDistanceV1MatrixResDTO.java new file mode 100644 index 0000000..0647dc9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tencent/map/dto/TencentWsDistanceV1MatrixResDTO.java @@ -0,0 +1,16 @@ +package com.senmesh.sdk.tencent.map.dto; + +import java.io.Serializable; +import java.util.List; + +import lombok.Data; + +/** + * @description: + * @author: guixinman + * @create: 2024-12-19 10:09 + **/ +@Data +public class TencentWsDistanceV1MatrixResDTO implements Serializable { + private List rows; +} diff --git a/backend/src/main/java/com/senmesh/sdk/tonglian/adapter/TongLianAdapter.java b/backend/src/main/java/com/senmesh/sdk/tonglian/adapter/TongLianAdapter.java new file mode 100644 index 0000000..3cfef7d --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tonglian/adapter/TongLianAdapter.java @@ -0,0 +1,210 @@ +package com.senmesh.sdk.tonglian.adapter; + +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.common.util.ParameterizedTypeImpl; +import com.senmesh.sdk.tonglian.config.TokenProvider; +import com.senmesh.sdk.tonglian.config.TongLianProperties; +import com.senmesh.sdk.tonglian.dto.check.RequestCheck; +import com.senmesh.sdk.tonglian.dto.common.BaseReqDTO; +import com.senmesh.sdk.tonglian.dto.common.TongLianBaseReqDTO; +import com.senmesh.sdk.tonglian.dto.common.TongLianBaseResDTO; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.Signature; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; +import javax.validation.ConstraintViolation; +import javax.validation.Validator; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.util.Base64Utils; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; + +@Slf4j +public class TongLianAdapter { + + @Autowired + private TongLianProperties tongLianProperties; + + @Lazy + @Autowired + private TokenProvider tokenProvider; + + @Autowired + private RestTemplate restTemplate; + + @Autowired + private Validator validator; + + public void invoke(BaseReqDTO req){ + if(validator != null) { + //普通参数校验 + String errorMsg = validator.validate(req).stream() + .map(ConstraintViolation::getMessage) + .collect(Collectors.joining(",")); + if (StringUtils.isNotEmpty(errorMsg)) { + req.setResult(TongLianBaseResDTO.error(errorMsg)); + return; + } + } + //自定义检查 + if (req instanceof RequestCheck){ + String errorMsg = ((RequestCheck) req).check(); + if (StringUtils.isNotEmpty(errorMsg)){ + req.setResult(TongLianBaseResDTO.error(errorMsg)); + return; + } + } + + TongLianBaseReqDTO baseReqDTO = packageReq(req); + if (Boolean.TRUE.equals(req.getNeedToken())){ + String token = tokenProvider.getToken(false,req); + if (StringUtils.isEmpty(token)){ + req.setResult(TongLianBaseResDTO.error("token获取失败")); + return; + } + Map params = baseReqDTO.getParams(); + params.put("token",token); + } + + String sign = getSign(baseReqDTO.toString(), tongLianProperties.getPrivateKey()); + if (StringUtils.isEmpty(sign)){ + req.setResult(TongLianBaseResDTO.error("签名异常")); + return; + } + baseReqDTO.setSign(sign); + + + String reqUri = tongLianProperties.getDomain() + baseReqDTO.getInterfaceStr(); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity requestEntity = new HttpEntity<>(baseReqDTO.toMap(), headers); + log.info("tonglian http invoke:{}, ", JsonUtils + .toJsonString(baseReqDTO)); + try { + ParameterizedType parameterizedType = (ParameterizedType)req.getClass().getGenericSuperclass(); + Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); + ParameterizedTypeReference objectParameterizedTypeReference = ParameterizedTypeReference.forType( + new ParameterizedTypeImpl(actualTypeArguments,TongLianBaseResDTO.class, TongLianBaseResDTO.class)); + + ResponseEntity exchange = restTemplate.exchange(reqUri, + HttpMethod.POST, requestEntity, objectParameterizedTypeReference); + HttpStatus statusCode = exchange.getStatusCode(); + if (statusCode.isError()){ + req.setResult(TongLianBaseResDTO.error("网络异常")); + return; + } + TongLianBaseResDTO resDTO = (TongLianBaseResDTO)exchange.getBody(); + if (Objects.isNull(resDTO)){ + req.setResult(TongLianBaseResDTO.error("网络请求异常")); + return; + } + + //获取authId,放到响应体,用于 身份证手机号解密 + if (StringUtils.isNotBlank(req.appId())){ + TongLianProperties.TongLianAppProperties appProperties = tongLianProperties.getApps() + .stream() + .filter(tongLianAppProperties -> StringUtils.equals(tongLianAppProperties.getAppId(), req.appId())) + .findFirst() + .orElse(null); + if (appProperties == null) { + throw new BusinessException("根据appId未找到secretNo,请联系管理员"); + } + resDTO.setAuthId(appProperties.getAuthId()); + }else { + resDTO.setAuthId(tongLianProperties.getApps().get(0).getAuthId()); + } + + log.info("tonglian http invoke result : [{}]", JsonUtils.toJsonString(resDTO)); + if (resDTO.isSuccess()){ + req.setResult(resDTO); + }else { + //token失效 + if (StringUtils.equals(resDTO.getErrorCode(),"0") + && StringUtils.contains(resDTO.getMessage(),"token")){ + if (req.getRetryNum() > 0){ + req.setResult(TongLianBaseResDTO.error("重试次数超限")); + return; + } + req.setRetryNum(req.getRetryNum() + 1); + tokenProvider.getToken(true,req); + invoke(req); + }else { + req.setResult(resDTO); + } + } + } catch (RestClientException e) { + log.info("tonglian http invoke error", e); + req.setResult(TongLianBaseResDTO.error("网络异常.")); + } + } + + /** + * 请求报文加签机制 + * 1.公共请求参数字段按字典升序排序(sign不参与排序), + * 2.键=值&符号拼接请求参数(sing不参与拼接) + * 范例: + * "appId=HO/d3EbvgufqDCyT3Jfo3Q==&interface=servicepro/Commpany/openAcct¶ms={"enterpriseId":"MUx0cDhrbTdZWkE3RnA3b2YvQTYyZz09","batchList":[{"personalId":"NlI5b0QrQ0Z0b2xJYkZlcG16RDFxQT09","workId":"TXpraU0vSjdVck5BT3pDK2hsZkZjZz09","money":1}]}×tamp=20201216112515&version=1.0" + * 2:对拼接后得到的字符串进行md5加密处理 + * 3:将md5加密后的结果转换成大写 + * 4:使用用户私钥进行SHA1WithRSA加密生成sign 签名串 + * 5:对生成的sign签名串进行base64编码 + * + * @param signBase + */ + private static String getSign(String signBase,String privateKey){ + String sign = null; + String md5 = DigestUtils.md5Hex(signBase); + String md5Upper = StringUtils.upperCase(md5); + + try { + PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64Utils.decodeFromString(privateKey)); + KeyFactory keyf = KeyFactory.getInstance("RSA"); + PrivateKey priKey = keyf.generatePrivate(priPKCS8); + // 这里签名使用的是 SHA1WithRSA + Signature signature = Signature.getInstance("SHA1WithRSA"); + // 以私钥字符串初始化签名 + signature.initSign(priKey); + // 将原始串注入签名中 + signature.update(md5Upper.getBytes()); + // 签名后的结果,以字符数组形式存在 + byte[] signed = signature.sign(); + // 签名后的结果,以base64编码形式存在 + sign = Base64Utils.encodeToString(signed); + } catch (Exception e) { + log.info("tonglian 加密异常,",e); + } + return sign; + } + + /** + * 构建请求对象 + * + * @param req 要求事情 + * @return {@link TongLianBaseReqDTO} + */ + private TongLianBaseReqDTO packageReq(BaseReqDTO req){ + TongLianBaseReqDTO baseReqDTO = new TongLianBaseReqDTO(); + baseReqDTO.setAppId(StringUtils.isNotBlank(req.appId()) ? req.appId() : tongLianProperties.getApps().get(0).getAppId()); + baseReqDTO.setVersion(tongLianProperties.getVersion()); + baseReqDTO.setInterfaceStr(req.interfaceStr()); + baseReqDTO.setParams(req.params()); + return baseReqDTO; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/tonglian/config/StandardTokenProvider.java b/backend/src/main/java/com/senmesh/sdk/tonglian/config/StandardTokenProvider.java new file mode 100644 index 0000000..4d212f8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tonglian/config/StandardTokenProvider.java @@ -0,0 +1,90 @@ +package com.senmesh.sdk.tonglian.config; + +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.frame.redis.dto.LockDTO; +import com.senmesh.frame.redis.redisson.RedissonUtils; +import com.senmesh.frame.redis.util.RedisUtils; +import com.senmesh.sdk.tonglian.adapter.TongLianAdapter; +import com.senmesh.sdk.tonglian.dto.GetTokenReqDTO; +import com.senmesh.sdk.tonglian.dto.GetTokenResDTO; +import com.senmesh.sdk.tonglian.dto.common.BaseReqDTO; +import com.senmesh.sdk.tonglian.dto.common.TongLianBaseResDTO; +import java.util.Objects; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +@Slf4j +public class StandardTokenProvider implements TokenProvider { + + private static final String TOKEN_KEY_PREFIX = "tl"; + private static final long TOKEN_EXPIRE = 55 * 60; + + private TongLianProperties tongLianProperties; + + private TongLianAdapter tongLianAdapter; + + public StandardTokenProvider(TongLianProperties tongLianProperties,TongLianAdapter tongLianAdapter){ + this.tongLianProperties = tongLianProperties; + this.tongLianAdapter = tongLianAdapter; + } + + @Override + public String getToken(Boolean refresh, BaseReqDTO req) { + String appId = ""; + String secretNo = ""; + if (StringUtils.isNotBlank(req.appId())){ + TongLianProperties.TongLianAppProperties appProperties = tongLianProperties.getApps() + .stream() + .filter(tongLianAppProperties -> StringUtils.equals(tongLianAppProperties.getAppId(), req.appId())) + .findFirst() + .orElse(null); + if (appProperties == null) { + throw new BusinessException("根据appId未找到secretNo,请联系管理员"); + } + secretNo = appProperties.getSecretNo(); + appId = appProperties.getAppId(); + }else { + secretNo = tongLianProperties.getApps().get(0).getSecretNo(); + appId = tongLianProperties.getApps().get(0).getAppId(); + } + + String tokenKey = String.join(":", TOKEN_KEY_PREFIX, appId, "token"); + Object tokenObj = RedisUtils.get(tokenKey); + //重新获取令牌 + if (Boolean.TRUE.equals(refresh) + || tokenObj == null) { + String tokenLock = String.join(":", TOKEN_KEY_PREFIX, appId, "lock"); + LockDTO lockDTONew = LockDTO.builder() + .tryLockWaitTime(10L) + .lockTimeout(60 * 5L) + .methodName(tokenLock) + .build(); + try { + Assert.isTrue(RedissonUtils.tryLock(lockDTONew), "token正在获取中"); + tokenObj = RedisUtils.get(tokenKey); + if (tokenObj != null) { + return tokenObj.toString(); + } + GetTokenReqDTO reqDTO = new GetTokenReqDTO(); + reqDTO.setNeedToken(Boolean.FALSE); + reqDTO.setSecretNo(secretNo); + reqDTO.setAppId(appId); + tongLianAdapter.invoke(reqDTO); + TongLianBaseResDTO result = reqDTO.getResult(); + if (Objects.nonNull(result) && result.isSuccess()) { + GetTokenResDTO data = result.getData(); + // 1小时有效期 这里设置55分钟 + RedisUtils.add(tokenKey, data.getToken(), TOKEN_EXPIRE); + return data.getToken(); + } + } catch (Exception e) { + log.info("获取token异常 ",e); + return null; + }finally { + RedissonUtils.unlock(lockDTONew); + } + } + return tokenObj.toString(); + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/tonglian/config/TokenProvider.java b/backend/src/main/java/com/senmesh/sdk/tonglian/config/TokenProvider.java new file mode 100644 index 0000000..ebfd972 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tonglian/config/TokenProvider.java @@ -0,0 +1,15 @@ +package com.senmesh.sdk.tonglian.config; + +import com.senmesh.sdk.tonglian.dto.common.BaseReqDTO; + +public interface TokenProvider { + + + /** + * 获得令牌 + * + * @param refresh 刷新 重新从第三方获取令牌 + * @return {@link String} + */ + String getToken(Boolean refresh, BaseReqDTO req); +} diff --git a/backend/src/main/java/com/senmesh/sdk/tonglian/config/TongLianConfig.java b/backend/src/main/java/com/senmesh/sdk/tonglian/config/TongLianConfig.java new file mode 100644 index 0000000..d685bec --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tonglian/config/TongLianConfig.java @@ -0,0 +1,42 @@ +package com.senmesh.sdk.tonglian.config; + +import com.senmesh.sdk.tonglian.adapter.TongLianAdapter; +import lombok.Data; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; + +/** + * tonglian 配置属性 + * + * @author Carlye + * @date 2022/03/17 + */ +@Data +@Configuration +@EnableConfigurationProperties(TongLianProperties.class) +@ConditionalOnProperty(name = TongLianConfig.TONGLIAN_ENABLE, havingValue = "true") +@ComponentScan(basePackages = {"com.senmesh.sdk.tonglian"}) +public class TongLianConfig { + + static final String TONGLIAN_ENABLE = "tong.lian.enable"; + + @Bean + @Lazy + public TongLianAdapter tongLianAdapter(){ + return new TongLianAdapter(); + } + + @Bean + @Lazy + @ConditionalOnMissingBean(TokenProvider.class) + public TokenProvider tokenProvider(TongLianProperties tongLianProperties,TongLianAdapter tongLianAdapter){ + return new StandardTokenProvider(tongLianProperties,tongLianAdapter); + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/tonglian/config/TongLianProperties.java b/backend/src/main/java/com/senmesh/sdk/tonglian/config/TongLianProperties.java new file mode 100644 index 0000000..2f10a52 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tonglian/config/TongLianProperties.java @@ -0,0 +1,57 @@ +package com.senmesh.sdk.tonglian.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.util.List; + +/** + * tonglian 配置属性 + * + * @author Carlye + * @date 2022/03/17 + */ +@Data +@ConfigurationProperties(prefix = TongLianProperties.PREFIX) +public class TongLianProperties { + + /** + * 创蓝配置前缀 + **/ + static final String PREFIX = "tong.lian"; + + /** + * 版本 + */ + private String version; + + /** + * 请求接口的前缀 + */ + private String domain; + + /** + * 私钥 + */ + private String privateKey; + + private List apps; + + + @Data + public static class TongLianAppProperties { + + /** + * 应用程序id + */ + private String appId; + + /** + * secret_no + */ + private String secretNo; + + private String authId; + + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/tonglian/constants/TongLianConstants.java b/backend/src/main/java/com/senmesh/sdk/tonglian/constants/TongLianConstants.java new file mode 100644 index 0000000..0a7f911 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tonglian/constants/TongLianConstants.java @@ -0,0 +1,16 @@ +package com.senmesh.sdk.tonglian.constants; + +/** + * 通连常量 + * + * @author Carlye + * @date 2022/03/18 + */ +public interface TongLianConstants { + + /** + * 服务调用是否成功 + */ + String STATUS_OK = "OK"; + String STATUS_ERROR = "error"; +} diff --git a/backend/src/main/java/com/senmesh/sdk/tonglian/dto/GetTokenReqDTO.java b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/GetTokenReqDTO.java new file mode 100644 index 0000000..4f58059 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/GetTokenReqDTO.java @@ -0,0 +1,44 @@ +package com.senmesh.sdk.tonglian.dto; + +import com.google.common.collect.Maps; +import com.senmesh.sdk.tonglian.dto.common.BaseReqDTO; +import java.util.Map; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 同步个人用户数据 + * + * @author Carlye + * @date 2022/03/18 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class GetTokenReqDTO extends BaseReqDTO { + + private static final long serialVersionUID = -7828198385545023898L; + /** + * 身份证列表,多个用','分割 + */ + private String secretNo; + + private String appId; + + @Override + public String interfaceStr() { + return "api/auth/get_token"; + } + + @Override + public Map params() { + Map params = Maps.newLinkedHashMap(); + params.put("secret_no",getSecretNo()); + return params; + } + + @Override + public String appId() { + return this.appId; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/tonglian/dto/GetTokenResDTO.java b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/GetTokenResDTO.java new file mode 100644 index 0000000..2bc93f2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/GetTokenResDTO.java @@ -0,0 +1,22 @@ +package com.senmesh.sdk.tonglian.dto; + +import java.io.Serializable; +import lombok.Data; + +@Data +public class GetTokenResDTO implements Serializable { + + private static final long serialVersionUID = 644712532066127542L; + /** + * 响应状态 + */ + private String res; + /** + * token + */ + private String token; + /** + * 响应信息 + */ + private String msg; +} diff --git a/backend/src/main/java/com/senmesh/sdk/tonglian/dto/SynWalletDTO.java b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/SynWalletDTO.java new file mode 100644 index 0000000..1c5776b --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/SynWalletDTO.java @@ -0,0 +1,89 @@ +package com.senmesh.sdk.tonglian.dto; + +import java.io.Serializable; + +import lombok.Data; + +/** + * @description: 同步钱包信息接口 + * @author: guixinman + * @create: 2024-02-22 16:39 + **/ +@Data +public class SynWalletDTO implements Serializable { + + /** + * 类型 1出账 0进账 + */ + private String type; + + /** + * 交易金额 + */ + private String act_amt; + + /** + * 交易时间 + */ + private String trans_time; + + /** + * 出账账户名 + */ + private String from_act_name; + + /** + * 入账账户名 + */ + private String to_act_name; + + /** + * 交易单号 + */ + private String act_sn; + + /** + * 备注 + */ + private String bak; + + /** + * 状态 0处理中 1成功 2失败 + */ + private String status; + + /** + * 转出方电子账户 + */ + private String from_custid; + + + /** + * 转入方电子账户 当bak为佣金发放成功时则代表C端用户电子账户 + */ + private String to_custid; + + /** + * 支付账单编号 默认0 当返回bak备注说明不为 '合作服务费收入' 或 '佣金发放成功'为0 + */ + private Integer bill_id; + + /** + * 当bak备注说明为 '佣金发放成功' 返回,bill_id的加密,用于获取支付账单回单 + */ + private String bill_id_enc; + + /** + * 提报批次编号 默认0 当返回bak备注说明不为 '合作服务费收入' 或 '佣金发放成功'为0 + */ + private Integer monthbase_id; + + private String mobile; + + private String id_card; + + /** + * 委托方(实际支付方) 当bak为佣金发放成功时返回 + */ + private String from_client_name; +} diff --git a/backend/src/main/java/com/senmesh/sdk/tonglian/dto/SynWalletReqDTO.java b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/SynWalletReqDTO.java new file mode 100644 index 0000000..48d1e7e --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/SynWalletReqDTO.java @@ -0,0 +1,76 @@ +package com.senmesh.sdk.tonglian.dto; + +import com.google.common.collect.Maps; + +import com.senmesh.sdk.tonglian.dto.check.RequestCheck; +import com.senmesh.sdk.tonglian.dto.common.BasePageReqDTO; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Map; + +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @description: 同步钱包信息接口 + * @author: guixinman + * @create: 2024-02-22 16:18 + **/ +@EqualsAndHashCode(callSuper = true) +@Data +@Builder +public class SynWalletReqDTO extends BasePageReqDTO implements RequestCheck { + + /** + * 通联税源地appId + */ + private String appId; + + /** + * 交易时间起 yyyy-MM-dd + */ + private String timeBegin; + + /** + * 交易时间止 yyyy-MM-dd + */ + private String timeEnd; + + @Override + public String check() { + if (StringUtils.isBlank(getAppId())) { + return "appId必传"; + } + if (StringUtils.isBlank(getTimeBegin())) { + return "timeBegin必传"; + } + if (StringUtils.isBlank(getTimeEnd())) { + return "timeEnd必传"; + } + return null; + } + + @Override + public String interfaceStr() { + return "api/commit/service/synWalletData"; + } + + @Override + public Map params() { + Map params = Maps.newLinkedHashMap(); + params.put("timeBegin", getTimeBegin()); + params.put("timeEnd", getTimeEnd()); + params.put("curPage", getCurPage()); + params.put("pageSize", getPageSize()); + params.put("token", getToken()); + params.put("passageway", 1); + return params; + } + + @Override + public String appId() { + return this.appId; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/tonglian/dto/SynWalletResDTO.java b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/SynWalletResDTO.java new file mode 100644 index 0000000..2eba55b --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/SynWalletResDTO.java @@ -0,0 +1,36 @@ +package com.senmesh.sdk.tonglian.dto; + +import java.io.Serializable; +import java.util.List; + +import lombok.Data; + +/** + * @description: 同步钱包信息接口 + * @author: guixinman + * @create: 2024-02-22 16:19 + **/ +@Data +public class SynWalletResDTO implements Serializable { + + /** + * 请求表示 1=成功 0=失败 + */ + private String res; + /** + * 响应信息 + */ + private String msg; + /** + * 当前页 + */ + private String current_page; + /** + * 单页显示条数 + */ + private String per_page; + /** + * 响应数据列表 + */ + private List list; +} diff --git a/backend/src/main/java/com/senmesh/sdk/tonglian/dto/SysUserContractDTO.java b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/SysUserContractDTO.java new file mode 100644 index 0000000..1f6f8a2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/SysUserContractDTO.java @@ -0,0 +1,18 @@ +package com.senmesh.sdk.tonglian.dto; + +import java.io.Serializable; +import lombok.Data; + +@Data +public class SysUserContractDTO implements Serializable { + + private static final long serialVersionUID = 8873108969832616738L; + /** + * 合同查看地址 + */ + private String viewUrl; + /** + * 合同下载地址 + */ + private String downloadUrl; +} diff --git a/backend/src/main/java/com/senmesh/sdk/tonglian/dto/SysUserDTO.java b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/SysUserDTO.java new file mode 100644 index 0000000..425f9d6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/SysUserDTO.java @@ -0,0 +1,51 @@ +package com.senmesh.sdk.tonglian.dto; + +import java.io.Serializable; +import java.util.List; +import lombok.Data; + +@Data +public class SysUserDTO implements Serializable { + + private static final long serialVersionUID = 2253570557412435722L; + /** + * 用户编号 + */ + private String userNo; + /** + * 用户姓名 + */ + private String name; + /** + * 注册电话 + */ + private String mobile; + /** + * 身份证编号 + */ + private String idNo; + /** + * 身份证正面 + */ + private String idCardFront; + /** + * 身份证反面 + */ + private String idCardBack; + /** + * 电子钱包编号 + */ + private String allinpayNo; + /** + * 用户状态 + */ + private String status; + /** + * 创建时间 + */ + private String createTime; + /** + * 合同列表 + */ + private List contractList; +} diff --git a/backend/src/main/java/com/senmesh/sdk/tonglian/dto/SysUserReqDTO.java b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/SysUserReqDTO.java new file mode 100644 index 0000000..09fc09c --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/SysUserReqDTO.java @@ -0,0 +1,75 @@ +package com.senmesh.sdk.tonglian.dto; + +import com.google.common.collect.Maps; +import com.senmesh.sdk.tonglian.dto.check.RequestCheck; +import com.senmesh.sdk.tonglian.dto.common.BasePageReqDTO; +import java.util.Map; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.commons.lang3.StringUtils; + +/** + * 同步个人用户数据 + * + * @author Carlye + * @date 2022/03/18 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@Builder +public class SysUserReqDTO extends BasePageReqDTO implements RequestCheck { + + private static final long serialVersionUID = -5929153041130241087L; + /** + * 身份证列表,多个用','分割 + */ + private String cardNoList; + + /** + * 手机号列表 + */ + private String mobileList; + + /** + * 账单编号 + */ + private String batchNo; + + /** + * 应用程序id + */ + private String appId; + + + @Override + public String interfaceStr() { + return "api/commit/service/synUser"; + } + + @Override + public Map params() { + Map params = Maps.newLinkedHashMap(); + params.put("cardNoList",getCardNoList()); + params.put("mobileList",getMobileList()); + params.put("batchNo",getBatchNo()); + params.put("curPage",getCurPage()); + params.put("pageSize",getPageSize()); + params.put("token",getToken()); + return params; + } + + @Override + public String check() { + if (StringUtils.isAllEmpty(getCardNoList(),getBatchNo(),getMobileList())){ + return "身份证列表/账单编号/手机号列表 三选一必传"; + } + return null; + } + + @Override + public String appId() { + return this.appId; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/tonglian/dto/SysUserResDTO.java b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/SysUserResDTO.java new file mode 100644 index 0000000..2683229 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/SysUserResDTO.java @@ -0,0 +1,31 @@ +package com.senmesh.sdk.tonglian.dto; + +import java.io.Serializable; +import java.util.List; +import lombok.Data; + +@Data +public class SysUserResDTO implements Serializable { + + private static final long serialVersionUID = 2253570557412435722L; + /** + * 用户编号 + */ + private String res; + /** + * 用户姓名 + */ + private String msg; + /** + * 当前页 + */ + private String current_page; + /** + * + */ + private String per_page; + /** + * 用户信息列表 + */ + private List list; +} diff --git a/backend/src/main/java/com/senmesh/sdk/tonglian/dto/check/RequestCheck.java b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/check/RequestCheck.java new file mode 100644 index 0000000..3a67531 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/check/RequestCheck.java @@ -0,0 +1,11 @@ +package com.senmesh.sdk.tonglian.dto.check; + +public interface RequestCheck { + + /** + * 检查 + * + * @return {@link String} 返回错误信息 , 如果没错误信息返回null + */ + String check(); +} diff --git a/backend/src/main/java/com/senmesh/sdk/tonglian/dto/common/BasePageReqDTO.java b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/common/BasePageReqDTO.java new file mode 100644 index 0000000..be13272 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/common/BasePageReqDTO.java @@ -0,0 +1,39 @@ +package com.senmesh.sdk.tonglian.dto.common; + +import java.util.Objects; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public abstract class BasePageReqDTO extends BaseReqDTO { + /** + * 页码 + */ + private Integer curPage; + + /** + * 每页展示条数 : 区间 1-100 + */ + private Integer pageSize; + + public Integer getCurPage() { + if (Objects.isNull(curPage)){ + curPage = 1; + } + return curPage; + } + + public Integer getPageSize() { + if (Objects.isNull(pageSize)){ + pageSize = 100; + }else { + if (pageSize <= 1){ + pageSize = 1; + }else if (pageSize >= 100){ + pageSize = 100; + } + } + return pageSize; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/tonglian/dto/common/BaseReqDTO.java b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/common/BaseReqDTO.java new file mode 100644 index 0000000..0a947db --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/common/BaseReqDTO.java @@ -0,0 +1,57 @@ +package com.senmesh.sdk.tonglian.dto.common; + +import java.io.Serializable; +import java.util.Map; +import java.util.Objects; +import lombok.Data; + +@Data +public abstract class BaseReqDTO implements Serializable { + + /** + * 令牌 + */ + private String token; + + /** + * 需要令牌 + */ + private Boolean needToken; + + /** + * 重试次数 + */ + private int retryNum; + + /** + * 处理结果 + */ + private TongLianBaseResDTO result; + + public Boolean getNeedToken() { + if (Objects.isNull(needToken)){ + needToken = Boolean.TRUE; + } + return needToken; + } + + /** + * 接口str + * + * @return {@link String} + */ + public abstract String interfaceStr(); + + /** + * 参数个数 + * + * @return {@link Map}<{@link String}, {@link Object}> + */ + public abstract Map params(); + + /** + * appId + */ + public abstract String appId(); + +} diff --git a/backend/src/main/java/com/senmesh/sdk/tonglian/dto/common/TongLianBaseReqDTO.java b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/common/TongLianBaseReqDTO.java new file mode 100644 index 0000000..2744e80 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/common/TongLianBaseReqDTO.java @@ -0,0 +1,78 @@ +package com.senmesh.sdk.tonglian.dto.common; + +import com.google.common.collect.Maps; +import com.senmesh.common.util.JsonUtils; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Map; +import java.util.Objects; +import lombok.Data; + +@Data +public class TongLianBaseReqDTO implements Serializable { + + private static final long serialVersionUID = 3088759886459500676L; + /** + * 应用程序id + */ + private String appId; + + /** + * 时间戳 + */ + private String timestamp; + + /** + * 版本 + */ + private String version; + + /** + * 请求接口(接口名称) + */ + private String interfaceStr; + + /** + * 签名串 + */ + private String sign; + + /** + * 请求参数 + */ + private Map params; + + public String getTimestamp() { + if (Objects.isNull(timestamp)){ + DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); + timestamp = format.format(LocalDateTime.now()); + } + return timestamp; + } + + @Override + public String toString(){ +// Map params = getParams(); +// HashMap stringObjectHashMap = Maps.newHashMap(params); +// stringObjectHashMap.remove("token"); + return String.join("&" + ,String.join("=","appId",getAppId()) + ,String.join("=","interface",getInterfaceStr()) + ,String.join("=","params", JsonUtils.toJsonString(getParams())) + ,String.join("=","timestamp",getTimestamp()) + ,String.join("=","version",getVersion()) + ); + } + + public Map toMap(){ + Map map = Maps.newLinkedHashMap(); + map.put("appId",getAppId()); + map.put("timestamp",getTimestamp()); + map.put("version",getVersion()); + map.put("interface",getInterfaceStr()); + map.put("params",JsonUtils.toJsonString(getParams())); + map.put("sign",getSign()); + return map; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/tonglian/dto/common/TongLianBaseResDTO.java b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/common/TongLianBaseResDTO.java new file mode 100644 index 0000000..7609baa --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/tonglian/dto/common/TongLianBaseResDTO.java @@ -0,0 +1,58 @@ +package com.senmesh.sdk.tonglian.dto.common; + +import com.senmesh.common.AlitaResult; +import com.senmesh.sdk.tonglian.constants.TongLianConstants; +import java.io.Serializable; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +@Data +public class TongLianBaseResDTO implements Serializable { + + private static final long serialVersionUID = -6153821486129399320L; + /** + * 服务调用是否成功 + */ + private String status; + + /** + * 错误代码 + */ + private String errorCode; + + /** + * 错误信息 + */ + private String message; + + /** + * 返回参数 + */ + private RES data; + + /** + * 签名串 + */ + private String sign; + + private String authId; + + public static TongLianBaseResDTO error(String errorMsg){ + TongLianBaseResDTO resDTO = new TongLianBaseResDTO<>(); + resDTO.setStatus(TongLianConstants.STATUS_ERROR); + resDTO.setMessage(errorMsg); + return resDTO; + } + + public Boolean isSuccess(){ + return StringUtils.equals(TongLianConstants.STATUS_OK,getStatus()); + } + + public AlitaResult toAlitaRes(){ + String status = getStatus(); + if (StringUtils.equals(TongLianConstants.STATUS_OK,status)){ + return AlitaResult.success(data); + } + return AlitaResult.error(message); + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/WechatClient.java b/backend/src/main/java/com/senmesh/sdk/wechat/WechatClient.java new file mode 100644 index 0000000..da2194c --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/WechatClient.java @@ -0,0 +1,201 @@ +package com.senmesh.sdk.wechat; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.client.RestTemplate; + +import com.google.common.collect.Lists; +import com.senmesh.common.AlitaResult; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.common.util.RandomUtils; +import com.senmesh.sdk.common.constant.SdkConstants; +import com.senmesh.sdk.common.dto.DefaultSdkInvokeLogDTO; +import com.senmesh.sdk.common.dto.ISdkRequest; +import com.senmesh.sdk.wechat.constants.WechatConstants; +import com.senmesh.sdk.wechat.convert.WechatAppletWXACodeHttpMessageConverter; +import com.senmesh.sdk.wechat.model.AccessTokenDTO; +import com.senmesh.sdk.wechat.model.AccessTokenReq; +import com.senmesh.sdk.wechat.model.BaseWeChatDTO; +import com.senmesh.sdk.wechat.model.BatchUnionDTO; +import com.senmesh.sdk.wechat.model.BatchUnionReq; +import com.senmesh.sdk.wechat.model.BufferDTO; +import com.senmesh.sdk.wechat.model.Code2SessionDTO; +import com.senmesh.sdk.wechat.model.Code2SessionReq; +import com.senmesh.sdk.wechat.model.FullUserInfoDTO; +import com.senmesh.sdk.wechat.model.JsApiTicketDTO; +import com.senmesh.sdk.wechat.model.JsApiTicketReq; +import com.senmesh.sdk.wechat.model.PhoneNumberDTO; +import com.senmesh.sdk.wechat.model.PhoneNumberReq; +import com.senmesh.sdk.wechat.model.SubscibeMessageReq; +import com.senmesh.sdk.wechat.model.TemplateMessageReq; +import com.senmesh.sdk.wechat.model.UniformMessageReq; +import com.senmesh.sdk.wechat.model.UnlimitedWxacodeReq; +import com.senmesh.sdk.wechat.model.UrlSchemeDTO; +import com.senmesh.sdk.wechat.model.UrlSchemeReq; +import com.senmesh.sdk.wechat.model.CodeUserInfoReq; +import com.senmesh.sdk.wechat.model.SubscibeUserDTO; +import com.senmesh.sdk.wechat.model.SubscibeUserReq; +import com.senmesh.sdk.wechat.model.WxacodeReq; +import com.senmesh.sdk.wechat.util.WechatConvertUtils; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author sr on 2021-02-03 + */ +@Slf4j +public class WechatClient implements Serializable { + + /** **/ + private static final long serialVersionUID = -7442540577253368037L; + private static RestTemplate restOperations; + + static { + restOperations = new RestTemplate(); + List> messageConverters = new ArrayList>(); + MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); + WechatAppletWXACodeHttpMessageConverter wxConvert = new WechatAppletWXACodeHttpMessageConverter(); + List mediaTypes = + Lists.newArrayList(MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON_UTF8); + converter.setSupportedMediaTypes(mediaTypes); + messageConverters.add(converter); + messageConverters.add(wxConvert); + restOperations.setMessageConverters(messageConverters); + } + + protected String appId; + protected String secret; + + public WechatClient(String appId, String secret) { + this.appId = appId; + this.secret = secret; + } + + public AlitaResult getAccessToken() { + AccessTokenReq param = AccessTokenReq.builder().appId(this.appId) + .secret(this.secret).build(); + return execute(WechatConvertUtils::convert, + param); + } + + public AlitaResult code2Session(String code) { + Code2SessionReq param = Code2SessionReq.builder().appId(this.appId) + .secret(this.secret).code(code).build(); + return execute(WechatConvertUtils::convert, + param); + } + + public static AlitaResult getJsApiTicket(String accessToken) { + JsApiTicketReq param = + JsApiTicketReq.builder().accessToken(accessToken).build(); + return execute(WechatConvertUtils::convert, + param); + } + + public static AlitaResult sendTemplateMessage( + TemplateMessageReq req) { + return execute(WechatConvertUtils::convertPost, req); + } + + public static AlitaResult getUrlscheme( + UrlSchemeReq req) { + return execute(WechatConvertUtils::convertPost, + req); + } + + public static AlitaResult getWxacode( + WxacodeReq req) { + return execute(WechatConvertUtils::convertPost, + req); + } + + public static AlitaResult getUnlimitedWxacode( + UnlimitedWxacodeReq req) { + String page = req.getPage(); + if (StringUtils.isNoneBlank(page) && page.startsWith("/")) { + req.setPage(page.substring(1)); + } + return execute(WechatConvertUtils::convertPost, + req); + } + + public static AlitaResult sendUniformMessage(UniformMessageReq req) { + return execute(WechatConvertUtils::convertPost, + req); + } + + public static AlitaResult subscibeMessage(SubscibeMessageReq req) { + return execute(WechatConvertUtils::convertPost, + req); + } + + public static AlitaResult getSubscibeUser(SubscibeUserReq req) { + return execute(WechatConvertUtils::convert, + req); + } + + public static AlitaResult getUserInfo(CodeUserInfoReq req) { + return execute(WechatConvertUtils::convert, + req); + } + + public static AlitaResult batchUnion(BatchUnionReq req) { + return execute(WechatConvertUtils::convertPost, + req); + } + + public static AlitaResult phoneNumber(PhoneNumberReq req) { + return execute(WechatConvertUtils::convertPost, + req); + } + + public static AlitaResult execute( + Function converter, S dto) { + // 日志记录调用结果 + Serializable responseData = null; + String requestId = RandomUtils.generateUUID(); + try { + // 获得request + RequestEntity request = converter + .apply(dto); + ResponseEntity response; + // 执行 + try { + response = restOperations.exchange(request, dto.getResponseClass()); + } catch (Exception e) { + e.printStackTrace(); + responseData = ExceptionUtils.getStackTrace(e); + return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_ERROR_CODE, e.getMessage()); + } + T result = response.getBody(); + responseData = result; + String errCode = result.getErrcode(); + // 成功 + if (StringUtils.isBlank(errCode) + || WechatConstants.REQUEST_OK_CODE.equals(errCode)) { + return AlitaResult.success(result).setRequestId(requestId); + } + return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_RESPONSE_FAIL_CODE, + String.join(CommonConstants.COLON, errCode, result.getErrmsg())) + .setRequestId(requestId); + } finally { + log.info("wechat invoke:{}", + JsonUtils + .toJsonString( + DefaultSdkInvokeLogDTO.builder().requestData(dto).responseData(responseData) + .requestId(requestId).methodType(dto.getMethodName()).build())); + } + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/constants/WechatConstants.java b/backend/src/main/java/com/senmesh/sdk/wechat/constants/WechatConstants.java new file mode 100644 index 0000000..f3a777f --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/constants/WechatConstants.java @@ -0,0 +1,64 @@ +package com.senmesh.sdk.wechat.constants; + +public interface WechatConstants { + + /** code授权获取用户信息 **/ + String USER_INFO_URL_FORMAT = + "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=%s"; + + /** 获取access_token **/ + String ACCESS_TOKEN_URL_FORMAT = + "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; + + /** 获取api_ticket **/ + String JS_API_TICKET_URL_FORMAT = + "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=%s"; + + /** 获取小程序授权码换session信息 **/ + String CODE2SESSION_URL_FORMAT = + "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code"; + + /** 获取小程序 scheme 码(weixin:):30 天,无永久 **/ + String URLSCHEME_URL_PREFIX = + "https://api.weixin.qq.com/wxa/generatescheme?access_token="; + + /** 获取小程序 URL Link(跳H5 中间页) **/ + String URLLINK_URL_PREFIX = + "https://api.weixin.qq.com/wxa/generate_urllink?access_token="; + + + /** 获取小程序码-永久有效,有数量限制(10w) **/ + String WXACODE_PREFIX = "https://api.weixin.qq.com/wxa/getwxacode?access_token="; + + /** 获取小程序码-永久有效,数量暂无限制 **/ + String UNLIMITED_WXACODE_PREFIX = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token="; + + /** 模版消息请求前缀 **/ + String TEMPLATE_MESSAGE_URL_PREFIX = + "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="; + + /** 统一服务消息前缀 **/ + String UNIFORM_MESSAGE_PREFIX = + "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token="; + + /** 订阅消息前缀 **/ + String SUBSCIBE_MESSAGE_PREFIX = + "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token="; + /** 公共号关注者列表 **/ + String SUBSCIBE_USER_FORMAT = + "https://api.weixin.qq.com/cgi-bin/user/get?access_token=%s&next_openid=%s"; + + /** 获取用户unionId **/ + String UNION_FORMAT = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s&lang=&s"; + /** 批量获取用户unionId **/ + String BATCH_UNION_PREFIX = "https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token="; + + /** 获取手机号 **/ + String PHONE_NUMBER_PREFIX = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token="; + + + String JS_API_TICKET_TYPE = "jsapi"; + + String REQUEST_OK_CODE = "0"; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/constants/WechatErrorCodeEnum.java b/backend/src/main/java/com/senmesh/sdk/wechat/constants/WechatErrorCodeEnum.java new file mode 100644 index 0000000..38ecd3e --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/constants/WechatErrorCodeEnum.java @@ -0,0 +1,33 @@ +package com.senmesh.sdk.wechat.constants; + +/** + * 标识:微信(04) + * + * @author sr on 2021-02-03 + */ +public enum WechatErrorCodeEnum { + + /** 放心签调用返回错误码 **/ + ACCESS_TOKEN_ERROR("060401", "获取token失败"), + /** 放心签调用成功,但信息不匹配 **/ + TICKET_ERROR("060402", "获取ticket失败"); + + /** 错误码 **/ + private String code; + /** 错误信息 **/ + private String msg; + + WechatErrorCodeEnum(String code, String msg){ + this.code = code; + this.msg = msg; + } + + public String getCode() { + return code; + } + + public String getMsg() { + return msg; + } + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/constants/WechatMethodEnum.java b/backend/src/main/java/com/senmesh/sdk/wechat/constants/WechatMethodEnum.java new file mode 100644 index 0000000..fea133b --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/constants/WechatMethodEnum.java @@ -0,0 +1,34 @@ +package com.senmesh.sdk.wechat.constants; + +/** + * 微信方法 + * @author sr on 2021-03-18 + */ +public enum WechatMethodEnum { + + ACCESS_TOKEN, + JS_API_TICKET, + USER_INFO, + TEMPLATE_MESSAGE, + LITE_ACCESS_TOKEN, + /** 小程序scheme **/ + URLSCHEME, + /** 小程序链接 **/ + URLLINK, + /** 有限制小程序码 **/ + WXACODE, + /** 无限制小程序码 **/ + UNLIMITED_WXACODE, + /** 统一服务消息 **/ + UNIFORM_MESSAGE, + /** 订阅消息 **/ + SUBSCIBE_MESSAGE, + /** 公共号关注者列表 **/ + SUBSCIBE_USER, + /** 获取unionId **/ + UNION, + /** 批量获取unionId **/ + BATCH_UNION, + /** 获取手机号 **/ + PHONE_NUMBER, +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/convert/WechatAppletWXACodeHttpMessageConverter.java b/backend/src/main/java/com/senmesh/sdk/wechat/convert/WechatAppletWXACodeHttpMessageConverter.java new file mode 100644 index 0000000..699d38d --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/convert/WechatAppletWXACodeHttpMessageConverter.java @@ -0,0 +1,50 @@ +package com.senmesh.sdk.wechat.convert; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Collections; + +import org.springframework.http.HttpInputMessage; +import org.springframework.http.HttpOutputMessage; +import org.springframework.http.MediaType; +import org.springframework.http.converter.AbstractHttpMessageConverter; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.http.converter.HttpMessageNotWritableException; +import org.springframework.util.StreamUtils; + +import com.senmesh.sdk.wechat.model.BufferDTO; + +public class WechatAppletWXACodeHttpMessageConverter + extends AbstractHttpMessageConverter { + + public WechatAppletWXACodeHttpMessageConverter() { + super.setSupportedMediaTypes(Collections.singletonList(MediaType.IMAGE_JPEG)); + } + + @Override + protected boolean supports(Class clazz) { + return BufferDTO.class == clazz; + } + + @Override + protected BufferDTO readInternal(Class clazz, HttpInputMessage inputMessage) + throws IOException, HttpMessageNotReadableException { + long contentLength = inputMessage.getHeaders().getContentLength(); + ByteArrayOutputStream bos = + new ByteArrayOutputStream( + contentLength >= 0 ? (int) contentLength : StreamUtils.BUFFER_SIZE); + StreamUtils.copy(inputMessage.getBody(), bos); + bos.toByteArray(); + BufferDTO bufferDTO = new BufferDTO(); + bufferDTO.setBuffer(bos.toByteArray()); + bufferDTO.setErrcode("0"); + bufferDTO.setErrmsg("ok"); + return bufferDTO; + } + + @Override + protected void writeInternal(BufferDTO bufferDTO, HttpOutputMessage outputMessage) + throws IOException, HttpMessageNotWritableException { + StreamUtils.copy(bufferDTO.getBuffer(), outputMessage.getBody()); + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/AbstractAccessTokenReq.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/AbstractAccessTokenReq.java new file mode 100644 index 0000000..4a6041c --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/AbstractAccessTokenReq.java @@ -0,0 +1,25 @@ +package com.senmesh.sdk.wechat.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.senmesh.sdk.common.dto.ISdkRequest; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * accessToken + * @author sr on 2021-12-24 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class AbstractAccessTokenReq implements ISdkRequest { + + /** 接口调用凭证 **/ + @JsonIgnore + private String accessToken; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/AccessTokenDTO.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/AccessTokenDTO.java new file mode 100644 index 0000000..d6cdc70 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/AccessTokenDTO.java @@ -0,0 +1,36 @@ +package com.senmesh.sdk.wechat.model; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2021-01-15 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@AllArgsConstructor +@NoArgsConstructor +public class AccessTokenDTO extends BaseWeChatDTO implements Serializable { + + /** **/ + private static final long serialVersionUID = -1105568745155586204L; + + /** + * 接口调用凭证 + */ + @JsonProperty("access_token") + private String accessToken; + + /** + * access_token接口调用凭证超时时间,单位(秒) + */ + @JsonProperty("expires_in") + private String expiresIn; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/AccessTokenReq.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/AccessTokenReq.java new file mode 100644 index 0000000..f7a5e2a --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/AccessTokenReq.java @@ -0,0 +1,49 @@ +package com.senmesh.sdk.wechat.model; + +import org.springframework.data.annotation.Transient; + +import com.senmesh.common.annotation.Mask; +import com.senmesh.sdk.common.dto.ISdkRequest; +import com.senmesh.sdk.wechat.constants.WechatConstants; +import com.senmesh.sdk.wechat.constants.WechatMethodEnum; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-01-15 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class AccessTokenReq implements ISdkRequest{ + + /** **/ + private static final long serialVersionUID = 4948765691546131290L; + + /** 第三方用户唯一凭证 **/ + private String appId; + /** 第三方用户唯一凭证密钥,即appsecret **/ + @Transient + @Mask + private String secret; + + @Override + public String getMethodName() { + return WechatMethodEnum.ACCESS_TOKEN.name(); + } + + @Override + public Class getResponseClass() { + return AccessTokenDTO.class; + } + + @Override + public String getUri() { + return WechatConstants.ACCESS_TOKEN_URL_FORMAT; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/BaseWeChatDTO.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/BaseWeChatDTO.java new file mode 100644 index 0000000..1482ce5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/BaseWeChatDTO.java @@ -0,0 +1,23 @@ +package com.senmesh.sdk.wechat.model; + +import lombok.Data; + +import java.io.Serializable; + +/** + * @author leijiaping + */ +@Data +public class BaseWeChatDTO implements Serializable { + + /** + * 错误编码 + */ + private String errcode; + + /** + * 错误信息 + */ + private String errmsg; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/BatchUnionDTO.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/BatchUnionDTO.java new file mode 100644 index 0000000..881bef6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/BatchUnionDTO.java @@ -0,0 +1,24 @@ +package com.senmesh.sdk.wechat.model; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +public class BatchUnionDTO extends BaseWeChatDTO{ + + /** **/ + private static final long serialVersionUID = -4977565962655123684L; + + @JsonProperty("user_info_list") + private List userInfoList; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/BatchUnionReq.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/BatchUnionReq.java new file mode 100644 index 0000000..3e264c0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/BatchUnionReq.java @@ -0,0 +1,47 @@ +package com.senmesh.sdk.wechat.model; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.senmesh.sdk.wechat.constants.WechatConstants; +import com.senmesh.sdk.wechat.constants.WechatMethodEnum; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.Singular; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-01-15 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class BatchUnionReq extends AbstractAccessTokenReq{ + + /** **/ + private static final long serialVersionUID = 4948765691546131290L; + + @JsonProperty("user_list") + @Singular + private List users; + + @Override + public String getMethodName() { + return WechatMethodEnum.BATCH_UNION.name(); + } + + @Override + public Class getResponseClass() { + return BatchUnionDTO.class; + } + + @Override + public String getUri() { + return WechatConstants.BATCH_UNION_PREFIX; + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/BufferDTO.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/BufferDTO.java new file mode 100644 index 0000000..a6e2c47 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/BufferDTO.java @@ -0,0 +1,24 @@ +package com.senmesh.sdk.wechat.model; + +import com.senmesh.common.annotation.Mask; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +public class BufferDTO extends BaseWeChatDTO{ + + /** **/ + private static final long serialVersionUID = -1193016127255040596L; + + @Mask + private byte[] buffer; + + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/Code2SessionDTO.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/Code2SessionDTO.java new file mode 100644 index 0000000..5fdbec5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/Code2SessionDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.sdk.wechat.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * @author leijiaping + */ +@EqualsAndHashCode(callSuper = true) +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Code2SessionDTO extends BaseWeChatDTO implements Serializable { + + /** + * 授权用户唯一标识 + */ + @JsonProperty("openid") + private String openId; + + /** + * 当且仅当该网站应用已获得该用户的userinfo授权时,才会出现该字段 + */ + @JsonProperty("unionid") + private String unionId; + + @JsonProperty("session_key") + private String sessionKey; +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/Code2SessionReq.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/Code2SessionReq.java new file mode 100644 index 0000000..a0014d3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/Code2SessionReq.java @@ -0,0 +1,51 @@ +package com.senmesh.sdk.wechat.model; + +import org.springframework.data.annotation.Transient; + +import com.senmesh.common.annotation.Mask; +import com.senmesh.sdk.common.dto.ISdkRequest; +import com.senmesh.sdk.wechat.constants.WechatConstants; +import com.senmesh.sdk.wechat.constants.WechatMethodEnum; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-01-15 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class Code2SessionReq implements ISdkRequest{ + + /** **/ + private static final long serialVersionUID = 4948765691546131290L; + /** 第三方用户唯一凭证 **/ + private String appId; + /** 第三方用户唯一凭证密钥,即appsecret **/ + @Transient + @Mask + private String secret; + /** 授权码 **/ + private String code; + + + @Override + public String getMethodName() { + return WechatMethodEnum.LITE_ACCESS_TOKEN.name(); + } + + @Override + public Class getResponseClass() { + return Code2SessionDTO.class; + } + + @Override + public String getUri() { + return WechatConstants.CODE2SESSION_URL_FORMAT; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/CodeUserInfoReq.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/CodeUserInfoReq.java new file mode 100644 index 0000000..876a788 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/CodeUserInfoReq.java @@ -0,0 +1,43 @@ +package com.senmesh.sdk.wechat.model; + + +import com.senmesh.sdk.wechat.constants.WechatConstants; +import com.senmesh.sdk.wechat.constants.WechatMethodEnum; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-02-03 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class CodeUserInfoReq extends AbstractAccessTokenReq { + + /** **/ + private static final long serialVersionUID = -6862280353550142248L; + + /** code换取的token **/ + private String accessToken; + private String openId; + + @Override + public String getMethodName() { + return WechatMethodEnum.USER_INFO.name(); + } + + @Override + public Class getResponseClass() { + return FullUserInfoDTO.class; + } + + @Override + public String getUri() { + return WechatConstants.USER_INFO_URL_FORMAT; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/FullUserInfoDTO.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/FullUserInfoDTO.java new file mode 100644 index 0000000..0619e65 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/FullUserInfoDTO.java @@ -0,0 +1,33 @@ +package com.senmesh.sdk.wechat.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 完整用户信息(包括敏感数据) + * @author sr on 2021-11-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class FullUserInfoDTO extends BaseWeChatDTO{ + + private static final long serialVersionUID = 267960916655973459L; + + + /** 用户唯一标识 **/ + @JsonProperty("openid") + private String openId; + private String nickname; + private Integer sex; + private String province; + private String city; + private String country; + private String headimgurl; + @JsonProperty("unionid") + private String unionId; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/JsApiTicketDTO.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/JsApiTicketDTO.java new file mode 100644 index 0000000..2c2de54 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/JsApiTicketDTO.java @@ -0,0 +1,27 @@ +package com.senmesh.sdk.wechat.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2021-01-15 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +public class JsApiTicketDTO extends BaseWeChatDTO { + + /** **/ + private static final long serialVersionUID = 1038878005278639836L; + + private String ticket; + + @JsonProperty("expires_in") + private String expiresIn; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/JsApiTicketReq.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/JsApiTicketReq.java new file mode 100644 index 0000000..f56902a --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/JsApiTicketReq.java @@ -0,0 +1,42 @@ +package com.senmesh.sdk.wechat.model; + +import com.senmesh.sdk.wechat.constants.WechatConstants; +import com.senmesh.sdk.wechat.constants.WechatMethodEnum; + +import lombok.AllArgsConstructor; +import lombok.Builder.Default; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-01-15 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class JsApiTicketReq extends AbstractAccessTokenReq{ + + /** **/ + private static final long serialVersionUID = -6514900861070288478L; + + /** 类型 **/ + @Default + private String type = "jsapi"; + @Override + public String getMethodName() { + return WechatMethodEnum.JS_API_TICKET.name(); + } + + @Override + public Class getResponseClass() { + return JsApiTicketDTO.class; + } + + @Override + public String getUri() { + return WechatConstants.JS_API_TICKET_URL_FORMAT; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/JumpWxa.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/JumpWxa.java new file mode 100644 index 0000000..077e443 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/JumpWxa.java @@ -0,0 +1,33 @@ +package com.senmesh.sdk.wechat.model; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 跳转到的目标小程序信息 + * @author sr on 2021-08-31 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class JumpWxa implements Serializable{ + + /** **/ + private static final long serialVersionUID = -1294493512859560222L; + + /** 通过 scheme 码进入的小程序页面路径,必须是已经发布的小程序存在的页面,不可携带 query。path 为空时会跳转小程序主页 **/ + private String path; + /** 通过 scheme 码进入小程序时的 query,最大1024个字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~% **/ + private String query; + /** 要打开的小程序版本。正式版为"release",体验版为"trial",开发版为"develop",仅在微信外打开时生效 **/ + @JsonProperty("env_version") + private String envVersion; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/KeyData.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/KeyData.java new file mode 100644 index 0000000..febc390 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/KeyData.java @@ -0,0 +1,28 @@ +package com.senmesh.sdk.wechat.model; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 模板数据 + * + * @author sr on 2021-02-03 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class KeyData implements Serializable{ + + /** **/ + private static final long serialVersionUID = 5875606119889091983L; + + private String value; + /** 模板内容字体颜色,不填默认为黑色 **/ + private String color; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/MiniProgram.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/MiniProgram.java new file mode 100644 index 0000000..19f68c5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/MiniProgram.java @@ -0,0 +1,29 @@ +package com.senmesh.sdk.wechat.model; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 跳小程序所需数据,不需跳小程序可不用传该数据 + * + * @author sr on 2021-02-03 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class MiniProgram implements Serializable { + + /** **/ + private static final long serialVersionUID = 1722801393721577667L; + + /** 必填;所需跳转到的小程序appid(该小程序appid必须与发模板消息的公众号是绑定关联关系,暂不支持小游戏) **/ + private String appid; + /** 所需跳转到小程序的具体页面路径,支持带参数,(示例index?foo=bar),要求该小程序已发布,暂不支持小游戏 **/ + private String pagepath; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/MpTemplateMsg.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/MpTemplateMsg.java new file mode 100644 index 0000000..336c60a --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/MpTemplateMsg.java @@ -0,0 +1,39 @@ +package com.senmesh.sdk.wechat.model; + +import java.io.Serializable; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 公众号模板消息相关的信息 + * @author sr on 2021-12-27 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class MpTemplateMsg implements Serializable{ + + /** **/ + private static final long serialVersionUID = 3061379199546766297L; + + /** 必填;公众号appid,要求与小程序有绑定且同主体 **/ + @JsonProperty("appid") + private String appId; + /** 必填;公众号模板id **/ + @JsonProperty("template_id") + private String templateId; + /** 必填;公众号模板消息所要跳转的url **/ + private String url; + /** 必填;公众号模板消息所要跳转的小程序,小程序的必须与公众号具有绑定关系 **/ + private MiniProgram miniprogram; + /** 必填;公众号模板消息的数据 **/ + private Map data; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/PhoneNumberDTO.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/PhoneNumberDTO.java new file mode 100644 index 0000000..a87442d --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/PhoneNumberDTO.java @@ -0,0 +1,21 @@ +package com.senmesh.sdk.wechat.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.senmesh.sdk.common.dto.LiteUserPhoneDTO; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PhoneNumberDTO extends BaseWeChatDTO{ + /** **/ + private static final long serialVersionUID = -4550034374482312096L; + + /** 用户手机号信息 **/ + @JsonProperty("phone_info") + private LiteUserPhoneDTO phoneInfo; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/PhoneNumberReq.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/PhoneNumberReq.java new file mode 100644 index 0000000..29731c7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/PhoneNumberReq.java @@ -0,0 +1,39 @@ +package com.senmesh.sdk.wechat.model; + +import com.senmesh.sdk.wechat.constants.WechatConstants; +import com.senmesh.sdk.wechat.constants.WechatMethodEnum; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class PhoneNumberReq extends AbstractAccessTokenReq { + + + /** **/ + private static final long serialVersionUID = 5602209770449461997L; + + /** 手机号获取凭证 **/ + private String code; + + @Override + public String getMethodName() { + return WechatMethodEnum.PHONE_NUMBER.name(); + } + + @Override + public String getUri() { + return WechatConstants.PHONE_NUMBER_PREFIX; + } + + @Override + public Class getResponseClass() { + return PhoneNumberDTO.class; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/SubscibeMessageReq.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/SubscibeMessageReq.java new file mode 100644 index 0000000..84716c0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/SubscibeMessageReq.java @@ -0,0 +1,57 @@ +package com.senmesh.sdk.wechat.model; + +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.senmesh.sdk.wechat.constants.WechatConstants; +import com.senmesh.sdk.wechat.constants.WechatMethodEnum; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 下发小程序和公众号统一的服务消息 + * @author sr on 2021-12-27 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class SubscibeMessageReq extends AbstractAccessTokenReq { + + /** **/ + private static final long serialVersionUID = -5132718249745640058L; + + /** 是;接收者(用户)的 openid **/ + @JsonProperty("touser") + private String touser; + /** 是;所需下发的订阅模板id **/ + @JsonProperty("template_id") + private String templateId; + /** 否;点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。 **/ + private String page; + /** 是;模板内容,格式形如 { "key1": { "value": any }, "key2": { "value": any } } **/ + private Map data; + /** 否;跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版 **/ + @JsonProperty("miniprogram_state") + private String miniprogramState; + /** 否;进入小程序查看”的语言类型,支持zh_CN(简体中文)、en_US(英文)、zh_HK(繁体中文)、zh_TW(繁体中文),默认为zh_CN **/ + private String lang; + + @Override + public String getMethodName() { + return WechatMethodEnum.SUBSCIBE_MESSAGE.name(); + } + + @Override + public Class getResponseClass() { + return BaseWeChatDTO.class; + } + + @Override + public String getUri() { + return WechatConstants.SUBSCIBE_MESSAGE_PREFIX; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/SubscibeUserDTO.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/SubscibeUserDTO.java new file mode 100644 index 0000000..528cc6f --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/SubscibeUserDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.sdk.wechat.model; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SubscibeUserDTO extends BaseWeChatDTO{ + + /** **/ + private static final long serialVersionUID = -1777884193437529632L; + + private Long total; + private Long count; + private UserData data; + + @Data + @NoArgsConstructor + @AllArgsConstructor + public class UserData{ + @JsonProperty("openid") + private List openId; + @JsonProperty("next_openid") + private String nextOpenId; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/SubscibeUserReq.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/SubscibeUserReq.java new file mode 100644 index 0000000..e25760b --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/SubscibeUserReq.java @@ -0,0 +1,44 @@ +package com.senmesh.sdk.wechat.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.senmesh.sdk.wechat.constants.WechatConstants; +import com.senmesh.sdk.wechat.constants.WechatMethodEnum; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 一次拉取调用最多拉取10000个关注者的OpenID + * @author sr on 2021-01-15 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class SubscibeUserReq extends AbstractAccessTokenReq{ + + /** **/ + private static final long serialVersionUID = 4948765691546131290L; + + /** 第一个拉取的OPENID,不填默认从头开始拉取 **/ + @JsonProperty("next_openid") + private String nextOpenId; + + @Override + public String getMethodName() { + return WechatMethodEnum.SUBSCIBE_USER.name(); + } + + @Override + public Class getResponseClass() { + return SubscibeUserDTO.class; + } + + @Override + public String getUri() { + return WechatConstants.SUBSCIBE_USER_FORMAT; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/TemplateMessageReq.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/TemplateMessageReq.java new file mode 100644 index 0000000..64d1f4d --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/TemplateMessageReq.java @@ -0,0 +1,53 @@ +package com.senmesh.sdk.wechat.model; + +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.senmesh.sdk.wechat.constants.WechatConstants; +import com.senmesh.sdk.wechat.constants.WechatMethodEnum; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class TemplateMessageReq extends AbstractAccessTokenReq { + + /** **/ + private static final long serialVersionUID = 9107415797489637178L; + + /** 必填;不参与body序列化 **/ + /** 必填;接收者openid **/ + @JsonProperty("touser") + private String toUser; + /** 必填;模板ID **/ + @JsonProperty("template_id") + private String templateId; + /** 模板跳转链接(海外帐号没有跳转能力) **/ + private String url; + /** 跳小程序所需数据,不需跳小程序可不用传该数据 **/ + @JsonProperty("miniprogram") + private MiniProgram miniProgram; + /** 必填;模板数据 **/ + private Map data; + + @Override + public String getMethodName() { + return WechatMethodEnum.TEMPLATE_MESSAGE.name(); + } + + @Override + public Class getResponseClass() { + return BaseWeChatDTO.class; + } + + @Override + public String getUri() { + return WechatConstants.TEMPLATE_MESSAGE_URL_PREFIX; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/UniformMessageReq.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/UniformMessageReq.java new file mode 100644 index 0000000..b0483f8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/UniformMessageReq.java @@ -0,0 +1,48 @@ +package com.senmesh.sdk.wechat.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.senmesh.sdk.wechat.constants.WechatConstants; +import com.senmesh.sdk.wechat.constants.WechatMethodEnum; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 下发小程序和公众号统一的服务消息 + * @author sr on 2021-12-27 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class UniformMessageReq extends AbstractAccessTokenReq { + + /** **/ + private static final long serialVersionUID = -5132718249745640058L; + + /** 必填;用户openid,可以是小程序的openid,也可以是mp_template_msg.appid对应的公众号的openid **/ + private String touser; + /** 小程序模板消息相关的信息,可以参考小程序模板消息接口; 有此节点则优先发送小程序模板消息;(小程序模板消息已下线,不用传此节点) **/ + @JsonProperty("weapp_template_msg") + private WeappTemplateMsg weappTemplateMsg; + /** 公众号模板消息相关的信息,可以参考公众号模板消息接口;有此节点并且没有weapp_template_msg节点时,发送公众号模板消息 **/ + @JsonProperty("mp_template_msg") + private MpTemplateMsg mpTemplateMsg; + + @Override + public String getMethodName() { + return WechatMethodEnum.UNIFORM_MESSAGE.name(); + } + + @Override + public Class getResponseClass() { + return BaseWeChatDTO.class; + } + + @Override + public String getUri() { + return WechatConstants.UNIFORM_MESSAGE_PREFIX; + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/UnionDTO.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/UnionDTO.java new file mode 100644 index 0000000..7faef78 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/UnionDTO.java @@ -0,0 +1,52 @@ +package com.senmesh.sdk.wechat.model; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UnionDTO extends BaseWeChatDTO{ + + /** **/ + private static final long serialVersionUID = 2798332163629305353L; + + /** 用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息。 **/ + private Integer subscribe; + /** 用户的标识,对当前公众号唯一 **/ + @JsonProperty("openid") + private String openId; + /** 用户的语言,简体中文为zh_CN **/ + private String language; + /** 用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间 **/ + @JsonProperty("subscribe_time") + private String subscribe_time; + /** 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。 **/ + @JsonProperty("unionid") + private String unionId; + /** 公众号运营者对粉丝的备注,公众号运营者可在微信公众平台用户管理界面对粉丝添加备注 **/ + private String remark; + /** 用户所在的分组ID(兼容旧的用户分组接口) **/ + @JsonProperty("groupid") + private String groupId; + /** 用户被打上的标签ID列表 **/ + @JsonProperty("tagid_list") + private List tagidList; + /** 返回用户关注的渠道来源,ADD_SCENE_SEARCH 公众号搜索,ADD_SCENE_ACCOUNT_MIGRATION 公众号迁移,ADD_SCENE_PROFILE_CARD 名片分享,ADD_SCENE_QR_CODE 扫描二维码,ADD_SCENE_PROFILE_LINK 图文页内名称点击,ADD_SCENE_PROFILE_ITEM 图文页右上角菜单,ADD_SCENE_PAID 支付后关注,ADD_SCENE_WECHAT_ADVERTISEMENT 微信广告,ADD_SCENE_REPRINT 他人转载 ,ADD_SCENE_LIVESTREAM 视频号直播,ADD_SCENE_CHANNELS 视频号 , ADD_SCENE_OTHERS其他 **/ + @JsonProperty("subscribe_scene") + private String subscribeScene; + /** 二维码扫码场景(开发者自定义) **/ + @JsonProperty("qr_scene") + private String qrScene; + /** 二维码扫码场景描述(开发者自定义) **/ + @JsonProperty("qr_scene_str") + private String qrSceneStr; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/UnionReq.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/UnionReq.java new file mode 100644 index 0000000..442691d --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/UnionReq.java @@ -0,0 +1,42 @@ +package com.senmesh.sdk.wechat.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.senmesh.sdk.wechat.constants.WechatConstants; +import com.senmesh.sdk.wechat.constants.WechatMethodEnum; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-01-15 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class UnionReq extends AbstractAccessTokenReq{ + + /** **/ + private static final long serialVersionUID = 4948765691546131290L; + + @JsonProperty("openid") + private String openId; + + @Override + public String getMethodName() { + return WechatMethodEnum.UNION.name(); + } + + @Override + public Class getResponseClass() { + return UnionDTO.class; + } + + @Override + public String getUri() { + return WechatConstants.UNION_FORMAT; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/UnionUser.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/UnionUser.java new file mode 100644 index 0000000..0e58181 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/UnionUser.java @@ -0,0 +1,22 @@ +package com.senmesh.sdk.wechat.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.Builder.Default; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class UnionUser{ + + @JsonProperty("openid") + private String openId; + @Default + private String lang = "zh_CN"; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/UnlimitedWxacodeReq.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/UnlimitedWxacodeReq.java new file mode 100644 index 0000000..0b51176 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/UnlimitedWxacodeReq.java @@ -0,0 +1,60 @@ +package com.senmesh.sdk.wechat.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.senmesh.sdk.wechat.constants.WechatConstants; +import com.senmesh.sdk.wechat.constants.WechatMethodEnum; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class UnlimitedWxacodeReq extends AbstractAccessTokenReq { + + /** **/ + private static final long serialVersionUID = -8932288648630324802L; + + /** + * 必填;最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~,其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式) + **/ + private String scene; + /** 页面 page,例如 pages/index/index,根路径前不要填加 /,不能携带参数(参数请放在scene字段里),如果不填写这个字段,默认跳主页面 **/ + private String page; + /** 检查page 是否存在,为 true 时 page 必须是已经发布的小程序存在的页面(否则报错);为 false 时允许小程序未发布或者 page 不存在, 但page 有数量上限(60000个)请勿滥用 **/ + @JsonProperty("check_path") + private Boolean checkPath; + /** 要打开的小程序版本。正式版为 "release",体验版为 "trial",开发版为 "develop" **/ + @JsonProperty("env_version") + private String envVersion; + /** 二维码的宽度,单位 px。最小 280px,最大 1280px **/ + private Integer width; + /** 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 **/ + @JsonProperty("auto_color") + private Boolean autoColor; + /** auto_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} 十进制表示 **/ + @JsonProperty("line_color") + private String lineColor; + /** 是否需要透明底色,为 true 时,生成透明底色的小程序码 **/ + @JsonProperty("is_hyaline") + private Boolean isHyaline; + + @Override + public String getMethodName() { + return WechatMethodEnum.UNLIMITED_WXACODE.name(); + } + + @Override + public Class getResponseClass() { + return BufferDTO.class; + } + + @Override + public String getUri() { + return WechatConstants.UNLIMITED_WXACODE_PREFIX; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/UrlLinkDTO.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/UrlLinkDTO.java new file mode 100644 index 0000000..e8643f8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/UrlLinkDTO.java @@ -0,0 +1,27 @@ +package com.senmesh.sdk.wechat.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2021-08-31 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UrlLinkDTO extends BaseWeChatDTO { + + /** **/ + private static final long serialVersionUID = 1038878005278639836L; + + /** 生成的小程序 URL Link **/ + @JsonProperty("url_link") + private String urlLink; + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/UrlLinkReq.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/UrlLinkReq.java new file mode 100644 index 0000000..26381b9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/UrlLinkReq.java @@ -0,0 +1,56 @@ +package com.senmesh.sdk.wechat.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.senmesh.sdk.wechat.constants.WechatConstants; +import com.senmesh.sdk.wechat.constants.WechatMethodEnum; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class UrlLinkReq extends AbstractAccessTokenReq { + + /** **/ + private static final long serialVersionUID = -1711028840697002351L; + + /** 否 通过 URL Link 进入的小程序页面路径,必须是已经发布的小程序存在的页面,不可携带 query 。path 为空时会跳转小程序主页 **/ + private String path; + /** 否 通过 URL Link 进入小程序时的query,最大1024个字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~% **/ + private String query; + /** 否 默认值false。生成的 URL Link 类型,到期失效:true,永久有效:false。注意,永久有效 Link 和有效时间超过180天的到期失效 Link 的总数上限为10万个,详见获取 URL Link,生成 Link 前请仔细确认。 **/ + @JsonProperty("is_expire") + private Boolean isExpire; + /** 否 默认值0.小程序 URL Link 失效类型,失效时间:0,失效间隔天数:1 **/ + @JsonProperty("expire_type") + private Integer expireType; + /** 否 到期失效的 URL Link 的失效时间,为 Unix 时间戳。生成的到期失效 URL Link 在该时间前有效。最长有效期为1年。expire_type 为 0 必填 **/ + @JsonProperty("expire_time") + private Long expireTime; + /** 否 到期失效的URL Link的失效间隔天数。生成的到期失效URL Link在该间隔时间到达前有效。最长间隔天数为365天。expire_type 为 1 必填 **/ + @JsonProperty("expire_interval") + private Integer expireInterval; + /** 要打开的小程序版本。正式版为"release",体验版为"trial",开发版为"develop",仅在微信外打开时生效 **/ + @JsonProperty("env_version") + private String envVersion; + + @Override + public String getMethodName() { + return WechatMethodEnum.URLLINK.name(); + } + + @Override + public String getUri() { + return WechatConstants.URLLINK_URL_PREFIX; + } + + @Override + public Class getResponseClass() { + return UrlLinkDTO.class; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/UrlSchemeDTO.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/UrlSchemeDTO.java new file mode 100644 index 0000000..5f93b30 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/UrlSchemeDTO.java @@ -0,0 +1,26 @@ +package com.senmesh.sdk.wechat.model; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2021-08-31 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UrlSchemeDTO extends BaseWeChatDTO implements Serializable { + + /** **/ + private static final long serialVersionUID = 1038878005278639836L; + + /** 生成的小程序 scheme 码 **/ + private String openlink; + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/UrlSchemeReq.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/UrlSchemeReq.java new file mode 100644 index 0000000..c8083de --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/UrlSchemeReq.java @@ -0,0 +1,55 @@ +package com.senmesh.sdk.wechat.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.senmesh.sdk.wechat.constants.WechatConstants; +import com.senmesh.sdk.wechat.constants.WechatMethodEnum; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class UrlSchemeReq extends AbstractAccessTokenReq { + + /** **/ + private static final long serialVersionUID = -4150840251643273167L; + + /** 跳转到的目标小程序信息 **/ + @JsonProperty("jump_wxa") + private JumpWxa jumpWxa; + /** 生成的 scheme 码类型, + * 到期失效:true, + * 永久有效:false。注意,永久有效 scheme 和有效时间超过180天的到期失效 scheme 的总数上限为10万个,详见获取 URL scheme,生成 scheme 码前请仔细确认 **/ + @JsonProperty("is_expire") + private Boolean isExpire; + /** 到期失效的 scheme 码失效类型,失效时间:0,失效间隔天数:1 **/ + @JsonProperty("expire_type") + private Integer expireType; + /** 到期失效的 scheme 码的失效时间,为 Unix 时间戳。生成的到期失效 scheme 码在该时间前有效。最长有效期为1年。is_expire 为 true 且 expire_type 为 0 时必填 **/ + @JsonProperty("expire_time") + private Long expireTime; + /** 到期失效的 scheme 码的失效间隔天数。生成的到期失效 scheme 码在该间隔时间到达前有效。最长间隔天数为365天。is_expire 为 true 且 expire_type 为 1 时必填 **/ + @JsonProperty("expire_interval") + private Integer expireInterval; + + + @Override + public String getMethodName() { + return WechatMethodEnum.URLSCHEME.name(); + } + + @Override + public Class getResponseClass() { + return UrlSchemeDTO.class; + } + + @Override + public String getUri() { + return WechatConstants.URLSCHEME_URL_PREFIX; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/Watermark.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/Watermark.java new file mode 100644 index 0000000..f635bb0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/Watermark.java @@ -0,0 +1,29 @@ +package com.senmesh.sdk.wechat.model; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 敏感数据加上的数据水印 + * @author sr on 2021-11-23 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Watermark implements Serializable{ + + /** **/ + private static final long serialVersionUID = -109291749778239377L; + + /** 敏感数据归属 appId,开发者可校验此参数与自身 appId 是否一致 **/ + @JsonProperty("appid") + private String appId; + /** 敏感数据获取的时间戳, 开发者可以用于数据时效性校验 **/ + private Integer timestamp; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/WeappTemplateMsg.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/WeappTemplateMsg.java new file mode 100644 index 0000000..2221580 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/WeappTemplateMsg.java @@ -0,0 +1,39 @@ +package com.senmesh.sdk.wechat.model; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 小程序模板消息相关的信息 + * @author sr on 2021-12-27 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class WeappTemplateMsg implements Serializable{ + + /** **/ + private static final long serialVersionUID = 5229761630079036441L; + + /** 必填;小程序模板ID **/ + @JsonProperty("template_id") + private String templateId; + /** 必填;小程序页面路径 **/ + private String page; + /** 必填;小程序模板消息formid **/ + @JsonProperty("form_id") + private String formId; + /** 必填;小程序模板数据 **/ + private String data; + /** 必填;小程序模板放大关键词 **/ + @JsonProperty("emphasis_keyword") + private String emphasisKeyword; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/model/WxacodeReq.java b/backend/src/main/java/com/senmesh/sdk/wechat/model/WxacodeReq.java new file mode 100644 index 0000000..2a5f699 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/model/WxacodeReq.java @@ -0,0 +1,54 @@ +package com.senmesh.sdk.wechat.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.senmesh.sdk.wechat.constants.WechatConstants; +import com.senmesh.sdk.wechat.constants.WechatMethodEnum; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class WxacodeReq extends AbstractAccessTokenReq { + + /** **/ + private static final long serialVersionUID = -8932288648630324802L; + + /** + * 必填;扫码进入的小程序页面路径,最大长度 128 字节,不能为空; + * 对于小游戏,可以只传入 query 部分,来实现传参效果, + * 如:传入 "?foo=bar",即可在 wx.getLaunchOptionsSync 接口中的 query 参数获取到 {foo:"bar"} + **/ + private String path; + /** 二维码的宽度,单位 px。最小 280px,最大 1280px **/ + private Integer width; + /** 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 **/ + @JsonProperty("auto_color") + private Boolean autoColor; + /** auto_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} 十进制表示 **/ + @JsonProperty("line_color") + private String lineColor; + /** 是否需要透明底色,为 true 时,生成透明底色的小程序码 **/ + @JsonProperty("is_hyaline") + private Boolean isHyaline; + + @Override + public String getMethodName() { + return WechatMethodEnum.WXACODE.name(); + } + + @Override + public Class getResponseClass() { + return BufferDTO.class; + } + + @Override + public String getUri() { + return WechatConstants.WXACODE_PREFIX; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/util/MessageParamUtils.java b/backend/src/main/java/com/senmesh/sdk/wechat/util/MessageParamUtils.java new file mode 100644 index 0000000..c48c6f7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/util/MessageParamUtils.java @@ -0,0 +1,38 @@ +package com.senmesh.sdk.wechat.util; + +import java.util.Collections; +import java.util.Map; + +import com.google.common.collect.Maps; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.sdk.wechat.model.KeyData; +import org.apache.commons.lang3.StringUtils; + +public class MessageParamUtils { + + public static final String THING_PREFIX = "thing"; + public static final int THING_LIMIT = 20; + + public static Map dealData(Map params) { + if (params == null) { + return Collections.emptyMap(); + } + Map data = Maps.newHashMapWithExpectedSize(params.size()); + params.forEach((k, v) -> { + String value = v == null ? null: v.toString(); + if (k.startsWith(THING_PREFIX)) { + value = dealThing(value); + } + data.put(k, KeyData.builder().value(value).build()); + }); + return data; + } + + public static String dealThing(String value) { + if (StringUtils.isBlank(value)) { + return CommonConstants.HYPHEN; + } + return value.length() > THING_LIMIT ? (value.substring(0, 17) + CommonConstants.ELLIPSIS) : value; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/wechat/util/WechatConvertUtils.java b/backend/src/main/java/com/senmesh/sdk/wechat/util/WechatConvertUtils.java new file mode 100644 index 0000000..bb9c232 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/wechat/util/WechatConvertUtils.java @@ -0,0 +1,87 @@ +package com.senmesh.sdk.wechat.util; + +import java.net.URI; +import java.util.Collections; +import java.util.Optional; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.web.util.UriComponentsBuilder; + +import com.senmesh.sdk.wechat.constants.WechatConstants; +import com.senmesh.sdk.wechat.model.AbstractAccessTokenReq; +import com.senmesh.sdk.wechat.model.AccessTokenReq; +import com.senmesh.sdk.wechat.model.Code2SessionReq; +import com.senmesh.sdk.wechat.model.CodeUserInfoReq; +import com.senmesh.sdk.wechat.model.FullUserInfoDTO; +import com.senmesh.sdk.wechat.model.JsApiTicketReq; +import com.senmesh.sdk.wechat.model.SubscibeUserReq; +import com.senmesh.sdk.wechat.model.UnionReq; + +public class WechatConvertUtils { + + public static RequestEntity convert(AccessTokenReq param) { + HttpHeaders headers = new HttpHeaders(); + headers.setAccept(Collections.singletonList(MediaType.TEXT_PLAIN)); + String url = + String.format(param.getUri(), param.getAppId(), + param.getSecret()); + URI uri = UriComponentsBuilder.fromUriString(url).build().toUri(); + return new RequestEntity<>(headers, HttpMethod.GET, uri); + } + + public static RequestEntity convert(Code2SessionReq param) { + String url = + String.format(param.getUri(), param.getAppId(), + param.getSecret(), param.getCode()); + URI uri = UriComponentsBuilder.fromUriString(url).build().toUri(); + return new RequestEntity<>(HttpMethod.GET, uri); + } + + public static RequestEntity convert(JsApiTicketReq param) { + HttpHeaders headers = new HttpHeaders(); + headers.setAccept(Collections.singletonList(MediaType.TEXT_PLAIN)); + String url = + String.format(param.getUri(), param.getAccessToken(), + param.getType()); + URI uri = UriComponentsBuilder.fromUriString(url).build().toUri(); + return new RequestEntity<>(headers, HttpMethod.GET, uri); + } + + public static RequestEntity convert(CodeUserInfoReq param) { + HttpHeaders headers = new HttpHeaders(); + headers.setAccept(Collections.singletonList(MediaType.TEXT_PLAIN)); + String url = + String.format(WechatConstants.USER_INFO_URL_FORMAT, + param.getAccessToken(), param.getOpenId(), "zh_CN"); + URI uri = UriComponentsBuilder.fromUriString(url).build().toUri(); + return new RequestEntity<>(headers, HttpMethod.GET, uri); + } + + public static RequestEntity convertPost(AbstractAccessTokenReq req) { + URI uri = UriComponentsBuilder + .fromUriString( + req.getUri() + req.getAccessToken()) + .build().toUri(); + return new RequestEntity<>(req, HttpMethod.POST, uri); + } + + public static RequestEntity convert(SubscibeUserReq param) { + String url = + String.format(param.getUri(), param.getAccessToken(), + Optional.ofNullable(param.getNextOpenId()).orElse("")); + URI uri = UriComponentsBuilder.fromUriString(url).build().toUri(); + return new RequestEntity<>(HttpMethod.GET, uri); + } + + public static RequestEntity convert(UnionReq param) { + String url = + String.format(param.getUri(), param.getAccessToken(), + param.getOpenId(), "zh_CN"); + URI uri = UriComponentsBuilder.fromUriString(url).build().toUri(); + return new RequestEntity<>(HttpMethod.GET, uri); + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/workwechat/constant/WorkWechatConstants.java b/backend/src/main/java/com/senmesh/sdk/workwechat/constant/WorkWechatConstants.java new file mode 100644 index 0000000..b019e95 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/workwechat/constant/WorkWechatConstants.java @@ -0,0 +1,10 @@ +package com.senmesh.sdk.workwechat.constant; + +/** + * @author sr on 2020-07-06 + */ +public interface WorkWechatConstants { + + String AT_ALL = "@all"; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/workwechat/model/WwrArticleMsg.java b/backend/src/main/java/com/senmesh/sdk/workwechat/model/WwrArticleMsg.java new file mode 100644 index 0000000..8ae3529 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/workwechat/model/WwrArticleMsg.java @@ -0,0 +1,45 @@ +package com.senmesh.sdk.workwechat.model; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.senmesh.sdk.robot.constant.WorkWechatMsgTypeEnum; +import com.senmesh.sdk.robot.model.IWorkWechatMsg; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 企业微信机器人消息-图文 + * + * @author sr on 2020-07-06 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class WwrArticleMsg extends IWorkWechatMsg implements Serializable { + + /** **/ + private static final long serialVersionUID = -1870915544362911162L; + + /** 标题,不超过128个字节,超过会自动截断 **/ + private String title; + /** 描述,不超过512个字节,超过会自动截断 **/ + private String description; + /** 点击后跳转的链接 **/ + private String url; + /** 图文消息的图片链接,支持JPG、PNG格式,较好的效果为大图 1068*455,小图150*150 **/ + @JsonProperty("picurl") + private String picUrl; + + @Override + public String getMsgType() { + return WorkWechatMsgTypeEnum.NEWS.getType(); + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/workwechat/model/WwrImageMsg.java b/backend/src/main/java/com/senmesh/sdk/workwechat/model/WwrImageMsg.java new file mode 100644 index 0000000..e0e566c --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/workwechat/model/WwrImageMsg.java @@ -0,0 +1,40 @@ +package com.senmesh.sdk.workwechat.model; + +import java.io.Serializable; + +import com.senmesh.sdk.robot.constant.WorkWechatMsgTypeEnum; +import com.senmesh.sdk.robot.model.IWorkWechatMsg; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 企业微信机器人消息-图片 + * + * @author sr on 2020-07-06 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class WwrImageMsg extends IWorkWechatMsg implements Serializable { + + /** **/ + private static final long serialVersionUID = 388617076942476152L; + + /** 图片内容的base64编码 **/ + private String base64; + /** 图片内容(base64编码前)的md5值 **/ + private String md5; + + + @Override + public String getMsgType() { + return WorkWechatMsgTypeEnum.IMAGE.getType(); + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/workwechat/model/WwrMarkdownMsg.java b/backend/src/main/java/com/senmesh/sdk/workwechat/model/WwrMarkdownMsg.java new file mode 100644 index 0000000..10804aa --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/workwechat/model/WwrMarkdownMsg.java @@ -0,0 +1,37 @@ +package com.senmesh.sdk.workwechat.model; + +import java.io.Serializable; + +import com.senmesh.sdk.robot.constant.WorkWechatMsgTypeEnum; +import com.senmesh.sdk.robot.model.IWorkWechatMsg; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 企业微信机器人消息-markdown + * + * @author sr on 2020-07-06 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class WwrMarkdownMsg extends IWorkWechatMsg implements Serializable { + + /** **/ + private static final long serialVersionUID = 3127170367241501732L; + + /** markdown内容,最长不超过4096个字节,必须是utf8编码 **/ + private String content; + + @Override + public String getMsgType() { + return WorkWechatMsgTypeEnum.MARKDOWN.getType(); + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/workwechat/model/WwrTextMsg.java b/backend/src/main/java/com/senmesh/sdk/workwechat/model/WwrTextMsg.java new file mode 100644 index 0000000..fdcf20d --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/workwechat/model/WwrTextMsg.java @@ -0,0 +1,45 @@ +package com.senmesh.sdk.workwechat.model; + +import java.io.Serializable; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.senmesh.sdk.robot.constant.WorkWechatMsgTypeEnum; +import com.senmesh.sdk.robot.model.IWorkWechatMsg; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 企业微信机器人消息-文本 + * + * @author sr on 2020-07-06 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class WwrTextMsg extends IWorkWechatMsg implements Serializable{ + + /** **/ + private static final long serialVersionUID = 6281117623858493719L; + + /** 文本内容,最长不超过2048个字节,必须是utf8编码 **/ + private String content; + + @JsonProperty("mentioned_list") + private List mentionedList; + + @JsonProperty("mentioned_mobile_list") + private List mentionedMobileList; + + @Override + public String getMsgType() { + return WorkWechatMsgTypeEnum.TEXT.getType(); + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/workwechat/service/WorkWechatRobotService.java b/backend/src/main/java/com/senmesh/sdk/workwechat/service/WorkWechatRobotService.java new file mode 100644 index 0000000..b91b004 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/workwechat/service/WorkWechatRobotService.java @@ -0,0 +1,19 @@ +package com.senmesh.sdk.workwechat.service; + +import com.senmesh.sdk.robot.model.IWorkWechatMsg; + +/** + * @author sr on 2020-07-06 + */ +public interface WorkWechatRobotService { + + /** + * 发送消息 + * + * @param robotKey 机器人key + * @param msg + * @author sr on 2020-07-07 + */ + void send(String robotKey, IWorkWechatMsg msg); + +} diff --git a/backend/src/main/java/com/senmesh/sdk/workwechat/service/impl/WorkWechatRobotServiceImpl.java b/backend/src/main/java/com/senmesh/sdk/workwechat/service/impl/WorkWechatRobotServiceImpl.java new file mode 100644 index 0000000..aba0205 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/workwechat/service/impl/WorkWechatRobotServiceImpl.java @@ -0,0 +1,53 @@ +package com.senmesh.sdk.workwechat.service.impl; + +import java.util.Arrays; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import com.dingtalk.api.request.OapiRobotSendRequest; +import com.senmesh.sdk.robot.model.IWorkWechatMsg; +import com.senmesh.sdk.robot.model.TextMsg; +import com.senmesh.sdk.workwechat.service.WorkWechatRobotService; +import com.senmesh.sdk.workwechat.util.WorkWechatUtils; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author sr on 2020-07-06 + */ +@Service +@Slf4j +public class WorkWechatRobotServiceImpl implements WorkWechatRobotService { + + private static final String URL_PREFIX = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key="; + + @Autowired + private RestTemplate restTemplate; + + public void send(String robotKey, IWorkWechatMsg msg) { + try { + restTemplate.postForEntity(URL_PREFIX + robotKey, WorkWechatUtils.parsePostData(msg), + Object.class); + } catch (Exception e) { + log.info("WorkWechatRobot send error:{}", e.getMessage()); + } + } + + public void sendDingText(String robotKey, TextMsg textMsg) { + // 76651782e4a03b420aff022e1a5e9010b3606648c40d2ab698d3d3e4ee691538 + + OapiRobotSendRequest request = new OapiRobotSendRequest(); + request.setMsgtype("text"); + OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text(); + text.setContent("前方高能😯😯:\n从前有座山..."); + request.setText(text); + OapiRobotSendRequest.At at = new OapiRobotSendRequest.At(); + at.setAtMobiles(Arrays.asList("13611806907")); + // isAtAll类型如果不为Boolean,请升级至最新SDK + // at.setIsAtAll(true); + request.setAt(at); + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/workwechat/util/WorkWechatUtils.java b/backend/src/main/java/com/senmesh/sdk/workwechat/util/WorkWechatUtils.java new file mode 100644 index 0000000..ad9865a --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/workwechat/util/WorkWechatUtils.java @@ -0,0 +1,40 @@ +package com.senmesh.sdk.workwechat.util; + +import java.util.Map; + +import com.google.common.collect.Maps; +import com.senmesh.sdk.robot.constant.WorkWechatMsgTypeEnum; +import com.senmesh.sdk.robot.model.IWorkWechatMsg; +import com.senmesh.sdk.workwechat.model.WwrTextMsg; + +/** + * @author sr on 2020-07-06 + */ +public class WorkWechatUtils { + + private static final String MSG_TYPE = "msgtype"; + + /** + * 转换消息发送对象数据 + * + * @param msg + * @return + * @author sr on 2020-07-06 + */ + public static Map parsePostData(IWorkWechatMsg msg) { + Map data = Maps.newHashMap(); + String msgType = msg.getMsgType(); + data.put(MSG_TYPE, msgType); + if (WorkWechatMsgTypeEnum.TEXT.getType().equals(msgType)) { + // 文本消息截取500长度 + WwrTextMsg textMsg = (WwrTextMsg) msg; + String context = textMsg.getContent(); + if (context.length() > 500) { + textMsg.setContent(textMsg.getContent().substring(0, 500)); + } + } + data.put(msgType, msg); + return data; + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/xf/config/XfProperties.java b/backend/src/main/java/com/senmesh/sdk/xf/config/XfProperties.java new file mode 100644 index 0000000..20b7980 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/xf/config/XfProperties.java @@ -0,0 +1,51 @@ +package com.senmesh.sdk.xf.config; + +import java.io.Serializable; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@ConfigurationProperties(prefix = XfProperties.PREFIX) +@Data +@Component +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class XfProperties implements Serializable{ + + /** **/ + private static final long serialVersionUID = 6362606996602121889L; + + public static final String PREFIX = "xf"; + + /** 控制台获取http服务接口认证信息中的APIPassword **/ + private String httpAPIPassword; + + /** 在控制台-我的应用获取 **/ + private String appId; + private String apiSecret; + private String apiKey; + /** 语音听写地址 **/ + private String iatHostUrl; + /** 语音合成地址 **/ + private String ttsHostUrl; + /** 机器翻译niutrans **/ + private String otsHostUrl; + /** 实时语音转写 **/ + private XfAppProperties rtasr; + + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class XfAppProperties implements Serializable{ + private String apiKey; + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/xf/dto/InterviewContentDTO.java b/backend/src/main/java/com/senmesh/sdk/xf/dto/InterviewContentDTO.java new file mode 100644 index 0000000..edf2ca4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/xf/dto/InterviewContentDTO.java @@ -0,0 +1,22 @@ +package com.senmesh.sdk.xf.dto; + +import java.io.Serializable; +import java.util.List; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.Singular; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class InterviewContentDTO implements Serializable{ + + private String positionName; + @Singular + private List qas; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/xf/dto/InterviewQaDTO.java b/backend/src/main/java/com/senmesh/sdk/xf/dto/InterviewQaDTO.java new file mode 100644 index 0000000..49b6c7e --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/xf/dto/InterviewQaDTO.java @@ -0,0 +1,23 @@ +package com.senmesh.sdk.xf.dto; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class InterviewQaDTO implements Serializable{ + + private Integer qno; + private String q; + private String a; + private String ua; + private String score; + private String advice; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/xf/dto/RtasrReqDTO.java b/backend/src/main/java/com/senmesh/sdk/xf/dto/RtasrReqDTO.java new file mode 100644 index 0000000..5789497 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/xf/dto/RtasrReqDTO.java @@ -0,0 +1,28 @@ +package com.senmesh.sdk.xf.dto; + +import java.io.Serializable; +import javax.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Builder.Default; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class RtasrReqDTO implements Serializable { + + @NotBlank(message = "语音文件不能为空") + private String fileCode; + /** + * 中文:cn + * 维语:cn_uyghur + */ + @Default + private String from = "cn_uyghur"; + + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/xf/dto/TtsReqDTO.java b/backend/src/main/java/com/senmesh/sdk/xf/dto/TtsReqDTO.java new file mode 100644 index 0000000..799e403 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/xf/dto/TtsReqDTO.java @@ -0,0 +1,40 @@ +package com.senmesh.sdk.xf.dto; + +import com.senmesh.sdk.xf.util.WebTtsWS; +import java.io.Serializable; +import javax.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Builder.Default; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class TtsReqDTO implements Serializable { + + @NotBlank(message = "合成文本不能为空") + private String text; + + /** + * 发音人 + * x4_yezi(中文)/x2_ugsp_dilare(维语) + */ + @Default + private String vcn = "xiaoyan"; + + /** + * 文本编码格式 + * GB2312 + * GBK + * BIG5 + * UNICODE(小语种) + * GB18030 + * UTF8(小语种推荐使用UTF8编码) + * */ + @Default + private String tte = WebTtsWS.TTL_UTF8; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/sdk/xf/model/ChatReq.java b/backend/src/main/java/com/senmesh/sdk/xf/model/ChatReq.java new file mode 100644 index 0000000..9fb9a3d --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/xf/model/ChatReq.java @@ -0,0 +1,40 @@ +package com.senmesh.sdk.xf.model; + +import java.io.Serializable; +import java.util.List; + +import javax.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.Singular; +import lombok.Builder.Default; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ChatReq implements Serializable{ + + @Default + private String model = "4.0Ultra"; + @Singular + @NotNull(message = "消息内容不能为空") + private List messages; + @Default + private Float temperature = 0.3f; + @Default + private Integer max_tokens = 150; +// @Default +// private String repetition_penalty = "1.25"; + @Default + private Float top_p = 0.65f; + @Default + private Float presence_penalty = -0.6f; + @Default + private Float frequency_penalty = 0.2f; + + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/xf/model/ChatRes.java b/backend/src/main/java/com/senmesh/sdk/xf/model/ChatRes.java new file mode 100644 index 0000000..36baf86 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/xf/model/ChatRes.java @@ -0,0 +1,22 @@ +package com.senmesh.sdk.xf.model; + +import java.io.Serializable; +import java.util.List; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ChatRes implements Serializable{ + + private String code; + private String message; + private List choices; + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/xf/model/ChoiceDTO.java b/backend/src/main/java/com/senmesh/sdk/xf/model/ChoiceDTO.java new file mode 100644 index 0000000..34d25b2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/xf/model/ChoiceDTO.java @@ -0,0 +1,17 @@ +package com.senmesh.sdk.xf.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ChoiceDTO { + + private MessageDTO message; + private Integer index; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/xf/model/MessageDTO.java b/backend/src/main/java/com/senmesh/sdk/xf/model/MessageDTO.java new file mode 100644 index 0000000..aa965d0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/xf/model/MessageDTO.java @@ -0,0 +1,22 @@ +package com.senmesh.sdk.xf.model; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class MessageDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 4026941416873536216L; + + private String role; + private String content; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/xf/model/TranslateReq.java b/backend/src/main/java/com/senmesh/sdk/xf/model/TranslateReq.java new file mode 100644 index 0000000..26f7430 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/xf/model/TranslateReq.java @@ -0,0 +1,67 @@ +package com.senmesh.sdk.xf.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.senmesh.sdk.common.dto.ISdkRequest; +import com.senmesh.sdk.xf.model.TranslateReq.TranslateRes; +import javax.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Builder.Default; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.core.ParameterizedTypeReference; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class TranslateReq implements ISdkRequest> { + + private static ParameterizedTypeReference> type = new ParameterizedTypeReference>() { + }; + /** 中文 */ + private static final String CN = "cn"; + /** 维语 */ + private static final String UY = "uy"; + + @NotBlank(message = "待翻译文本不能为空") + private String text; + @Default + private String from = CN; + @Default + private String to = UY; + + @Override + public ParameterizedTypeReference getResponseType() { + return type; + } + + @Data + @AllArgsConstructor + @NoArgsConstructor + @Builder + public static class TranslateRes { + private TranslateResDTO result; + } + @Data + @AllArgsConstructor + @NoArgsConstructor + @Builder + public static class TranslateResDTO { + private String from; + private String to; + @JsonProperty("trans_result") + private TranslateResultDTO transResult; + } + + @Data + @AllArgsConstructor + @NoArgsConstructor + @Builder + public static class TranslateResultDTO { + private String src; + private String dst; + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/xf/model/XfRes.java b/backend/src/main/java/com/senmesh/sdk/xf/model/XfRes.java new file mode 100644 index 0000000..6ca36a0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/xf/model/XfRes.java @@ -0,0 +1,19 @@ +package com.senmesh.sdk.xf.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class XfRes { + + private Integer code; + private String message; + private String sid; + private T data; + +} diff --git a/backend/src/main/java/com/senmesh/sdk/xf/service/RtasrClientApp.java b/backend/src/main/java/com/senmesh/sdk/xf/service/RtasrClientApp.java new file mode 100644 index 0000000..166773d --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/xf/service/RtasrClientApp.java @@ -0,0 +1,153 @@ +package com.senmesh.sdk.xf.service; + +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import cn.xfyun.api.RtasrClient; +import cn.xfyun.model.response.rtasr.RtasrResponse; +import cn.xfyun.service.rta.AbstractRtasrWebSocketListener; +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.sdk.xf.config.XfProperties; +import java.io.InputStream; +import java.util.concurrent.CountDownLatch; +import okhttp3.Response; +import okhttp3.WebSocket; +import org.apache.commons.codec.binary.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * ( Real-time ASR ) 实时语音转写 1、APPID、APIKey信息获取:... 2、文档地址:... + * + * @author kaili23 + */ +public class RtasrClientApp extends AbstractRtasrWebSocketListener{ + + private static final Logger logger = LoggerFactory.getLogger(RtasrClientApp.class); + + /** + * 记录完整结果 + */ + private StringBuffer finalResult = new StringBuffer(); + + private AlitaResult result; + + /** + * 线程同步 + */ + private CountDownLatch latch; + + RtasrClientApp(CountDownLatch latch){ + this.latch = latch; + } + + public AlitaResult getResult() { + return result; + } + + @Override + public void onSuccess(WebSocket webSocket, String text) { + RtasrResponse response = JsonUtils.toObject(text, RtasrResponse.class); + // finalResult为服务端已转写的完整语句,后面拼接服务端本次返回的当前语句的转写中间结果。 + String tempResult = handleAndReturnContent(response.getData()); + logger.info("实时转写结果:{}", finalResult + tempResult); + result = AlitaResult.success(finalResult.toString()); + } + + @Override + public void onFail(WebSocket webSocket, Throwable t, Response response) { + result = AlitaResult.bizError(t.getMessage()); + latch.countDown(); + webSocket.close(1000, ""); + } + + @Override + public void onBusinessFail(WebSocket webSocket, String text) { + logger.error("业务异常,返回信息为:{}", text); + result = AlitaResult.bizError(text); + latch.countDown(); + webSocket.close(1000, ""); + } + + @Override + public void onClosing(WebSocket webSocket, int code, String reason) { + latch.countDown(); + webSocket.close(1000, ""); + } + + @Override + public void onClosed() { + latch.countDown(); + } + + public static AlitaResult execute(InputStream is, String from, XfProperties xfProperties) { + try { + CountDownLatch latch = new CountDownLatch(1); + RtasrClientApp app = new RtasrClientApp(latch); + RtasrClient client = new RtasrClient.Builder() + .signature(xfProperties.getAppId(), xfProperties.getRtasr().getApiKey()) + .lang(from) + // 设置此参数需需开通翻译功能,请在控制台申请并开通 +// .targetLang(to) + .build(); + client.send(is, app); + latch.await(); + return app.getResult(); + } catch (Exception e) { + if (e instanceof InterruptedException) { + Thread.currentThread().interrupt(); + } + logger.error("语音转写失败", e); + return AlitaResult.error("语音转写失败:{}", e.getMessage()); + } + } + + /** + * 解析转写流式响应,更新实时结果,返回此次的中间结果 + */ + public String handleAndReturnContent(String message) { + StringBuilder tempResult = new StringBuilder(); + + try { + // 解析本次服务端返回的文本内容 + + JSONObject messageObj = JSONUtil.parseObj(message); + JSONObject cn = messageObj.getJSONObject("cn"); + JSONObject st = cn.getJSONObject("st"); + JSONArray rtArr = st.getJSONArray("rt"); + for (int i = 0; i < rtArr.size(); i++) { + JSONObject rtArrObj = rtArr.getJSONObject(i); + JSONArray wsArr = rtArrObj.getJSONArray("ws"); + for (int j = 0; j < wsArr.size(); j++) { + JSONObject wsArrObj = wsArr.getJSONObject(j); + JSONArray cwArr = wsArrObj.getJSONArray("cw"); + for (int k = 0; k < cwArr.size(); k++) { + JSONObject cwArrObj = cwArr.getJSONObject(k); + String wStr = cwArrObj.getStr("w"); + tempResult.append(wStr); + } + } + } + + // 根据中间结果类型更新最终结果 + String type = st.getStr("type"); + if (StringUtils.equals("1", type)) { + // 此时服务端返回的是当前语句的实时转写内容,不保存到最终结果中,返回到调用处进行拼接展示。 + return tempResult.toString(); + } else if (StringUtils.equals("0", type)) { + // 此时服务端返回的是当前语句的完整转写内容,保存到最终结果中,并返回空字符串。 + finalResult.append(tempResult); + return ""; + } else { + logger.warn("未知的转写响应类型:{}", type); + return tempResult.toString(); + } + } catch (Exception e) { + return message; + } + } + +} diff --git a/backend/src/main/java/com/senmesh/sdk/xf/service/XfSparkProvider.java b/backend/src/main/java/com/senmesh/sdk/xf/service/XfSparkProvider.java new file mode 100644 index 0000000..68f12ba --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/xf/service/XfSparkProvider.java @@ -0,0 +1,234 @@ +package com.senmesh.sdk.xf.service; + +import com.google.gson.JsonObject; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.sdk.xf.model.TranslateReq; +import com.senmesh.sdk.xf.model.TranslateReq.TranslateRes; +import com.senmesh.sdk.xf.model.XfRes; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.charset.Charset; +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.text.SimpleDateFormat; +import java.util.Base64; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.sdk.common.constant.SdkConstants; +import com.senmesh.sdk.common.dto.DefaultSdkInvokeLogDTO; +import com.senmesh.sdk.common.util.HttpUtils; +import com.senmesh.sdk.xf.config.XfProperties; +import com.senmesh.sdk.xf.model.ChatReq; +import com.senmesh.sdk.xf.model.ChatRes; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class XfSparkProvider { + + private static XfProperties xfProperties; + + private XfSparkProvider(XfProperties xfProperties) { + XfSparkProvider.xfProperties = xfProperties; + } + + public static AlitaResult httpChat(ChatReq req) { + return httpChat(req, xfProperties.getHttpAPIPassword()); + } + + public static AlitaResult httpChat(ChatReq req, String httpAPIPassword) { + ResponseEntity response = null; + try { + try { + HttpHeaders header = new HttpHeaders(); + header.add("Authorization", "Bearer " + httpAPIPassword); + header.add("Content-Type", "application/json"); + // 发送请求 + HttpEntity requestEntity = new HttpEntity(req, header); + response = + HttpUtils.restTemplate.exchange("https://spark-api-open.xf-yun.com/v1/chat/completions", + HttpMethod.POST, requestEntity, ChatRes.class); + } catch (Exception e) { + log.error("xfSpark http error:{}", e.getMessage()); + return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_ERROR_CODE, e.getMessage()); + } + try { + String content = response.getBody().getChoices().get(0).getMessage().getContent(); + content = dealJson(content); + return AlitaResult.success(content); + } catch (Exception e) { + return AlitaResult.error(SdkConstants.SDK_RESPONSE_CONVERT_ERROR_CODE, "xf返回结果获取content失败"); + } + + } finally { + log.info("xfSpark invoke:{}", + JsonUtils + .toJsonString( + DefaultSdkInvokeLogDTO.builder().requestData(req).responseData(response) + .build())); + } + } + + public static String dealJson(String content) { + return content.replaceAll("(```json\n)|(\n```)|(\n)", ""); + } + + public static AlitaResult translate(TranslateReq translateReq){ + return translate(translateReq, xfProperties); + } + + public static AlitaResult translate(TranslateReq translateReq, XfProperties xfProperties){ + + ResponseEntity> response = null; + try { + try { + String body = buildHttpBody(translateReq, xfProperties); + + HttpHeaders header = buildHttpHeader(body, xfProperties); + // 发送请求 + HttpEntity requestEntity = new HttpEntity(body, header); + response = + HttpUtils.restTemplate.exchange(xfProperties.getOtsHostUrl(), + HttpMethod.POST, requestEntity, translateReq.getResponseType()); + } catch (Exception e) { + log.error("xfSpark http error:{}", e.getMessage()); + return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_ERROR_CODE, e.getMessage()); + } + try { + XfRes res = response.getBody(); + if (!res.getCode().equals(0)) { + return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_RESPONSE_FAIL_CODE, + res.getCode() + CommonConstants.COLON + res.getMessage()); + } + return AlitaResult.success(res.getData().getResult().getTransResult().getDst()); + } catch (Exception e) { + return AlitaResult.error(SdkConstants.SDK_RESPONSE_CONVERT_ERROR_CODE, "xf返回结果获取content失败"); + } + + } finally { + log.info("xfSpark invoke:{}", + JsonUtils + .toJsonString( + DefaultSdkInvokeLogDTO.builder().requestData(translateReq).responseData(response) + .build())); + } + + } + /** + * 组装http请求头 + */ + public static HttpHeaders buildHttpHeader(String body, XfProperties xfProperties) + throws MalformedURLException, NoSuchAlgorithmException, InvalidKeyException { + HttpHeaders header = new HttpHeaders(); + URL url = new URL(xfProperties.getOtsHostUrl()); + + //时间戳 + SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); + format.setTimeZone(TimeZone.getTimeZone("GMT")); + Date dateD = new Date(); + String date = format.format(dateD); + //System.out.println("【OTS WebAPI date】\n" + date); + + //对body进行sha256签名,生成digest头部,POST请求必须对body验证 + String digestBase64 = "SHA-256=" + signBody(body); + //System.out.println("【OTS WebAPI digestBase64】\n" + digestBase64); + + //hmacsha256加密原始字符串 + StringBuilder builder = new StringBuilder("host: ").append(url.getHost()).append("\n").// + append("date: ").append(date).append("\n").// + append("POST ").append(url.getPath()).append(" HTTP/1.1").append("\n").// + append("digest: ").append(digestBase64); + //System.out.println("【OTS WebAPI builder】\n" + builder); + String sha = hmacsign(builder.toString(), xfProperties.getApiSecret()); + //System.out.println("【OTS WebAPI sha】\n" + sha); + + //组装authorization + String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", xfProperties.getApiKey(), "hmac-sha256", "host date request-line digest", sha); + //System.out.println("【OTS WebAPI authorization】\n" + authorization); + + header.add("Authorization", authorization); + header.add("Content-Type", "application/json"); + header.add("Accept", "application/json,version=1.0"); + header.add("Host", url.getHost()); + header.add("Date", date); + header.add("Digest", digestBase64); + //System.out.println("【OTS WebAPI header】\n" + header); + return header; + } + + + /** + * 组装http请求体 + */ + public static String buildHttpBody(TranslateReq translateReq, XfProperties xfProperties) + throws UnsupportedEncodingException { + JsonObject body = new JsonObject(); + JsonObject business = new JsonObject(); + JsonObject common = new JsonObject(); + JsonObject data = new JsonObject(); + //填充common + common.addProperty("app_id", xfProperties.getAppId()); + //填充business + business.addProperty("from", translateReq.getFrom()); + business.addProperty("to", translateReq.getTo()); + //填充data + //System.out.println("【OTS WebAPI TEXT字个数:】\n" + TEXT.length()); + byte[] textByte = translateReq.getText().getBytes("UTF-8"); + String textBase64 = new String(Base64.getEncoder().encodeToString(textByte)); + //System.out.println("【OTS WebAPI textBase64编码后长度:】\n" + textBase64.length()); + data.addProperty("text", textBase64); + //填充body + body.add("common", common); + body.add("business", business); + body.add("data", data); + return body.toString(); + } + + + /** + * 对body进行SHA-256加密 + */ + private static String signBody(String body) { + MessageDigest messageDigest; + String encodestr = ""; + try { + messageDigest = MessageDigest.getInstance("SHA-256"); + messageDigest.update(body.getBytes("UTF-8")); + encodestr = Base64.getEncoder().encodeToString(messageDigest.digest()); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return encodestr; + } + + /** + * hmacsha256加密 + */ + private static String hmacsign(String signature, String apiSecret) + throws NoSuchAlgorithmException, InvalidKeyException { + Charset charset = Charset.forName("UTF-8"); + Mac mac = Mac.getInstance("hmacsha256"); + SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(charset), "hmacsha256"); + mac.init(spec); + byte[] hexDigits = mac.doFinal(signature.getBytes(charset)); + return Base64.getEncoder().encodeToString(hexDigits); + } + + +} diff --git a/backend/src/main/java/com/senmesh/sdk/xf/util/WebIATWS.java b/backend/src/main/java/com/senmesh/sdk/xf/util/WebIATWS.java new file mode 100644 index 0000000..7aeb668 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/xf/util/WebIATWS.java @@ -0,0 +1,426 @@ +package com.senmesh.sdk.xf.util; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.charset.Charset; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Base64; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.senmesh.common.AlitaResult; +import com.senmesh.sdk.xf.config.XfProperties; + +import lombok.extern.slf4j.Slf4j; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.WebSocket; +import okhttp3.WebSocketListener; + +/** + * 语音听写流式 WebAPI 接口调用示例 接口文档(必看):https://doc.xfyun.cn/rest_api/语音听写(流式版).html + * webapi 听写服务参考帖子(必看):http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=38947&extra= + * 语音听写流式WebAPI 服务,热词使用方式:登陆开放平台https://www.xfyun.cn/后,找到控制台--我的应用---语音听写---个性化热词,上传热词 + * 注意:热词只能在识别的时候会增加热词的识别权重,需要注意的是增加相应词条的识别率,但并不是绝对的,具体效果以您测试为准。 + * 错误码链接:https://www.xfyun.cn/document/error-code (code返回错误码时必看) + * 语音听写流式WebAPI 服务,方言或小语种试用方法:登陆开放平台https://www.xfyun.cn/后,在控制台--语音听写(流式)--方言/语种处添加 + * 添加后会显示该方言/语种的参数值 + * @author iflytek + */ +@Slf4j +public class WebIATWS extends WebSocketListener { + // private static final String hostUrl = "https://iat-api.xfyun.cn/v2/iat"; //中英文,http url 不支持解析 ws/wss schema + // private static final String hostUrl = "https://iat-niche-api.xfyun.cn/v2/iat";//小语种 + public static final int StatusFirstFrame = 0; + public static final int StatusContinueFrame = 1; + public static final int StatusLastFrame = 2; + public static final Gson json = new Gson(); + Decoder decoder = new Decoder(); + // 开始时间 + private static Date dateBegin = new Date(); + // 结束时间 + private static Date dateEnd = new Date(); + private static final SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd HH:mm:ss.SSS"); + + InputStream is; + private String appId; + // mp3格式 + private String encoding = "raw"; + private AlitaResult result; + + WebIATWS(InputStream is, String appId) { + this.is = is; + this.appId = appId; + } + + public AlitaResult getResult() { + return result; + } + + + @Override + public void onOpen(WebSocket webSocket, Response response) { + super.onOpen(webSocket, response); + new Thread(() -> { + //连接成功,开始发送数据 + // int frameSize = 1280; //每一帧音频的大小,建议每 40ms 发送 122B + int frameSize = 1280 * 64; //每一帧音频的大小,建议每 40ms 发送 122B + int intervel = 40; + // int intervel = 0; + int status = 0; // 音频的状态 + try { + byte[] buffer = new byte[frameSize]; + // 发送音频 + end: while (true) { + int len = is.read(buffer); + if (len == -1) { + status = StatusLastFrame; //文件读完,改变status 为 2 + } + + switch (status) { + case StatusFirstFrame: // 第一帧音频status = 0 + JsonObject frame = new JsonObject(); + JsonObject business = new JsonObject(); //第一帧必须发送 + JsonObject common = new JsonObject(); //第一帧必须发送 + JsonObject data = new JsonObject(); //每一帧都要发送 + // 填充common + common.addProperty("app_id", this.appId); + //填充business + business.addProperty("language", "zh_cn"); + //business.addProperty("language", "en_us");//英文 + //business.addProperty("language", "ja_jp");//日语,在控制台可添加试用或购买 + //business.addProperty("language", "ko_kr");//韩语,在控制台可添加试用或购买 + //business.addProperty("language", "ru-ru");//俄语,在控制台可添加试用或购买 + business.addProperty("domain", "iat"); + business.addProperty("accent", "mandarin");//中文方言请在控制台添加试用,添加后即展示相应参数值 + //business.addProperty("nunum", 0); + //business.addProperty("ptt", 0);//标点符号 + //business.addProperty("rlang", "zh-hk"); // zh-cn :简体中文(默认值)zh-hk :繁体香港(若未授权不生效,在控制台可免费开通) + //business.addProperty("vinfo", 1); + business.addProperty("dwa", "wpgs");//动态修正(若未授权不生效,在控制台可免费开通) + //business.addProperty("nbest", 5);// 句子多候选(若未授权不生效,在控制台可免费开通) + //business.addProperty("wbest", 3);// 词级多候选(若未授权不生效,在控制台可免费开通) + //填充data + data.addProperty("status", StatusFirstFrame); + data.addProperty("format", "audio/L16;rate=16000"); + // data.addProperty("encoding", "raw"); + data.addProperty("encoding", this.encoding); + data.addProperty("audio", + Base64.getEncoder().encodeToString(Arrays.copyOf(buffer, len))); + //填充frame + frame.add("common", common); + frame.add("business", business); + frame.add("data", data); + webSocket.send(frame.toString()); + status = StatusContinueFrame; // 发送完第一帧改变status 为 1 + break; + case StatusContinueFrame: //中间帧status = 1 + JsonObject frame1 = new JsonObject(); + JsonObject data1 = new JsonObject(); + data1.addProperty("status", StatusContinueFrame); + data1.addProperty("format", "audio/L16;rate=16000"); + data1.addProperty("encoding", this.encoding); + data1.addProperty("audio", + Base64.getEncoder().encodeToString(Arrays.copyOf(buffer, len))); + frame1.add("data", data1); + webSocket.send(frame1.toString()); + // log.info("send continue"); + break; + case StatusLastFrame: // 最后一帧音频status = 2 ,标志音频发送结束 + JsonObject frame2 = new JsonObject(); + JsonObject data2 = new JsonObject(); + data2.addProperty("status", StatusLastFrame); + data2.addProperty("audio", ""); + data2.addProperty("format", "audio/L16;rate=16000"); + // data2.addProperty("encoding", "raw"); + data2.addProperty("encoding", this.encoding); + frame2.add("data", data2); + webSocket.send(frame2.toString()); + log.info("sendlast"); + break end; + } + Thread.sleep(intervel); //模拟音频采样延时 + } + log.info("all data is send"); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }).start(); + } + + @Override + public void onMessage(WebSocket webSocket, String text) { + super.onMessage(webSocket, text); + //log.info(text); + ResponseData resp = json.fromJson(text, ResponseData.class); + if (resp != null) { + if (resp.getCode() != 0) { + // log.info( "code=>" + resp.getCode() + " error=>" + resp.getMessage() + " sid=" + resp.getSid()); + // log.info( "错误码查询链接:https://www.xfyun.cn/document/error-code"); + result = AlitaResult.error(resp.getCode() + ":" + resp.getMessage()); + webSocket.close(1000, ""); + return; + } + if (resp.getData() != null) { + if (resp.getData().getResult() != null) { + Text te = resp.getData().getResult().getText(); + //log.info(te.toString()); + try { + decoder.decode(te); + log.debug("中间识别结果 ==》" + decoder.toString()); + } catch (Exception e) { + e.printStackTrace(); + } + } + if (resp.getData().getStatus() == 2) { + // todo resp.data.status ==2 说明数据全部返回完毕,可以关闭连接,释放资源 + // log.info("session end "); + dateEnd = new Date(); + log.info("开始-{},结束-{},耗时:{}", sdf.format(dateBegin), sdf.format(dateEnd), + (dateEnd.getTime() - dateBegin.getTime()) + "ms"); + String resultStr = decoder.toString(); + log.info("最终识别结果 ==》{},本次识别sid ==》{}", resultStr, resp.getSid()); + decoder.discard(); + webSocket.close(1000, ""); + result = AlitaResult.success(resultStr); + } else { + // todo 根据返回的数据处理 + } + } + } + } + + @Override + public void onFailure(WebSocket webSocket, Throwable t, Response response) { + super.onFailure(webSocket, t, response); + try { + if (null != response) { + int code = response.code(); + log.info("onFailure code:" + code); + log.info("onFailure body:" + response.body().string()); + if (101 != code) { + log.info("connection failed"); + webSocket.close(1000, ""); + } + } + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public static AlitaResult execute(InputStream is, XfProperties xfProperties) { + try { + // 构建鉴权url + String authUrl = getAuthUrl(xfProperties.getIatHostUrl(), xfProperties.getApiKey(), + xfProperties.getApiSecret()); + OkHttpClient client = new OkHttpClient.Builder().build(); + //将url中的 schema http://和https://分别替换为ws:// 和 wss:// + String url = authUrl.toString().replace("http://", "ws://").replace("https://", "wss://"); + Request request = new Request.Builder().url(url).build(); + WebIATWS webIATWS = new WebIATWS(is, xfProperties.getAppId()); + WebSocket webSocket = client.newWebSocket(request, webIATWS); + while (webIATWS.getResult() == null) { + // 未拿到结果等待 + Thread.sleep(1000l); + } + return webIATWS.getResult(); + } catch (Exception e) { + log.info("err ", e); + return AlitaResult.error("语音听写失败:{}", e.getMessage()); + } + + } + + public static String getAuthUrl(String hostUrl, String apiKey, String apiSecret) + throws Exception { + URL url = new URL(hostUrl); + SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); + format.setTimeZone(TimeZone.getTimeZone("GMT")); + String date = format.format(new Date()); + StringBuilder builder = new StringBuilder("host: ").append(url.getHost()).append("\n").// + append("date: ").append(date).append("\n").// + append("GET ").append(url.getPath()).append(" HTTP/1.1"); + //log.info(builder); + Charset charset = Charset.forName("UTF-8"); + Mac mac = Mac.getInstance("hmacsha256"); + SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(charset), "hmacsha256"); + mac.init(spec); + byte[] hexDigits = mac.doFinal(builder.toString().getBytes(charset)); + String sha = Base64.getEncoder().encodeToString(hexDigits); + + //log.info(sha); + String authorization = + String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey, + "hmac-sha256", "host date request-line", sha); + //log.info(authorization); + HttpUrl httpUrl = HttpUrl.parse("https://" + url.getHost() + url.getPath()).newBuilder().// + addQueryParameter("authorization", + Base64.getEncoder().encodeToString(authorization.getBytes(charset))) + .// + addQueryParameter("date", date).// + addQueryParameter("host", url.getHost()).// + build(); + return httpUrl.toString(); + } + + public static class ResponseData { + private int code; + private String message; + private String sid; + private Data data; + + public int getCode() { + return code; + } + + public String getMessage() { + return this.message; + } + + public String getSid() { + return sid; + } + + public Data getData() { + return data; + } + } + public static class Data { + private int status; + private Result result; + + public int getStatus() { + return status; + } + + public Result getResult() { + return result; + } + } + public static class Result { + int bg; + int ed; + String pgs; + int[] rg; + int sn; + Ws[] ws; + boolean ls; + JsonObject vad; + + public Text getText() { + Text text = new Text(); + StringBuilder sb = new StringBuilder(); + for (Ws ws : this.ws) { + sb.append(ws.cw[0].w); + } + text.sn = this.sn; + text.text = sb.toString(); + text.sn = this.sn; + text.rg = this.rg; + text.pgs = this.pgs; + text.bg = this.bg; + text.ed = this.ed; + text.ls = this.ls; + text.vad = this.vad == null ? null : this.vad; + return text; + } + } + public static class Ws { + Cw[] cw; + int bg; + int ed; + } + public static class Cw { + int sc; + String w; + } + public static class Text { + int sn; + int bg; + int ed; + String text; + String pgs; + int[] rg; + boolean deleted; + boolean ls; + JsonObject vad; + + @Override + public String toString() { + return "Text{" + + "bg=" + bg + + ", ed=" + ed + + ", ls=" + ls + + ", sn=" + sn + + ", text='" + text + '\'' + + ", pgs=" + pgs + + ", rg=" + Arrays.toString(rg) + + ", deleted=" + deleted + + ", vad=" + (vad == null ? "null" : vad.getAsJsonArray("ws").toString()) + + '}'; + } + } + //解析返回数据,仅供参考 + public static class Decoder { + private Text[] texts; + private int defc = 10; + + public Decoder() { + this.texts = new Text[this.defc]; + } + + public synchronized void decode(Text text) { + if (text.sn >= this.defc) { + this.resize(); + } + if ("rpl".equals(text.pgs)) { + for (int i = text.rg[0]; i <= text.rg[1]; i++) { + this.texts[i].deleted = true; + } + } + this.texts[text.sn] = text; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + for (Text t : this.texts) { + if (t != null && !t.deleted) { + sb.append(t.text); + } + } + return sb.toString(); + } + + public void resize() { + int oc = this.defc; + this.defc <<= 1; + Text[] old = this.texts; + this.texts = new Text[this.defc]; + for (int i = 0; i < oc; i++) { + this.texts[i] = old[i]; + } + } + + public void discard() { + for (int i = 0; i < this.texts.length; i++) { + this.texts[i] = null; + } + } + } +} diff --git a/backend/src/main/java/com/senmesh/sdk/xf/util/WebTtsWS.java b/backend/src/main/java/com/senmesh/sdk/xf/util/WebTtsWS.java new file mode 100644 index 0000000..1be83f2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/xf/util/WebTtsWS.java @@ -0,0 +1,224 @@ +package com.senmesh.sdk.xf.util; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.Base64; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +import com.google.gson.Gson; +import com.senmesh.common.AlitaResult; +import com.senmesh.sdk.xf.config.XfProperties; +import com.senmesh.sdk.xf.dto.TtsReqDTO; + +import lombok.extern.slf4j.Slf4j; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.WebSocket; +import okhttp3.WebSocketListener; + +/** + * 语音合成流式 WebAPI 接口调用示例 接口文档(必看):https://www.xfyun.cn/doc/tts/online_tts/API.html + * 发音人使用方式:登陆开放平台https://www.xfyun.cn/后,到控制台-我的应用-语音合成-添加试用或购买发音人,添加后即显示该发音人参数值 + * 错误码链接:https://www.xfyun.cn/document/error-code (code返回错误码时必看) + * 小语种需要传输小语种文本、使用小语种发音人vcn、tte=unicode以及修改文本编码方式 + * + * @author xlliu24 + */ +@Slf4j +public class WebTtsWS extends WebSocketListener { + public static final int StatusFirstFrame = 0; + public static final int StatusContinueFrame = 1; + public static final int StatusLastFrame = 2; + public static final String TTL_UTF8 = "UTF8"; + public static final String TTL_UNICODE = "UNICODE"; + + public static final Gson json = new Gson(); + // mp3格式 + private String encoding = "lame"; + private AlitaResult result; + + private String text; + private String appId; + OutputStream outputStream; + // 小语种必须使用UNICODE编码作为值 + private String tte; + // 发音人参数。到控制台-我的应用-语音合成-添加试用或购买发音人,添加后即显示该发音人参数值,若试用未添加的发音人会报错11200 + private String vcn; + + WebTtsWS(String text, String appId, String vcn, String tte, OutputStream outputStream){ + this.text = text; + this.appId = appId; + this.vcn = vcn; + this.tte = tte; + this.outputStream = outputStream; + } + + public AlitaResult getResult() { + return result; + } + + + @Override + public void onOpen(WebSocket webSocket, Response response) { + super.onOpen(webSocket, response); + log.info("ws建立连接成功..."); + String requestJson;//请求参数json串 + String encodedText ; + if (WebTtsWS.TTL_UNICODE.equals(tte)) { + try { + encodedText = Base64.getEncoder().encodeToString(text.getBytes("UTF-16LE")); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } else { + encodedText = Base64.getEncoder().encodeToString(text.getBytes(StandardCharsets.UTF_8)); + } + requestJson = "{\n" + + " \"common\": {\n" + + " \"app_id\": \"" + appId + "\"\n" + + " },\n" + + " \"business\": {\n" + + " \"aue\": \"lame\",\n" + + " \"sfl\": 1,\n" + + " \"tte\": \"" + tte + "\",\n" + + " \"ent\": \"intp65\",\n" + + " \"vcn\": \"" + vcn + "\",\n" + + " \"pitch\": 50,\n" + + " \"speed\": 50\n" + + " },\n" + + " \"data\": {\n" + + " \"status\": 2,\n" + + " \"text\": \"" + + encodedText + "\"\n" + + " }\n" + + "}"; + webSocket.send(requestJson); + } + + @Override + public void onMessage(WebSocket webSocket, String text) { + super.onMessage(webSocket, text); + JsonParse myJsonParse = json.fromJson(text, JsonParse.class); + if (myJsonParse.code != 0) { + log.info("发生错误,错误码为:" + myJsonParse.code); + log.info("本次请求的sid为:" + myJsonParse.sid); + result = AlitaResult.error(myJsonParse.code + ":" + myJsonParse.sid); + webSocket.close(1000, ""); + return; + } + if (myJsonParse.data != null) { + try { + byte[] textBase64Decode = Base64.getDecoder().decode(myJsonParse.data.audio); + outputStream.write(textBase64Decode); + outputStream.flush(); + log.info("本次请求的状态==>" + myJsonParse.data.status); + } catch (Exception e) { + e.printStackTrace(); + } + if (myJsonParse.data.status == 2) { + result = AlitaResult.success(); + log.info("本次请求的sid==>" + myJsonParse.sid); + // 可以关闭连接,释放资源 + webSocket.close(1000, ""); + } + } + + } + + @Override + public void onFailure(WebSocket webSocket, Throwable t, Response response) { + super.onFailure(webSocket, t, response); + try { + if (null != response) { + int code = response.code(); + log.info("onFailure code:" + code); + log.info("onFailure body:" + response.body().string()); + if (101 != code) { + log.info("connection failed"); + webSocket.close(1000, ""); + } + } + } catch (IOException e) { + log.info("failure:", e); + } + } + + public static AlitaResult execute(TtsReqDTO ttsReq, XfProperties xfProperties, OutputStream outputStream) { + try { + // 构建鉴权url + String authUrl = getAuthUrl(xfProperties.getTtsHostUrl(), xfProperties.getApiKey(), + xfProperties.getApiSecret()); + OkHttpClient client = new OkHttpClient.Builder().build(); + //将url中的 schema http://和https://分别替换为ws:// 和 wss:// + String url = authUrl.toString().replace("http://", "ws://").replace("https://", "wss://"); + Request request = new Request.Builder().url(url).build(); + WebTtsWS webIATWS = new WebTtsWS(ttsReq.getText(), xfProperties.getAppId(), ttsReq.getVcn(), ttsReq.getTte(), outputStream); + WebSocket webSocket = client.newWebSocket(request, webIATWS); + while (webIATWS.result == null) { + // 未拿到结果等待 + Thread.sleep(1000l); + } + return AlitaResult.success(); + } catch (Exception e) { + log.info("err ", e); + return AlitaResult.error("语音合成失败:{}", e.getMessage()); + } + } + + public static String getAuthUrl(String hostUrl, String apiKey, String apiSecret) + throws Exception { + URL url = new URL(hostUrl); + SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); + format.setTimeZone(TimeZone.getTimeZone("GMT")); + String date = format.format(new Date()); + StringBuilder builder = new StringBuilder("host: ").append(url.getHost()).append("\n").// + append("date: ").append(date).append("\n").// + append("GET ").append(url.getPath()).append(" HTTP/1.1"); + //log.info(builder); + Charset charset = Charset.forName("UTF-8"); + Mac mac = Mac.getInstance("hmacsha256"); + SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(charset), "hmacsha256"); + mac.init(spec); + byte[] hexDigits = mac.doFinal(builder.toString().getBytes(charset)); + String sha = Base64.getEncoder().encodeToString(hexDigits); + + //log.info(sha); + String authorization = + String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey, + "hmac-sha256", "host date request-line", sha); + //log.info(authorization); + HttpUrl httpUrl = HttpUrl.parse("https://" + url.getHost() + url.getPath()).newBuilder().// + addQueryParameter("authorization", + Base64.getEncoder().encodeToString(authorization.getBytes(charset))) + .// + addQueryParameter("date", date).// + addQueryParameter("host", url.getHost()).// + build(); + return httpUrl.toString(); + } + +//返回的json结果拆解 + class JsonParse { + int code; + String sid; + Data data; + } + + class Data { + int status; + String audio; +} + +} diff --git a/backend/src/main/java/com/senmesh/sdk/xf/util/XfUtils.java b/backend/src/main/java/com/senmesh/sdk/xf/util/XfUtils.java new file mode 100644 index 0000000..31d0af7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sdk/xf/util/XfUtils.java @@ -0,0 +1,286 @@ +package com.senmesh.sdk.xf.util; + +import com.senmesh.sdk.xf.dto.RtasrReqDTO; +import com.senmesh.sdk.xf.model.TranslateReq; +import com.senmesh.sdk.xf.service.RtasrClientApp; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.tomcat.util.http.fileupload.ByteArrayOutputStream; +import org.springframework.stereotype.Component; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.component.file.entity.FileRecord; +import com.senmesh.component.file.service.FileRecordService; +import com.senmesh.component.file.service.FileService; +import com.senmesh.component.file.util.FileUtils; +import com.senmesh.config.service.ConfigService; +import com.senmesh.sdk.xf.config.XfProperties; +import com.senmesh.sdk.xf.dto.InterviewContentDTO; +import com.senmesh.sdk.xf.dto.TtsReqDTO; +import com.senmesh.sdk.xf.model.ChatReq; +import com.senmesh.sdk.xf.model.MessageDTO; +import com.senmesh.sdk.xf.service.XfSparkProvider; + +@Component +public class XfUtils { + + private static ConfigService configService; + private static XfProperties xfProperties; + private static FileService fileService; + private static FileRecordService fileRecordService; + + XfUtils(ConfigService configService, XfProperties xfProperties, FileService fileService, FileRecordService fileRecordService){ + XfUtils.configService = configService; + XfUtils.xfProperties = xfProperties; + XfUtils.fileService = fileService; + XfUtils.fileRecordService = fileRecordService; + } + + /** + * 生成面试问题 + * @return InterviewContentDTO json + * @author sr on 2024-12-10 + */ + public static String generateInterviewQuestion(InterviewContentDTO content) { + ChatReq req = ChatReq.builder() + .message(MessageDTO.builder().role("system") + .content("你是一位专业的HR。目标任务:请根据我给出的positionName生成5个相关的面试中可能会问到的问题,并为每个问题都生成一个参考答案,并从1开始生成问题序号") + .build()) + .message(MessageDTO.builder().role("system") + .content("全部数据以JSON模版的形式返回,格式为:{positionName:岗位信息, qas:[{qno:问题序号,q:问题,a:参考答案}]}").build()) + .message(MessageDTO.builder().role("user").content(JsonUtils.toNoEmptyJson(content)).build()).build(); + AlitaResult result = XfSparkProvider.httpChat(req); + Assert.isTrue(result.getSuccess(), result.getMsg()); + return result.getData(); + } + + /** + * 评分面试 + * @return InterviewContentDTO json + * @author sr on 2024-12-10 + */ + public static String gradeInterview(InterviewContentDTO content) { + ChatReq req = ChatReq.builder() + .message(MessageDTO.builder().role("system") + .content("全部数据以JSON模版的形式返回,格式为:{positionName:岗位信息, qas:[{qno:问题序号,q:问题,a:参考答案,score:得分,根据问题q,结合参考答案a,对用户回答ua,在1-10分范围内为用户回答打分赋值,advice:作为资深的position_name提供该问题的回答建议,针对用户回答ua给出建议advice,建议内容包含不足之处+建议}]}") + .build()) + .message(MessageDTO.builder().role("user") + .content(JsonUtils.toNoEmptyJson(content)).build()) + .build(); + AlitaResult result = XfSparkProvider.httpChat(req); + Assert.isTrue(result.getSuccess(), result.getMsg()); + return result.getData(); + } + + /** + * 生成简历 + * @return + * @author sr on 2024-12-10 + */ + public static String generateResume(String content) { + String key01 = configService.getConfigValue("ai_jianli_key01", CommonConstants.PLATFORM_ORG_ID, true); + String key02 = configService.getConfigValue("ai_jianli_key02", CommonConstants.PLATFORM_ORG_ID, true); + String key03 = configService.getConfigValue("ai_jianli_key03", CommonConstants.PLATFORM_ORG_ID, true); + ChatReq req = ChatReq.builder() + .message(MessageDTO.builder().role("system") + .content(key01) + .build()) + .message(MessageDTO.builder().role("system").content(key02).build()) + .message(MessageDTO.builder().role("system").content(key03).build()) + .message(MessageDTO.builder().role("user").content(content).build()) + .build(); + AlitaResult result = XfSparkProvider.httpChat(req); + Assert.isTrue(result.getSuccess(), result.getMsg()); + return result.getData(); + } + + /** + * 语音听写 + * @param fileCode + * @return + * @author sr on 2025-01-09 + */ + public static String iat(String fileCode) { + try (InputStream fileis = fileRecordService.getFile(fileCode)){ + File file = FileUtils.createTempFile("pcm"); + try (InputStream is = FileUtils.copyToTempFile(fileis, file)) { + AlitaResult result = WebIATWS.execute(is, xfProperties); + Assert.isTrue(result.getSuccess(), result.getMsg()); + return result.getData(); + } catch (Exception e) { + throw e; + } finally { + file.delete(); + } + } catch (Exception e) { + throw new BusinessException("语音听写异常:" + e.getMessage()); + } + } + + + /** + * 语音合成 + * @return + * @author sr on 2025-01-09 + */ + public static String tts(TtsReqDTO ttsReq) { + try(ByteArrayOutputStream outputStream = new ByteArrayOutputStream()){ + AlitaResult result = WebTtsWS.execute(ttsReq, xfProperties, outputStream); + Assert.isTrue(result.getSuccess(), result.getMsg()); + FileRecord fileRecord = fileService.upload("语音合成.mp3", outputStream.toByteArray()); + return fileRecord.getFileCode(); + } catch (IOException e) { + throw new BusinessException("语音合成异常:" + e.getMessage()); + } + } + + + /** + * 生成自我评价 + * @return + */ + public static String generateSelfEvaluate(String content) { + ChatReq req = ChatReq.builder() + .message(MessageDTO.builder().role("system") + .content("你是一位专业的简历撰写专家。目标任务:请根据我给出的信息,生成指定的内容。需求说明:要求在与原文语意一致的基础上扩写内容,风格设定,简明扼要。") + .build()) + .message(MessageDTO.builder().role("system") + .content("根据我输入的信息,输出1段自我评价,包含学习能力、工作态度、团队协作等方面,字数在300字左右") + .build()) + .message(MessageDTO.builder().role("system") + .content("全部数据以JSON模版的形式返回, 格式为:{'selfEva':xxx}") + .build()) + .message(MessageDTO.builder().role("user").content(content).build()).build(); + AlitaResult result = XfSparkProvider.httpChat(req); + Assert.isTrue(result.getSuccess(), result.getMsg()); + return result.getData(); + } + + /** + * 生成工作经历 + * @return + */ + public static String generateWorkExperience(String content) { + ChatReq req = ChatReq.builder() + .message(MessageDTO.builder().role("system") + .content("你是一位专业的简历撰写专家。目标任务:请根据我给出的信息,生成一份履历丰富的简历。") + .build()) + .message(MessageDTO.builder().role("system") + .content("简历内容包含个人信息简介、工作经历、教育背景、掌握技能、自我评价。以JSON格式返回,每个点作为一个对象。") + .build()) + .message(MessageDTO.builder().role("system") + .content("个人信息输出格式为:{姓名:xxx, 年龄:xxx,联系电话:xxx,联系邮箱:xxx}") + .build()) + .message(MessageDTO.builder().role("system") + .content("工作经历以数组的形式返回。输出格式为:[{企业名称:xxx, 岗位:xxx,工作职责:[xxx,xxx,xxx],工作时间:xxx-xxx}]") + .build()) + .message(MessageDTO.builder().role("system") + .content("掌握技能必须作为数组输出") + .build()) + .message(MessageDTO.builder().role("system") + .content("自我评价必须作为数组输出") + .build()) + .message(MessageDTO.builder().role("user").content(content).build()).build(); + AlitaResult result = XfSparkProvider.httpChat(req); + Assert.isTrue(result.getSuccess(), result.getMsg()); + return result.getData(); + } + + /** + * 分析简历 + * @param content + * @return + */ + public static String analyseResume(String content) { + ChatReq req = ChatReq.builder() + .message(MessageDTO.builder().role("system") + .content("你是一位专业的简历分析专家。目标任务:请根据我给出的信息,分析得出简历信息,不要自己填充json信息。") + .build()) + .message(MessageDTO.builder().role("system") + .content("请生成一个包含以下信息的 JSON 数据,根据用户给出的实际信息解析,值都可为空:\n" + + "- name(字符串类型):表示用户的姓名。\n" + + "- sex(字符串类型):表示用户的性别,值为 \"1\"(男)或 \"2\"(女),身份证号倒数第二位,奇数是男,偶数是女。\n" + + "- phone(字符串类型):表示用户的联系电话,可为空,不为空的格式为 以 1 开头,共 11 位数字。\n" + + "- email(字符串类型):表示用户的联系电子邮箱地址,可为空,不为空的格式为 包含 @ 符号,且 @ 前后至少有一个字符 及 域名部分至少包含一个 . 符号。\n" + + "- intentionPosition(字符串类型):表示用户的意向职位。\n" + + "- major(字符串类型):表示用户的专业。\n" + + "- birthday(日期类型):表示用户的出生日期,格式为 YYYY-MM。\n" + + "- jobTime(日期类型):表示用户的参加工作时间,格式为 YYYY-MM。\n" + + "- school(字符串类型):表示用户的毕业院校。\n" + + "- education(字符串类型):表示用户的学历,值为:\n" + + " - \"1\":\"博士\"\n" + + " - \"2\":\"硕士\"\n" + + " - \"3\":\"本科\"\n" + + " - \"4\":\"大专\"\n" + + " - \"5\":\"中专\"\n" + + " - \"6\":\"技校\"\n" + + " - \"7\":\"职高\"\n" + + " - \"9\":\"高中\"\n" + + " - \"10\":\"初中\"\n" + + " - \"11\":\"小学\"\n" + + "- workExperience(字符串类型):表示用户的工作经历,格式为文本,包含以下信息:\n" + + " - 企业名称\n" + + " - 岗位\n" + + " - 工作时间\n" + + " - 工作职责\n" + + "- selfEvaluation(字符串类型):表示用户的自我评价,格式为文本。") + .build()) + .message(MessageDTO.builder().role("system").content("如果用户回答与简历无关,则返回空json,不回答其他无关问题,只返回能解析到的json数据。").build()) + .message(MessageDTO.builder().role("user").content(content).build()).build(); + AlitaResult result = XfSparkProvider.httpChat(req); + Assert.isTrue(result.getSuccess(), result.getMsg()); + return result.getData(); + } + + /** + * 对话 + * @param req + * @return + */ + public static String chat(ChatReq req) { + AlitaResult result = XfSparkProvider.httpChat(req); + Assert.isTrue(result.getSuccess(), result.getMsg()); + return result.getData(); + } + + /** + * 翻译 + * @param req + * @return + */ + public static String translate(TranslateReq req) { + AlitaResult result = XfSparkProvider.translate(req); + Assert.isTrue(result.getSuccess(), result.getMsg()); + return result.getData(); + } + + /** + * 实时语音转写 + * @param reqDTO + * @return + */ + public static String rtasr(RtasrReqDTO reqDTO) { + try (InputStream fileis = fileRecordService.getFile(reqDTO.getFileCode())){ + File file = FileUtils.createTempFile("pcm"); + try (InputStream is = FileUtils.copyToTempFile(fileis, file)) { + AlitaResult result = RtasrClientApp.execute(is, reqDTO.getFrom(), xfProperties); + Assert.isTrue(result.getSuccess(), result.getMsg()); + return result.getData(); + } catch (Exception e) { + throw e; + } finally { + file.delete(); + } + }catch (Exception e) { + throw new BusinessException("语音听写异常:" + e.getMessage()); + } + + } + +} diff --git a/backend/src/main/java/com/senmesh/security/access/intercept/FilterSecurityInterceptor.java b/backend/src/main/java/com/senmesh/security/access/intercept/FilterSecurityInterceptor.java new file mode 100644 index 0000000..2466347 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/access/intercept/FilterSecurityInterceptor.java @@ -0,0 +1,220 @@ +/* + * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package com.senmesh.security.access.intercept; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.security.access.SecurityMetadataSource; +import org.springframework.security.access.intercept.AbstractSecurityInterceptor; +import org.springframework.security.access.intercept.InterceptorStatusToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.FilterInvocation; +import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.util.matcher.RequestMatcher; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.ResponseUtils; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.security.access.request.AuthDtoUtils; +import com.senmesh.security.expection.BadLoginException; +import com.senmesh.security.util.SecurityPropertyUtils; +import com.senmesh.usercenter.user.login.service.UserLoginService; + +import lombok.extern.slf4j.Slf4j; + + +/** + * 菜单安全拦截器 + * + * @author on 2019-11-05 + */ +@Slf4j +public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter { + + // ~ Static fields/initializers + // ===================================================================================== + + private static final String FILTER_APPLIED = + "__spring_security_filterSecurityInterceptor_filterApplied_2"; + + public static final String AUTH_URL = "/sys_security_auth"; + public static final String ERROR_URL = "/error"; + + // ~ Instance fields + // ================================================================================================ + + private FilterInvocationSecurityMetadataSource securityMetadataSource; + private boolean observeOncePerRequest = true; + + // ~ Methods + // ======================================================================================================== + + /** + * Not used (we rely on IoC container lifecycle services instead) + * + * @param arg0 ignored + * + * @throws ServletException never thrown + */ + @Override + public void init(FilterConfig arg0) throws ServletException {} + + /** + * Not used (we rely on IoC container lifecycle services instead) + */ + @Override + public void destroy() {} + + /** + * Method that is actually called by the filter chain. Simply delegates to the + * {@link #invoke(FilterInvocation)} method. + * + * @param request the servlet request + * @param response the servlet response + * @param chain the filter chain + * + * @throws IOException if the filter chain fails + * @throws ServletException if the filter chain fails + */ + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + FilterInvocation fi = new FilterInvocation(request, response, chain); + invoke(fi); + } + + public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() { + return this.securityMetadataSource; + } + + @Override + public SecurityMetadataSource obtainSecurityMetadataSource() { + return this.securityMetadataSource; + } + + public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource newSource) { + this.securityMetadataSource = newSource; + } + + @Override + public Class getSecureObjectClass() { + return FilterInvocation.class; + } + + private RequestMatcher authRequestMatcher = new AntPathRequestMatcher(AUTH_URL, "POST"); + + private UserLoginService userLoginService; + + public void setUserLoginService(UserLoginService userLoginService) { + this.userLoginService = userLoginService; + } + + public void invoke(FilterInvocation fi) throws IOException, ServletException { + if (fi.getRequestUrl().equals(ERROR_URL)) { + log.info("访问资源不存在"); + throw new BadLoginException("访问资源不存在"); + } + // 如果是其他系统,调用用户中心鉴权 + // 如果是用户中心,其他系统鉴权路径, + HttpServletRequest request = fi.getRequest(); + HttpServletResponse response = fi.getResponse(); + // 外部系统调用用户中心鉴权 + boolean authInvoke = authRequestMatcher.matches(request); + if (authInvoke) { + FilterInvocation authFilterInvocation = AuthDtoUtils.analy(request); + try { + userLoginService.checkActive(request); + InterceptorStatusToken token = super.beforeInvocation(authFilterInvocation); + ResponseUtils.printJson(response, AlitaResult.success()); + return; + } catch (BadLoginException be) { + ResponseUtils.printJson(response, be.getResult()); + } catch (Exception e) { + log.error("鉴权失败", e); + ResponseUtils.printJson(response, + AlitaResult.error(AlitaResult.LOGIN_ERROR_CODE, e.getMessage())); + } + return; + } + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + + boolean isAnno = auth.isAuthenticated() && SecurityPropertyUtils.isAnon(request); + boolean isUnac = !isAnno && SecurityPropertyUtils.isUnac(request); + boolean hasLogin = UserContextHolder.getLoginUser() != null; + // 匿名路径 | 未激活路径且已登录 直接过 + boolean isAllowed = + (request != null) && (request.getAttribute(FILTER_APPLIED) != null) && observeOncePerRequest + || isAnno + || (hasLogin && isUnac); + if (isAllowed) { + // filter already applied to this request and user wants us to observe + // once-per-request handling, so don't re-do security checking + fi.getChain().doFilter(request, response); + } else { + // 未登录 去登录 + Assert.isTrue(hasLogin, new BadLoginException(AlitaResult.unLogin())); + // first time this request being called, so perform security checking + if (request != null && observeOncePerRequest) { + request.setAttribute(FILTER_APPLIED, Boolean.TRUE); + } + InterceptorStatusToken token = null; + // 用户中心鉴权 + userLoginService.checkActive(request); + token = super.beforeInvocation(fi); + if (token == null) { + // TODO token 为空,资源未被分配,又不在白名单(只要登录就可访问),默认无权访问 + // throw AccessDeniedException ; + } + try { + fi.getChain().doFilter(request, response); + } finally { + super.finallyInvocation(token); + } + + super.afterInvocation(token, null); + } + } + + /** + * Indicates whether once-per-request handling will be observed. By default this is + * true, meaning the FilterSecurityInterceptor will only execute + * once-per-request. Sometimes users may wish it to execute more than once per request, such as + * when JSP forwards are being used and filter security is desired on each included fragment of + * the HTTP request. + * + * @return true (the default) if once-per-request is honoured, otherwise + * false if FilterSecurityInterceptor will enforce + * authorizations for each and every fragment of the HTTP request. + */ + public boolean isObserveOncePerRequest() { + return observeOncePerRequest; + } + + public void setObserveOncePerRequest(boolean observeOncePerRequest) { + this.observeOncePerRequest = observeOncePerRequest; + } +} diff --git a/backend/src/main/java/com/senmesh/security/access/metadata/ResourceSecurityMetadataSource.java b/backend/src/main/java/com/senmesh/security/access/metadata/ResourceSecurityMetadataSource.java new file mode 100644 index 0000000..cc022d2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/access/metadata/ResourceSecurityMetadataSource.java @@ -0,0 +1,65 @@ +package com.senmesh.security.access.metadata; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; +import org.springframework.security.access.ConfigAttribute; +import org.springframework.stereotype.Component; + +import com.google.common.collect.Maps; +import com.senmesh.security.access.provider.ResourceConfigAttributeProvider; +import com.senmesh.usercenter.authority.dto.PermissionQueryDTO; +import com.senmesh.usercenter.dto.Resource; + +import lombok.RequiredArgsConstructor; + + +/** + * 资源安全元数据源 + * + * @author on 2019-11-05 + */ +@Component +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class ResourceSecurityMetadataSource { + + private final List providers; + + public Collection getAttributes(Object object, + PermissionQueryDTO permissionQueryDTO) throws IllegalArgumentException { + if (!this.supports(object.getClass())) { + return Collections.emptyList(); + } + Long resourceId = ((Resource) object).getId(); + Collection attributes = + getComponentMap(object, permissionQueryDTO).get(resourceId); + return attributes == null ? Collections.emptyList() : attributes; + } + + public Map> getComponentMap(Object object, + PermissionQueryDTO permissionQueryDTO) { + AnnotationAwareOrderComparator.sort(providers); + Map> componentMap = Maps.newLinkedHashMap(); + providers.forEach(provider -> { + // 选择支持的提供者 + if (!provider.supports(object.getClass())) { + return; + } + Map> map = provider.provide(permissionQueryDTO); + if (map != null && !map.isEmpty()) { + componentMap.putAll(map); + } + + }); + return componentMap; + } + + public boolean supports(Class clazz) { + return Resource.class.isAssignableFrom(clazz); + } + +} diff --git a/backend/src/main/java/com/senmesh/security/access/metadata/UrlFilterInvocationSecurityMetadataSource.java b/backend/src/main/java/com/senmesh/security/access/metadata/UrlFilterInvocationSecurityMetadataSource.java new file mode 100644 index 0000000..d665435 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/access/metadata/UrlFilterInvocationSecurityMetadataSource.java @@ -0,0 +1,76 @@ +package com.senmesh.security.access.metadata; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map.Entry; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; +import org.springframework.security.access.ConfigAttribute; +import org.springframework.security.web.FilterInvocation; +import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.stereotype.Component; + +import com.senmesh.common.util.SpringContextHolder; +import com.senmesh.security.access.provider.FilterConfigAttributeProvider; +import com.senmesh.security.access.request.AuthDtoUtils; + +/** + * 菜单安全元数据源 + * + * @author on 2019-11-05 + */ +@Component +public class UrlFilterInvocationSecurityMetadataSource + implements FilterInvocationSecurityMetadataSource { + + @Autowired + private List providers; + + + @Override + public Collection getAllConfigAttributes() { + /*Set allAttributes = new HashSet(); + + for (Map.Entry> entry : getRequestMap() + .entrySet()) { + allAttributes.addAll(entry.getValue()); + }*/ + return Collections.emptyList(); + } + + @Override + public Collection getAttributes(Object object) { + final HttpServletRequest request = ((FilterInvocation) object).getRequest(); + Integer systemCode = AuthDtoUtils.getSystemCode(SpringContextHolder.getRequest()); + return getAttributes(request, systemCode); + } + + public Collection getAttributes(HttpServletRequest request, Integer systemCode) { + for (FilterConfigAttributeProvider provider : providers) { + for (Entry> entry : provider.provide(systemCode).entrySet()) { + if (new AntPathRequestMatcher("/" + entry.getKey(), null).matches(request)) { + return entry.getValue(); + } + } + } + return Collections.emptyList(); + } + + + @Override + public boolean supports(Class clazz) { + return FilterInvocation.class.isAssignableFrom(clazz); + } + + @Autowired + public void setProvider(List providers) { + AnnotationAwareOrderComparator.sort(providers); + this.providers = providers; + } + +} diff --git a/backend/src/main/java/com/senmesh/security/access/provider/FilterConfigAttributeProvider.java b/backend/src/main/java/com/senmesh/security/access/provider/FilterConfigAttributeProvider.java new file mode 100644 index 0000000..8b03915 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/access/provider/FilterConfigAttributeProvider.java @@ -0,0 +1,21 @@ +package com.senmesh.security.access.provider; + +import java.util.Collection; +import java.util.Map; +import org.springframework.security.access.ConfigAttribute; + +/** + * 访问菜单权限信息提供者 + * 资源被谁配置列表(可扩展configAttribute,可以有role_(目前),resource_等) + * + * @author on 2019-11-05 + */ +public interface FilterConfigAttributeProvider { + /** + * 提供菜单权限信息,以Map结构返回,Key为路径,
+ * Value为对应的权限信息 + * + * @return 权限信息 + */ + Map> provide(Integer systemCode); +} diff --git a/backend/src/main/java/com/senmesh/security/access/provider/GrantedAuthorityProvider.java b/backend/src/main/java/com/senmesh/security/access/provider/GrantedAuthorityProvider.java new file mode 100644 index 0000000..9fda38d --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/access/provider/GrantedAuthorityProvider.java @@ -0,0 +1,25 @@ +package com.senmesh.security.access.provider; + +import java.util.Collection; + +import org.springframework.security.core.GrantedAuthority; + +import com.senmesh.usercenter.dto.IUserDetail; + +/** + * 授权信息提供者 + * 人被分配角色列表(后面可扩展authority,可以有role_(目前),resource_等) + * + * @author on 2019-11-05 + */ +public interface GrantedAuthorityProvider { + + /** + * 提供授权权限信息 + * + * @param userDetails 用户信息 + * @return 授权信息 + */ + Collection provide(IUserDetail userDetails); + +} diff --git a/backend/src/main/java/com/senmesh/security/access/provider/IConfigAttribute.java b/backend/src/main/java/com/senmesh/security/access/provider/IConfigAttribute.java new file mode 100644 index 0000000..58e77c2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/access/provider/IConfigAttribute.java @@ -0,0 +1,23 @@ +package com.senmesh.security.access.provider; + +import java.io.Serializable; + +import org.springframework.security.access.ConfigAttribute; + +/** + * 资源权限 + * + * @author sr on 2020-09-04 + * @param + */ +public interface IConfigAttribute extends ConfigAttribute { + + /** + * 唯一标识 + * + * @return + * @author sr on 2020-09-04 + */ + K getKey(); + +} diff --git a/backend/src/main/java/com/senmesh/security/access/provider/IUrlConfigAttribute.java b/backend/src/main/java/com/senmesh/security/access/provider/IUrlConfigAttribute.java new file mode 100644 index 0000000..a8e6cbd --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/access/provider/IUrlConfigAttribute.java @@ -0,0 +1,15 @@ +package com.senmesh.security.access.provider; + +import java.io.Serializable; + +/** + * 请求资源权限 + * + * @author sr on 2020-09-07 + * @param + */ +public interface IUrlConfigAttribute extends IConfigAttribute { + + String getUrl(); + +} diff --git a/backend/src/main/java/com/senmesh/security/access/provider/ResourceConfigAttributeProvider.java b/backend/src/main/java/com/senmesh/security/access/provider/ResourceConfigAttributeProvider.java new file mode 100644 index 0000000..e51095b --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/access/provider/ResourceConfigAttributeProvider.java @@ -0,0 +1,54 @@ +package com.senmesh.security.access.provider; + +import java.io.Serializable; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.google.common.collect.Sets; +import com.senmesh.usercenter.authority.dto.PermissionQueryDTO; + +/** + * 资源权限信息提供者 + * + * @author on 2019-11-05 + */ +public interface ResourceConfigAttributeProvider> { + /** + * 提供资源权限信息 + * + * @return 权限信息 + */ + List list(PermissionQueryDTO permissionQueryDTO); + + /** + * 支持类型 + * + * @param clazz + * @return + * @author sr on 2019-11-05 + */ + boolean supports(Class clazz); + + /** + * + * @return + * @author sr on 2020-09-07 + */ + default Map> provide(PermissionQueryDTO permissionQueryDTO) { + return this.list(permissionQueryDTO) + .stream() + .collect( + Collectors.toMap( + IConfigAttribute::getKey, v -> { + Collection values = Sets.newHashSet(); + values.add(v); + return values; + }, + (v1, v2) -> { + v1.addAll(v2); + return v1; + })); + } +} diff --git a/backend/src/main/java/com/senmesh/security/access/provider/impl/ComponentConfigAttributeProvider.java b/backend/src/main/java/com/senmesh/security/access/provider/impl/ComponentConfigAttributeProvider.java new file mode 100644 index 0000000..438fd7a --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/access/provider/impl/ComponentConfigAttributeProvider.java @@ -0,0 +1,42 @@ +package com.senmesh.security.access.provider.impl; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import com.senmesh.security.access.provider.ResourceConfigAttributeProvider; +import com.senmesh.usercenter.authority.dto.ComponentPermissionDTO; +import com.senmesh.usercenter.authority.dto.PermissionQueryDTO; +import com.senmesh.usercenter.authority.service.UcPermissionService; +import com.senmesh.usercenter.constants.SecurityConstants; +import com.senmesh.usercenter.resource.dto.ComponentDTO; + +/** + * 默认组件权限信息提供者 + * + * @author on 2019-11-05 + */ +@Order(100) +@Component +public class ComponentConfigAttributeProvider + implements ResourceConfigAttributeProvider { + + @Autowired + private UcPermissionService ucPermissionService; + + @Override + public boolean supports(Class clazz) { + return ComponentDTO.class.isAssignableFrom(clazz); + } + + @Override + @Cacheable(cacheNames = SecurityConstants.CacheName.COMPONENT_ATTRIBUTE_MAP_CACHE_KEY, + key = SecurityConstants.CACHE_KEY_PERMISSION_ORG_SYSTEM) + public List list(PermissionQueryDTO permissionQueryDTO) { + return ucPermissionService.listComponent(permissionQueryDTO); + } + +} diff --git a/backend/src/main/java/com/senmesh/security/access/provider/impl/UrlConfigAttributeProvider.java b/backend/src/main/java/com/senmesh/security/access/provider/impl/UrlConfigAttributeProvider.java new file mode 100644 index 0000000..b701c5b --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/access/provider/impl/UrlConfigAttributeProvider.java @@ -0,0 +1,42 @@ +package com.senmesh.security.access.provider.impl; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import com.senmesh.security.access.provider.ResourceConfigAttributeProvider; +import com.senmesh.usercenter.authority.dto.PermissionQueryDTO; +import com.senmesh.usercenter.authority.dto.UrlPermissionDTO; +import com.senmesh.usercenter.authority.service.UcPermissionService; +import com.senmesh.usercenter.constants.SecurityConstants; +import com.senmesh.usercenter.resource.dto.UrlDTO; + +/** + * 默认菜单权限信息提供者 + * + * @author on 2019-11-05 + */ +@Component +@Order(100) +public class UrlConfigAttributeProvider + implements ResourceConfigAttributeProvider { + + @Autowired + private UcPermissionService ucPermissionService; + + @Override + public boolean supports(Class clazz) { + return UrlDTO.class.isAssignableFrom(clazz); + } + + @Override + @Cacheable(cacheNames = SecurityConstants.CacheName.URL_ATTRIBUTE_MAP_CACHE_KEY, + key = SecurityConstants.CACHE_KEY_PERMISSION_ORG_SYSTEM) + public List list(PermissionQueryDTO permissionQueryDTO) { + return ucPermissionService.listUrl(permissionQueryDTO).getData(); + } + +} diff --git a/backend/src/main/java/com/senmesh/security/access/provider/impl/UrlFilterConfigAttribueProvider.java b/backend/src/main/java/com/senmesh/security/access/provider/impl/UrlFilterConfigAttribueProvider.java new file mode 100644 index 0000000..96b35aa --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/access/provider/impl/UrlFilterConfigAttribueProvider.java @@ -0,0 +1,62 @@ +package com.senmesh.security.access.provider.impl; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.core.annotation.Order; +import org.springframework.security.access.ConfigAttribute; +import org.springframework.stereotype.Component; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.security.access.provider.FilterConfigAttributeProvider; +import com.senmesh.security.service.IPermissionSecurityService; +import com.senmesh.usercenter.authority.dto.PermissionQueryDTO; +import com.senmesh.usercenter.authority.dto.UrlPermissionDTO; +import com.senmesh.usercenter.constants.SecurityConstants; +import com.senmesh.usercenter.resource.enums.UrlTypeEnum; + +/** + * 默认菜单权限信息提供者 + * + * @author on 2019-11-05 + */ +@Component +@Order(100) +public class UrlFilterConfigAttribueProvider implements FilterConfigAttributeProvider { + + @Autowired + private IPermissionSecurityService iPermissionSecurityService; + + @Override + @Cacheable(cacheNames = SecurityConstants.CacheName.URL_FILTER_ATTRIBUTE_MAP_CACHE_KEY, + key = SecurityConstants.CACHE_KEY_SYSTEM) + public Map> provide( + Integer systemCode) { + // 应用下所有授权信息 + PermissionQueryDTO permissionQueryDTO = + PermissionQueryDTO.builder().systemCode(systemCode).build(); + AlitaResult> result = + iPermissionSecurityService.listUrl(permissionQueryDTO); + Assert.isTrue(result.getSuccess(), "资源权限获取失败"); + Map> map = result.getData().stream().filter(p -> StringUtils.isNotBlank(p.getLink()) + && UrlTypeEnum.INTERFACE.getType().toString().equals(p.getResourceType())) + .collect(Collectors.toMap(UrlPermissionDTO::getLink, v -> { + Collection values = new HashSet(); + values.add(v); + return values; + }, (v1, v2) -> { + v1.addAll(v2); + return v1; + })); + return map; + } + +} diff --git a/backend/src/main/java/com/senmesh/security/access/provider/impl/UserGrantedAuthorityProvider.java b/backend/src/main/java/com/senmesh/security/access/provider/impl/UserGrantedAuthorityProvider.java new file mode 100644 index 0000000..118d298 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/access/provider/impl/UserGrantedAuthorityProvider.java @@ -0,0 +1,40 @@ +package com.senmesh.security.access.provider.impl; + +import java.util.Collection; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.stereotype.Component; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.security.access.provider.GrantedAuthorityProvider; +import com.senmesh.security.service.IRoleAllocationSecurityService; +import com.senmesh.usercenter.authority.dto.RoleAllocationDTO; +import com.senmesh.usercenter.constants.SecurityConstants; +import com.senmesh.usercenter.dto.IUserDetail; + +/** + * 默认用户授权信息提供者 + * + * @author on 2019-11-05 + */ +@Component +public class UserGrantedAuthorityProvider implements GrantedAuthorityProvider { + + @Autowired + private IRoleAllocationSecurityService iRoleAllocationSecurityService; + + @Override + @Cacheable(cacheNames = SecurityConstants.CacheName.USER_GRANTED_AUTHORITY_CACHE_KEY, + key = SecurityConstants.CACHE_KEY_ORG_USER) + public Collection provide(IUserDetail userDetails) { + AlitaResult> result = + iRoleAllocationSecurityService.findByUserId(userDetails.getId()); + Assert.isTrue(result.getSuccess(), "用户权限获取失败"); + return result.getData(); + } + +} diff --git a/backend/src/main/java/com/senmesh/security/access/request/AuthDTO.java b/backend/src/main/java/com/senmesh/security/access/request/AuthDTO.java new file mode 100644 index 0000000..d4cb992 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/access/request/AuthDTO.java @@ -0,0 +1,28 @@ +package com.senmesh.security.access.request; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-09-09 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = -6816336716189522975L; + + private String url; + + private String method; + + private Integer systemCode; + +} diff --git a/backend/src/main/java/com/senmesh/security/access/request/AuthDtoUtils.java b/backend/src/main/java/com/senmesh/security/access/request/AuthDtoUtils.java new file mode 100644 index 0000000..a3ae239 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/access/request/AuthDtoUtils.java @@ -0,0 +1,58 @@ +package com.senmesh.security.access.request; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.security.web.FilterInvocation; + +import com.senmesh.common.util.EnvironmentUtils; + +/** + * @author sr on 2020-09-10 + */ +public abstract class AuthDtoUtils { + + public static final String PARAM_URL = "url"; + public static final String PARAM_METHOD = "method"; + public static final String PARAM_SYSTEMCODE = "systemCode"; + + /** + * 转换request为认证对象 + * + * @param request + * @return + * @author sr on 2020-09-10 + */ + public static AuthDTO convert(HttpServletRequest request) { + return AuthDTO.builder().url(request.getServletPath()).method(request.getMethod()) + .systemCode(EnvironmentUtils.getSystemCode()).build(); + } + + /** + * 根据请求对象解析成拦截器调用对象 + * + * @param request + * @return + * @author sr on 2020-09-10 + */ + public static FilterInvocation analy(HttpServletRequest request) { + return new FilterInvocation(request.getParameter(PARAM_URL), + request.getParameter(PARAM_METHOD)); + } + + + /** + * 获取请求的应用标识 + * + * @param request + * @return + * @author sr on 2020-09-10 + */ + public static Integer getSystemCode(HttpServletRequest request) { + String systemCodeStr = null; + if (request == null || (systemCodeStr = request.getParameter(PARAM_SYSTEMCODE)) == null) { + return EnvironmentUtils.getSystemCode(); + } + return Integer.valueOf(systemCodeStr); + } + +} diff --git a/backend/src/main/java/com/senmesh/security/access/vote/AccessDecisionManagerImpl.java b/backend/src/main/java/com/senmesh/security/access/vote/AccessDecisionManagerImpl.java new file mode 100644 index 0000000..b82e47b --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/access/vote/AccessDecisionManagerImpl.java @@ -0,0 +1,76 @@ +package com.senmesh.security.access.vote; + +import java.util.Collection; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.AccessDecisionVoter; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.access.ConfigAttribute; +import org.springframework.security.access.vote.AbstractAccessDecisionManager; +import org.springframework.security.authentication.InsufficientAuthenticationException; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Component; + +import com.senmesh.security.config.SecurityProperties; +import com.senmesh.security.dto.SecurityUserDTO; + +/** + * 默认访问决策管理器 + * + * @author on 2019-11-05 + */ +@Component +public class AccessDecisionManagerImpl extends AbstractAccessDecisionManager { + + private List> decisionVoters; + + @Autowired + public AccessDecisionManagerImpl(List> decisionVoters, SecurityProperties securityProperties) { + super(decisionVoters); + this.decisionVoters = decisionVoters; + this.setAllowIfAllAbstainDecisions(securityProperties.getAllowIfAllAbstainDecisions()); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public void decide(Authentication authentication, Object object, + Collection configAttributes) + throws AccessDeniedException, InsufficientAuthenticationException { + Object principal = authentication.getPrincipal(); + if (principal instanceof SecurityUserDTO + && ((SecurityUserDTO) principal).getSupeiror()) { + // 平台管理员放行 + return; + } + int deny = 0; + if (!configAttributes.isEmpty()) { + for (AccessDecisionVoter voter : getDecisionVoters()) { + if (voter.supports(object.getClass())) { + int result = voter.vote(authentication, object, configAttributes); + if (logger.isDebugEnabled()) { + logger.debug("Voter: " + voter + ", returned: " + result); + } + switch (result) { + case AccessDecisionVoter.ACCESS_GRANTED: + return; + case AccessDecisionVoter.ACCESS_DENIED: + deny++; + break; + default: + break; + } + } + } + } + + if (deny > 0) { + throw new AccessDeniedException( + messages.getMessage("AbstractAccessDecisionManager.accessDenied", "Access is denied")); + } + + checkAllowIfAllAbstainDecisions(); + + } + +} diff --git a/backend/src/main/java/com/senmesh/security/access/vote/ResourceRoleVoter.java b/backend/src/main/java/com/senmesh/security/access/vote/ResourceRoleVoter.java new file mode 100644 index 0000000..5b896a5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/access/vote/ResourceRoleVoter.java @@ -0,0 +1,100 @@ +/* + * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package com.senmesh.security.access.vote; + +import java.util.Collection; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.AccessDecisionVoter; +import org.springframework.security.access.ConfigAttribute; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.web.FilterInvocation; +import org.springframework.stereotype.Component; + +import com.senmesh.security.service.GrantedAuthorityService; +import com.senmesh.usercenter.dto.IUserDetail; +import com.senmesh.usercenter.dto.Resource; + +/** + * 资源角色投票器 重写RoleVoter,获取用户授权信息authorities方式更改 + * + * @author on 2019-11-05 + */ +@Component +public class ResourceRoleVoter implements AccessDecisionVoter { + + @Autowired + private GrantedAuthorityService grantedAuthorityService; + + private String rolePrefix = "ROLE_"; + + + public String getRolePrefix() { + return rolePrefix; + } + + public void setRolePrefix(String rolePrefix) { + this.rolePrefix = rolePrefix; + } + + @Override + public boolean supports(ConfigAttribute attribute) { + if ((attribute.getAttribute() != null) + && attribute.getAttribute().startsWith(getRolePrefix())) { + return true; + } else { + return false; + } + } + + @Override + public boolean supports(Class clazz) { + return FilterInvocation.class.isAssignableFrom(clazz) || Resource.class.isAssignableFrom(clazz); + } + + @Override + public int vote(Authentication authentication, Object object, + Collection attributes) { + if (authentication == null) { + return ACCESS_DENIED; + } + + int result = ACCESS_ABSTAIN; + Collection authorities = extractAuthorities(authentication); + + for (ConfigAttribute attribute : attributes) { + if (this.supports(attribute)) { + result = ACCESS_DENIED; + + for (GrantedAuthority authority : authorities) { + if (attribute.getAttribute().equals(authority.getAuthority())) { + return ACCESS_GRANTED; + } + } + } + } + + return result; + } + + Collection extractAuthorities(Authentication authentication) { + if (authentication.getPrincipal() instanceof IUserDetail) { + IUserDetail userDetails = (IUserDetail) authentication.getPrincipal(); + return grantedAuthorityService.getGrantedAuthorities(userDetails); + } + return authentication.getAuthorities(); + } +} diff --git a/backend/src/main/java/com/senmesh/security/cas/CasAuthenticationToken.java b/backend/src/main/java/com/senmesh/security/cas/CasAuthenticationToken.java new file mode 100644 index 0000000..c6bcbd1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/cas/CasAuthenticationToken.java @@ -0,0 +1,60 @@ +package com.senmesh.security.cas; + +import java.util.Collection; + +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; + +/** + * cas认证信息 + * + * @author sr on 2020-06-04 + */ +public class CasAuthenticationToken extends AbstractAuthenticationToken { + + /** **/ + private static final long serialVersionUID = 4078096826251434490L; + + private final Object principal; + private String credentials; + + public CasAuthenticationToken(Object principal, String credentials) { + super(null); + this.principal = principal; + this.credentials = credentials; + setAuthenticated(false); + } + + public CasAuthenticationToken(Object principal, + Collection authorities) { + super(authorities); + this.principal = principal; + this.credentials = null; + super.setAuthenticated(true); + } + + @Override + public Object getCredentials() { + return this.credentials; + } + + @Override + public Object getPrincipal() { + return this.principal; + } + + @Override + public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { + if (isAuthenticated) { + throw new IllegalArgumentException( + "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); + } + super.setAuthenticated(false); + } + + @Override + public void eraseCredentials() { + super.eraseCredentials(); + credentials = null; + } +} diff --git a/backend/src/main/java/com/senmesh/security/config/SecurityConfiguration.java b/backend/src/main/java/com/senmesh/security/config/SecurityConfiguration.java new file mode 100644 index 0000000..2a94d21 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/config/SecurityConfiguration.java @@ -0,0 +1,88 @@ +package com.senmesh.security.config; + +import com.senmesh.security.ucard.UcardAuthenticationProvider; +import org.springframework.boot.autoconfigure.AutoConfigurationPackage; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +import com.senmesh.security.handle.MyAuthenctiationFailureHandler; +import com.senmesh.security.mobile.MobileAuthenticationProvider; +import com.senmesh.security.social.service.StandardClientRegistrationRepository; +import com.senmesh.security.social.wechat.service.WechatOauthLoginProvider; +import com.senmesh.security.temptoken.TokenAuthenticationProvider; +import com.senmesh.security.upassword.UpasswordAuthenticationProvider; +import com.senmesh.security.util.SecurityPropertyUtils; +import com.senmesh.usercenter.constants.SecurityConstants; +import com.senmesh.usercenter.user.login.service.UserLoginService; + +/** + * security配置类 + * + * @author on 2019-11-05 + */ +@Configuration +@AutoConfigurationPackage +public class SecurityConfiguration { + + private SecurityProperties securityProperties; + + SecurityConfiguration(SecurityProperties securityProperties){ + this.securityProperties = securityProperties; + SecurityPropertyUtils.setSecurityProperties(securityProperties); + } + + /** + * 声明密码加密方式 + */ + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + MyAuthenctiationFailureHandler myAuthenctiationFailureHandler() { + return new MyAuthenctiationFailureHandler(securityProperties.getLoginPage()); + } + + @Bean + @ConditionalOnProperty(name = SecurityConstants.PROP_KEY_SECURITY_OAUTH2_USEDB, havingValue = "true", + matchIfMissing = false) + StandardClientRegistrationRepository standardClientRegistrationRepository(UserLoginService userLoginService) { + return new StandardClientRegistrationRepository(userLoginService); + } + + @Bean + @ConditionalOnBean(UserLoginService.class) + MobileAuthenticationProvider mobileAuthenticationProvider(UserLoginService userLoginService) { + return new MobileAuthenticationProvider(userLoginService); + } + + @Bean + @ConditionalOnBean(UserLoginService.class) + WechatOauthLoginProvider wechatOauthLoginProvider(UserLoginService userLoginService) { + return new WechatOauthLoginProvider(userLoginService); + } + + @Bean + @ConditionalOnBean(UserLoginService.class) + TokenAuthenticationProvider tokenAuthenticationProvider(UserLoginService userLoginService) { + return new TokenAuthenticationProvider(userLoginService); + } + + @Bean + @ConditionalOnBean(UserLoginService.class) + UpasswordAuthenticationProvider upasswordAuthenticationProvider(UserLoginService userLoginService) { + return new UpasswordAuthenticationProvider(userLoginService); + } + + @Bean + @ConditionalOnBean(UserLoginService.class) + UcardAuthenticationProvider ucardAuthenticationProvider(UserLoginService userLoginService) { + return new UcardAuthenticationProvider(userLoginService); + } + +} diff --git a/backend/src/main/java/com/senmesh/security/config/SecurityProperties.java b/backend/src/main/java/com/senmesh/security/config/SecurityProperties.java new file mode 100644 index 0000000..a9f8aee --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/config/SecurityProperties.java @@ -0,0 +1,76 @@ +package com.senmesh.security.config; + +import com.senmesh.security.jwt.JwtProperties; +import lombok.Data; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 安全相关配置项 + * + * @author guhong + */ +@Component +@Data +@ConfigurationProperties(prefix = SecurityProperties.PREFIX) +public class SecurityProperties { + + /** 配置前缀 **/ + public final static String PREFIX = "security"; + + /** + * 匿名访问的url + */ + private String anonymous; + + /** + * 忽略的资源,直接跳过spring security权限校验,一般是用做静态资源 + */ + private String ignoring; + + /** 登录页面 **/ + private String loginPage; + + private String loginSuccessPage; + /** h5登录成功页 **/ + private String loginH5SuccessPage; + + /** 登录请求路径 **/ + private String loginProcessingUrl; + + private Boolean allowIfAllAbstainDecisions; + + /** 域名 **/ + private String domain; + + private Boolean superiorOnly; + + /** 不记日志路径,contains匹配 **/ + private String notLogs; + + private JwtProperties jwt = new JwtProperties(); + + /** 是否调用本地认证鉴权,默认本地;调用户中心配置false **/ + private Boolean useLocal; + + private Oauth2Properties oauth2 = new Oauth2Properties(); + + public String[] getAnonymousArray() { + return StringUtils.isBlank(anonymous) ? ArrayUtils.EMPTY_STRING_ARRAY : anonymous.split(","); + } + + public String[] getIgnoringArray() { + return StringUtils.isBlank(ignoring) ? ArrayUtils.EMPTY_STRING_ARRAY : ignoring.split(","); + } + + @Data + public class Oauth2Properties{ + /** 是否启用 **/ + private Boolean enable; + /** oauth配置类型:true使用数据库配置,否则配置文件 **/ + private Boolean usedb; + } + +} diff --git a/backend/src/main/java/com/senmesh/security/config/WebSecurityConfigurer.java b/backend/src/main/java/com/senmesh/security/config/WebSecurityConfigurer.java new file mode 100644 index 0000000..a30432b --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/config/WebSecurityConfigurer.java @@ -0,0 +1,263 @@ +package com.senmesh.security.config; + +import com.senmesh.security.ucard.UcardAuthenticationFilter; +import com.senmesh.security.ucard.UcardAuthenticationProvider; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.AccessDecisionManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter; +import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; +import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; +import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.csrf.CookieCsrfTokenRepository; +import org.springframework.stereotype.Component; + +import com.senmesh.security.access.intercept.FilterSecurityInterceptor; +import com.senmesh.security.handle.MyAuthenctiationFailureHandler; +import com.senmesh.security.handle.MyLoginSuccessHandler; +import com.senmesh.security.handle.MyLoginUrlAuthenticationEntryPoint; +import com.senmesh.security.handle.MyLogoutSuccessHandler; +import com.senmesh.security.jwt.JwtAuthenticationTokenFilter; +import com.senmesh.security.mobile.MobileAuthenticationFilter; +import com.senmesh.security.mobile.MobileAuthenticationProvider; +import com.senmesh.security.social.service.StandardAuthorizationCodeTokenResponseClient; +import com.senmesh.security.social.service.StandardOAuth2UserService; +import com.senmesh.security.social.service.StandardOauth2AuthorizationRequestResolver; +import com.senmesh.security.temptoken.TokenAuthenticationFilter; +import com.senmesh.security.temptoken.TokenAuthenticationProvider; +import com.senmesh.security.upassword.UpasswordAuthenticationFilter; +import com.senmesh.security.upassword.UpasswordAuthenticationProvider; +import com.senmesh.swagger.config.SwaggerConfig; +import com.senmesh.usercenter.user.login.service.UserLoginService; +import com.senmesh.usercenter.websocket.util.WebSocketUtils; + +import lombok.extern.slf4j.Slf4j; + +/** + * security配置 + * + * @author on 2019-11-05 + */ +@Slf4j +@Component +public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { + + @Autowired + private SecurityProperties securityProperties; + + @Autowired + private MyLogoutSuccessHandler myLogoutSuccessHandler; + + @Autowired + private MyLoginSuccessHandler myLoginSuccessHandler; + + @Autowired + private MyAuthenctiationFailureHandler myAuthenctiationFailureHandler; + + @Autowired + private FilterInvocationSecurityMetadataSource securityMetadataSource; + + @Autowired + private AccessDecisionManager accessDecisionManager; + + @Autowired(required = false) + private UpasswordAuthenticationProvider upasswordAuthenticationProvider; + + @Autowired(required = false) + private MobileAuthenticationProvider mobileAuthenticationProvider; + + @Autowired(required = false) + private TokenAuthenticationProvider tokenAuthenticationProvider; + + @Autowired(required = false) + private UcardAuthenticationProvider ucardAuthenticationProvider; + + @Autowired(required = false) + private SwaggerConfig swaggerConfig; + + @Autowired(required = false) + private UserLoginService userLoginService; + + @Autowired(required = false) + private ClientRegistrationRepository standardClientRegistrationRepository; + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + // 添加cas认证提供者 + auth.authenticationProvider(upasswordAuthenticationProvider) + .authenticationProvider(mobileAuthenticationProvider) + .authenticationProvider(tokenAuthenticationProvider) + .authenticationProvider(ucardAuthenticationProvider); + ; + } + + @Override + public void configure(WebSecurity web) throws Exception { + String[] ignoringArray = securityProperties.getIgnoringArray(); + // swagger 接口文档,不设置访问权限 + if (swaggerConfig != null && swaggerConfig.isSwaggerEnable() && StringUtils.isNotBlank(SwaggerConfig.ACCESS_PREFIX)) { + ignoringArray = ArrayUtils.addAll(ignoringArray, SwaggerConfig.ACCESS_PREFIX.split(",")); + } + // websocket + if (StringUtils.isNotBlank(WebSocketUtils.getPath())) { + ignoringArray = ArrayUtils.add(ignoringArray, WebSocketUtils.getPath()); + } + // 忽略的资源,直接跳过spring security权限校验 + web.ignoring() + .antMatchers(ignoringArray)/*.antMatchers(securityProperties.getAnonymousArray())*/; + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + log.info("------WebSecurityConfigurer configure"); + http + .logout() + .logoutSuccessHandler(myLogoutSuccessHandler).and() + // 自定义认证失败处理器 + .exceptionHandling().authenticationEntryPoint( + new MyLoginUrlAuthenticationEntryPoint(securityProperties.getLoginPage())) + .and(); + + if (BooleanUtils.isTrue(securityProperties.getOauth2().getEnable())) { + // oauth2 + http.oauth2Login() + .authorizationEndpoint() + .authorizationRequestResolver( + new StandardOauth2AuthorizationRequestResolver( + this.standardClientRegistrationRepository, + OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI)) + .and() + .tokenEndpoint() + .accessTokenResponseClient(new StandardAuthorizationCodeTokenResponseClient()) + .and() + .userInfoEndpoint().userService(new StandardOAuth2UserService()).and() + .failureHandler(myAuthenctiationFailureHandler) + .successHandler(myLoginSuccessHandler).and(); + } + http.addFilterAfter(upasswordAuthenticationFilter(), + UsernamePasswordAuthenticationFilter.class); + http.addFilterAfter(mobileAuthenticationFilter(), UpasswordAuthenticationFilter.class); + http.addFilterAfter(tokenAuthenticationFilter(), UpasswordAuthenticationFilter.class); + http.addFilterAfter(ucardAuthenticationFilter(), UpasswordAuthenticationFilter.class); + + + // 禁用CSRF +// http.csrf().disable(); + http.csrf(c -> c.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).ignoringAntMatchers("/login")) // 登录接口免 CSRF + ; + http.headers().frameOptions().deny(); + http.headers().xssProtection().block(true); + http.headers().contentTypeOptions(); + + // 拦截器 + FilterSecurityInterceptor securityInterceptor = createFilterSecurityInterceptor(); + http.addFilterAfter(securityInterceptor, + org.springframework.security.web.access.intercept.FilterSecurityInterceptor.class); + + http.setSharedObject(FilterSecurityInterceptor.class, securityInterceptor); + + // 启用jwt + if (Boolean.TRUE.equals(securityProperties.getJwt().getEnable())) { + JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter = + createJwtAuthenticationTokenFilter(); + http.addFilterAfter(jwtAuthenticationTokenFilter, + AnonymousAuthenticationFilter.class); + // 禁用session + http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); + } + + } + + private JwtAuthenticationTokenFilter createJwtAuthenticationTokenFilter() { + return new JwtAuthenticationTokenFilter(securityProperties); + } + + /** + * 拦截器 + * + * @return + * @throws Exception + * @author sr on 2019-11-28 + */ + private FilterSecurityInterceptor createFilterSecurityInterceptor() throws Exception { + FilterSecurityInterceptor securityInterceptor = new FilterSecurityInterceptor(); + securityInterceptor.setSecurityMetadataSource(securityMetadataSource); + securityInterceptor.setAccessDecisionManager(accessDecisionManager); + // httpSecurity中shareobject共用的authenticationBuilder + securityInterceptor.setAuthenticationManager(this.authenticationManagerBean()); + securityInterceptor.setUserLoginService(userLoginService); + securityInterceptor.afterPropertiesSet(); + return securityInterceptor; + } + + /** + * 手机号登录请求过滤器 + * + * @param + * @return + * @throws Exception + * @author sr on 2020-06-04 + */ + private MobileAuthenticationFilter mobileAuthenticationFilter() throws Exception { + MobileAuthenticationFilter filter = new MobileAuthenticationFilter(); + addHandler(filter); + return filter; + } + + private void addHandler(AbstractAuthenticationProcessingFilter filter) throws Exception { + filter.setAuthenticationManager(this.authenticationManagerBean()); + filter.setAuthenticationSuccessHandler(myLoginSuccessHandler); + filter.setAuthenticationFailureHandler(myAuthenctiationFailureHandler); + } + + /** + * 账号密码 + * + * @return + * @throws Exception + * @author sr on 2021-06-22 + */ + private UpasswordAuthenticationFilter upasswordAuthenticationFilter() throws Exception { + UpasswordAuthenticationFilter filter = new UpasswordAuthenticationFilter(); + addHandler(filter); + return filter; + } + + /** + * 临时token + * + * @return + * @throws Exception + * @author sr on 2021-06-22 + */ + private TokenAuthenticationFilter tokenAuthenticationFilter() throws Exception { + TokenAuthenticationFilter filter = new TokenAuthenticationFilter(); + addHandler(filter); + return filter; + } + + + + /** + * 身份证登录 + * @return + * @throws Exception + * @author sr on 2024-09-23 + */ + private UcardAuthenticationFilter ucardAuthenticationFilter() throws Exception { + UcardAuthenticationFilter filter = new UcardAuthenticationFilter(); + addHandler(filter); + return filter; + } + + +} diff --git a/backend/src/main/java/com/senmesh/security/decision/manager/SecurityDecisionManager.java b/backend/src/main/java/com/senmesh/security/decision/manager/SecurityDecisionManager.java new file mode 100644 index 0000000..c48e962 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/decision/manager/SecurityDecisionManager.java @@ -0,0 +1,45 @@ +package com.senmesh.security.decision.manager; + +import java.util.Collection; + +import org.springframework.security.access.ConfigAttribute; +import org.springframework.security.core.userdetails.UserDetails; + +import com.senmesh.usercenter.authority.dto.PermissionQueryDTO; +import com.senmesh.usercenter.dto.Resource; + +/** + * 权限决策管理器。
+ * 实现{@link org.springframework.security.access.SecurityMetadataSource}来
+ * 提供自己定义资源的权限信息,就可以实现权限决策判断 + * + * @author on 2019-11-05 + */ +public interface SecurityDecisionManager { + + /** + * 决策给定的资源,当前登录用户是否有权限 + * + * @param resource 资源 + * @return 结果。true为有权限,否则没有 + */ + boolean decide(Resource resource, PermissionQueryDTO permissionQueryDTO); + + /** + * 根据资源获取权限信息 + * + * @param resource 资源 + * @return 权限列表 + */ + Collection findConfigAttributes(Resource resource, PermissionQueryDTO permissionQueryDTO); + + /** + * 决策给定的资源,给定用户是否有权限 + * + * @param userDetails 用户实体 + * @param resource 资源 + * @return 结果。true为有权限,否则没有 + * @author sr on 2019-10-16 + */ + boolean decide(UserDetails userDetails, Resource resource, PermissionQueryDTO permissionQueryDTO); +} diff --git a/backend/src/main/java/com/senmesh/security/decision/manager/impl/SecurityDecisionManagerImpl.java b/backend/src/main/java/com/senmesh/security/decision/manager/impl/SecurityDecisionManagerImpl.java new file mode 100644 index 0000000..2b1a792 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/decision/manager/impl/SecurityDecisionManagerImpl.java @@ -0,0 +1,86 @@ +package com.senmesh.security.decision.manager.impl; + +import java.util.Collection; +import java.util.Collections; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.AccessDecisionManager; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.access.ConfigAttribute; +import org.springframework.security.authentication.InsufficientAuthenticationException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import com.senmesh.security.access.metadata.ResourceSecurityMetadataSource; +import com.senmesh.security.decision.manager.SecurityDecisionManager; +import com.senmesh.usercenter.authority.dto.PermissionQueryDTO; +import com.senmesh.usercenter.dto.Resource; + +/** + * 权限决策管理器 + * + * @author on 2019-11-05 + */ +@Service +public class SecurityDecisionManagerImpl implements SecurityDecisionManager { + + @Autowired + private ResourceSecurityMetadataSource resourceSecurityMetadataSource; + + @Autowired + private AccessDecisionManager accessDecisionManager; + + @Override + public boolean decide(Resource resource, PermissionQueryDTO permissionQueryDTO) { + return decide(SecurityContextHolder.getContext().getAuthentication(), resource, permissionQueryDTO); + } + + + @Override + public boolean decide(UserDetails userDetails, Resource resource, + PermissionQueryDTO permissionQueryDTO) { + return decide(getAuthentication(userDetails), resource, permissionQueryDTO); + } + + private boolean decide(Authentication authentication, Resource resource, + PermissionQueryDTO permissionQueryDTO) { + try { + Collection attributes = findConfigAttributes(resource, permissionQueryDTO); + accessDecisionManager.decide(authentication, resource, attributes); + return true; + } catch (AccessDeniedException e) { + return false; + } catch (InsufficientAuthenticationException e) { + return false; + } + } + + /** + * 获取用户认证信息 + * + * @return + * @author sr on 2019-10-16 + */ + protected Authentication getAuthentication(UserDetails userDetails) { + return userDetails != null ? new UsernamePasswordAuthenticationToken(userDetails, null) + : SecurityContextHolder.getContext().getAuthentication(); + } + + @Override + public Collection findConfigAttributes(Resource resource, + PermissionQueryDTO permissionQueryDTO) { + Collection attributes = resource.getAttributes(); + if (CollectionUtils.isEmpty(attributes) + && resourceSecurityMetadataSource.supports(resource.getClass())) { + return resourceSecurityMetadataSource.getAttributes(resource, permissionQueryDTO); + } + return Collections.emptyList(); + } + + + +} diff --git a/backend/src/main/java/com/senmesh/security/dto/RoleDTO.java b/backend/src/main/java/com/senmesh/security/dto/RoleDTO.java new file mode 100644 index 0000000..c06b3c9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/dto/RoleDTO.java @@ -0,0 +1,62 @@ +package com.senmesh.security.dto; + +import java.io.Serializable; +import java.util.Date; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 角色 + * + * @author sr on 2019-11-05 + */ +@ApiModel("角色") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RoleDTO implements Serializable { + + /** **/ + private static final long serialVersionUID = -1148469623294607563L; + + @ApiModelProperty("角色id") + @NotNull(message = "角色id不能为空", groups = {Update.class}) + private Long id; + + @ApiModelProperty("名称") + @NotBlank(message = "角色名称不能为空", groups = {Create.class}) + @Size(max = 128) + private String name; + + /** 类型 **/ + @JsonIgnore + private String type; + + @ApiModelProperty("是否启用") + private Boolean enabled; + + @ApiModelProperty("描述") + @Size(max = 64, groups = {Create.class, Update.class}) + private String description; + + @ApiModelProperty("标准角色类型:见role_standard_type") + private String standardType; + + @ApiModelProperty("创建时间") + private Date createTime; + +} diff --git a/backend/src/main/java/com/senmesh/security/dto/SecurityUserDTO.java b/backend/src/main/java/com/senmesh/security/dto/SecurityUserDTO.java new file mode 100644 index 0000000..fd2381d --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/dto/SecurityUserDTO.java @@ -0,0 +1,102 @@ +package com.senmesh.security.dto; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.oauth2.core.user.OAuth2User; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.google.common.collect.Sets; +import com.senmesh.usercenter.dto.IUserDetail; +import com.senmesh.usercenter.user.login.dto.UserDetailDTO; + +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +/** + * userDetails + * + * @author sr on 2020-06-10 + */ +@NoArgsConstructor +@AllArgsConstructor +@Setter +@ToString +public class SecurityUserDTO extends UserDetailDTO implements Serializable, IUserDetail, UserDetails, OAuth2User { + + /** **/ + private static final long serialVersionUID = -4158044873830314665L; + + /** 标签 **/ + private String tag; + + @JsonIgnore + private Collection authorities; + + + @Override + public String getTag() { + return tag; + } + + @JsonIgnore + public Boolean getAccountNonExpired() { + return super.getAccountNonExpired(); + } + + @JsonIgnore + public Boolean getAccountNonLocked() { + return super.getAccountNonLocked(); + } + + @JsonIgnore + public Boolean getCredentialsNonExpired() { + return super.getCredentialsNonExpired(); + } + + @Override + @JsonIgnore + public Collection getAuthorities() { + return authorities == null ? Sets.newHashSet() : authorities; + } + + @Override + public boolean isAccountNonExpired() { + return !Boolean.FALSE.equals(getAccountNonExpired()); + } + + @Override + public boolean isAccountNonLocked() { + return !Boolean.FALSE.equals(getAccountNonLocked()); + } + + @Override + public boolean isCredentialsNonExpired() { + return !Boolean.FALSE.equals(getCredentialsNonExpired()); + } + + @Override + public boolean isEnabled() { + return !Boolean.FALSE.equals(getEnabled()); + } + + + @Override + @JsonIgnore + public String getName() { + return getUsername(); + } + + @Override + @JsonIgnore + public Map getAttributes() { + return Collections.emptyMap(); + } + +} diff --git a/backend/src/main/java/com/senmesh/security/dto/UserInfoDTO.java b/backend/src/main/java/com/senmesh/security/dto/UserInfoDTO.java new file mode 100644 index 0000000..409bae3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/dto/UserInfoDTO.java @@ -0,0 +1,95 @@ +package com.senmesh.security.dto; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.security.util.PasswordUtils; +import com.senmesh.usercenter.user.util.UserUtils; +import java.io.Serializable; + +import org.apache.commons.lang3.StringUtils; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Builder.Default; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2019-10-22 + */ +@ApiModel("用户信息") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class UserInfoDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = -684945131805466713L; + + @ApiModelProperty("账号") + private String username; + + @ApiModelProperty("用户类型") + private Integer userType; + + @ApiModelProperty("昵称") + private String nickname; + + @ApiModelProperty("机构id") + private Long orgId; + + @ApiModelProperty("机构名称") + private String orgName; + + @ApiModelProperty("机构类型") + private String orgType; + + @ApiModelProperty("电话") + private String phone; + + @ApiModelProperty("邮箱") + private String email; + + @ApiModelProperty("是否已初始密码") + private Boolean initialedPassword; + + @ApiModelProperty("是否忽略初始密码") + private Boolean ignoreInitPwd; + + @ApiModelProperty("招聘岗位类型") + private String recruitPositionType; + + private String avatar; + + @ApiModelProperty("密码") + @JsonIgnore + private String password; + + @ApiModelProperty("是否初始密码") + @Default + private Boolean originPassword = Boolean.TRUE; + + @ApiModelProperty("是否机构管理员") + private Boolean administrator; + + public void setPassword(String password){ + this.password = password; + // 未配置默认密码(user.default.password)或密码哈希为空时跳过比对, + // 视为非初始密码,避免缺配置导致登录链路抛 rawPassword cannot be null + String defaultPassword = UserUtils.getDefaultOrgUserPassword(); + if (!StringUtils.isNotBlank(defaultPassword) || !StringUtils.isNotBlank(password)) { + this.originPassword = Boolean.FALSE; + return; + } + if (!PasswordUtils.match(defaultPassword, password)) { + this.originPassword = Boolean.FALSE; + } + } + public Boolean getAdministrator(){ + return UserContextHolder.isAdministrator(); + } + +} diff --git a/backend/src/main/java/com/senmesh/security/expection/BadLoginException.java b/backend/src/main/java/com/senmesh/security/expection/BadLoginException.java new file mode 100644 index 0000000..88c4c86 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/expection/BadLoginException.java @@ -0,0 +1,38 @@ +package com.senmesh.security.expection; + +import org.springframework.security.core.AuthenticationException; + +import com.senmesh.common.AlitaResult; + +/** + * 登录信息异常 + * + * @author sr on 2020-06-15 + */ +public class BadLoginException extends AuthenticationException { + + /** **/ + private static final long serialVersionUID = -5461032165020284506L; + + private AlitaResult result; + + public BadLoginException(String msg) { + super(msg); + result = AlitaResult.error(AlitaResult.LOGIN_ERROR_CODE, msg); + } + + public BadLoginException(String msg, Throwable t) { + super(msg, t); + result = AlitaResult.error(AlitaResult.LOGIN_ERROR_CODE, msg); + } + + public BadLoginException(AlitaResult result) { + super(result.getMsg()); + this.result = result; + } + + public AlitaResult getResult(){ + return result; + } + +} diff --git a/backend/src/main/java/com/senmesh/security/expection/DuplicateOrgException.java b/backend/src/main/java/com/senmesh/security/expection/DuplicateOrgException.java new file mode 100644 index 0000000..df03182 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/expection/DuplicateOrgException.java @@ -0,0 +1,31 @@ +package com.senmesh.security.expection; + +import com.senmesh.common.AlitaResult; +import com.senmesh.security.temptoken.dto.DuplUserToken; + +/** + * 多个登录机构异常 + * + * @author sr on 2020-06-15 + */ +public class DuplicateOrgException extends BadLoginException { + + /** **/ + private static final long serialVersionUID = -5461032165020284506L; + + /** 用户信息 **/ + private final DuplUserToken duplUserToken; + + public static final String MSG = "登录用户存在多机构"; + + public DuplicateOrgException(DuplUserToken duplUserToken) { + super(AlitaResult.error(AlitaResult.DUPLICATE_ORG_CODE, MSG, duplUserToken)); + super.getResult().setErrorData(duplUserToken); + this.duplUserToken = duplUserToken; + } + + public DuplUserToken getDuplUserToken() { + return this.duplUserToken; + } + +} diff --git a/backend/src/main/java/com/senmesh/security/expection/DuplicateUserException.java b/backend/src/main/java/com/senmesh/security/expection/DuplicateUserException.java new file mode 100644 index 0000000..0fc7988 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/expection/DuplicateUserException.java @@ -0,0 +1,38 @@ +package com.senmesh.security.expection; + +import java.util.List; + +import com.senmesh.common.AlitaResult; +import com.senmesh.security.temptoken.dto.DuplMobileToken; + +/** + * 多个登录用户异常 + * + * @author sr on 2020-06-15 + */ +public class DuplicateUserException extends BadLoginException { + + /** **/ + private static final long serialVersionUID = -5461032165020284506L; + + /** 用户信息 **/ + private final DuplMobileToken duplMobileToken; + + public static final String MSG = "登录用户存在多用户"; + + public DuplicateUserException(DuplMobileToken duplMobileToken) { + super(AlitaResult.error(AlitaResult.DUPLICATE_USER_CODE, + MSG, duplMobileToken)); + super.getResult().setErrorData(duplMobileToken); + this.duplMobileToken = duplMobileToken; + } + + public DuplMobileToken getDuplMobileToken() { + return this.duplMobileToken; + } + + public List getUsers(){ + return this.duplMobileToken.getUsers(); + } + +} diff --git a/backend/src/main/java/com/senmesh/security/handle/MyAuthenctiationFailureHandler.java b/backend/src/main/java/com/senmesh/security/handle/MyAuthenctiationFailureHandler.java new file mode 100644 index 0000000..0bbbf67 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/handle/MyAuthenctiationFailureHandler.java @@ -0,0 +1,61 @@ +package com.senmesh.security.handle; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.DisabledException; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.RequestUtils; +import com.senmesh.common.util.ResponseUtils; +import com.senmesh.security.expection.BadLoginException; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author guhong + * @date 2019/8/25 + */ +@Slf4j +public class MyAuthenctiationFailureHandler extends SimpleUrlAuthenticationFailureHandler { + + private static final String DIABLE_MSG = "用户被禁用"; + private static final String BAD_CREDENTIALS_MSG = "账号和密码不匹配,请重新登录"; + + + public MyAuthenctiationFailureHandler(String loginFormUrl) { + super(loginFormUrl); + } + + @Override + public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, + AuthenticationException exception) throws IOException, ServletException { + log.debug("登录失败:{}", exception); + if (exception instanceof BadLoginException) { + ResponseUtils.printJson(response, ((BadLoginException) exception).getResult()); + return; + } + if (RequestUtils.isAjaxRequest(request)) { + ResponseUtils.printJson(response, AlitaResult.error(dealExceptionMsg(exception))); + } else { + super.onAuthenticationFailure(request, response, exception); + } + } + + public String dealExceptionMsg(AuthenticationException exception) { + if (exception instanceof DisabledException) { + return DIABLE_MSG; + } + if (exception instanceof BadCredentialsException) { + return BAD_CREDENTIALS_MSG; + } + return exception.getMessage(); + } + +} diff --git a/backend/src/main/java/com/senmesh/security/handle/MyLoginSuccessHandler.java b/backend/src/main/java/com/senmesh/security/handle/MyLoginSuccessHandler.java new file mode 100644 index 0000000..8f38d45 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/handle/MyLoginSuccessHandler.java @@ -0,0 +1,85 @@ +package com.senmesh.security.handle; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; +import org.springframework.stereotype.Component; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.dto.CasTokenDTO; +import com.senmesh.common.util.CookieUtils; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.common.util.RequestUtils; +import com.senmesh.common.util.ResponseUtils; +import com.senmesh.security.config.SecurityProperties; +import com.senmesh.security.dto.SecurityUserDTO; +import com.senmesh.security.jwt.JwtTokenUtils; +import com.senmesh.security.util.SecurityUtils; + +import lombok.extern.slf4j.Slf4j; + +/** + * 登录成功处理器 + * + * @author guhong + * @date 2019/8/19 + */ +@Slf4j +@Component +public class MyLoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler { + + @Autowired + private SecurityProperties securityProperties; + + @Autowired + private JwtTokenUtils jwtTokenUtils; + + @Override + public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, + Authentication authentication) throws ServletException, IOException { + Object principal = authentication.getPrincipal(); + + log.debug("------MyLoginSuccessHandler onAuthenticationSuccess userDTO: {}", + JsonUtils.toJsonString(principal)); + CasTokenDTO caseTokenDTO = null; + if (principal instanceof SecurityUserDTO) { + SecurityUserDTO securityUserDto = (SecurityUserDTO) principal; + caseTokenDTO = CasTokenDTO.builder().register(securityUserDto.getRegister()) + .token(jwtTokenUtils.generateToken(securityUserDto)).build(); + } else if (principal instanceof CasTokenDTO) { + caseTokenDTO = (CasTokenDTO) principal; + } else { + throw new RuntimeException("数据异常"); + } + String token = caseTokenDTO.getToken(); + this.dealCookie(token, request, response); + if (RequestUtils.isAjaxRequest(request) || RequestUtils.isFeignRequest(request)) { + // ajax + ResponseUtils.printJson(response, + AlitaResult.success(CasTokenDTO.builder().token(token).build())); + } else { + String successPage = securityProperties.getLoginSuccessPage(); + response.sendRedirect(successPage); + } + } + + private void dealCookie(String token, HttpServletRequest request, + HttpServletResponse response) { + // 处理cookie + String domainStr = RequestUtils.getRootDomain(request); + String key = CookieUtils.getLoginTokenCookieKey(); + Cookie cookie = CookieUtils.createCookie(key, token, domainStr, + null, jwtTokenUtils.getExpiration().intValue()); + //写入Cookie + response.addCookie(cookie); + + } + +} diff --git a/backend/src/main/java/com/senmesh/security/handle/MyLoginUrlAuthenticationEntryPoint.java b/backend/src/main/java/com/senmesh/security/handle/MyLoginUrlAuthenticationEntryPoint.java new file mode 100644 index 0000000..ba3e87e --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/handle/MyLoginUrlAuthenticationEntryPoint.java @@ -0,0 +1,49 @@ +package com.senmesh.security.handle; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.RequestUtils; +import com.senmesh.common.util.ResponseUtils; +import com.senmesh.security.expection.BadLoginException; + +/** + * 自定义认证失败处理器 + * @author guhong + * @date 2019/8/25 + */ +public class MyLoginUrlAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint { + + /** + * @param loginFormUrl URL where the login page can be found. Should either be relative to the + * web-app context path (include a leading {@code /}) or an absolute URL. + */ + public MyLoginUrlAuthenticationEntryPoint(String loginFormUrl) { + super(loginFormUrl); + } + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, + AuthenticationException authException) throws IOException, ServletException { + // ajax|feign + if (RequestUtils.isAjaxRequest(request) || RequestUtils.isFeignRequest(request)) { + if (authException instanceof BadLoginException) { + ResponseUtils.printJson(response, ((BadLoginException) authException).getResult()); + return; + } + ResponseUtils.printJson(response, + AlitaResult.error(AlitaResult.LOGIN_ERROR_CODE, "鉴权失败:" + authException.getMessage())); + } else { + super.commence(request, response, authException); + } + } + + +} diff --git a/backend/src/main/java/com/senmesh/security/handle/MyLogoutSuccessHandler.java b/backend/src/main/java/com/senmesh/security/handle/MyLogoutSuccessHandler.java new file mode 100644 index 0000000..46d85c1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/handle/MyLogoutSuccessHandler.java @@ -0,0 +1,37 @@ +package com.senmesh.security.handle; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; +import org.springframework.stereotype.Component; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.CookieUtils; +import com.senmesh.common.util.RequestUtils; +import com.senmesh.common.util.ResponseUtils; + +/** + * @author guhong + */ +@Component +public class MyLogoutSuccessHandler implements LogoutSuccessHandler { + + @Override + public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, + Authentication authentication) throws IOException, ServletException { + //清空Cookie + CookieUtils.removeCookie(CookieUtils.getLoginTokenCookieKey(), + RequestUtils.getRootDomain(request), request, response); + // ajax登出 + if (RequestUtils.isAjaxRequest(request)) { + ResponseUtils.printJson(response, AlitaResult.success()); + } else { + response.sendRedirect("/"); + } + } +} diff --git a/backend/src/main/java/com/senmesh/security/jwt/JwtAuthenticationTokenFilter.java b/backend/src/main/java/com/senmesh/security/jwt/JwtAuthenticationTokenFilter.java new file mode 100644 index 0000000..961a2e9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/jwt/JwtAuthenticationTokenFilter.java @@ -0,0 +1,119 @@ +package com.senmesh.security.jwt; + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.filter.GenericFilterBean; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.exception.ChangeTokenException; +import com.senmesh.common.util.CookieUtils; +import com.senmesh.common.util.RequestUtils; +import com.senmesh.common.util.ResponseUtils; +import com.senmesh.common.util.StrUtils; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.security.config.SecurityProperties; +import com.senmesh.security.util.HostContextHolder; +import com.senmesh.security.util.UserDisabledCache; +import com.senmesh.usercenter.constants.OrgConstants; +import com.senmesh.usercenter.dto.IUserDetail; + +import lombok.extern.slf4j.Slf4j; + +/** + * jwt过滤器 解析token,setContext + * + * @author sr on 2019-12-21 + */ +@Slf4j +public class JwtAuthenticationTokenFilter extends GenericFilterBean { + + private SecurityProperties securityProperties; + + public JwtAuthenticationTokenFilter(SecurityProperties securityProperties) { + this.securityProperties = securityProperties; + } + + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, + FilterChain chain) throws ServletException, IOException {} + + @Override + public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) + throws IOException, ServletException { + HttpServletRequest request = (HttpServletRequest) req; + HttpServletResponse response = (HttpServletResponse) res; + IUserDetail userDto = UserContextHolder.getLoginUser(); + String headerToken = request.getHeader(securityProperties.getJwt().getHeader()); + String feignHeader = request.getHeader(RequestUtils.FEIGN_REQUEST_HEADER_KEY); + try { + dealHostHeader(request); + // 未登录,但有token + if (userDto == null) { + if (StrUtils.isNotNull(headerToken)) { + log.debug("analyse header toke:{}", headerToken); + userDto = JwtTokenUtils.getUserLoginDtoFromToken(headerToken); + } + String cookieToken = + CookieUtils.getCookieValue(CookieUtils.getLoginTokenCookieKey(), request.getCookies()); + if (userDto == null && StrUtils.isNotNull(cookieToken)) { + log.debug("analyse cookie toke :{}", cookieToken); + userDto = JwtTokenUtils.getUserLoginDtoFromToken(cookieToken); + } + if (userDto != null) { + // 禁用/注销用户的已发放token立即失效(黑名单命中则不建立登录上下文) + if (UserDisabledCache.isMarked(userDto.getId())) { + log.debug("user is disabled or canceled, token rejected, userId:{}", userDto.getId()); + } else { + SecurityContextHolder.getContext() + .setAuthentication(JwtTokenUtils.getAuthentication(userDto)); + UserContextHolder.setContext(userDto); + } + } + } + + // 登录用户只有平台用户能使用: 已登录 且 平台用户 且 非内部调用 + //&& !StringUtils.equals(OrgConstants.ORG_TYPE_AGENT,userDto.getOrgType()) 开放代理机构登录中台判断条件 + if (!RequestUtils.FEIGN_REQUEST_HEADER_VALUE.equals(feignHeader) + && Boolean.TRUE.equals(securityProperties.getSuperiorOnly()) + && userDto != null + && !OrgConstants.PLATFORM_ORG_ID.equals(userDto.getOrgId())) { + ResponseUtils.printJson(response, AlitaResult.error("该用户不能使用系统")); + return; + } + chain.doFilter(request, response); + + } catch (ChangeTokenException cte) { + ResponseUtils.printJson(response, cte.getResult()); + } catch (Throwable e) { + throw e; + } finally { + // 清理上下文 + UserContextHolder.clearContext(); + HostContextHolder.clearHost(); + log.debug("clear context...."); + } + } + + private static void dealHostHeader(HttpServletRequest request) { + if (HostContextHolder.getHost() != null) { + return; + } + String hostHeader = request.getHeader(RequestUtils.ORIGIN_HOST_HEADER_KEY); + if (StringUtils.isNoneBlank(hostHeader)) { + HostContextHolder.setHost(hostHeader); + log.debug("get request head origin_host:{}", hostHeader); + } else { + HostContextHolder.setHost(RequestUtils.getDomain(request)); + } + } + +} + diff --git a/backend/src/main/java/com/senmesh/security/jwt/JwtProperties.java b/backend/src/main/java/com/senmesh/security/jwt/JwtProperties.java new file mode 100644 index 0000000..4fd1459 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/jwt/JwtProperties.java @@ -0,0 +1,22 @@ +package com.senmesh.security.jwt; + +import lombok.Data; + +/** + * jwt属性 + * @author sr on 2019-12-21 + */ +@Data +public class JwtProperties { + /** 是否启用 **/ + private Boolean enable; + /** 加密密钥 **/ + private String secret; + /** 过期时间(秒) **/ + private Long expiration; + /** token对应request header的key **/ + private String header = "Authorization"; + /** token发行者 **/ + private String iss; + +} diff --git a/backend/src/main/java/com/senmesh/security/jwt/JwtTokenUtils.java b/backend/src/main/java/com/senmesh/security/jwt/JwtTokenUtils.java new file mode 100644 index 0000000..7152e62 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/jwt/JwtTokenUtils.java @@ -0,0 +1,344 @@ +package com.senmesh.security.jwt; + +import java.util.Date; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Component; + +import com.google.common.base.Strings; +import com.google.common.collect.Maps; +import com.senmesh.common.dto.CasTokenDTO; +import com.senmesh.common.exception.ChangeTokenException; +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.security.dto.SecurityUserDTO; +import com.senmesh.security.util.UserLoginUtils; +import com.senmesh.usercenter.constants.SecurityConstants; +import com.senmesh.usercenter.dto.IUserDetail; +import com.senmesh.usercenter.user.constant.UserTypeEnum; +import com.senmesh.usercenter.user.dto.UserDetailQueryDTO; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.MalformedJwtException; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.UnsupportedJwtException; +import lombok.extern.slf4j.Slf4j; + +/** + * @author sr on 2020-06-18 + */ +@Component +@Slf4j +public class JwtTokenUtils { + + /** + * Authorization认证开头是"bearer " + */ + private static final String BEARER = "Bearer "; + + /** 默认过期时间-秒 **/ + private static final Long DEFAULT_EXPIRATION = 3600 * 2L; + + /** 默认密钥 **/ + private static final String DEFAULT_SECRET = "ca0f2602eacd4db79e92c8f1f7ff3d66"; + + /** 登录信息前缀 **/ + private static final String LOGIN_INFO_KEY_PREFIX = "login:info:uid:"; + private static final String TAG_KEY = "tag:"; + private static final String PRINCIPAL = "principal"; + + /** 默认 **/ + private static final int DEFAULT_TAG_LENGTH = 6; + + /** + * 过期时间 + * + * @return + * @author sr on 2020-06-10 + */ + public static Long getExpiration() { + Object time = EnvironmentUtils.getProperty(SecurityConstants.PROP_KEY_JWT_EXPIRATION); + try { + return Long.parseLong((String) time); + } catch (NumberFormatException e) { + return DEFAULT_EXPIRATION; + } + } + + /** + * 密钥 + * + * @return + * @author sr on 2020-06-10 + */ + public static String getSecret() { + String secret = (String) EnvironmentUtils.getProperty(SecurityConstants.PROP_KEY_JWT_SECRET); + return Strings.isNullOrEmpty(secret) ? DEFAULT_SECRET : secret; + } + + + /** + * 从数据声明生成令牌 + * + * @param claims 数据声明 + * @return 令牌 + */ + private static String generateTokenByClaims(Map claims) { + Date expirationDate = + new Date(System.currentTimeMillis() + getExpiration() * 1000); + return Jwts.builder().setClaims(claims).setExpiration(expirationDate) + .signWith(SignatureAlgorithm.HS512, getSecret().getBytes()) + .compact(); + } + + /** + * 从令牌中获取数据声明 + * + * @param token 令牌 + * @return 数据声明 + */ + private static Claims getClaimsFromToken(String token) { + try { + if (token.startsWith(BEARER)) { + token = StringUtils.substring(token, BEARER.length()); + } + return Jwts.parser().setSigningKey(getSecret().getBytes()) + .parseClaimsJws(token).getBody(); + } catch (SecurityException | MalformedJwtException e) { + log.info("Invalid JWT signature."); + log.trace("Invalid JWT signature trace: {}", e); + } catch (ExpiredJwtException e) { + Claims claims = e.getClaims(); + SecurityUserDTO securityUserDTO = JsonUtils.objToClassObj(claims.get(PRINCIPAL), SecurityUserDTO.class); + if (UserTypeEnum.PERSON.getType().equals(securityUserDTO.getType())) { + changeToken(securityUserDTO.getId()); + } + log.info("Expired JWT token."); + log.trace("Expired JWT token trace: {}", e); + } catch (UnsupportedJwtException e) { + log.info("Unsupported JWT token."); + log.trace("Unsupported JWT token trace: {}", e); + } catch (IllegalArgumentException e) { + log.info("JWT token compact of handler are invalid."); + log.trace("JWT token compact of handler are invalid trace: {}", e); + } + return null; + } + + /** + * 根据securityUserDetail登录用户对象生成token + * + * @param securityUserDTO + * @return + * @author sr on 2020-06-19 + */ + public static String generateToken(SecurityUserDTO securityUserDTO) { + try { + if (securityUserDTO == null) { + return null; + } + Map claims = Maps.newHashMap(); + claims.put("created", new Date()); + claims.put(PRINCIPAL, securityUserDTO); + return generateTokenByClaims(claims); + } catch (Exception e) { + log.info("generateToken error : {}", e.getMessage()); + return null; + } + } + + /** + * 根据登录用户生成token + * + * @return + * @author sr on 2020-06-19 + */ + public String generateTokenByUserDetail(IUserDetail userDetail) { + return generateToken((SecurityUserDTO) userDetail); + } + + /** + * 根据当前登录用户生成token + * + * @return + * @author sr on 2020-06-19 + */ + public String generateTokenByCurrentLoginUser() { + return this.generateTokenByUserDetail(UserContextHolder.getLoginUser()); + } + + + /** + * 根据用户id获取用户信息生成token + * + * @param userId + * @return + * @author sr on 2020-06-19 + */ + @Deprecated + public String generateToken(Long userId) { + return generateToken(UserDetailQueryDTO.builder().userId(userId).build()); + } + + /** + * 根据登录关键信息获取登录对象,生成token + * + * @param userDetailQueryDto + * @return + * @author sr on 2020-06-19 + */ + public static String generateToken(UserDetailQueryDTO userDetailQueryDto) { + return generateToken(UserLoginUtils.loadUserToMock(userDetailQueryDto)); + } + + /** + * 替换token(个人) + * @param userId + * @throws ChangeTokenException + * @author sr on 2021-08-10 + */ + public static void changeToken(Long userId) + throws ChangeTokenException { + changeToken(userId, null); + } + + /** + * 替换token(企业) + * @param userDetailQueryDto + * @throws ChangeTokenException + * @author sr on 2021-07-07 + */ + public static void changeToken(Long userId, Long orgId) + throws ChangeTokenException { + String token = generateToken(UserDetailQueryDTO.builder().userId(userId).orgId(orgId).build()); + throw new ChangeTokenException(CasTokenDTO.builder().userId(userId).token(token).build()); + } + + + /** + * 根据token解析登录用户对象信息 + * + * @param token + * @return securityUserDetail + * @author sr on 2020-06-19 + */ + public static SecurityUserDTO getUserLoginDtoFromToken(String token) { + Claims claims = getClaimsFromToken(token); + if (claims == null) { + return null; + } + return JsonUtils.objToClassObj(claims.get(PRINCIPAL), SecurityUserDTO.class); + } + + /** + * 从令牌中获取认证信息 + * + * @param token + * @return + */ + public static Authentication getAuthentication(IUserDetail securityUserDTO) { + try { + if (securityUserDTO == null) { + return null; + } + // TODO 凭证暂为null + Object credentials = null; + return new UsernamePasswordAuthenticationToken(securityUserDTO, + credentials == null ? "N/A" : credentials, null); + } catch (Exception e) { + log.info("getAuthenticationFromToken error : {}", e.getMessage()); + } + return null; + } + + /** + * 获取当前登录用户 + * + * @param auth + * @return + * @author sr on 2020-06-16 + */ + public static IUserDetail getLoginUser(Authentication auth) { + Object principal = auth == null ? null : auth.getPrincipal(); + if (principal != null && principal instanceof IUserDetail) { + try { + return (IUserDetail) principal; + } catch (Exception e) { + log.info("context user not userDetail..."); + return null; + } + } + return null; + } + + /** + * 从令牌中获取账号 + * + * @param token 令牌 + * @return 账号 + */ + public String getUsernameFromToken(String token) { + String username; + try { + Claims claims = getClaimsFromToken(token); + username = claims.getSubject(); + } catch (Exception e) { + username = null; + } + return username; + } + + /** + * 判断令牌是否过期 + * + * @param token 令牌 + * @return 是否过期 + */ + public Boolean isTokenExpired(String token) { + try { + Claims claims = getClaimsFromToken(token); + Date expiration = claims.getExpiration(); + return expiration.before(new Date()); + } catch (Exception e) { + return false; + } + } + + /** + * 刷新令牌 + * + * @param token 原令牌 + * @return 新令牌 + */ + public String refreshToken(String token) { + String refreshedToken; + try { + Claims claims = getClaimsFromToken(token); + claims.put("created", new Date()); + refreshedToken = generateTokenByClaims(claims); + } catch (Exception e) { + refreshedToken = null; + } + return refreshedToken; + } + + + /** + * 获取登录Redis存储的key key=login:uid:${userId} + * + * @param userId 用户ID + * @param tag 唯一标示 + * @return + */ + public String getLoginInfoRedisKey(Long userId, String tag) { + log.info("------getLoginRedisKey userId: {}, tag: {}", userId, tag); + return LOGIN_INFO_KEY_PREFIX + userId + TAG_KEY + tag; + } + +} diff --git a/backend/src/main/java/com/senmesh/security/mapstruct/AuthDetailMapMapper.java b/backend/src/main/java/com/senmesh/security/mapstruct/AuthDetailMapMapper.java new file mode 100644 index 0000000..7fddbf3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/mapstruct/AuthDetailMapMapper.java @@ -0,0 +1,24 @@ +package com.senmesh.security.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.auth.dto.AuthDetailLoginDTO; +import com.senmesh.usercenter.auth.wechat.dto.WechatAuthUserInfoDTO; + +@Mapper +public interface AuthDetailMapMapper{ + + AuthDetailMapMapper INSTANCE = Mappers.getMapper(AuthDetailMapMapper.class); + + @Mappings(value = { + @Mapping(target = "avatar", source = "headimgurl"), + @Mapping(target = "gender", source = "sex"), + @Mapping(target = "uniqueId", source = "unionid"), + }) + AuthDetailLoginDTO toDto(WechatAuthUserInfoDTO wechatDto); + + +} diff --git a/backend/src/main/java/com/senmesh/security/mapstruct/UserMapMapper.java b/backend/src/main/java/com/senmesh/security/mapstruct/UserMapMapper.java new file mode 100644 index 0000000..016bf53 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/mapstruct/UserMapMapper.java @@ -0,0 +1,29 @@ +package com.senmesh.security.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import com.senmesh.security.dto.SecurityUserDTO; +import com.senmesh.usercenter.user.login.dto.UserDetailDTO; + +/** + * @author sr on 2020-06-08 + */ +@Mapper +public interface UserMapMapper { + + UserMapMapper INSTANCE = Mappers.getMapper(UserMapMapper.class); + + /** + * to dto + * + * @param userDto + * @return + * @author sr on 2020-06-08 + */ + @Mapping(target = "tag", expression = "java(com.senmesh.common.util.RandomUtils.getRandomString(6))") + SecurityUserDTO dtoToDto(UserDetailDTO userDto); + + +} diff --git a/backend/src/main/java/com/senmesh/security/mobile/MobileAuthenticationFilter.java b/backend/src/main/java/com/senmesh/security/mobile/MobileAuthenticationFilter.java new file mode 100644 index 0000000..98b5f69 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/mobile/MobileAuthenticationFilter.java @@ -0,0 +1,78 @@ +package com.senmesh.security.mobile; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.authentication.AuthenticationServiceException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.security.expection.BadLoginException; +import com.senmesh.usercenter.constants.SecurityConstants; +import com.senmesh.usercenter.user.login.dto.LoginPhoneDTO; + +/** + * 手机号认证过滤器,指定请求组装token,调起认证 + * + * @author sr on 2020-06-04 + */ +public class MobileAuthenticationFilter extends AbstractAuthenticationProcessingFilter { + + private boolean postOnly = true; + + public static final String REQUEST_METHOD = "POST"; + public static final AntPathRequestMatcher requiresAuthenticationRequestMatcher = + new AntPathRequestMatcher("/login_phone", REQUEST_METHOD); + + public MobileAuthenticationFilter() { + super(requiresAuthenticationRequestMatcher); + } + + @Override + public Authentication attemptAuthentication(HttpServletRequest request, + HttpServletResponse response) throws AuthenticationException, IOException, ServletException { + + if (postOnly && !REQUEST_METHOD.equals(request.getMethod())) { + throw new AuthenticationServiceException( + "Authentication method not supported: " + request.getMethod()); + } + + String userTypeStr = request.getParameter(SecurityConstants.LOGIN_USER_TYPE_KEY); + Assert.isTrue(StringUtils.isNotBlank(userTypeStr), new BadLoginException("用户类型不能为空")); + Integer userType = null; + try { + userType = Integer.valueOf(userTypeStr); + } catch (NumberFormatException e) { + throw new BadLoginException("用户类型错误:" + userTypeStr); + } + + String phone = request.getParameter(SecurityConstants.LOGIN_PHONE_KEY); + String code = request.getParameter(SecurityConstants.LOGIN_CODE_KEY); + String registerCode = request.getParameter(SecurityConstants.LOGIN_REGISTER_CODE_KEY); + String entrypoint = request.getParameter(SecurityConstants.LOGIN_ENTRYPOINT_KEY); + phone = phone == null ? "" : phone.trim(); + code = code == null ? "" : code.trim(); + + AbstractAuthenticationToken authRequest = new MobileAuthenticationToken( + LoginPhoneDTO.builder().phone(phone).code(code).userType(userType) + .registerCode(registerCode).entrypoint(entrypoint).build(), + code); + + // Allow subclasses to set the "details" property + setDetails(request, authRequest); + + return this.getAuthenticationManager().authenticate(authRequest); + } + + protected void setDetails(HttpServletRequest request, AbstractAuthenticationToken authRequest) { + authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); + } +} diff --git a/backend/src/main/java/com/senmesh/security/mobile/MobileAuthenticationProvider.java b/backend/src/main/java/com/senmesh/security/mobile/MobileAuthenticationProvider.java new file mode 100644 index 0000000..e61c511 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/mobile/MobileAuthenticationProvider.java @@ -0,0 +1,65 @@ +package com.senmesh.security.mobile; + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.validation.util.ValidateUtils; +import com.senmesh.security.dto.SecurityUserDTO; +import com.senmesh.security.expection.BadLoginException; +import com.senmesh.security.mapstruct.UserMapMapper; +import com.senmesh.usercenter.user.login.dto.LoginPhoneDTO; +import com.senmesh.usercenter.user.login.dto.UserDetailDTO; +import com.senmesh.usercenter.user.login.service.UserLoginService; + +/** + * 手机号认证provider,比对信息是否匹配 + * + * @author sr on 2020-06-04 + */ +public class MobileAuthenticationProvider implements AuthenticationProvider { + + private UserLoginService userLoginService; + + public MobileAuthenticationProvider(UserLoginService userLoginService) { + this.userLoginService = userLoginService; + } + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + LoginPhoneDTO loginPhoneDTO = (LoginPhoneDTO) authentication.getPrincipal(); + String errMsg = ValidateUtils.validate(loginPhoneDTO); + Assert.isTrue(errMsg == null, new BadLoginException(errMsg)); + SecurityUserDTO loadedUser = null; + try { + UserDetailDTO userDetailDTO = this.userLoginService.loadUser(loginPhoneDTO); + loadedUser = UserMapMapper.INSTANCE.dtoToDto(userDetailDTO); + } catch (BadLoginException be) { + throw be; + } catch (Exception e) { + throw new BadLoginException(e.getMessage(), e); + } + + MobileAuthenticationToken result = + new MobileAuthenticationToken(loadedUser, listUserGrantedAuthorities(loadedUser)); + result.setDetails(authentication.getDetails()); + return result; + } + + @Override + public boolean supports(Class authentication) { + return (MobileAuthenticationToken.class.isAssignableFrom(authentication)); + } + + private Set listUserGrantedAuthorities(UserDetails userDetails) { + // 什么都不用做,访问资源鉴权的时会拿userDetail去缓存获取对应权限 + return new HashSet(); + } + +} diff --git a/backend/src/main/java/com/senmesh/security/mobile/MobileAuthenticationToken.java b/backend/src/main/java/com/senmesh/security/mobile/MobileAuthenticationToken.java new file mode 100644 index 0000000..d7f7b0e --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/mobile/MobileAuthenticationToken.java @@ -0,0 +1,24 @@ +package com.senmesh.security.mobile; + +import java.util.Collection; + +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; + +/** + * 手机号认证信息 + * + * @author sr on 2020-06-04 + */ +public class MobileAuthenticationToken extends UsernamePasswordAuthenticationToken { + + public MobileAuthenticationToken(Object principal, Object credentials) { + super(principal, credentials); + } + + public MobileAuthenticationToken(Object principal, Object credentials, + Collection authorities) { + super(principal, credentials, authorities); + } + +} diff --git a/backend/src/main/java/com/senmesh/security/service/GrantedAuthorityService.java b/backend/src/main/java/com/senmesh/security/service/GrantedAuthorityService.java new file mode 100644 index 0000000..0bd97ca --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/service/GrantedAuthorityService.java @@ -0,0 +1,26 @@ +package com.senmesh.security.service; + +import java.util.Collection; + +import org.springframework.security.core.GrantedAuthority; + +import com.senmesh.usercenter.dto.IUserDetail; + +/** + * 主要提供用户的授权信息的收集功能 + * + * @author on 2019-11-05 + */ +public interface GrantedAuthorityService { + + /** + * 获取用户的授权信息 + * + * @param userDetails 用户信息 + * @return 权限信息 + */ + Collection getGrantedAuthorities(IUserDetail userDetails); + + + +} diff --git a/backend/src/main/java/com/senmesh/security/service/IPermissionSecurityService.java b/backend/src/main/java/com/senmesh/security/service/IPermissionSecurityService.java new file mode 100644 index 0000000..a85743f --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/service/IPermissionSecurityService.java @@ -0,0 +1,22 @@ +package com.senmesh.security.service; + +import java.util.List; + +import org.springframework.web.bind.annotation.GetMapping; + +import com.senmesh.common.AlitaResult; +import com.senmesh.usercenter.authority.dto.PermissionQueryDTO; +import com.senmesh.usercenter.authority.dto.UrlPermissionDTO; + +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2020-09-07 + */ +public interface IPermissionSecurityService { + + @ApiOperation("查询角色权限分配菜单接口") + @GetMapping("/permission/list_url") + AlitaResult> listUrl(PermissionQueryDTO permissionQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/security/service/IResourceSecurityService.java b/backend/src/main/java/com/senmesh/security/service/IResourceSecurityService.java new file mode 100644 index 0000000..05f2b77 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/service/IResourceSecurityService.java @@ -0,0 +1,51 @@ +package com.senmesh.security.service; + +import java.util.List; + +import com.senmesh.usercenter.dto.IUserDetail; +import com.senmesh.usercenter.resource.dto.ComponentDTO; +import com.senmesh.usercenter.resource.dto.UrlDTO; + +/** + * @author sr on 2020-09-08 + */ +public interface IResourceSecurityService { + + /** + * 查询当前登录用户资源树状列表(包含菜单组件) + * @param systemCode + * @return + * @author sr on 2019-10-15 + */ + List listResource(Integer systemCode, IUserDetail iUserDetail); + + /** + * 获取当前登录用户指定角色的资源树状列表(包含菜单组件) + * @param systemCode + * @param roleId + * @return + * @author sr on 2019-10-16 + */ + List listResource(Integer systemCode, IUserDetail iUserDetail, Long roleId); + + /** + * 根据应用+机构获取url资源 + * + * @param systemCode + * @param orgId + * @return + * @author sr on 2020-09-08 + */ + List listUrlDTO(Integer systemCode, Long orgId); + + /** + * 根据应用+机构获取Component资源 + * + * @param systemCode + * @param orgId + * @return + * @author sr on 2020-09-08 + */ + List listComponentDTO(Integer systemCode, Long orgId); + +} diff --git a/backend/src/main/java/com/senmesh/security/service/IRoleAllocationSecurityService.java b/backend/src/main/java/com/senmesh/security/service/IRoleAllocationSecurityService.java new file mode 100644 index 0000000..e00e334 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/service/IRoleAllocationSecurityService.java @@ -0,0 +1,22 @@ +package com.senmesh.security.service; + +import java.util.List; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; + +import com.senmesh.common.AlitaResult; +import com.senmesh.usercenter.authority.dto.RoleAllocationDTO; + +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2020-09-07 + */ +public interface IRoleAllocationSecurityService { + + @ApiOperation("查询用户分配的角色") + @GetMapping("/role/findByUserId/{userId}") + AlitaResult> findByUserId(@PathVariable("userId") Long userId); + +} diff --git a/backend/src/main/java/com/senmesh/security/service/IUserSecurityService.java b/backend/src/main/java/com/senmesh/security/service/IUserSecurityService.java new file mode 100644 index 0000000..ef1bd8c --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/service/IUserSecurityService.java @@ -0,0 +1,20 @@ +package com.senmesh.security.service; + +import org.springframework.web.bind.annotation.PostMapping; + +import com.senmesh.common.AlitaResult; +import com.senmesh.usercenter.user.dto.UserDetailQueryDTO; +import com.senmesh.usercenter.user.login.dto.UserDetailDTO; + +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2020-09-07 + */ +public interface IUserSecurityService { + + @ApiOperation("根据登录信息获取用户信息") + @PostMapping("/anon/user/find_user_detail_dto") + AlitaResult findUserDetailDTOResult(UserDetailQueryDTO userDetailQueryDto); + +} diff --git a/backend/src/main/java/com/senmesh/security/service/impl/GrantedAuthorityServiceImpl.java b/backend/src/main/java/com/senmesh/security/service/impl/GrantedAuthorityServiceImpl.java new file mode 100644 index 0000000..1645671 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/service/impl/GrantedAuthorityServiceImpl.java @@ -0,0 +1,56 @@ +package com.senmesh.security.service.impl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; + +import com.senmesh.security.access.provider.GrantedAuthorityProvider; +import com.senmesh.security.service.GrantedAuthorityService; +import com.senmesh.usercenter.dto.IUserDetail; + +/** + * 主要提供用户的授权信息的收集功能 + * + * @author on 2019-11-05 + */ +@Service +@Transactional(readOnly = true) +public class GrantedAuthorityServiceImpl implements GrantedAuthorityService, InitializingBean { + + @Autowired + private List providers; + + /** + * 获取用户的授权信息 + * + * @param userDetails 用户信息 + * @return 权限信息 + */ + @Override + public Collection getGrantedAuthorities(IUserDetail userDetails) { + Collection grantedAuthorities = new ArrayList(); + for (GrantedAuthorityProvider provider : providers) { + Collection list = provider.provide(userDetails); + if (list != null && !list.isEmpty()) { + grantedAuthorities.addAll(list); + } + } + return grantedAuthorities; + } + + @Override + public void afterPropertiesSet() throws Exception { + Assert.notEmpty(providers, "providers can not be empty"); + AnnotationAwareOrderComparator.sort(providers); + } + + +} diff --git a/backend/src/main/java/com/senmesh/security/social/service/CommonOAuth2Provider.java b/backend/src/main/java/com/senmesh/security/social/service/CommonOAuth2Provider.java new file mode 100644 index 0000000..f434b18 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/social/service/CommonOAuth2Provider.java @@ -0,0 +1,87 @@ +package com.senmesh.security.social.service; + +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.ClientRegistration.Builder; +import org.springframework.security.oauth2.core.AuthorizationGrantType; +import org.springframework.security.oauth2.core.ClientAuthenticationMethod; + +import com.senmesh.usercenter.auth.constant.AuthTypeEnum; + +public enum CommonOAuth2Provider { + + WECHAT { + + @Override + public Builder getBuilder(String registrationId) { + ClientRegistration.Builder builder = getBuilder(registrationId, + ClientAuthenticationMethod.BASIC, DEFAULT_REDIRECT_URL); + builder.scope("snsapi_userinfo"); + builder.authorizationUri("https://open.weixin.qq.com/connect/oauth2/authorize"); + builder.tokenUri("https://api.weixin.qq.com/sns/oauth2/access_token"); + builder.userInfoUri("https://api.weixin.qq.com/sns/userinfo"); + builder.userNameAttributeName("openid"); + builder.clientName(AuthTypeEnum.WECHAT.name()); + builder.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE); + return builder; + } + }, + + + WECHAT_LITE { + + @Override + public Builder getBuilder(String registrationId) { + ClientRegistration.Builder builder = getBuilder(registrationId, + ClientAuthenticationMethod.BASIC, DEFAULT_REDIRECT_URL); + builder.clientName(AuthTypeEnum.WECHAT_LITE.name()); + return builder; + } + }, + + ALIPAY { + + @Override + public Builder getBuilder(String registrationId) { + ClientRegistration.Builder builder = getBuilder(registrationId, + ClientAuthenticationMethod.POST, DEFAULT_REDIRECT_URL); + builder.clientName(AuthTypeEnum.ALIPAY.name()); + return builder; + } + }, + + ALIPAY_LITE { + + @Override + public Builder getBuilder(String registrationId) { + ClientRegistration.Builder builder = getBuilder(registrationId, + ClientAuthenticationMethod.BASIC, DEFAULT_REDIRECT_URL); + builder.clientName(AuthTypeEnum.ALIPAY_LITE.name()); + return builder; + } + }, + + ; + + + private static final String DEFAULT_REDIRECT_URL = + "{baseUrl}/{action}/oauth2/code/{registrationId}"; + + protected final ClientRegistration.Builder getBuilder(String registrationId, + ClientAuthenticationMethod method, String redirectUri) { + ClientRegistration.Builder builder = ClientRegistration.withRegistrationId(registrationId); + builder.clientAuthenticationMethod(method); + builder.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE); + builder.redirectUriTemplate(redirectUri); + return builder; + } + + /** + * Create a new + * {@link org.springframework.security.oauth2.client.registration.ClientRegistration.Builder + * ClientRegistration.Builder} pre-configured with provider defaults. + * @param registrationId the registration-id used with the new builder + * @return a builder instance + */ + public abstract ClientRegistration.Builder getBuilder(String registrationId); + +} diff --git a/backend/src/main/java/com/senmesh/security/social/service/IOauthProvider.java b/backend/src/main/java/com/senmesh/security/social/service/IOauthProvider.java new file mode 100644 index 0000000..2a0e83e --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/social/service/IOauthProvider.java @@ -0,0 +1,66 @@ +package com.senmesh.security.social.service; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.http.RequestEntity; +import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; +import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse; +import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; +import org.springframework.security.oauth2.core.user.OAuth2User; + +public interface IOauthProvider { + + String getName(); + + /** + * 修改默认auth的请求地址 + * + * @param request + * @param authorizationRequest + * @return + * @author sr on 2021-06-28 + */ + default OAuth2AuthorizationRequest decorateRequest(HttpServletRequest request, + OAuth2AuthorizationRequest authorizationRequest) { + return authorizationRequest; + } + + default OAuth2AccessTokenResponse getTokenResponse( + OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) { + return null; + } + + /** + * 获取token转换器(无则OAuth2AuthorizationCodeGrantRequestEntityConverter) + * @return + * @author sr on 2021-06-28 + */ + default Converter> getTokenConvert(){ + return null; + } + + /** + * 获取用户转换器(无则OAuth2UserRequestEntityConverter) + * @return + * @author sr on 2021-06-28 + */ + default Converter> getUserConvert(){ + return null; + } + + + /** + * 处理第三方用户信息,获取登录用户 + * @param userRequest + * @param userJsonStr + * @return + * @author sr on 2021-06-28 + */ + default OAuth2User dealUser(OAuth2UserRequest userRequest, String userJsonStr) { + return null; + } + + +} diff --git a/backend/src/main/java/com/senmesh/security/social/service/OAuth2ClientRegistrationAdapter.java b/backend/src/main/java/com/senmesh/security/social/service/OAuth2ClientRegistrationAdapter.java new file mode 100644 index 0000000..dc101bd --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/social/service/OAuth2ClientRegistrationAdapter.java @@ -0,0 +1,74 @@ +package com.senmesh.security.social.service; + +import java.util.Map; + +import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties; +import org.springframework.boot.context.properties.PropertyMapper; +import org.springframework.boot.convert.ApplicationConversionService; +import org.springframework.core.convert.ConversionException; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.ClientRegistration.Builder; +import org.springframework.security.oauth2.core.AuthorizationGrantType; +import org.springframework.security.oauth2.core.ClientAuthenticationMethod; +import org.springframework.util.StringUtils; + +import com.google.common.collect.Maps; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.usercenter.auth.constant.AuthTypeEnum; +import com.senmesh.usercenter.auth.dto.AuthClientDTO; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class OAuth2ClientRegistrationAdapter { + + private static Map providers = Maps.newConcurrentMap(); + + private OAuth2ClientRegistrationAdapter() {} + + public static ClientRegistration getClientRegistration(String registrationId, + AuthTypeEnum authTypeEnum, + AuthClientDTO authClientDTO) { + Assert.isTrue(authTypeEnum != null, new IllegalArgumentException("非法授权标识")); + OAuth2ClientProperties.Registration registration = + JsonUtils.toObject(authClientDTO.getParamData(), OAuth2ClientProperties.Registration.class); + return getClientRegistration(registrationId, authTypeEnum, registration); + } + + private static ClientRegistration getClientRegistration(String registrationId, + AuthTypeEnum authTypeEnum, + OAuth2ClientProperties.Registration registration) { + Assert.isTrue(authTypeEnum != null, new IllegalArgumentException("非法授权标识")); + Builder builder = getBuilder(authTypeEnum.name()).getBuilder(registrationId); + PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); + map.from(registration::getClientId).to(builder::clientId); + map.from(registration::getClientSecret).to(builder::clientSecret); + map.from(registration::getClientAuthenticationMethod).as(ClientAuthenticationMethod::new) + .to(builder::clientAuthenticationMethod); + map.from(registration::getAuthorizationGrantType).as(AuthorizationGrantType::new) + .to(builder::authorizationGrantType); + map.from(registration::getRedirectUri).to(builder::redirectUriTemplate); + map.from(registration::getScope).as((scope) -> StringUtils.toStringArray(scope)) + .to(builder::scope); + map.from(registration::getClientName).to(builder::clientName); + return builder.build(); + } + + public static CommonOAuth2Provider getBuilder(String authTypeName) { + CommonOAuth2Provider provider = providers.get(authTypeName); + if (provider == null) { + try { + provider = + ApplicationConversionService.getSharedInstance().convert(authTypeName, + CommonOAuth2Provider.class); + providers.put(authTypeName, provider); + } catch (ConversionException ex) { + log.error("授权类型标识错误,未找到对应的oauth2提供者:{}", authTypeName); + throw new IllegalArgumentException("授权类型标识错误,未找到对应的oauth2提供者:" + authTypeName, ex); + } + } + return provider; + } + +} diff --git a/backend/src/main/java/com/senmesh/security/social/service/StandardAuthorizationCodeTokenResponseClient.java b/backend/src/main/java/com/senmesh/security/social/service/StandardAuthorizationCodeTokenResponseClient.java new file mode 100644 index 0000000..ca6b114 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/social/service/StandardAuthorizationCodeTokenResponseClient.java @@ -0,0 +1,103 @@ +package com.senmesh.security.social.service; + + +import java.util.Arrays; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.FormHttpMessageConverter; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient; +import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest; +import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequestEntityConverter; +import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler; +import org.springframework.security.oauth2.core.OAuth2AuthorizationException; +import org.springframework.security.oauth2.core.OAuth2Error; +import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse; +import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +import com.senmesh.security.social.util.Oauth2ProviderUtils; + +/** + * code获取token + * + * @author sr on 2021-01-12 + */ +public class StandardAuthorizationCodeTokenResponseClient + implements OAuth2AccessTokenResponseClient { + public static final String INVALID_TOKEN_RESPONSE_ERROR_CODE = "invalid_token_response"; + public static final RestOperations restOperations; + + private Converter> requestEntityConverter = + new OAuth2AuthorizationCodeGrantRequestEntityConverter(); + + static { + RestTemplate restTemplate = new RestTemplate(Arrays.asList( + new FormHttpMessageConverter(), new OAuth2AccessTokenResponseHttpMessageConverter(), + new StringHttpMessageConverter())); + restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler()); + restOperations = restTemplate; + } + + @Override + public OAuth2AccessTokenResponse getTokenResponse( + OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) { + + Assert.notNull(authorizationCodeGrantRequest, "authorizationCodeGrantRequest cannot be null"); + + // 不同类型不同请求体 + OAuth2AccessTokenResponse tokenResponse = Oauth2ProviderUtils + .getProvider(authorizationCodeGrantRequest.getClientRegistration().getClientName()) + .getTokenResponse(authorizationCodeGrantRequest); + + if (tokenResponse != null) { + return tokenResponse; + } + + RequestEntity request = this.requestEntityConverter.convert(authorizationCodeGrantRequest); + + ResponseEntity response; + try { + response = restOperations.exchange(request, OAuth2AccessTokenResponse.class); + } catch (RestClientException ex) { + OAuth2Error oauth2Error = new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE, + "An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: " + + ex.getMessage(), + null); + throw new OAuth2AuthorizationException(oauth2Error, ex); + } + + tokenResponse = response.getBody(); + + if (CollectionUtils.isEmpty(tokenResponse.getAccessToken().getScopes())) { + // As per spec, in Section 5.1 Successful Access Token Response + // https://tools.ietf.org/html/rfc6749#section-5.1 + // If AccessTokenResponse.scope is empty, then default to the scope + // originally requested by the client in the Token Request + tokenResponse = OAuth2AccessTokenResponse.withResponse(tokenResponse) + .scopes(authorizationCodeGrantRequest.getClientRegistration().getScopes()) + .build(); + } + + return tokenResponse; + } + + /** + * Sets the {@link Converter} used for converting the {@link OAuth2AuthorizationCodeGrantRequest} + * to a {@link RequestEntity} representation of the OAuth 2.0 Access Token Request. + * + * @param requestEntityConverter the {@link Converter} used for converting to a {@link RequestEntity} representation of the Access Token Request + */ + public void setRequestEntityConverter( + Converter> requestEntityConverter) { + Assert.notNull(requestEntityConverter, "requestEntityConverter cannot be null"); + this.requestEntityConverter = requestEntityConverter; + } + +} diff --git a/backend/src/main/java/com/senmesh/security/social/service/StandardClientRegistrationRepository.java b/backend/src/main/java/com/senmesh/security/social/service/StandardClientRegistrationRepository.java new file mode 100644 index 0000000..40082c9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/social/service/StandardClientRegistrationRepository.java @@ -0,0 +1,50 @@ +package com.senmesh.security.social.service; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.usercenter.auth.constant.AuthTypeEnum; +import com.senmesh.usercenter.auth.dto.AuthClientDTO; +import com.senmesh.usercenter.auth.dto.AuthClientQueryDTO; +import com.senmesh.usercenter.user.login.service.UserLoginService; + +public class StandardClientRegistrationRepository implements ClientRegistrationRepository { + + private UserLoginService userLoginService; + + public StandardClientRegistrationRepository(UserLoginService userLoginService) { + this.userLoginService = userLoginService; + } + + @Override + public ClientRegistration findByRegistrationId(String registrationId) { + Assert.isTrue(StringUtils.isNotBlank(registrationId), + new IllegalArgumentException("oauth授权注册标识不能为空")); + AuthClientDTO authClientDTO = userLoginService + .findAuthClientDTO(AuthClientQueryDTO.builder().id(Long.valueOf(registrationId)).build()); + AuthTypeEnum authTypeEnum = AuthTypeEnum.getByCode(authClientDTO.getAuthTypeCode()); + return OAuth2ClientRegistrationAdapter.getClientRegistration(authClientDTO.getId().toString(), + authTypeEnum, authClientDTO); + } + + public ClientRegistration findByRegistrationId(String authTypeName, String domainOrIp) { + AuthTypeEnum authTypeEnum = AuthTypeEnum.valueOf(authTypeName.toUpperCase()); + return this.findByRegistrationId(authTypeEnum, domainOrIp); + } + + public ClientRegistration findByRegistrationId(Integer authTypeCode, String domainOrIp) { + AuthTypeEnum authTypeEnum = AuthTypeEnum.getByCode(authTypeCode); + return this.findByRegistrationId(authTypeEnum, domainOrIp); + } + + private ClientRegistration findByRegistrationId(AuthTypeEnum authTypeEnum, String domainOrIp) { + AuthClientDTO authClientDTO = userLoginService.findAuthClientDTO( + AuthClientQueryDTO.builder().domainOrIp(domainOrIp).authTypeCode(authTypeEnum.getCode()) + .build()); + return OAuth2ClientRegistrationAdapter.getClientRegistration(authClientDTO.getId().toString(), + authTypeEnum, authClientDTO); + } + +} diff --git a/backend/src/main/java/com/senmesh/security/social/service/StandardOAuth2UserService.java b/backend/src/main/java/com/senmesh/security/social/service/StandardOAuth2UserService.java new file mode 100644 index 0000000..d77add0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/social/service/StandardOAuth2UserService.java @@ -0,0 +1,109 @@ +package com.senmesh.security.social.service; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequestEntityConverter; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserService; +import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +import org.springframework.security.oauth2.core.OAuth2AuthorizationException; +import org.springframework.security.oauth2.core.OAuth2Error; +import org.springframework.security.oauth2.core.user.OAuth2User; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +import com.senmesh.security.social.util.Oauth2ProviderUtils; + +public class StandardOAuth2UserService implements OAuth2UserService { + + private static final String MISSING_USER_INFO_URI_ERROR_CODE = "missing_user_info_uri"; + + private static final String MISSING_USER_NAME_ATTRIBUTE_ERROR_CODE = + "missing_user_name_attribute"; + + private static final String INVALID_USER_INFO_RESPONSE_ERROR_CODE = "invalid_user_info_response"; + + private Converter> requestEntityConverter = + new OAuth2UserRequestEntityConverter(); + + private RestOperations restOperations; + + public StandardOAuth2UserService() { + RestTemplate restTemplate = new RestTemplate(); + restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler()); + this.restOperations = restTemplate; + } + + @Override + public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { + Assert.notNull(userRequest, "userRequest cannot be null"); + + if (!StringUtils.hasText( + userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUri())) { + OAuth2Error oauth2Error = new OAuth2Error(MISSING_USER_INFO_URI_ERROR_CODE, + "Missing required UserInfo Uri in UserInfoEndpoint for Client Registration: " + + userRequest.getClientRegistration().getRegistrationId(), + null); + throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString()); + } + + String userNameAttributeName = userRequest.getClientRegistration().getProviderDetails() + .getUserInfoEndpoint().getUserNameAttributeName(); + if (!StringUtils.hasText(userNameAttributeName)) { + OAuth2Error oauth2Error = new OAuth2Error(MISSING_USER_NAME_ATTRIBUTE_ERROR_CODE, + "Missing required \"user name\" attribute name in UserInfoEndpoint for Client Registration: " + + userRequest.getClientRegistration().getRegistrationId(), + null); + throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString()); + } + + IOauthProvider provider = Oauth2ProviderUtils + .getProvider(userRequest.getClientRegistration().getClientName()); + // 不同类型不同请求体 + Converter> converter = + provider.getUserConvert(); + if (converter == null) { + converter = requestEntityConverter; + } + + // 获得request + RequestEntity request = converter.convert(userRequest); + + ResponseEntity response; + try { + // 执行request + response = this.restOperations.exchange(request, String.class); + } catch (OAuth2AuthorizationException ex) { + OAuth2Error oauth2Error = ex.getError(); + StringBuilder errorDetails = new StringBuilder(); + errorDetails.append("Error details: ["); + errorDetails.append("UserInfo Uri: ").append( + userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUri()); + errorDetails.append(", Error Code: ").append(oauth2Error.getErrorCode()); + if (oauth2Error.getDescription() != null) { + errorDetails.append(", Error Description: ").append(oauth2Error.getDescription()); + } + errorDetails.append("]"); + oauth2Error = new OAuth2Error(INVALID_USER_INFO_RESPONSE_ERROR_CODE, + "An error occurred while attempting to retrieve the UserInfo Resource: " + + errorDetails.toString(), + null); + throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString(), ex); + } catch (RestClientException ex) { + OAuth2Error oauth2Error = new OAuth2Error(INVALID_USER_INFO_RESPONSE_ERROR_CODE, + "An error occurred while attempting to retrieve the UserInfo Resource: " + + ex.getMessage(), + null); + throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString(), ex); + } + + // 解析response + String userAttributes = response.getBody(); + return provider.dealUser(userRequest, userAttributes); + } +} diff --git a/backend/src/main/java/com/senmesh/security/social/service/StandardOauth2AuthorizationRequestResolver.java b/backend/src/main/java/com/senmesh/security/social/service/StandardOauth2AuthorizationRequestResolver.java new file mode 100644 index 0000000..79e394a --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/social/service/StandardOauth2AuthorizationRequestResolver.java @@ -0,0 +1,188 @@ +package com.senmesh.security.social.service; + +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.security.crypto.keygen.Base64StringKeyGenerator; +import org.springframework.security.crypto.keygen.StringKeyGenerator; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter; +import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver; +import org.springframework.security.oauth2.core.AuthorizationGrantType; +import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; +import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; +import org.springframework.security.web.util.UrlUtils; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.util.Assert; +import org.springframework.web.util.UriComponentsBuilder; + +import com.senmesh.common.util.RequestUtils; +import com.senmesh.security.social.util.Oauth2ProviderUtils; +import com.senmesh.usercenter.constants.SecurityConstants; +import com.senmesh.usercenter.user.constant.UserTypeEnum; + +/** +* An implementation of an {@link OAuth2AuthorizationRequestResolver} that attempts to +* resolve an {@link OAuth2AuthorizationRequest} from the provided {@code HttpServletRequest} +* using the default request {@code URI} pattern {@code /oauth2/authorization/{registrationId}}. +* +*

+* NOTE: The default base {@code URI} {@code /oauth2/authorization} may be overridden +* via it's constructor {@link #DefaultOAuth2AuthorizationRequestResolver(ClientRegistrationRepository, String)}. +* +* @author Joe Grandja +* @author Rob Winch +* @since 5.1 +* @see OAuth2AuthorizationRequestResolver +* @see OAuth2AuthorizationRequestRedirectFilter +*/ +public final class StandardOauth2AuthorizationRequestResolver + implements OAuth2AuthorizationRequestResolver { + private static final String REGISTRATION_ID_URI_VARIABLE_NAME = "registrationId"; + private final ClientRegistrationRepository clientRegistrationRepository; + private final AntPathRequestMatcher authorizationRequestMatcher; + private final StringKeyGenerator stateGenerator = + new Base64StringKeyGenerator(Base64.getUrlEncoder()); + + /** + * Constructs a {@code DefaultOAuth2AuthorizationRequestResolver} using the provided parameters. + * + * @param clientRegistrationRepository the repository of client registrations + * @param authorizationRequestBaseUri the base {@code URI} used for resolving authorization requests + */ + public StandardOauth2AuthorizationRequestResolver( +// StandardClientRegistrationRepository standardClientRegistrationRepository, + ClientRegistrationRepository standardClientRegistrationRepository, + String authorizationRequestBaseUri) { + Assert.notNull(standardClientRegistrationRepository, + "clientRegistrationRepository cannot be null"); + Assert.hasText(authorizationRequestBaseUri, "authorizationRequestBaseUri cannot be empty"); + this.clientRegistrationRepository = standardClientRegistrationRepository; + this.authorizationRequestMatcher = new AntPathRequestMatcher( + authorizationRequestBaseUri + "/{" + REGISTRATION_ID_URI_VARIABLE_NAME + "}"); + } + + @Override + public OAuth2AuthorizationRequest resolve(HttpServletRequest request) { + String registrationId = this.resolveRegistrationId(request); + String redirectUriAction = getAction(request, "login"); + return resolve(request, registrationId, redirectUriAction); + } + + @Override + public OAuth2AuthorizationRequest resolve(HttpServletRequest request, String registrationId) { + if (registrationId == null) { + return null; + } + String redirectUriAction = getAction(request, "authorize"); + return resolve(request, registrationId, redirectUriAction); + } + + private String getAction(HttpServletRequest request, String defaultAction) { + String action = request.getParameter("action"); + if (action == null) { + return defaultAction; + } + return action; + } + + private OAuth2AuthorizationRequest resolve(HttpServletRequest request, String registrationId, + String redirectUriAction) { + if (registrationId == null) { + return null; + } + String domainOrIp = RequestUtils.getDomain(request); + ClientRegistration clientRegistration = null; + if (clientRegistrationRepository instanceof StandardClientRegistrationRepository) { + clientRegistration = + ((StandardClientRegistrationRepository) this.clientRegistrationRepository) + .findByRegistrationId(registrationId, domainOrIp); + } else { + clientRegistration = this.clientRegistrationRepository.findByRegistrationId(registrationId); + } + + if (clientRegistration == null) { + throw new IllegalArgumentException("Invalid Client Registration with Id: " + registrationId); + } + + OAuth2AuthorizationRequest.Builder builder; + if (AuthorizationGrantType.AUTHORIZATION_CODE + .equals(clientRegistration.getAuthorizationGrantType())) { + builder = OAuth2AuthorizationRequest.authorizationCode(); + } else if (AuthorizationGrantType.IMPLICIT + .equals(clientRegistration.getAuthorizationGrantType())) { + builder = OAuth2AuthorizationRequest.implicit(); + } else { + throw new IllegalArgumentException("Invalid Authorization Grant Type (" + + clientRegistration.getAuthorizationGrantType().getValue() + + ") for Client Registration with Id: " + clientRegistration.getRegistrationId()); + } + + String redirectUriStr = this.expandRedirectUri(request, clientRegistration, redirectUriAction); + + Map additionalParameters = new HashMap<>(); + additionalParameters.put(OAuth2ParameterNames.REGISTRATION_ID, + clientRegistration.getRegistrationId()); + String userType = request.getParameter(SecurityConstants.LOGIN_USER_TYPE_KEY); + String registerCode = request.getParameter(SecurityConstants.LOGIN_REGISTER_CODE_KEY); + String entrypoint = request.getParameter(SecurityConstants.LOGIN_ENTRYPOINT_KEY); + if (StringUtils.isBlank(userType)) { + userType = UserTypeEnum.PERSON.getType().toString(); + } + additionalParameters.put(SecurityConstants.LOGIN_USER_TYPE_KEY, userType); + if (StringUtils.isNotBlank(registerCode)) { + additionalParameters.put(SecurityConstants.LOGIN_REGISTER_CODE_KEY, registerCode); + } + if (StringUtils.isNotBlank(entrypoint)) { + additionalParameters.put(SecurityConstants.LOGIN_ENTRYPOINT_KEY, entrypoint); + } + + OAuth2AuthorizationRequest authorizationRequest = builder + .clientId(clientRegistration.getClientId()) + .authorizationUri(clientRegistration.getProviderDetails().getAuthorizationUri()) + .redirectUri(redirectUriStr) + .scopes(clientRegistration.getScopes()) + .state(this.stateGenerator.generateKey()) + .additionalParameters(additionalParameters) + .build(); + // 不同授权需要额外修饰 + IOauthProvider oauthProvider = Oauth2ProviderUtils.getProvider(registrationId); + if (oauthProvider != null) { + return oauthProvider.decorateRequest(request, authorizationRequest); + } + return authorizationRequest; + } + + private String resolveRegistrationId(HttpServletRequest request) { + if (this.authorizationRequestMatcher.matches(request)) { + return this.authorizationRequestMatcher + .extractUriTemplateVariables(request).get(REGISTRATION_ID_URI_VARIABLE_NAME); + } + return null; + } + + private String expandRedirectUri(HttpServletRequest request, + ClientRegistration clientRegistration, String action) { + // Supported URI variables -> baseUrl, action, registrationId + // Used in -> CommonOAuth2Provider.DEFAULT_REDIRECT_URL = "{baseUrl}/{action}/oauth2/code/{registrationId}" + Map uriVariables = new HashMap<>(); + uriVariables.put("registrationId", clientRegistration.getRegistrationId()); + String baseUrl = UriComponentsBuilder.fromHttpUrl(UrlUtils.buildFullRequestUrl(request)) + .replaceQuery(null) + .replacePath(request.getContextPath()) + .build() + .toUriString(); + uriVariables.put("baseUrl", baseUrl); + if (action != null) { + uriVariables.put("action", action); + } + return UriComponentsBuilder.fromUriString(clientRegistration.getRedirectUriTemplate()) + .buildAndExpand(uriVariables) + .toUriString(); + } +} diff --git a/backend/src/main/java/com/senmesh/security/social/util/Oauth2ProviderUtils.java b/backend/src/main/java/com/senmesh/security/social/util/Oauth2ProviderUtils.java new file mode 100644 index 0000000..8505348 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/social/util/Oauth2ProviderUtils.java @@ -0,0 +1,25 @@ +package com.senmesh.security.social.util; + +import java.util.List; +import java.util.Map; + +import org.apache.commons.collections4.map.CaseInsensitiveMap; +import org.springframework.stereotype.Component; + +import com.senmesh.security.social.service.IOauthProvider; + +@Component +public class Oauth2ProviderUtils { + + private static Map providerMap = new CaseInsensitiveMap(); + + private Oauth2ProviderUtils(List providers) { + providers.forEach(provider -> providerMap.put(provider.getName(), provider)); + } + + public static IOauthProvider getProvider(String providerName) { + IOauthProvider provider = providerMap.get(providerName); + return provider; + } + +} diff --git a/backend/src/main/java/com/senmesh/security/social/wechat/constant/WechatConstants.java b/backend/src/main/java/com/senmesh/security/social/wechat/constant/WechatConstants.java new file mode 100644 index 0000000..c102488 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/social/wechat/constant/WechatConstants.java @@ -0,0 +1,20 @@ +package com.senmesh.security.social.wechat.constant; + +/** + * @author sr on 2021-01-13 + */ +public interface WechatConstants { + + /** 授权code获取token **/ + String TOKEN_URL_FORMAT = + "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=%s"; + + /** openId换取用户信息 **/ + String USER_URL_FORMAT = + "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=%s"; + + /** 调起微信授权地址 **/ + String AUTH_URL_FORMAT = + "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=%s&scope=%s&state=%s#wechat_redirect"; + +} diff --git a/backend/src/main/java/com/senmesh/security/social/wechat/convert/WeChatAuthorizationCodeGrantRequestEntityConverter.java b/backend/src/main/java/com/senmesh/security/social/wechat/convert/WeChatAuthorizationCodeGrantRequestEntityConverter.java new file mode 100644 index 0000000..d34dd6a --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/social/wechat/convert/WeChatAuthorizationCodeGrantRequestEntityConverter.java @@ -0,0 +1,57 @@ +package com.senmesh.security.social.wechat.convert; + +import java.net.URI; +import java.util.Collections; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.web.util.UriComponentsBuilder; + +import com.senmesh.security.social.wechat.constant.WechatConstants; + +import lombok.extern.slf4j.Slf4j; + + +/** + * code换token + * + * @author sr on 2021-01-12 + */ +@Slf4j +public class WeChatAuthorizationCodeGrantRequestEntityConverter + implements Converter> { + + @Override + public RequestEntity convert( + OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) { + HttpHeaders headers = getTokenRequestHeaders(); + URI uri = buildUri(authorizationCodeGrantRequest); + return new RequestEntity<>(headers, HttpMethod.GET, uri); + } + + private HttpHeaders getTokenRequestHeaders() { + HttpHeaders headers = new HttpHeaders(); + headers.setAccept(Collections.singletonList(MediaType.TEXT_PLAIN)); + return headers; + } + + private URI buildUri(OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) { + ClientRegistration clientRegistration = authorizationCodeGrantRequest.getClientRegistration(); + String tokenUri = clientRegistration.getProviderDetails().getTokenUri(); + String appid = clientRegistration.getClientId(); + String secret = clientRegistration.getClientSecret(); + String code = authorizationCodeGrantRequest.getAuthorizationExchange() + .getAuthorizationResponse().getCode(); + String grantType = authorizationCodeGrantRequest.getGrantType().getValue(); + + String uriString = + String.format(WechatConstants.TOKEN_URL_FORMAT, + appid, secret, code, grantType); + return UriComponentsBuilder.fromUriString(uriString).build().toUri(); + } +} diff --git a/backend/src/main/java/com/senmesh/security/social/wechat/convert/WeChatUserRequestEntityConverter.java b/backend/src/main/java/com/senmesh/security/social/wechat/convert/WeChatUserRequestEntityConverter.java new file mode 100644 index 0000000..9bbd00d --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/social/wechat/convert/WeChatUserRequestEntityConverter.java @@ -0,0 +1,44 @@ +package com.senmesh.security.social.wechat.convert; + +import java.net.URI; +import java.util.Collections; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; +import org.springframework.web.util.UriComponentsBuilder; + +import com.senmesh.security.social.wechat.constant.WechatConstants; + +public class WeChatUserRequestEntityConverter + implements Converter> { + + @Override + public RequestEntity convert(OAuth2UserRequest userRequest) { + HttpHeaders headers = getUserRequestHeaders(); + URI uri = buildUri(userRequest); + return new RequestEntity<>(headers, HttpMethod.GET, uri); + } + + private HttpHeaders getUserRequestHeaders() { + HttpHeaders headers = new HttpHeaders(); + headers.setAccept(Collections.singletonList(MediaType.TEXT_PLAIN)); + return headers; + } + + private URI buildUri(OAuth2UserRequest userRequest) { + ClientRegistration clientRegistration = userRequest.getClientRegistration(); + String uri = clientRegistration.getProviderDetails().getUserInfoEndpoint().getUri(); + String accessToken = userRequest.getAccessToken().getTokenValue(); + String openId = (String) userRequest.getAdditionalParameters().get("openid"); + + String userInfoUrl = + String.format(WechatConstants.USER_URL_FORMAT, + accessToken, openId, "zh_CN"); + return UriComponentsBuilder.fromUriString(userInfoUrl).build().toUri(); + } +} diff --git a/backend/src/main/java/com/senmesh/security/social/wechat/service/WeChatAccessTokenResponse.java b/backend/src/main/java/com/senmesh/security/social/wechat/service/WeChatAccessTokenResponse.java new file mode 100644 index 0000000..2523d30 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/social/wechat/service/WeChatAccessTokenResponse.java @@ -0,0 +1,68 @@ +package com.senmesh.security.social.wechat.service; + +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest; +import org.springframework.security.oauth2.core.OAuth2AccessToken; +import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.senmesh.common.util.JsonUtils; + +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +@Getter +@Setter +@Slf4j +public class WeChatAccessTokenResponse { + @JsonProperty("access_token") + private String accessToken; + @JsonProperty("expires_in") + private Long expiresIn; + @JsonProperty("refresh_token") + private String refreshToken; + private String openid; + private String scope; + + private WeChatAccessTokenResponse() { + + } + + public static WeChatAccessTokenResponse build(String json) { + try { + return JsonUtils.toObject(json, WeChatAccessTokenResponse.class); + } catch (Exception e) { + log.error("An error occurred while attempting to parse the WeiXin Access Token Response: " + + e.getMessage()); + return null; + } + } + + public OAuth2AccessTokenResponse toOAuth2AccessTokenResponse( + OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) { + OAuth2AccessTokenResponse.Builder builder = OAuth2AccessTokenResponse.withToken(accessToken); + builder.tokenType(OAuth2AccessToken.TokenType.BEARER); + builder.expiresIn(expiresIn); + builder.refreshToken(refreshToken); + + String[] scopes = scope.split(","); + Set scopeSet = new HashSet<>(); + Collections.addAll(scopeSet, scopes); + builder.scopes(scopeSet); + + Map additionalParameters = new LinkedHashMap<>(); + additionalParameters.put("openid", openid); + Map originParam = authorizationCodeGrantRequest.getAuthorizationExchange().getAuthorizationRequest() + .getAdditionalParameters(); + additionalParameters.putAll(originParam); + builder.additionalParameters(additionalParameters); + return builder.build(); + } + +} diff --git a/backend/src/main/java/com/senmesh/security/social/wechat/service/WechatOauthLoginProvider.java b/backend/src/main/java/com/senmesh/security/social/wechat/service/WechatOauthLoginProvider.java new file mode 100644 index 0000000..77b1807 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/social/wechat/service/WechatOauthLoginProvider.java @@ -0,0 +1,157 @@ +package com.senmesh.security.social.wechat.service; + +import java.io.UnsupportedEncodingException; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.springframework.core.convert.converter.Converter; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; +import org.springframework.security.oauth2.core.OAuth2AuthorizationException; +import org.springframework.security.oauth2.core.OAuth2Error; +import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse; +import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; +import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponseType; +import org.springframework.security.oauth2.core.user.OAuth2User; +import org.springframework.web.client.RestClientException; + +import com.senmesh.common.util.JsonUtils; +import com.senmesh.security.mapstruct.AuthDetailMapMapper; +import com.senmesh.security.mapstruct.UserMapMapper; +import com.senmesh.security.social.service.IOauthProvider; +import com.senmesh.security.social.service.StandardAuthorizationCodeTokenResponseClient; +import com.senmesh.security.social.wechat.constant.WechatConstants; +import com.senmesh.security.social.wechat.convert.WeChatAuthorizationCodeGrantRequestEntityConverter; +import com.senmesh.security.social.wechat.convert.WeChatUserRequestEntityConverter; +import com.senmesh.security.util.SecurityUtils; +import com.senmesh.usercenter.auth.constant.AuthTypeEnum; +import com.senmesh.usercenter.auth.dto.AuthDetailLoginDTO; +import com.senmesh.usercenter.auth.wechat.dto.WechatAuthUserInfoDTO; +import com.senmesh.usercenter.constants.SecurityConstants; +import com.senmesh.usercenter.user.login.dto.UserDetailDTO; +import com.senmesh.usercenter.user.login.service.UserLoginService; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class WechatOauthLoginProvider implements IOauthProvider { + + private Converter> tokenConverter = + new WeChatAuthorizationCodeGrantRequestEntityConverter(); + + private Converter> userConverter = + new WeChatUserRequestEntityConverter(); + + private UserLoginService userLoginService; + + public WechatOauthLoginProvider(UserLoginService userLoginService) { + this.userLoginService = userLoginService; + } + + @Override + public String getName() { + return AuthTypeEnum.WECHAT.name(); + } + + @Override + public OAuth2AuthorizationRequest decorateRequest(HttpServletRequest request, + OAuth2AuthorizationRequest authorizationRequest) { + // 指定成功跳转地址 + String redirectUrl = + SecurityUtils.dealRedirectUrl(request, authorizationRequest.getRedirectUri()); + + // 微信Authorization Request URL + String authorizationRequestUri = + String.format(WechatConstants.AUTH_URL_FORMAT, + authorizationRequest.getClientId(), + SecurityUtils.encodeURL(redirectUrl), + OAuth2AuthorizationResponseType.CODE.getValue(), getScope(authorizationRequest), + authorizationRequest.getState()); + + return OAuth2AuthorizationRequest.from(authorizationRequest) + .authorizationRequestUri(authorizationRequestUri) + .build(); + } + + private static String getScope(OAuth2AuthorizationRequest authorizationRequest) { + return authorizationRequest.getScopes().stream().findFirst().orElse("snsapi_userinfo"); + } + + @Override + public OAuth2AccessTokenResponse getTokenResponse( + OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) { + + // 调用WeChatAuthorizationCodeGrantRequestEntityConverter获取request + RequestEntity request = this.tokenConverter.convert(authorizationCodeGrantRequest); + + ResponseEntity response; + try { + // 执行request + response = StandardAuthorizationCodeTokenResponseClient.restOperations.exchange(request, + String.class); + } catch (RestClientException ex) { + String description = + "An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: "; + log.error(description, ex); + OAuth2Error oauth2Error = + new OAuth2Error( + StandardAuthorizationCodeTokenResponseClient.INVALID_TOKEN_RESPONSE_ERROR_CODE, + description + ex.getMessage(), null); + throw new OAuth2AuthorizationException(oauth2Error, ex); + } + + // 解析response + OAuth2AccessTokenResponse tokenResponse = + WeChatAccessTokenResponse.build(response.getBody()).toOAuth2AccessTokenResponse(authorizationCodeGrantRequest); + + if (CollectionUtils.isEmpty(tokenResponse.getAccessToken().getScopes())) { + tokenResponse = OAuth2AccessTokenResponse.withResponse(tokenResponse) + .scopes(authorizationCodeGrantRequest.getClientRegistration().getScopes()) + .build(); + } + + return tokenResponse; + + } + + + @Override + public Converter> getUserConvert() { + return userConverter; + } + + @Override + public OAuth2User dealUser(OAuth2UserRequest userRequest, String userJsonStr) { + WechatAuthUserInfoDTO wechatUserInfoDTO = null; + try { + // 编码转换 + userJsonStr = new String(userJsonStr.getBytes("ISO-8859-1"), "UTF-8"); + wechatUserInfoDTO = JsonUtils.toObject(userJsonStr, WechatAuthUserInfoDTO.class); + } catch (UnsupportedEncodingException e) { + log.error("An error occurred while attempting to encode userAttributes: " + e.getMessage()); + } + AuthDetailLoginDTO authDetailLoginDTO = AuthDetailMapMapper.INSTANCE.toDto(wechatUserInfoDTO); + Integer userType = MapUtils.getInteger(userRequest.getAdditionalParameters(), + SecurityConstants.LOGIN_USER_TYPE_KEY); + String registerCode = MapUtils.getString(userRequest.getAdditionalParameters(), + SecurityConstants.LOGIN_REGISTER_CODE_KEY); + String entrypoint = MapUtils.getString(userRequest.getAdditionalParameters(), + SecurityConstants.LOGIN_ENTRYPOINT_KEY); + authDetailLoginDTO + .setUserType(userType); + authDetailLoginDTO + .setAuthClientId(Long.valueOf(userRequest.getClientRegistration().getRegistrationId())); + authDetailLoginDTO.setAuthTypeCode(AuthTypeEnum.WECHAT.getCode()); + authDetailLoginDTO.setRegisterCode(registerCode); + authDetailLoginDTO.setEntrypoint(entrypoint); + UserDetailDTO userDetailDTO = userLoginService.findUserDetailDTO(authDetailLoginDTO); + return UserMapMapper.INSTANCE.dtoToDto(userDetailDTO); + } + + + +} diff --git a/backend/src/main/java/com/senmesh/security/temptoken/TokenAuthenticationFilter.java b/backend/src/main/java/com/senmesh/security/temptoken/TokenAuthenticationFilter.java new file mode 100644 index 0000000..f980583 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/temptoken/TokenAuthenticationFilter.java @@ -0,0 +1,100 @@ +package com.senmesh.security.temptoken; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.authentication.AuthenticationServiceException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; + +import com.senmesh.security.expection.BadLoginException; +import com.senmesh.usercenter.constants.SecurityConstants; +import com.senmesh.usercenter.user.login.dto.LoginPhoneToken; +import com.senmesh.usercenter.user.login.dto.LoginUserToken; +import com.senmesh.usercenter.user.login.dto.TempTokenDTO; + +/** + * 临时token认证过滤器,指定请求组装token,调起认证 + * + * @author sr on 2020-06-04 + */ +public class TokenAuthenticationFilter extends AbstractAuthenticationProcessingFilter { + + + public static final String TYPE_KEY = "type"; + public static final String REQUEST_METHOD = "POST"; + + private static final AntPathRequestMatcher requiresAuthenticationRequestMatcher = + new AntPathRequestMatcher("/login_token_" + "{" + TYPE_KEY + "}", REQUEST_METHOD); + + private boolean postOnly = true; + + public TokenAuthenticationFilter() { + super(requiresAuthenticationRequestMatcher); + } + + @Override + public Authentication attemptAuthentication(HttpServletRequest request, + HttpServletResponse response) throws AuthenticationException, IOException, ServletException { + + if (postOnly && !REQUEST_METHOD.equals(request.getMethod())) { + throw new AuthenticationServiceException( + "Authentication method not supported: " + request.getMethod()); + } + + String type = this.resolveType(request); + String tempToken = request.getParameter(SecurityConstants.LOGIN_TEMP_TOKEN_KEY); + String entrypoint = request.getParameter(SecurityConstants.LOGIN_ENTRYPOINT_KEY); + TempTokenDTO tempTokenDTO = null; + if (TempTokenDTO.TYPE_PHONE.equals(type)) { + Long userId = null; + String userIdStr = request.getParameter(SecurityConstants.LOGIN_USER_ID_KEY); + if (StringUtils.isNotBlank(userIdStr)) { + try { + userId = Long.valueOf(userIdStr); + } catch (NumberFormatException e) { + throw new BadLoginException("用户id错误:" + userIdStr); + } + + } + tempTokenDTO = LoginPhoneToken.builder().tempToken(tempToken).entrypoint(entrypoint) + .userId(userId).build(); + } else if (TempTokenDTO.TYPE_USER.equals(type)) { + Long orgId = null; + String orgIdStr = request.getParameter(SecurityConstants.LOGIN_ORG_ID_KEY); + try { + orgId = Long.valueOf(orgIdStr); + } catch (NumberFormatException e) { + throw new BadLoginException("机构id错误:" + orgIdStr); + } + tempTokenDTO = LoginUserToken.builder().tempToken(tempToken).orgId(orgId).build(); + } else { + throw new BadLoginException("token认证类型有误"); + } + AbstractAuthenticationToken authRequest = new TokenAuthenticationToken(tempTokenDTO, tempToken); + + // Allow subclasses to set the "details" property + setDetails(request, authRequest); + + return this.getAuthenticationManager().authenticate(authRequest); + } + + protected void setDetails(HttpServletRequest request, AbstractAuthenticationToken authRequest) { + authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); + } + + private String resolveType(HttpServletRequest request) { + if (requiresAuthenticationRequestMatcher.matches(request)) { + return requiresAuthenticationRequestMatcher.extractUriTemplateVariables(request) + .get(TYPE_KEY); + } + return null; + } +} diff --git a/backend/src/main/java/com/senmesh/security/temptoken/TokenAuthenticationProvider.java b/backend/src/main/java/com/senmesh/security/temptoken/TokenAuthenticationProvider.java new file mode 100644 index 0000000..76b4107 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/temptoken/TokenAuthenticationProvider.java @@ -0,0 +1,74 @@ +package com.senmesh.security.temptoken; + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.validation.util.ValidateUtils; +import com.senmesh.security.dto.SecurityUserDTO; +import com.senmesh.security.expection.BadLoginException; +import com.senmesh.security.mapstruct.UserMapMapper; +import com.senmesh.usercenter.user.login.dto.LoginPhoneToken; +import com.senmesh.usercenter.user.login.dto.LoginUserToken; +import com.senmesh.usercenter.user.login.dto.UserDetailDTO; +import com.senmesh.usercenter.user.login.service.UserLoginService; + +/** + * token认证provider,比对信息是否匹配 + * + * @author sr on 2020-06-04 + */ +public class TokenAuthenticationProvider implements AuthenticationProvider { + + private UserLoginService userLoginService; + + public TokenAuthenticationProvider(UserLoginService userLoginService) { + this.userLoginService = userLoginService; + } + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + Object principal = authentication.getPrincipal(); + + String errMsg = ValidateUtils.validate(principal); + Assert.isTrue(errMsg == null, new BadLoginException(errMsg)); + SecurityUserDTO loadedUser = null; + try { + UserDetailDTO userDetailDTO = null; + if (principal instanceof LoginPhoneToken) { + userDetailDTO = userLoginService.loadUser((LoginPhoneToken) principal); + } else if (principal instanceof LoginUserToken) { + userDetailDTO = userLoginService.loadUser((LoginUserToken) principal); + }else { + throw new BadLoginException("token认证类型有误"); + } + loadedUser = UserMapMapper.INSTANCE.dtoToDto(userDetailDTO); + } catch (BadLoginException be) { + throw be; + } catch (Exception e) { + throw new BadLoginException(e.getMessage(), e); + } + + TokenAuthenticationToken result = + new TokenAuthenticationToken(loadedUser, listUserGrantedAuthorities(loadedUser)); + result.setDetails(authentication.getDetails()); + return result; + } + + @Override + public boolean supports(Class authentication) { + return (TokenAuthenticationToken.class.isAssignableFrom(authentication)); + } + + private Set listUserGrantedAuthorities(UserDetails userDetails) { + // 什么都不用做,访问资源鉴权的时会拿userDetail去缓存获取对应权限 + return new HashSet(); + } + +} diff --git a/backend/src/main/java/com/senmesh/security/temptoken/TokenAuthenticationToken.java b/backend/src/main/java/com/senmesh/security/temptoken/TokenAuthenticationToken.java new file mode 100644 index 0000000..afe9089 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/temptoken/TokenAuthenticationToken.java @@ -0,0 +1,24 @@ +package com.senmesh.security.temptoken; + +import java.util.Collection; + +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; + +/** + * 临时token认证信息 + * + * @author sr on 2020-06-04 + */ +public class TokenAuthenticationToken extends UsernamePasswordAuthenticationToken { + + public TokenAuthenticationToken(Object principal, Object credentials) { + super(principal, credentials); + } + + public TokenAuthenticationToken(Object principal, Object credentials, + Collection authorities) { + super(principal, credentials, authorities); + } + +} diff --git a/backend/src/main/java/com/senmesh/security/temptoken/dto/DuplMobileToken.java b/backend/src/main/java/com/senmesh/security/temptoken/dto/DuplMobileToken.java new file mode 100644 index 0000000..2991462 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/temptoken/dto/DuplMobileToken.java @@ -0,0 +1,25 @@ +package com.senmesh.security.temptoken.dto; + +import java.util.List; + +import com.senmesh.usercenter.user.login.dto.PhoneToken; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@SuperBuilder +@ApiModel(description = "多用户手机号token") +public class DuplMobileToken extends PhoneToken{ + + /** **/ + private static final long serialVersionUID = -4119001378908265360L; + + @ApiModelProperty("用户列表") + private List users; + +} diff --git a/backend/src/main/java/com/senmesh/security/temptoken/dto/DuplUserToken.java b/backend/src/main/java/com/senmesh/security/temptoken/dto/DuplUserToken.java new file mode 100644 index 0000000..73120ca --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/temptoken/dto/DuplUserToken.java @@ -0,0 +1,25 @@ +package com.senmesh.security.temptoken.dto; + +import java.util.List; + +import com.senmesh.usercenter.user.login.dto.UserToken; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@SuperBuilder +@ApiModel(description = "多机构用户token") +public class DuplUserToken extends UserToken{ + + /** **/ + private static final long serialVersionUID = -374663184680420441L; + + @ApiModelProperty("机构列表") + private List orgs; + +} diff --git a/backend/src/main/java/com/senmesh/security/temptoken/dto/PhoneTokenCreateDTO.java b/backend/src/main/java/com/senmesh/security/temptoken/dto/PhoneTokenCreateDTO.java new file mode 100644 index 0000000..aab9465 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/temptoken/dto/PhoneTokenCreateDTO.java @@ -0,0 +1,19 @@ +package com.senmesh.security.temptoken.dto; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class PhoneTokenCreateDTO implements Serializable{ + + private Integer userType; + private String phone; + +} diff --git a/backend/src/main/java/com/senmesh/security/temptoken/dto/UserTokenCreateDTO.java b/backend/src/main/java/com/senmesh/security/temptoken/dto/UserTokenCreateDTO.java new file mode 100644 index 0000000..5f9cc6e --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/temptoken/dto/UserTokenCreateDTO.java @@ -0,0 +1,19 @@ +package com.senmesh.security.temptoken.dto; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class UserTokenCreateDTO implements Serializable{ + + private Integer userType; + private Long userId; + +} diff --git a/backend/src/main/java/com/senmesh/security/ucard/UcardAuthenticationFilter.java b/backend/src/main/java/com/senmesh/security/ucard/UcardAuthenticationFilter.java new file mode 100644 index 0000000..58e7e73 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/ucard/UcardAuthenticationFilter.java @@ -0,0 +1,60 @@ +package com.senmesh.security.ucard; + +import com.senmesh.usercenter.user.login.dto.LoginUCardDTO; +import java.io.IOException; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.authentication.AuthenticationServiceException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; + +/** + * 账号密码认证过滤器,指定请求组装token,调起认证 + * + * @author sr on 2021-06-21 + */ +public class UcardAuthenticationFilter extends AbstractAuthenticationProcessingFilter { + + private boolean postOnly = true; + + public static final String REQUEST_METHOD = "POST"; + public static final AntPathRequestMatcher requiresAuthenticationRequestMatcher = + new AntPathRequestMatcher("/login_ucard", REQUEST_METHOD); + public static final String LOGIN_REAL_NAME_KEY = "realName"; + public static final String LOGIN_CARD_NO_KEY = "cardNo"; + + public UcardAuthenticationFilter() { + super(requiresAuthenticationRequestMatcher); + } + + @Override + public Authentication attemptAuthentication(HttpServletRequest request, + HttpServletResponse response) throws AuthenticationException, IOException, ServletException { + + if (postOnly && !REQUEST_METHOD.equals(request.getMethod())) { + throw new AuthenticationServiceException( + "Authentication method not supported: " + request.getMethod()); + } + + String realName = request.getParameter(LOGIN_REAL_NAME_KEY); + String cardNo = request.getParameter(LOGIN_CARD_NO_KEY); + realName = realName == null ? "" : realName.trim(); + cardNo = cardNo == null ? "" : cardNo.trim(); + + AbstractAuthenticationToken authRequest = new UcardAuthenticationToken( + LoginUCardDTO.builder().realName(realName).cardNo(cardNo).build(), cardNo); + + // Allow subclasses to set the "details" property + setDetails(request, authRequest); + + return this.getAuthenticationManager().authenticate(authRequest); + } + + protected void setDetails(HttpServletRequest request, AbstractAuthenticationToken authRequest) { + authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); + } +} diff --git a/backend/src/main/java/com/senmesh/security/ucard/UcardAuthenticationProvider.java b/backend/src/main/java/com/senmesh/security/ucard/UcardAuthenticationProvider.java new file mode 100644 index 0000000..c2cc8df --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/ucard/UcardAuthenticationProvider.java @@ -0,0 +1,64 @@ +package com.senmesh.security.ucard; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.validation.util.ValidateUtils; +import com.senmesh.security.dto.SecurityUserDTO; +import com.senmesh.security.expection.BadLoginException; +import com.senmesh.security.mapstruct.UserMapMapper; +import com.senmesh.usercenter.user.login.dto.LoginUCardDTO; +import com.senmesh.usercenter.user.login.dto.UserDetailDTO; +import com.senmesh.usercenter.user.login.service.UserLoginService; +import java.util.HashSet; +import java.util.Set; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +/** + * 账号密码认证provider,比对信息是否匹配 + * + * @author sr on 2021-06-21 + */ +public class UcardAuthenticationProvider implements AuthenticationProvider { + + private UserLoginService userLoginService; + + public UcardAuthenticationProvider(UserLoginService userLoginService) { + this.userLoginService = userLoginService; + } + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + LoginUCardDTO loginUCardDTO = + (LoginUCardDTO) authentication.getPrincipal(); + String errMsg = ValidateUtils.validate(LoginUCardDTO.class); + Assert.isTrue(errMsg == null, new BadLoginException(errMsg)); + SecurityUserDTO loadedUser = null; + try { + UserDetailDTO userDetailDTO = this.userLoginService.loadUser(loginUCardDTO); + loadedUser = UserMapMapper.INSTANCE.dtoToDto(userDetailDTO); + } catch (BadLoginException be) { + throw be; + } catch (Exception e) { + throw new BadLoginException(e.getMessage(), e); + } + + UcardAuthenticationToken result = + new UcardAuthenticationToken(loadedUser, listUserGrantedAuthorities(loadedUser)); + result.setDetails(authentication.getDetails()); + return result; + } + + @Override + public boolean supports(Class authentication) { + return (UcardAuthenticationToken.class.isAssignableFrom(authentication)); + } + + private Set listUserGrantedAuthorities(UserDetails userDetails) { + // 什么都不用做,访问资源鉴权的时会拿userDetail去缓存获取对应权限 + return new HashSet(); + } + +} diff --git a/backend/src/main/java/com/senmesh/security/ucard/UcardAuthenticationToken.java b/backend/src/main/java/com/senmesh/security/ucard/UcardAuthenticationToken.java new file mode 100644 index 0000000..76b7ccb --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/ucard/UcardAuthenticationToken.java @@ -0,0 +1,23 @@ +package com.senmesh.security.ucard; + +import java.util.Collection; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; + + +/** + * 账号密码认证信息 + * @author sr on 2021-06-21 + */ +public class UcardAuthenticationToken extends UsernamePasswordAuthenticationToken { + + public UcardAuthenticationToken(Object principal, Object credentials) { + super(principal, credentials); + } + + public UcardAuthenticationToken(Object principal, Object credentials, + Collection authorities) { + super(principal, credentials, authorities); + } + +} diff --git a/backend/src/main/java/com/senmesh/security/upassword/UpasswordAuthenticationFilter.java b/backend/src/main/java/com/senmesh/security/upassword/UpasswordAuthenticationFilter.java new file mode 100644 index 0000000..9e79c7f --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/upassword/UpasswordAuthenticationFilter.java @@ -0,0 +1,71 @@ +package com.senmesh.security.upassword; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.authentication.AuthenticationServiceException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; + +import com.senmesh.security.expection.BadLoginException; +import com.senmesh.usercenter.constants.SecurityConstants; +import com.senmesh.usercenter.user.login.dto.LoginUsernamePasswordDTO; + +/** + * 账号密码认证过滤器,指定请求组装token,调起认证 + * + * @author sr on 2021-06-21 + */ +public class UpasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter { + + private boolean postOnly = true; + + public static final String REQUEST_METHOD = "POST"; + public static final AntPathRequestMatcher requiresAuthenticationRequestMatcher = + new AntPathRequestMatcher("/login", REQUEST_METHOD); + + public UpasswordAuthenticationFilter() { + super(requiresAuthenticationRequestMatcher); + } + + @Override + public Authentication attemptAuthentication(HttpServletRequest request, + HttpServletResponse response) throws AuthenticationException, IOException, ServletException { + + if (postOnly && !REQUEST_METHOD.equals(request.getMethod())) { + throw new AuthenticationServiceException( + "Authentication method not supported: " + request.getMethod()); + } + + String userTypeStr = request.getParameter(SecurityConstants.LOGIN_USER_TYPE_KEY); + Integer userType = null; + try { + userType = Integer.valueOf(userTypeStr); + } catch (NumberFormatException e) { + throw new BadLoginException("用户类型错误:" + userTypeStr); + } + + String username = request.getParameter(SecurityConstants.LOGIN_USERNAME_KEY); + String password = request.getParameter(SecurityConstants.LOGIN_PASSWORD_KEY); + username = username == null ? "" : username.trim(); + password = password == null ? "" : password.trim(); + + AbstractAuthenticationToken authRequest = new UpasswordAuthenticationToken( + LoginUsernamePasswordDTO.builder().username(username).password(password).userType(userType).build(), password); + + // Allow subclasses to set the "details" property + setDetails(request, authRequest); + + return this.getAuthenticationManager().authenticate(authRequest); + } + + protected void setDetails(HttpServletRequest request, AbstractAuthenticationToken authRequest) { + authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); + } +} diff --git a/backend/src/main/java/com/senmesh/security/upassword/UpasswordAuthenticationProvider.java b/backend/src/main/java/com/senmesh/security/upassword/UpasswordAuthenticationProvider.java new file mode 100644 index 0000000..2f88a8e --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/upassword/UpasswordAuthenticationProvider.java @@ -0,0 +1,66 @@ +package com.senmesh.security.upassword; + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.validation.util.ValidateUtils; +import com.senmesh.security.dto.SecurityUserDTO; +import com.senmesh.security.expection.BadLoginException; +import com.senmesh.security.mapstruct.UserMapMapper; +import com.senmesh.usercenter.user.login.dto.LoginUsernamePasswordDTO; +import com.senmesh.usercenter.user.login.dto.UserDetailDTO; +import com.senmesh.usercenter.user.login.service.UserLoginService; + +/** + * 账号密码认证provider,比对信息是否匹配 + * + * @author sr on 2021-06-21 + */ +public class UpasswordAuthenticationProvider implements AuthenticationProvider { + + private UserLoginService userLoginService; + + public UpasswordAuthenticationProvider(UserLoginService userLoginService) { + this.userLoginService = userLoginService; + } + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + LoginUsernamePasswordDTO loginUsernamePasswordDTO = + (LoginUsernamePasswordDTO) authentication.getPrincipal(); + String errMsg = ValidateUtils.validate(loginUsernamePasswordDTO); + Assert.isTrue(errMsg == null, new BadLoginException(errMsg)); + SecurityUserDTO loadedUser = null; + try { + UserDetailDTO userDetailDTO = this.userLoginService.loadUser(loginUsernamePasswordDTO); + loadedUser = UserMapMapper.INSTANCE.dtoToDto(userDetailDTO); + } catch (BadLoginException be) { + throw be; + } catch (Exception e) { + throw new BadLoginException(e.getMessage(), e); + } + + UpasswordAuthenticationToken result = + new UpasswordAuthenticationToken(loadedUser, listUserGrantedAuthorities(loadedUser)); + result.setDetails(authentication.getDetails()); + return result; + } + + @Override + public boolean supports(Class authentication) { + return (UpasswordAuthenticationToken.class.isAssignableFrom(authentication)); + } + + private Set listUserGrantedAuthorities(UserDetails userDetails) { + // 什么都不用做,访问资源鉴权的时会拿userDetail去缓存获取对应权限 + return new HashSet(); + } + +} diff --git a/backend/src/main/java/com/senmesh/security/upassword/UpasswordAuthenticationToken.java b/backend/src/main/java/com/senmesh/security/upassword/UpasswordAuthenticationToken.java new file mode 100644 index 0000000..67ff479 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/upassword/UpasswordAuthenticationToken.java @@ -0,0 +1,24 @@ +package com.senmesh.security.upassword; + +import java.util.Collection; + +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; + + +/** + * 账号密码认证信息 + * @author sr on 2021-06-21 + */ +public class UpasswordAuthenticationToken extends UsernamePasswordAuthenticationToken { + + public UpasswordAuthenticationToken(Object principal, Object credentials) { + super(principal, credentials); + } + + public UpasswordAuthenticationToken(Object principal, Object credentials, + Collection authorities) { + super(principal, credentials, authorities); + } + +} diff --git a/backend/src/main/java/com/senmesh/security/util/HostContextHolder.java b/backend/src/main/java/com/senmesh/security/util/HostContextHolder.java new file mode 100644 index 0000000..5c41bbf --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/util/HostContextHolder.java @@ -0,0 +1,35 @@ +package com.senmesh.security.util; + +/** + * request请求host上下文 + * @author sr on 2021-08-23 + */ +public class HostContextHolder { + + private static final ThreadLocal HOST = new ThreadLocal(); + + /** + * + * @author sr on 2021-08-18 + */ + public static void clearHost() { + HOST.remove(); + } + + /** + * @param host + * @author sr on 2021-08-18 + */ + public static void setHost(String host) { + HOST.set(host); + } + + /** + * @param host + * @author sr on 2021-08-18 + */ + public static String getHost() { + return HOST.get(); + } + +} diff --git a/backend/src/main/java/com/senmesh/security/util/MockUtils.java b/backend/src/main/java/com/senmesh/security/util/MockUtils.java new file mode 100644 index 0000000..ddbf2af --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/util/MockUtils.java @@ -0,0 +1,68 @@ +package com.senmesh.security.util; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.security.dto.SecurityUserDTO; +import com.senmesh.usercenter.constants.OrgConstants; +import com.senmesh.usercenter.constants.UserConstants; +import com.senmesh.usercenter.user.constant.UserTypeEnum; +import com.senmesh.usercenter.user.dto.UserDetailQueryDTO; + +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; + +/** + * @author sr on 2020-01-05 + */ +public class MockUtils { + + + /** + * 模拟登录机构用户,默认超级管理员/平台机构 + */ + public static void mockPlatUser() { + mockUser(UserConstants.SUPERIOR_USER_ID, OrgConstants.PLATFORM_ORG_ID,UserTypeEnum.ORG.getType()); + } + + /** + * 模拟登录用户 + * + * @param userId + * @param orgId(企业用户需要,个人不用可不传) + * @author sr on 2020-09-07 + */ + public static void mockUser(Long userId, Long orgId) { + mockUser(userId, orgId, null); + } + + /** + * 模拟登录用户(能拿到外部线程登录用户信息,则直接用外部的,不要自己定义固定值) + * 使用mockUser(userId,orgId), 不需要userType,userId已经有用户类型了 + * @param userId + * @param orgId 个人用户可为空 + * @param userType {@link UserTypeEnum} + * @author sr on 2020-09-07 + */ + @Deprecated + public static void mockUser(Long userId, Long orgId,Integer userType) { + Assert.notNull(userId, "无userId,无法mock.."); + UserDetailQueryDTO userDetailQueryDto = + UserDetailQueryDTO.builder().userId(userId).orgId(orgId).userType(userType).build(); + SecurityUserDTO securityUserDTO = UserLoginUtils.loadUserToMock(userDetailQueryDto); + SecurityContextHolder.getContext() + .setAuthentication(new UsernamePasswordAuthenticationToken( + securityUserDTO, null)); + UserContextHolder.setContext(securityUserDTO); + } + + /** + * + * @author sr on 2020-06-17 + */ + public static void clearUser() { + SecurityContextHolder.clearContext(); + UserContextHolder.clearContext(); + } + + +} diff --git a/backend/src/main/java/com/senmesh/security/util/PasswordUtils.java b/backend/src/main/java/com/senmesh/security/util/PasswordUtils.java new file mode 100644 index 0000000..77d57a2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/util/PasswordUtils.java @@ -0,0 +1,25 @@ +package com.senmesh.security.util; + +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Component; + +@Component +public class PasswordUtils { + + private static PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + + private PasswordUtils(PasswordEncoder passwordEncoder) { + PasswordUtils.passwordEncoder = passwordEncoder; + } + + public static String encode(String password) { + return passwordEncoder.encode(password); + } + + public static boolean match(String password, String encodedPassword) { + return passwordEncoder.matches(password, encodedPassword); + } + + +} diff --git a/backend/src/main/java/com/senmesh/security/util/SecurityMockProvider.java b/backend/src/main/java/com/senmesh/security/util/SecurityMockProvider.java new file mode 100644 index 0000000..a31098a --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/util/SecurityMockProvider.java @@ -0,0 +1,25 @@ +package com.senmesh.security.util; + +import org.springframework.stereotype.Service; + +import com.senmesh.common.service.IMockProvider; + +@Service +public class SecurityMockProvider implements IMockProvider{ + + @Override + public void mockPlatUser() { + MockUtils.mockPlatUser(); + } + + @Override + public void mockUser(Long userId, Long orgId) { + MockUtils.mockUser(userId, orgId); + } + + @Override + public void clearUser() { + MockUtils.clearUser(); + } + +} diff --git a/backend/src/main/java/com/senmesh/security/util/SecurityPropertyUtils.java b/backend/src/main/java/com/senmesh/security/util/SecurityPropertyUtils.java new file mode 100644 index 0000000..3a80d30 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/util/SecurityPropertyUtils.java @@ -0,0 +1,119 @@ +package com.senmesh.security.util; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpMethod; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.util.matcher.RequestMatcher; + +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.security.config.SecurityProperties; +import com.senmesh.usercenter.constants.SecurityConstants; + +/** + * @author sr on 2020-09-10 + */ +public abstract class SecurityPropertyUtils { + + private static SecurityProperties securityProperties; + + + private static List anonRequestMatchers; + private static RequestMatcher unacRequestMatcher = new AntPathRequestMatcher("/unac/**"); + private static RequestMatcher authedRequestMatcher = new AntPathRequestMatcher("/authed/**"); + + public static void setSecurityProperties(SecurityProperties securityProperties) { + SecurityPropertyUtils.securityProperties = securityProperties; + } + + public static SecurityProperties getProperties() { + return securityProperties; + } + + /** + * 根据匹配路径获取请求匹配对象 + * + * @param httpMethod + * @param antPatterns + * @return + * @author sr on 2020-09-10 + */ + public static List antMatchers(HttpMethod httpMethod, + String... antPatterns) { + String method = httpMethod == null ? null : httpMethod.toString(); + List matchers = new ArrayList<>(); + for (String pattern : antPatterns) { + matchers.add(new AntPathRequestMatcher(pattern, method)); + } + return matchers; + } + + /** + * 获取匿名配置匹配 + * + * @return + * @author sr on 2020-09-10 + */ + public static List getAnonRequestMatchers() { + if (anonRequestMatchers != null) { + return anonRequestMatchers; + } + + String anonymous = EnvironmentUtils.getProperty(SecurityConstants.PROP_KEY_SECURITY_ANONYMOUS); + if (StringUtils.isBlank(anonymous)) { + anonRequestMatchers = Collections.emptyList(); + return anonRequestMatchers; + } + anonRequestMatchers = antMatchers(null, anonymous.split(",")); + return anonRequestMatchers; + } + + /** + * 判断请求是否匿名请求 + * + * @param request + * @return + * @author sr on 2020-09-10 + */ + public static boolean isAnon(HttpServletRequest request) { + List matchers = getAnonRequestMatchers(); + if (matchers.isEmpty()) { + return false; + } + for (RequestMatcher matcher : matchers) { + if (matcher.matches(request)) { + return true; + } + } + return false; + } + + /** + * 判断请求是否未激活请求 + * + * @param request + * @return + * @author sr on 2021-06-29 + */ + public static boolean isUnac(HttpServletRequest request) { + return unacRequestMatcher.matches(request); + } + + /** + * 判断请求是否已实名请求 + * @param request + * @return + * @author sr on 2021-11-05 + */ + public static boolean isAuthed(HttpServletRequest request) { + return authedRequestMatcher.matches(request); + } + + + +} diff --git a/backend/src/main/java/com/senmesh/security/util/SecurityUtils.java b/backend/src/main/java/com/senmesh/security/util/SecurityUtils.java new file mode 100644 index 0000000..4a0dfa1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/util/SecurityUtils.java @@ -0,0 +1,146 @@ +package com.senmesh.security.util; + +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLDecoder; +import java.net.URLEncoder; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang3.StringUtils; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.common.util.RequestUtils; +import com.senmesh.usercenter.constants.SecurityConstants; + +import cn.hutool.core.util.URLUtil; +import lombok.extern.slf4j.Slf4j; + +/** + * @author sr on 2020-06-15 + */ +@Slf4j +public class SecurityUtils { + + /** 代理域名 **/ + private static final String PROXY_DOMAIN = "proxy.niuyetai.cn"; + + /** 代理路径请求head-key **/ + public static final String PROXY_REQUEST_HEADER_KEY = "X-Proxy-Uri"; + + + public static String encodeURL(String url) { + try { + return URLEncoder.encode(url, "UTF-8"); + } catch (UnsupportedEncodingException e) { + log.info("encode失败:{}", e.getMessage()); + return null; + } + } + + public static String decodeURL(String url) { + try { + if(url.contains("%")) { + return URLDecoder.decode(url, "UTF-8"); + } + return url; + } catch (UnsupportedEncodingException e) { + log.info("encode失败:{}", e.getMessage()); + return null; + } + } + + /** + * 是否本地security调用 ;security.useLocal=false则关闭(调用户中心),其他都本地调用 + * + * @return + * @author sr on 2020-06-15 + */ + public static boolean useLocal() { + return !CommonConstants.FALSE_STR + .equals(EnvironmentUtils.getProperty(SecurityConstants.PROP_KEY_SECURITY_USELOCAL)); + } + + /** + * 处理代理路径 + * @param request + * @param uri + * @return + * @author sr on 2021-01-16 + */ + private static String dealProxy(HttpServletRequest request, String uri) { + String proxyUri = request.getHeader(PROXY_REQUEST_HEADER_KEY); + log.info("proxyUri {}", proxyUri); + // replace域名到代理域名 + if (StringUtils.isNotBlank(proxyUri) && uri.contains(PROXY_DOMAIN)) { + return uri.replace(PROXY_DOMAIN, PROXY_DOMAIN + proxyUri); + } + return uri; + } + + /** + * 指定成功跳转地址 + * + * @param request + * @param redirectUri + * @return + * @author sr on 2021-01-12 + */ + public static String dealRedirectUrl(HttpServletRequest request, final String redirectUri) { + String newRedirectUri = redirectUri; + String successToUrl = request.getParameter(SecurityConstants.SUCCESS_TO_URL); + if (StringUtils.isNotBlank(successToUrl)) { + newRedirectUri = + String.format(SecurityConstants.REDIRECT_URL_FORMAT, newRedirectUri, + encodeURL(successToUrl)); + } + newRedirectUri = dealProxy(request, newRedirectUri); + log.info("newRedirectUri:{}", newRedirectUri); + return newRedirectUri; + } + + public static String dealLoginUrl(HttpServletRequest request, String loginUri) { + String successToUrl = request.getParameter(SecurityConstants.SUCCESS_TO_URL); + // 指定成功跳转,但登陆地址未配置域名 + if (StringUtils.isNotBlank(successToUrl) + && loginUri.indexOf(RequestUtils.DOMAIN_SEPARATOR) < 0) { + String baseUrl = null; + try { + baseUrl = URLUtil.getHost(new URL(successToUrl)).toString(); + } catch (MalformedURLException e) { + log.error("successToUrl get domain error:{}", e.getMessage()); + return null; + } + loginUri = baseUrl + loginUri; + } + dealProxy(request, loginUri); + return loginUri; + } + + public static String dealSuccessUrl(HttpServletRequest request, String successUri, String token) { + if (successUri == null) { + return null; + } + String redirectSuccessToUrl = request.getParameter(SecurityConstants.SUCCESS_TO_URL); + log.debug("redirectSuccessToUrl:{}", redirectSuccessToUrl); + successUri = + StringUtils.isBlank(redirectSuccessToUrl) ? successUri : decodeURL(redirectSuccessToUrl); + if (successUri.indexOf(RequestUtils.DOMAIN_SEPARATOR) > 0) { + String requestBaseUrl = RequestUtils.getHttpDomain(request); + // 成功地址与当前地址域名不一致,跨域,拼接token + if (!successUri.startsWith(requestBaseUrl)) { + if (successUri.indexOf("?") > 0) { + successUri += "&" + SecurityConstants.TOKEN + "=" + token; + } else { + successUri += "?" + SecurityConstants.TOKEN + "=" + token; + } + } + } + dealProxy(request, successUri); + log.info("last redirectSuccessToUrl:{}", successUri); + return successUri; + } + +} diff --git a/backend/src/main/java/com/senmesh/security/util/UserDisabledCache.java b/backend/src/main/java/com/senmesh/security/util/UserDisabledCache.java new file mode 100644 index 0000000..348d173 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/util/UserDisabledCache.java @@ -0,0 +1,64 @@ +package com.senmesh.security.util; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.frame.redis.redisson.RedissonUtils; + +import lombok.extern.slf4j.Slf4j; + +/** + * 用户禁用/注销登录态黑名单 + * 用户被禁用或注销后,其已发放且未过期的token需要立即失效: + * 写入黑名单标记后,JwtAuthenticationTokenFilter将对命中标记的用户不再建立登录上下文, + * 标记TTL与token有效期一致,token自然过期后标记自动清理 + * + * @author liu on 2026-09-14 + */ +@Slf4j +public class UserDisabledCache { + + private UserDisabledCache() { + } + + private static String key(Long userId) { + return CommonConstants.USER_DISABLED_KEY + userId; + } + + /** + * 标记用户登录态失效 + * + * @param userId 用户id + * @param ttlSeconds 存活秒数(取token有效期) + */ + public static void mark(Long userId, long ttlSeconds) { + try { + RedissonUtils.getClient().getBucket(key(userId)).set(Boolean.TRUE, ttlSeconds, java.util.concurrent.TimeUnit.SECONDS); + } catch (Exception e) { + log.error("标记用户登录态失效失败,userId:{}", userId, e); + } + } + + /** + * 解除标记(启用用户) + */ + public static void unmark(Long userId) { + try { + RedissonUtils.getClient().getBucket(key(userId)).delete(); + } catch (Exception e) { + log.error("解除用户登录态标记失败,userId:{}", userId, e); + } + } + + /** + * 是否被标记(禁用/注销) + * Redis异常时降级放行,由数据库状态在后续链路兜底 + */ + public static boolean isMarked(Long userId) { + try { + return Boolean.TRUE.equals(RedissonUtils.getClient().getBucket(key(userId)).get()); + } catch (Exception e) { + log.warn("查询用户登录态标记异常,降级放行,userId:{}", userId, e); + return false; + } + } + +} diff --git a/backend/src/main/java/com/senmesh/security/util/UserLoginUtils.java b/backend/src/main/java/com/senmesh/security/util/UserLoginUtils.java new file mode 100644 index 0000000..c2061e8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/security/util/UserLoginUtils.java @@ -0,0 +1,51 @@ +package com.senmesh.security.util; + +import org.springframework.stereotype.Component; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.security.dto.SecurityUserDTO; +import com.senmesh.security.mapstruct.UserMapMapper; +import com.senmesh.security.service.IUserSecurityService; +import com.senmesh.usercenter.user.dto.UserDetailQueryDTO; +import com.senmesh.usercenter.user.login.dto.UserDetailDTO; + +/** + * @author sr on 2020-06-15 + */ +@Component +public class UserLoginUtils { + + public static final String SPRING_SECURITY_FORM_ORG_ID_KEY = "orgId"; + + private static IUserSecurityService userService; + + private UserLoginUtils(IUserSecurityService userService) { + UserLoginUtils.userService = userService; + } + + /** + * 根据登录信息获取登录对象 + * + * @param userCloudService + * @param userService + * @param userDetailQueryDto + * @return + * @author sr on 2020-06-15 + */ + public static SecurityUserDTO loadUserToMock(UserDetailQueryDTO userDetailQueryDto) { + AlitaResult result = null; + result = + userService.findUserDetailDTOResult(userDetailQueryDto); + UserDetailDTO userDetailDTO = result.getData(); + Assert.isTrue(result.getSuccess(), "mock失败:" + result.getMsg()); + return UserMapMapper.INSTANCE.dtoToDto(userDetailDTO); + } + + public static AlitaResult findUserDetailDTOResult( + UserDetailQueryDTO userDetailQueryDto) { + return userService.findUserDetailDTOResult(userDetailQueryDto); + } + + +} diff --git a/backend/src/main/java/com/senmesh/sfile/client/MeshSafeClient.java b/backend/src/main/java/com/senmesh/sfile/client/MeshSafeClient.java new file mode 100644 index 0000000..000bcf1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/client/MeshSafeClient.java @@ -0,0 +1,280 @@ +package com.senmesh.sfile.client; + +import cn.hutool.core.io.IoUtil; +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.sfile.config.MeshSafeProperties; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.UUID; + +/** + * MeshSafe 文件安全检测客户端 + *

+ * 对接 MeshSafe /api/v1 接口,认证规范见 MeshSafe《对外接口文档》: + * 请求需携带 HMAC-SHA256 签名(密钥经 HKDF-SHA256 派生),响应需验签, + * 验签失败的检测结论一律拒绝使用。 + */ +@Slf4j +@Component +public class MeshSafeClient { + + private static final String PATH_SCANS = "/api/v1/scans"; + + private static final String INFO_REQUEST_SIGNING = "meshsafe/api/v1/request-signing"; + + private static final String INFO_RESPONSE_SIGNING = "meshsafe/api/v1/response-signing"; + + private static final String HEADER_CLIENT_ID = "X-MS-Client-Id"; + + private static final String HEADER_TIMESTAMP = "X-MS-Timestamp"; + + private static final String HEADER_NONCE = "X-MS-Nonce"; + + private static final String HEADER_BODY_SHA256 = "X-MS-Body-SHA256"; + + private static final String HEADER_SIGNATURE = "X-MS-Signature"; + + private static final String HEADER_RESPONSE_TIMESTAMP = "X-MS-Response-Timestamp"; + + private static final String HEADER_RESPONSE_SIGNATURE = "X-MS-Response-Signature"; + + private static final String MULTIPART_BOUNDARY_PREFIX = "----MeshSafeBoundary"; + + @Autowired + private MeshSafeProperties meshSafeProperties; + + /** + * 提交文件检测(同步模式直接返回结论,异步模式返回受理结果需轮询) + * + * @param fileName 文件名 + * @param fileBytes 文件字节 + * @return 检测结果 + */ + public MeshSafeScanResult scan(String fileName, byte[] fileBytes) { + String boundary = MULTIPART_BOUNDARY_PREFIX + UUID.randomUUID().toString().replace("-", ""); + byte[] body = buildMultipartBody(boundary, fileName, fileBytes); + String contentType = "multipart/form-data; boundary=" + boundary; + + Map headers = signHeaders("POST", PATH_SCANS, body); + headers.put("Content-Type", contentType); + + String responseBody = execute("POST", PATH_SCANS, headers, body); + return parseScanResult(responseBody); + } + + /** + * 查询检测任务结果 + * + * @param taskId MeshSafe 任务ID + * @return 检测结果 + */ + public MeshSafeScanResult getScan(String taskId) { + String path = PATH_SCANS + "/" + taskId; + Map headers = signHeaders("GET", path, new byte[0]); + String responseBody = execute("GET", path, headers, null); + return parseScanResult(responseBody); + } + + /** + * 回写人工复核结论到 MeshSafe + * + * @param taskId MeshSafe 任务ID + * @param decision 复核结论:pass / reject + * @param comment 复核说明 + */ + public void review(String taskId, String decision, String comment) { + String path = PATH_SCANS + "/" + taskId + "/review"; + Map bodyMap = new LinkedHashMap<>(); + bodyMap.put("decision", decision); + bodyMap.put("comment", comment); + byte[] body = JsonUtils.toJsonString(bodyMap).getBytes(StandardCharsets.UTF_8); + + Map headers = signHeaders("POST", path, body); + headers.put("Content-Type", "application/json"); + execute("POST", path, headers, body); + } + + /** + * 发送请求并验签 + * 使用JDK原生HttpURLConnection保证multipart字节与签名计算完全一致 + * (hutool检测到multipart Content-Type时会重建表单体导致body被覆盖) + */ + private String execute(String method, String path, Map headers, byte[] body) { + String url = StringUtils.removeEnd(meshSafeProperties.getBaseUrl(), "/") + path; + byte[] bodyBytes = body == null ? new byte[0] : body; + try { + HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); + conn.setRequestMethod(method); + conn.setConnectTimeout(meshSafeProperties.getTimeoutSeconds() * 1000); + conn.setReadTimeout(meshSafeProperties.getTimeoutSeconds() * 1000); + conn.setDoOutput(true); + for (Map.Entry entry : headers.entrySet()) { + conn.setRequestProperty(entry.getKey(), entry.getValue()); + } + try (OutputStream os = conn.getOutputStream()) { + os.write(bodyBytes); + } + + int status = conn.getResponseCode(); + byte[] responseBytes; + try (InputStream is = status >= 400 ? conn.getErrorStream() : conn.getInputStream()) { + responseBytes = IoUtil.readBytes(is); + } + + String responseTimestamp = conn.getHeaderField(HEADER_RESPONSE_TIMESTAMP); + String responseSignature = conn.getHeaderField(HEADER_RESPONSE_SIGNATURE); + verifyResponseSignature(responseTimestamp, responseSignature, responseBytes); + + String responseBody = new String(responseBytes, StandardCharsets.UTF_8); + if (status < 200 || status >= 300) { + log.error("MeshSafe请求失败, method: {}, path: {}, status: {}, response: {}", + method, path, status, responseBody); + throw new BusinessException("MeshSafe服务返回异常: HTTP " + status); + } + return responseBody; + } catch (BusinessException e) { + throw e; + } catch (Exception e) { + log.error("MeshSafe请求异常, method: {}, path: {}", method, path, e); + throw new BusinessException("MeshSafe服务请求失败: " + e.getMessage(), e); + } + } + + /** + * 校验响应签名,验签失败拒绝使用该结论 + */ + private void verifyResponseSignature(String timestamp, String signature, byte[] responseBytes) { + if (StringUtils.isBlank(timestamp) || StringUtils.isBlank(signature)) { + throw new BusinessException("MeshSafe响应缺少签名头,拒绝使用该检测结论"); + } + byte[] responseKey = deriveKey(INFO_RESPONSE_SIGNING); + String payload = DigestUtils.sha256Hex(responseBytes) + timestamp; + String expected = hmacHex(responseKey, payload); + if (!expected.equalsIgnoreCase(signature)) { + throw new BusinessException("MeshSafe响应签名校验失败,拒绝使用该检测结论"); + } + } + + private MeshSafeScanResult parseScanResult(String responseBody) { + MeshSafeScanResult result = JsonUtils.toObject(responseBody, MeshSafeScanResult.class); + if (result == null || StringUtils.isBlank(result.getTaskId())) { + throw new BusinessException("MeshSafe响应解析失败: " + responseBody); + } + result.setRawJson(responseBody); + return result; + } + + /** + * 构造请求签名头 + * 待签名串: METHOD \n PATH \n CANONICAL_QUERY \n BODY_SHA256 \n TIMESTAMP \n NONCE \n CLIENT_ID + */ + private Map signHeaders(String method, String path, byte[] body) { + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + String nonce = UUID.randomUUID().toString().replace("-", ""); + String bodySha256 = DigestUtils.sha256Hex(body); + + String payload = String.join("\n", + method.toUpperCase(), path, "", bodySha256, timestamp, nonce, + meshSafeProperties.getClientId()); + + String signature = hmacHex(deriveKey(INFO_REQUEST_SIGNING), payload); + + Map headers = new LinkedHashMap<>(); + headers.put(HEADER_CLIENT_ID, meshSafeProperties.getClientId()); + headers.put(HEADER_TIMESTAMP, timestamp); + headers.put(HEADER_NONCE, nonce); + headers.put(HEADER_BODY_SHA256, bodySha256); + headers.put(HEADER_SIGNATURE, signature); + return headers; + } + + /** + * HKDF-SHA256 密钥派生(RFC 5869, extract + expand 两步) + */ + private byte[] deriveKey(String info) { + try { + byte[] ikm = meshSafeProperties.getSecret().getBytes(StandardCharsets.UTF_8); + byte[] salt = meshSafeProperties.getClientId().getBytes(StandardCharsets.UTF_8); + + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init(new SecretKeySpec(salt, "HmacSHA256")); + byte[] prk = mac.doFinal(ikm); + + byte[] okm = new byte[32]; + byte[] block = new byte[0]; + int offset = 0; + byte counter = 1; + while (offset < okm.length) { + mac.init(new SecretKeySpec(prk, "HmacSHA256")); + mac.update(block); + mac.update(info.getBytes(StandardCharsets.UTF_8)); + mac.update(new byte[]{counter}); + block = mac.doFinal(); + int n = Math.min(block.length, okm.length - offset); + System.arraycopy(block, 0, okm, offset, n); + offset += n; + counter++; + } + return okm; + } catch (Exception e) { + throw new BusinessException("MeshSafe签名密钥派生失败", e); + } + } + + private String hmacHex(byte[] key, String message) { + try { + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init(new SecretKeySpec(key, "HmacSHA256")); + return hex(mac.doFinal(message.getBytes(StandardCharsets.UTF_8))); + } catch (Exception e) { + throw new BusinessException("MeshSafe签名计算失败", e); + } + } + + private String hex(byte[] bytes) { + StringBuilder sb = new StringBuilder(bytes.length * 2); + for (byte b : bytes) { + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } + + /** + * 手工构造 multipart 请求体(签名需基于最终字节计算,不能用HTTP库自动构造) + */ + private byte[] buildMultipartBody(String boundary, String fileName, byte[] fileBytes) { + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + String channel = StringUtils.defaultIfBlank(meshSafeProperties.getChannel(), "default"); + + bos.write(("--" + boundary + "\r\n" + + "Content-Disposition: form-data; name=\"channel\"\r\n\r\n" + + channel + "\r\n").getBytes(StandardCharsets.UTF_8)); + + String safeName = fileName.replace("\"", ""); + bos.write(("--" + boundary + "\r\n" + + "Content-Disposition: form-data; name=\"file\"; filename=\"" + safeName + "\"\r\n" + + "Content-Type: application/octet-stream\r\n\r\n").getBytes(StandardCharsets.UTF_8)); + bos.write(fileBytes); + bos.write(("\r\n--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8)); + return bos.toByteArray(); + } catch (Exception e) { + throw new BusinessException("构造MeshSafe检测请求失败", e); + } + } +} diff --git a/backend/src/main/java/com/senmesh/sfile/client/MeshSafeScanResult.java b/backend/src/main/java/com/senmesh/sfile/client/MeshSafeScanResult.java new file mode 100644 index 0000000..108a352 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/client/MeshSafeScanResult.java @@ -0,0 +1,47 @@ +package com.senmesh.sfile.client; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * MeshSafe 检测结果 + *

+ * 字段说明见 MeshSafe《对外接口文档》§5,action 是调用方唯一决策依据。 + * MeshSafe 返回 snake_case 字段名。 + */ +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class MeshSafeScanResult { + + /** + * 任务标识,用于后续查询与审计追溯 + */ + @JsonProperty("task_id") + private String taskId; + + /** + * 处置动作:pass / manual_review / reject / pending + */ + private String action; + + /** + * 人可读的判定理由,可直接展示给用户 + */ + private String reason; + + /** + * 任务状态:pending / running / completed / failed + */ + private String status; + + /** + * 提示信息(异步受理时返回) + */ + private String message; + + /** + * 原始响应JSON + */ + private String rawJson; +} diff --git a/backend/src/main/java/com/senmesh/sfile/config/MeshSafeProperties.java b/backend/src/main/java/com/senmesh/sfile/config/MeshSafeProperties.java new file mode 100644 index 0000000..a9cf8fc --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/config/MeshSafeProperties.java @@ -0,0 +1,61 @@ +package com.senmesh.sfile.config; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * MeshSafe 文件安全检测对接配置 + */ +@ConfigurationProperties(prefix = "meshsafe") +@Component +@Data +@NoArgsConstructor +public class MeshSafeProperties { + + /** + * 是否开启文件安全检测(关闭时上传/解包不提交检测,分享传输不校验) + */ + private Boolean enabled = false; + + /** + * MeshSafe 服务地址,如 https://meshsafe.internal + */ + private String baseUrl; + + /** + * 调用方标识(MeshSafe 申请的 client_id) + */ + private String clientId; + + /** + * 调用方密钥(MeshSafe 申请的 secret,用于 HMAC 签名) + */ + private String secret; + + /** + * 业务通道标识,仅用于 MeshSafe 日志追溯 + */ + private String channel = "default"; + + /** + * 请求超时时间(秒) + */ + private Integer timeoutSeconds = 120; + + /** + * 检测服务异常时的降级策略:true-放行(仅标记检测失败) / false-阻断 + */ + private Boolean failOpen = true; + + /** + * 检测中的记录超过该分钟数仍未拿到结论则标记为检测失败(防死轮询) + */ + private Integer pollTimeoutMinutes = 60; + + /** + * 人工复核是否尽力回写 MeshSafe(失败仅告警,不影响本地生效) + */ + private Boolean reviewSyncToMeshSafe = true; +} diff --git a/backend/src/main/java/com/senmesh/sfile/constant/FileLocationEnum.java b/backend/src/main/java/com/senmesh/sfile/constant/FileLocationEnum.java new file mode 100644 index 0000000..d739e15 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/constant/FileLocationEnum.java @@ -0,0 +1,59 @@ +package com.senmesh.sfile.constant; + +/** + * 文件位置枚举 + */ +public enum FileLocationEnum { + + /** + * 内网 + */ + INTERNAL("1", "内网"), + + /** + * 外网 + */ + EXTERNAL("2", "外网"); + + private final String location; + private final String desc; + + FileLocationEnum(String location, String desc) { + this.location = location; + this.desc = desc; + } + + public String getLocation() { + return location; + } + + public String getDesc() { + return desc; + } + + /** + * 根据位置获取枚举 + * + * @param location 位置 + * @return FileLocationEnum + */ + public static FileLocationEnum getByLocation(String location) { + for (FileLocationEnum fileLocationEnum : FileLocationEnum.values()) { + if (fileLocationEnum.getLocation().equals(location)) { + return fileLocationEnum; + } + } + return null; + } + + /** + * 判断是否为内网 + * + * @param location 位置 + * @return true-内网,false-外网 + */ + public static boolean isInternal(String location) { + return INTERNAL.getLocation().equals(location); + } +} + diff --git a/backend/src/main/java/com/senmesh/sfile/constant/FileRecordTypeEnum.java b/backend/src/main/java/com/senmesh/sfile/constant/FileRecordTypeEnum.java new file mode 100644 index 0000000..645c999 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/constant/FileRecordTypeEnum.java @@ -0,0 +1,53 @@ +package com.senmesh.sfile.constant; + +/** + * 文件记录类型枚举(按手机号查询上传/发送/接收记录) + */ +public enum FileRecordTypeEnum { + + /** + * 上传记录 + */ + UPLOAD(1, "上传记录"), + + /** + * 发送记录(本端发起文件传输) + */ + SEND(2, "发送记录"), + + /** + * 接收记录(本端接收文件传输) + */ + RECEIVE(3, "接收记录"); + + private final Integer type; + private final String desc; + + FileRecordTypeEnum(Integer type, String desc) { + this.type = type; + this.desc = desc; + } + + public Integer getType() { + return type; + } + + public String getDesc() { + return desc; + } + + /** + * 根据类型获取枚举 + * + * @param type 类型 + * @return FileRecordTypeEnum + */ + public static FileRecordTypeEnum getByType(Integer type) { + for (FileRecordTypeEnum recordTypeEnum : FileRecordTypeEnum.values()) { + if (recordTypeEnum.getType().equals(type)) { + return recordTypeEnum; + } + } + return null; + } +} diff --git a/backend/src/main/java/com/senmesh/sfile/constant/FileStatusEnum.java b/backend/src/main/java/com/senmesh/sfile/constant/FileStatusEnum.java new file mode 100644 index 0000000..cab6c10 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/constant/FileStatusEnum.java @@ -0,0 +1,79 @@ +package com.senmesh.sfile.constant; + +/** + * 文件状态枚举 + */ +public enum FileStatusEnum { + + /** + * 正常 + */ + NORMAL("1", "正常"), + + /** + * 失效 + */ + INVALID("2", "失效"), + + /** + * 解析中 + */ + PARSING("11", "解析中"), + + /** + * 待审核 + */ + PENDING_REVIEW("12", "待审核"), + + /** + * 传输中 + */ + TRANSFERRING("13", "传输中"), + + /** + * 失败 + */ + FAILED("14", "失败"); + + private final String status; + private final String desc; + + FileStatusEnum(String status, String desc) { + this.status = status; + this.desc = desc; + } + + public String getStatus() { + return status; + } + + public String getDesc() { + return desc; + } + + /** + * 根据状态获取枚举 + * + * @param status 状态 + * @return FileStatusEnum + */ + public static FileStatusEnum getByStatus(String status) { + for (FileStatusEnum fileStatusEnum : FileStatusEnum.values()) { + if (fileStatusEnum.getStatus().equals(status)) { + return fileStatusEnum; + } + } + return null; + } + + /** + * 判断是否为正常状态 + * + * @param status 状态 + * @return true-正常,false-不正常 + */ + public static boolean isNormal(String status) { + return NORMAL.getStatus().equals(status); + } +} + diff --git a/backend/src/main/java/com/senmesh/sfile/constant/FileTypeEnum.java b/backend/src/main/java/com/senmesh/sfile/constant/FileTypeEnum.java new file mode 100644 index 0000000..d970f70 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/constant/FileTypeEnum.java @@ -0,0 +1,69 @@ +package com.senmesh.sfile.constant; + +/** + * 文件类型枚举 + */ +public enum FileTypeEnum { + + /** + * 文件 + */ + FILE("1", "文件"), + + /** + * 文件夹 + */ + FOLDER("2", "文件夹"); + + private final String type; + private final String desc; + + FileTypeEnum(String type, String desc) { + this.type = type; + this.desc = desc; + } + + public String getType() { + return type; + } + + public String getDesc() { + return desc; + } + + /** + * 根据类型获取枚举 + * + * @param type 类型 + * @return FileTypeEnum + */ + public static FileTypeEnum getByType(String type) { + for (FileTypeEnum fileTypeEnum : FileTypeEnum.values()) { + if (fileTypeEnum.getType().equals(type)) { + return fileTypeEnum; + } + } + return null; + } + + /** + * 判断是否为文件 + * + * @param type 类型 + * @return true-是文件,false-不是文件 + */ + public static boolean isFile(String type) { + return FILE.getType().equals(type); + } + + /** + * 判断是否为文件夹 + * + * @param type 类型 + * @return true-是文件夹,false-不是文件夹 + */ + public static boolean isFolder(String type) { + return FOLDER.getType().equals(type); + } +} + diff --git a/backend/src/main/java/com/senmesh/sfile/constant/RiskLevelEnum.java b/backend/src/main/java/com/senmesh/sfile/constant/RiskLevelEnum.java new file mode 100644 index 0000000..4267fd9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/constant/RiskLevelEnum.java @@ -0,0 +1,100 @@ +package com.senmesh.sfile.constant; + +import com.baomidou.mybatisplus.annotation.EnumValue; +import com.senmesh.mybatis.handle.BaseEnum; + +/** + * 风险等级枚举 + */ +public enum RiskLevelEnum implements BaseEnum { + + /** + * 重度风险 + */ + SEVERE("1", "重度"), + + /** + * 中度风险 + */ + MODERATE("2", "中度"), + + /** + * 轻度风险 + */ + MILD("3", "轻度"); + + /** + * 风险等级 + */ + @EnumValue + private final String level; + + /** + * 等级描述 + */ + private final String desc; + + RiskLevelEnum(String level, String desc) { + this.level = level; + this.desc = desc; + } + + public String getLevel() { + return level; + } + + public String getDesc() { + return desc; + } + + @Override + public String getValue() { + return this.level; + } + + /** + * 根据等级获取枚举 + * + * @param level 等级 + * @return RiskLevelEnum + */ + public static RiskLevelEnum getByLevel(String level) { + for (RiskLevelEnum riskLevelEnum : RiskLevelEnum.values()) { + if (riskLevelEnum.getLevel().equals(level)) { + return riskLevelEnum; + } + } + return null; + } + + /** + * 判断是否为重度风险 + * + * @param level 等级 + * @return true-重度,false-非重度 + */ + public static boolean isSevere(String level) { + return SEVERE.getLevel().equals(level); + } + + /** + * 判断是否为中度风险 + * + * @param level 等级 + * @return true-中度,false-非中度 + */ + public static boolean isModerate(String level) { + return MODERATE.getLevel().equals(level); + } + + /** + * 判断是否为轻度风险 + * + * @param level 等级 + * @return true-轻度,false-非轻度 + */ + public static boolean isMild(String level) { + return MILD.getLevel().equals(level); + } +} + diff --git a/backend/src/main/java/com/senmesh/sfile/constant/RootTypeEnum.java b/backend/src/main/java/com/senmesh/sfile/constant/RootTypeEnum.java new file mode 100644 index 0000000..02fb79d --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/constant/RootTypeEnum.java @@ -0,0 +1,69 @@ +package com.senmesh.sfile.constant; + +/** + * 根类型枚举 + */ +public enum RootTypeEnum { + + /** + * 普通 + */ + NORMAL("1", "普通"), + + /** + * 内穿外 + */ + INTERNAL_TO_EXTERNAL("2", "内穿外"), + + /** + * 外传内 + */ + EXTERNAL_TO_INTERNAL("3", "外传内"), + + /** + * 分享 + */ + SHARE("4", "分享"); + + private final String type; + private final String desc; + + RootTypeEnum(String type, String desc) { + this.type = type; + this.desc = desc; + } + + public String getType() { + return type; + } + + public String getDesc() { + return desc; + } + + /** + * 根据类型获取枚举 + * + * @param type 类型 + * @return RootTypeEnum + */ + public static RootTypeEnum getByType(String type) { + for (RootTypeEnum rootTypeEnum : RootTypeEnum.values()) { + if (rootTypeEnum.getType().equals(type)) { + return rootTypeEnum; + } + } + return null; + } + + /** + * 判断是否为普通类型 + * + * @param type 类型 + * @return true-是普通类型,false-不是普通类型 + */ + public static boolean isNormal(String type) { + return NORMAL.getType().equals(type); + } +} + diff --git a/backend/src/main/java/com/senmesh/sfile/constant/SecurityScanStatusEnum.java b/backend/src/main/java/com/senmesh/sfile/constant/SecurityScanStatusEnum.java new file mode 100644 index 0000000..be0ae7c --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/constant/SecurityScanStatusEnum.java @@ -0,0 +1,64 @@ +package com.senmesh.sfile.constant; + +/** + * 文件安全检测状态枚举 + */ +public enum SecurityScanStatusEnum { + + /** + * 检测中 + */ + SCANNING("1", "检测中"), + + /** + * 检测通过 + */ + PASSED("2", "通过"), + + /** + * 检测不通过(禁止分享传输) + */ + REJECTED("3", "不通过"), + + /** + * 检测失败(MeshSafe异常/超时) + */ + FAILED("4", "检测失败"); + + private final String status; + + private final String desc; + + SecurityScanStatusEnum(String status, String desc) { + this.status = status; + this.desc = desc; + } + + public String getStatus() { + return status; + } + + public String getDesc() { + return desc; + } + + /** + * 判断是否为不通过状态 + * + * @param status 检测状态 + * @return true-不通过,false-非不通过 + */ + public static boolean isRejected(String status) { + return REJECTED.getStatus().equals(status); + } + + /** + * 判断是否为检测中状态 + * + * @param status 检测状态 + * @return true-检测中,false-非检测中 + */ + public static boolean isScanning(String status) { + return SCANNING.getStatus().equals(status); + } +} diff --git a/backend/src/main/java/com/senmesh/sfile/controller/DifyController.java b/backend/src/main/java/com/senmesh/sfile/controller/DifyController.java new file mode 100644 index 0000000..0e3ff7c --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/controller/DifyController.java @@ -0,0 +1,32 @@ +package com.senmesh.sfile.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.sdk.dify.dto.DifyChatRequest; +import com.senmesh.sdk.dify.dto.DifyChatResponse; +import com.senmesh.sdk.dify.dto.DifyFileUploadRequest; +import com.senmesh.sdk.dify.dto.DifyFileUploadResponse; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.http.MediaType; +import org.springframework.validation.annotation.Validated; +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.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +/** + * Dify接口Controller + * + * @author sr + */ +@RestController +@RequestMapping("/dify") +@Api(tags = "Dify接口") +public class DifyController { + +} + diff --git a/backend/src/main/java/com/senmesh/sfile/controller/FileCategoryController.java b/backend/src/main/java/com/senmesh/sfile/controller/FileCategoryController.java new file mode 100644 index 0000000..37fa71a --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/controller/FileCategoryController.java @@ -0,0 +1,68 @@ +package com.senmesh.sfile.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.sfile.dto.FileCategoryCreateDTO; +import com.senmesh.sfile.dto.FileCategoryDTO; +import com.senmesh.sfile.dto.FileCategoryModifyDTO; +import com.senmesh.sfile.dto.FileCategoryQueryDTO; +import com.senmesh.sfile.service.FileCategoryService; +import com.senmesh.tkmybatis.pojo.Page; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 文件种类Controller + */ +@Api(tags = "文件种类") +@RestController +@RequestMapping("file_category") +public class FileCategoryController { + + @Autowired + private FileCategoryService fileCategoryService; + + @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create(@Validated @RequestBody FileCategoryCreateDTO createDTO) { + return AlitaResult.success(fileCategoryService.create(createDTO)); + } + + @PostMapping("/modify") + @ApiOperation("修改") + public AlitaResult modify(@Validated @RequestBody FileCategoryModifyDTO modifyDTO) { + fileCategoryService.modify(modifyDTO); + return AlitaResult.success(true); + } + + @DeleteMapping("/remove/{id}") + @ApiOperation("删除") + public AlitaResult remove(@PathVariable Long id) { + fileCategoryService.remove(id); + return AlitaResult.success(true); + } + + @GetMapping("/find") + @ApiOperation("查询") + public AlitaResult find(FileCategoryQueryDTO queryDTO) { + return AlitaResult.success(fileCategoryService.find(queryDTO)); + } + + @GetMapping("/list") + @ApiOperation("列表查询") + public AlitaResult> list(FileCategoryQueryDTO queryDTO) { + return AlitaResult.success(fileCategoryService.list(queryDTO)); + } + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(FileCategoryQueryDTO queryDTO) { + fileCategoryService.page(queryDTO); + return AlitaResult.success(queryDTO.getPageResult()); + } +} + diff --git a/backend/src/main/java/com/senmesh/sfile/controller/FileRiskController.java b/backend/src/main/java/com/senmesh/sfile/controller/FileRiskController.java new file mode 100644 index 0000000..ca8aa5a --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/controller/FileRiskController.java @@ -0,0 +1,97 @@ +package com.senmesh.sfile.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.sfile.dto.FileRiskCreateDTO; +import com.senmesh.sfile.dto.FileRiskDTO; +import com.senmesh.sfile.dto.FileRiskQueryDTO; +import com.senmesh.sfile.service.FileRiskService; +import com.senmesh.tkmybatis.pojo.Page; + +import javax.validation.Valid; +import java.util.List; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.beans.factory.annotation.Autowired; +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.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * 文件风险Controller + */ +@RestController +@Api(tags = "文件风险") +public class FileRiskController { + + @Autowired + private FileRiskService fileRiskService; + + @PostMapping("/file_risk/create") + @ApiOperation("创建文件风险") + public AlitaResult create(@Valid @RequestBody FileRiskCreateDTO createDTO) { + FileRiskDTO fileRiskDTO = fileRiskService.create(createDTO); + return AlitaResult.success(fileRiskDTO); + } + + @GetMapping("/file_risk/rule") + @ApiOperation("获取风险规则") + public AlitaResult getRiskRule() { + return AlitaResult.success(fileRiskService.getRiskRule(UserContextHolder.getExistLoginOrgId())); + } + + @PostMapping("/file_risk/rule") + @ApiOperation("保存风险规则") + public AlitaResult saveRiskRule(@RequestBody String riskRule) { + fileRiskService.saveRiskRule(riskRule); + return AlitaResult.success(); + } + + @GetMapping("/file_risk/min_audit_risk_level") + @ApiOperation("获取最低审核风险等级") + public AlitaResult getMinAuditRiskLevel() { + return AlitaResult.success(fileRiskService.getMinAuditRiskLevel(UserContextHolder.getExistLoginOrgId())); + } + + @PostMapping("/file_risk/min_audit_risk_level") + @ApiOperation("保存最低审核风险等级") + public AlitaResult saveMinAuditRiskLevel(@RequestBody String minAuditRiskLevel) { + fileRiskService.saveMinAuditRiskLevel(minAuditRiskLevel); + return AlitaResult.success(); + } + + @GetMapping("/file_risk/scan") + @ApiOperation("扫描文件风险") + public AlitaResult scanFileRisk( + @ApiParam(value = "文件编码", required = true) @RequestParam String fileCode) { + FileRiskDTO fileRiskDTO = fileRiskService.scanFileRisk(fileCode); + return AlitaResult.success(fileRiskDTO); + } + + @GetMapping("/file_risk/dify_risk_rule") + @ApiOperation("获取Dify风险规则") + public AlitaResult getDifyRiskRule( + @ApiParam(value = "文件编码", required = true) @RequestParam String fileCode) { + String answer = fileRiskService.getDifyRiskRule(fileCode); + return AlitaResult.success(answer); + } + + @GetMapping("/file_risk/list") + @ApiOperation("列表查询文件风险") + public AlitaResult> list(FileRiskQueryDTO queryDTO) { + List list = fileRiskService.list(queryDTO); + return AlitaResult.success(list); + } + + @GetMapping("/file_risk/page") + @ApiOperation("分页查询文件风险") + public AlitaResult> page(FileRiskQueryDTO queryDTO) { + fileRiskService.page(queryDTO); + return AlitaResult.success(queryDTO.getPageResult()); + } + +} + diff --git a/backend/src/main/java/com/senmesh/sfile/controller/FileSecurityController.java b/backend/src/main/java/com/senmesh/sfile/controller/FileSecurityController.java new file mode 100644 index 0000000..0c5c76b --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/controller/FileSecurityController.java @@ -0,0 +1,69 @@ +package com.senmesh.sfile.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.sfile.config.MeshSafeProperties; +import com.senmesh.sfile.dto.FileSecurityDTO; +import com.senmesh.sfile.dto.FileSecurityReviewDTO; +import com.senmesh.sfile.dto.FileSecurityShareCheckDTO; +import com.senmesh.sfile.service.FileSecurityService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +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.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * 文件安全检测Controller + */ +@Api(tags = "文件安全检测") +@RestController +@RequestMapping("file_security") +public class FileSecurityController { + + @Autowired + private FileSecurityService fileSecurityService; + + @Autowired + private MeshSafeProperties meshSafeProperties; + + @GetMapping("/enabled") + @ApiOperation("查询安全检测开关(meshsafe.enabled,前端据此展示/隐藏检测列)") + public AlitaResult enabled() { + return AlitaResult.success(Boolean.TRUE.equals(meshSafeProperties.getEnabled())); + } + + @GetMapping("/detail") + @ApiOperation("查询文件最新检测结果") + public AlitaResult detail( + @ApiParam(value = "文件编码", required = true) @RequestParam String fileCode) { + return AlitaResult.success(fileSecurityService.latest(fileCode)); + } + + @GetMapping("/share_check") + @ApiOperation("分享/传输预检:统计文件及子文件的检测拦截情况") + public AlitaResult shareCheck( + @ApiParam(value = "用户文件ID", required = true) @RequestParam Long userFileId) { + return AlitaResult.success(fileSecurityService.shareCheck(userFileId)); + } + + @PostMapping("/review") + @ApiOperation("人工复核修改检测结果(超管/机构管理员)") + public AlitaResult review( + @Validated @RequestBody FileSecurityReviewDTO reviewDTO) { + return AlitaResult.success(fileSecurityService.review(reviewDTO)); + } + + @PostMapping("/rescan") + @ApiOperation("重新提交安全检测(超管/机构管理员)") + public AlitaResult rescan( + @ApiParam(value = "文件编码", required = true) @RequestParam String fileCode) { + fileSecurityService.rescan(fileCode); + return AlitaResult.success(true); + } +} diff --git a/backend/src/main/java/com/senmesh/sfile/controller/NormalUserFileController.java b/backend/src/main/java/com/senmesh/sfile/controller/NormalUserFileController.java new file mode 100644 index 0000000..11f474f --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/controller/NormalUserFileController.java @@ -0,0 +1,65 @@ +package com.senmesh.sfile.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.sfile.constant.FileStatusEnum; +import com.senmesh.sfile.constant.RootTypeEnum; +import com.senmesh.sfile.dto.UserFileCreateDTO; +import com.senmesh.sfile.dto.UserFileDTO; +import com.senmesh.sfile.dto.UserFileModifyDTO; +import com.senmesh.sfile.dto.UserFileModifyStatusDTO; +import com.senmesh.sfile.dto.UserFileQueryDTO; +import com.senmesh.sfile.service.NormalUserFileService; +import com.senmesh.sfile.service.UserFileService; +import com.senmesh.tkmybatis.pojo.Page; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 普通用户文件Controller + */ +@RestController +@RequestMapping("normal_user_file") +@Api(tags = "普通用户文件") +public class NormalUserFileController { + + @Autowired + private NormalUserFileService normalUserFileService; + + @Autowired + private UserFileService userFileService; + + @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create(@Validated @RequestBody UserFileCreateDTO createDTO) { + return AlitaResult.success(normalUserFileService.create(createDTO)); + } + + + @PutMapping("/recover/{id}") + @ApiOperation("恢复") + public AlitaResult recover(@PathVariable Long id) { + UserFileModifyStatusDTO modifyStatusDTO = UserFileModifyStatusDTO.builder() + .id(id) + .oldStatus(FileStatusEnum.INVALID.getStatus()) + .newStatus(FileStatusEnum.NORMAL.getStatus()) + .build(); + userFileService.modifyStatus(modifyStatusDTO); + return AlitaResult.success(true); + } + + +} + diff --git a/backend/src/main/java/com/senmesh/sfile/controller/ShareUserFileController.java b/backend/src/main/java/com/senmesh/sfile/controller/ShareUserFileController.java new file mode 100644 index 0000000..ea4d53b --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/controller/ShareUserFileController.java @@ -0,0 +1,45 @@ +package com.senmesh.sfile.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.sfile.dto.ShareUserFileCreateDTO; +import com.senmesh.sfile.dto.UserFileDTO; +import com.senmesh.sfile.service.ShareUserFileService; +import com.senmesh.sfile.service.UserFileService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * 分享用户文件Controller + */ +@RestController +@Api(tags = "分享用户文件") +public class ShareUserFileController { + + @Autowired + private ShareUserFileService shareUserFileService; + + @Autowired + private UserFileService userFileService; + + @PostMapping("share_user_file/create") + @ApiOperation("创建") + public AlitaResult create(@Validated @RequestBody ShareUserFileCreateDTO createDTO) { + return AlitaResult.success(shareUserFileService.create(createDTO)); + } + + @GetMapping("share_user_file/{id}") + @ApiOperation("匿名查询分享文件") + public AlitaResult> list(@PathVariable Long id, @RequestParam String accessCode, @RequestParam(required = false) Long parentId) { + return AlitaResult.success(shareUserFileService.list(id, accessCode, parentId)); + } + +} diff --git a/backend/src/main/java/com/senmesh/sfile/controller/TransferUserFileController.java b/backend/src/main/java/com/senmesh/sfile/controller/TransferUserFileController.java new file mode 100644 index 0000000..82be6a0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/controller/TransferUserFileController.java @@ -0,0 +1,32 @@ +package com.senmesh.sfile.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.sfile.dto.TransferUserFileCreateDTO; +import com.senmesh.sfile.service.TransferUserFileService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +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; + +/** + * 传输用户文件Controller + */ +@RestController +@RequestMapping("transfer_user_file") +@Api(tags = "传输用户文件") +public class TransferUserFileController { + + @Autowired + private TransferUserFileService transferUserFileService; + + @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create(@Validated @RequestBody TransferUserFileCreateDTO createDTO) { + return AlitaResult.success(transferUserFileService.create(createDTO)); + } +} + diff --git a/backend/src/main/java/com/senmesh/sfile/controller/UploadConfigController.java b/backend/src/main/java/com/senmesh/sfile/controller/UploadConfigController.java new file mode 100644 index 0000000..384f371 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/controller/UploadConfigController.java @@ -0,0 +1,52 @@ +package com.senmesh.sfile.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.sfile.dto.UploadConfigDTO; +import com.senmesh.sfile.dto.UploadConfigModifyDTO; +import com.senmesh.sfile.service.UploadConfigService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +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.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * 机构上传配置Controller + * 机构管理员可配置本机构允许上传的文件类型/大小等,配置对网盘上传生效 + * + * @author liu on 2026-09-14 + */ +@Api(tags = "机构上传配置") +@RestController +@RequestMapping("upload_config") +public class UploadConfigController { + + @Autowired + private UploadConfigService uploadConfigService; + + @GetMapping("/info") + @ApiOperation("查询当前登录机构的上传配置(未配置返回默认策略)") + public AlitaResult info() { + return AlitaResult.success(uploadConfigService.info()); + } + + @PostMapping("/modify") + @ApiOperation("保存当前登录机构的上传配置(机构管理员/平台超管)") + public AlitaResult modify(@Validated @RequestBody UploadConfigModifyDTO modifyDTO) { + return AlitaResult.success(uploadConfigService.modify(modifyDTO)); + } + + @GetMapping("/check") + @ApiOperation("上传预检(按文件名校验当前机构配置,不通过返回业务异常)") + public AlitaResult check(@RequestParam("fileName") String fileName, + @RequestParam(value = "fileSize", required = false) Long fileSize) { + uploadConfigService.check(fileName, fileSize); + return AlitaResult.success(true); + } + +} diff --git a/backend/src/main/java/com/senmesh/sfile/controller/UserFileController.java b/backend/src/main/java/com/senmesh/sfile/controller/UserFileController.java new file mode 100644 index 0000000..de23afc --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/controller/UserFileController.java @@ -0,0 +1,129 @@ +package com.senmesh.sfile.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.sfile.constant.FileStatusEnum; +import com.senmesh.sfile.dto.UserFileCreateDTO; +import com.senmesh.sfile.dto.UserFileDTO; +import com.senmesh.sfile.dto.UserFileModifyDTO; +import com.senmesh.sfile.dto.UserFileModifyStatusDTO; +import com.senmesh.sfile.dto.UserFileQueryDTO; +import com.senmesh.sfile.dto.UserFileRecordDTO; +import com.senmesh.sfile.dto.UserFileRecordQueryDTO; +import com.senmesh.sfile.dto.UserFileStatisticsDTO; +import com.senmesh.sfile.service.UserFileService; +import com.senmesh.tkmybatis.pojo.Page; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 用户文件Controller + */ +@Api(tags = "用户文件") +@RestController +@RequestMapping("user_file") +public class UserFileController { + + @Autowired + private UserFileService userFileService; + +/* @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create(@Validated @RequestBody UserFileCreateDTO createDTO) { + return AlitaResult.success(userFileService.create(createDTO)); + }*/ + + @PostMapping("/modify") + @ApiOperation("修改") + public AlitaResult modify(@Validated @RequestBody UserFileModifyDTO modifyDTO) { + modifyDTO.setUserId(UserContextHolder.getExistLoginUserId()); + userFileService.modify(modifyDTO); + return AlitaResult.success(true); + } + + @DeleteMapping("/remove/{id}") + @ApiOperation("删除") + public AlitaResult remove(@PathVariable Long id) { + Long userId = UserContextHolder.getExistLoginUserId(); + userFileService.remove(id, userId); + return AlitaResult.success(true); + } + + @DeleteMapping("/remove_by_ids") + @ApiOperation("批量删除") + public AlitaResult removeByIds(@RequestBody List ids) { + Long userId = UserContextHolder.getExistLoginUserId(); + userFileService.removeByIds(ids, userId); + return AlitaResult.success(true); + } + + @PutMapping("/invalid/{id}") + @ApiOperation("失效") + public AlitaResult invalid(@PathVariable Long id) { + UserFileModifyStatusDTO modifyStatusDTO = UserFileModifyStatusDTO.builder() + .id(id) + .oldStatus(FileStatusEnum.NORMAL.getStatus()) + .newStatus(FileStatusEnum.INVALID.getStatus()) + .build(); + userFileService.modifyStatus(modifyStatusDTO); + return AlitaResult.success(true); + } + + @PutMapping("/modify_status") + @ApiOperation("修改状态") + public AlitaResult modifyStatus(@Validated @RequestBody UserFileModifyStatusDTO modifyStatusDTO) { + userFileService.modifyStatus(modifyStatusDTO); + return AlitaResult.success(true); + } + + @GetMapping("/find") + @ApiOperation("查询") + public AlitaResult find(UserFileQueryDTO queryDTO) { + queryDTO.setUserId(UserContextHolder.getExistLoginUserId()); + return AlitaResult.success(userFileService.find(queryDTO)); + } + + @GetMapping("/list") + @ApiOperation("列表查询") + public AlitaResult> list(UserFileQueryDTO queryDTO) { + queryDTO.setUserId(UserContextHolder.getExistLoginUserId()); + return AlitaResult.success(userFileService.list(queryDTO)); + } + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(UserFileQueryDTO queryDTO) { + queryDTO.setUserId(UserContextHolder.getExistLoginUserId()); + userFileService.page(queryDTO); + return AlitaResult.success(queryDTO.getPageResult()); + } + + @GetMapping("/page_super") + @ApiOperation("分页查询(超级管理员)") + public AlitaResult> pageSuper(UserFileQueryDTO queryDTO) { + userFileService.page(queryDTO); + return AlitaResult.success(queryDTO.getPageResult()); + } + + @GetMapping("/statistics/category") + @ApiOperation("按文件种类统计") + public AlitaResult> statisticsByCategory(UserFileQueryDTO queryDTO) { + queryDTO.setUserId(UserContextHolder.getExistLoginUserId()); + return AlitaResult.success(userFileService.statisticsByCategory(queryDTO)); + } + + @GetMapping("/record/page_by_phone") + @ApiOperation("按手机号分页查询文件记录(上传/发送/接收,系统管理员)") + public AlitaResult> pageRecordByPhone(UserFileRecordQueryDTO queryDTO) { + userFileService.pageRecordByPhone(queryDTO); + return AlitaResult.success(queryDTO.getPageResult()); + } + + +} + diff --git a/backend/src/main/java/com/senmesh/sfile/controller/UserSpaceController.java b/backend/src/main/java/com/senmesh/sfile/controller/UserSpaceController.java new file mode 100644 index 0000000..561f08a --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/controller/UserSpaceController.java @@ -0,0 +1,60 @@ +package com.senmesh.sfile.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.sfile.dto.UserSpaceCreateDTO; +import com.senmesh.sfile.dto.UserSpaceDTO; +import com.senmesh.sfile.dto.UserSpaceModifyDTO; +import com.senmesh.sfile.dto.UserSpaceQueryDTO; +import com.senmesh.sfile.service.UserSpaceService; +import com.senmesh.tkmybatis.pojo.Page; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 用户空间Controller + */ +@Api(tags = "用户空间") +@RestController +@RequestMapping("user_space") +public class UserSpaceController { + + @Autowired + private UserSpaceService userSpaceService; + + @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create(@Validated @RequestBody UserSpaceCreateDTO createDTO) { + createDTO.setUserId(UserContextHolder.getExistLoginUserId()); + return AlitaResult.success(userSpaceService.create(createDTO)); + } + + @PostMapping("/modify") + @ApiOperation("修改") + public AlitaResult modify(@Validated @RequestBody UserSpaceModifyDTO modifyDTO) { + modifyDTO.setUserId(UserContextHolder.getExistLoginUserId()); + userSpaceService.modify(modifyDTO); + return AlitaResult.success(true); + } + + @DeleteMapping("/remove/{id}") + @ApiOperation("删除") + public AlitaResult remove(@PathVariable Long id) { + userSpaceService.remove(id); + return AlitaResult.success(true); + } + + @GetMapping("/find") + @ApiOperation("查询") + public AlitaResult find(UserSpaceQueryDTO queryDTO) { + queryDTO.setUserId(UserContextHolder.getExistLoginUserId()); + return AlitaResult.success(userSpaceService.find(queryDTO)); + } + +} + diff --git a/backend/src/main/java/com/senmesh/sfile/convert/FileCategoryConvert.java b/backend/src/main/java/com/senmesh/sfile/convert/FileCategoryConvert.java new file mode 100644 index 0000000..c5ed49a --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/convert/FileCategoryConvert.java @@ -0,0 +1,26 @@ +package com.senmesh.sfile.convert; + +import com.senmesh.sfile.dto.FileCategoryCreateDTO; +import com.senmesh.sfile.dto.FileCategoryDTO; +import com.senmesh.sfile.dto.FileCategoryModifyDTO; +import com.senmesh.sfile.entity.FileCategory; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * 文件种类转换器 + */ +@Mapper +public interface FileCategoryConvert { + + FileCategoryConvert INSTANCE = Mappers.getMapper(FileCategoryConvert.class); + + FileCategory toEntity(FileCategoryDTO dto); + + FileCategoryDTO toDto(FileCategory entity); + + FileCategory toEntity(FileCategoryCreateDTO dto); + + FileCategory toEntity(FileCategoryModifyDTO dto); +} + diff --git a/backend/src/main/java/com/senmesh/sfile/convert/FileRiskConvert.java b/backend/src/main/java/com/senmesh/sfile/convert/FileRiskConvert.java new file mode 100644 index 0000000..b384ddd --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/convert/FileRiskConvert.java @@ -0,0 +1,23 @@ +package com.senmesh.sfile.convert; + +import com.senmesh.sfile.dto.FileRiskCreateDTO; +import com.senmesh.sfile.dto.FileRiskDTO; +import com.senmesh.sfile.entity.FileRisk; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * 文件风险转换器 + */ +@Mapper +public interface FileRiskConvert { + + FileRiskConvert INSTANCE = Mappers.getMapper(FileRiskConvert.class); + + FileRisk toEntity(FileRiskDTO dto); + +// FileRiskDTO toDto(FileRisk entity); + + FileRisk toEntity(FileRiskCreateDTO dto); +} + diff --git a/backend/src/main/java/com/senmesh/sfile/convert/UserFileConvert.java b/backend/src/main/java/com/senmesh/sfile/convert/UserFileConvert.java new file mode 100644 index 0000000..8cc89e5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/convert/UserFileConvert.java @@ -0,0 +1,26 @@ +package com.senmesh.sfile.convert; + +import com.senmesh.sfile.dto.UserFileCreateDTO; +import com.senmesh.sfile.dto.UserFileDTO; +import com.senmesh.sfile.dto.UserFileModifyDTO; +import com.senmesh.sfile.entity.UserFile; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * 用户文件转换器 + */ +@Mapper +public interface UserFileConvert { + + UserFileConvert INSTANCE = Mappers.getMapper(UserFileConvert.class); + + UserFile toEntity(UserFileDTO dto); + + UserFileDTO toDto(UserFile entity); + + UserFile toEntity(UserFileCreateDTO dto); + + UserFile toEntity(UserFileModifyDTO dto); +} + diff --git a/backend/src/main/java/com/senmesh/sfile/convert/UserSpaceConvert.java b/backend/src/main/java/com/senmesh/sfile/convert/UserSpaceConvert.java new file mode 100644 index 0000000..1c46fa4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/convert/UserSpaceConvert.java @@ -0,0 +1,26 @@ +package com.senmesh.sfile.convert; + +import com.senmesh.sfile.dto.UserSpaceCreateDTO; +import com.senmesh.sfile.dto.UserSpaceDTO; +import com.senmesh.sfile.dto.UserSpaceModifyDTO; +import com.senmesh.sfile.entity.UserSpace; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * 用户空间转换器 + */ +@Mapper +public interface UserSpaceConvert { + + UserSpaceConvert INSTANCE = Mappers.getMapper(UserSpaceConvert.class); + + UserSpace toEntity(UserSpaceDTO dto); + + UserSpaceDTO toDto(UserSpace entity); + + UserSpace toEntity(UserSpaceCreateDTO dto); + + UserSpace toEntity(UserSpaceModifyDTO dto); +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dao/FileCategoryMapper.java b/backend/src/main/java/com/senmesh/sfile/dao/FileCategoryMapper.java new file mode 100644 index 0000000..e04ad78 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dao/FileCategoryMapper.java @@ -0,0 +1,26 @@ +package com.senmesh.sfile.dao; + +import com.senmesh.sfile.dto.FileCategoryDTO; +import com.senmesh.sfile.dto.FileCategoryQueryDTO; +import com.senmesh.sfile.entity.FileCategory; +import com.senmesh.tkmybatis.mybatis.MyMapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 文件种类Mapper + */ +@Mapper +public interface FileCategoryMapper extends MyMapper { + + /** + * 查询列表(PageHelper会根据queryDTO自动判断是否分页) + * + * @param queryDTO 查询DTO + * @return List + */ + List list(@Param("param") FileCategoryQueryDTO queryDTO); +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dao/FileRiskMapper.java b/backend/src/main/java/com/senmesh/sfile/dao/FileRiskMapper.java new file mode 100644 index 0000000..73f6429 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dao/FileRiskMapper.java @@ -0,0 +1,26 @@ +package com.senmesh.sfile.dao; + +import com.senmesh.sfile.dto.FileRiskDTO; +import com.senmesh.sfile.dto.FileRiskQueryDTO; +import com.senmesh.sfile.entity.FileRisk; +import com.senmesh.tkmybatis.mybatis.MyMapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 文件风险Mapper + */ +@Mapper +public interface FileRiskMapper extends MyMapper { + + /** + * 查询列表(PageHelper会根据queryDTO自动判断是否分页) + * + * @param queryDTO 查询DTO + * @return List + */ + List list(@Param("param") FileRiskQueryDTO queryDTO); +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dao/FileSecurityMapper.java b/backend/src/main/java/com/senmesh/sfile/dao/FileSecurityMapper.java new file mode 100644 index 0000000..c9de138 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dao/FileSecurityMapper.java @@ -0,0 +1,43 @@ +package com.senmesh.sfile.dao; + +import com.senmesh.sfile.dto.FileSecurityDTO; +import com.senmesh.sfile.entity.FileSecurity; +import com.senmesh.tkmybatis.mybatis.MyMapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 文件安全检测Mapper + */ +@Mapper +public interface FileSecurityMapper extends MyMapper { + + /** + * 查询检测记录列表(按id倒序) + * + * @param fileCodes 文件编码集合 + * @param fileCode 文件编码 + * @return List + */ + List list(@Param("fileCodes") List fileCodes, + @Param("fileCode") String fileCode); + + /** + * 查询最新检测状态为指定集合的记录(每个文件编码取最新一条) + * + * @param fileCodes 文件编码集合 + * @param scanStatusIn 检测状态集合 + * @return List + */ + List listLatestByStatusIn(@Param("fileCodes") List fileCodes, + @Param("scanStatusIn") List scanStatusIn); + + /** + * 查询检测中的记录(定时轮询用) + * + * @return List + */ + List listScanning(); +} diff --git a/backend/src/main/java/com/senmesh/sfile/dao/UploadConfigMapper.java b/backend/src/main/java/com/senmesh/sfile/dao/UploadConfigMapper.java new file mode 100644 index 0000000..726d824 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dao/UploadConfigMapper.java @@ -0,0 +1,15 @@ +package com.senmesh.sfile.dao; + +import com.senmesh.sfile.entity.UploadConfig; +import com.senmesh.tkmybatis.mybatis.MyMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * 机构上传配置Mapper + * + * @author liu on 2026-09-14 + */ +@Mapper +public interface UploadConfigMapper extends MyMapper { + +} diff --git a/backend/src/main/java/com/senmesh/sfile/dao/UserFileMapper.java b/backend/src/main/java/com/senmesh/sfile/dao/UserFileMapper.java new file mode 100644 index 0000000..e4e30cd --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dao/UserFileMapper.java @@ -0,0 +1,78 @@ +package com.senmesh.sfile.dao; + +import com.senmesh.sfile.dto.UserFileDTO; +import com.senmesh.sfile.dto.UserFileQueryDTO; +import com.senmesh.sfile.dto.UserFileRecordDTO; +import com.senmesh.sfile.dto.UserFileRecordQueryDTO; +import com.senmesh.sfile.dto.UserFileStatisticsDTO; +import com.senmesh.sfile.entity.UserFile; +import com.senmesh.tkmybatis.mybatis.MyMapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户文件Mapper + */ +@Mapper +public interface UserFileMapper extends MyMapper { + + /** + * 查询列表(PageHelper会根据queryDTO自动判断是否分页) + * + * @param queryDTO 查询DTO + * @return List + */ + List list(@Param("param") UserFileQueryDTO queryDTO); + + /** + * 根据父节点变化更新路径(包含当前节点和所有子孙节点) + * 只更新与当前文件相同 userId 和 rootType 的子节点 + * + * @param fileId 文件ID + * @param newParentId 新父节点ID + * @param operateUserId 操作用户ID + */ + void updatePathByParentIdChange(@Param("fileId") Long fileId, @Param("newParentId") Long newParentId, @Param("operateUserId") Long operateUserId); + + /** + * 删除文件及其所有子文件(逻辑删除) + * 只删除与当前文件相同 userId 和 rootType 的子节点 + * + * @param fileId 文件ID + * @param operateUserId 操作用户ID + */ + void deleteFileWithChildren(@Param("fileId") Long fileId, @Param("operateUserId") Long operateUserId); + + /** + * 更新文件状态及其所有子文件状态 + * 只更新与当前文件相同 userId 和 rootType 的子节点 + * + * @param fileId 文件ID + * @param oldStatus 老状态 + * @param newStatus 新状态 + * @param operateUserId 操作用户ID + */ + void updateStatusWithChildren(@Param("fileId") Long fileId, + @Param("oldStatus") String oldStatus, + @Param("newStatus") String newStatus, + @Param("operateUserId") Long operateUserId); + + /** + * 按文件种类统计文件个数和总大小 + * + * @param queryDTO 查询DTO + * @return List + */ + List statisticsByCategory(@Param("param") UserFileQueryDTO queryDTO); + + /** + * 按手机号查询文件记录(上传/发送/接收,PageHelper会根据queryDTO自动判断是否分页) + * + * @param queryDTO 查询DTO + * @return List + */ + List listRecordByPhone(@Param("param") UserFileRecordQueryDTO queryDTO); +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dao/UserSpaceMapper.java b/backend/src/main/java/com/senmesh/sfile/dao/UserSpaceMapper.java new file mode 100644 index 0000000..0168b4e --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dao/UserSpaceMapper.java @@ -0,0 +1,26 @@ +package com.senmesh.sfile.dao; + +import com.senmesh.sfile.dto.UserSpaceDTO; +import com.senmesh.sfile.dto.UserSpaceQueryDTO; +import com.senmesh.sfile.entity.UserSpace; +import com.senmesh.tkmybatis.mybatis.MyMapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户空间Mapper + */ +@Mapper +public interface UserSpaceMapper extends MyMapper { + + /** + * 查询列表(PageHelper会根据queryDTO自动判断是否分页) + * + * @param queryDTO 查询DTO + * @return List + */ + List list(@Param("param") UserSpaceQueryDTO queryDTO); +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dto/ExpandUserFileCreateDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/ExpandUserFileCreateDTO.java new file mode 100644 index 0000000..d1ff9df --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/ExpandUserFileCreateDTO.java @@ -0,0 +1,59 @@ +package com.senmesh.sfile.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.senmesh.common.dto.BaseOperateDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.util.Date; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.List; + +/** + * 扩展用户文件创建DTO + * 根据普通文件创建新的文件(复制) + */ +@ApiModel("扩展用户文件创建DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class ExpandUserFileCreateDTO extends BaseOperateDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("用户文件ID") + @NotNull(message = "用户文件ID不能为空") + private Long userFileId; + + @ApiModelProperty("用户id") + private Long userId; + + @ApiModelProperty("根类型:1普通/2内穿外/3外传内/4分享") + @NotEmpty(message = "根类型不能为空") + private String rootType; + + @ApiModelProperty("文件状态:1正常2失效11解析中12待审核13传输中14失败") + private String fileStatus; + + @ApiModelProperty("有效期") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date endTime; + + @ApiModelProperty("访问码") + private String accessCode; + + @ApiModelProperty("复制时需排除的用户文件ID(安全检测未通过跳过分享场景)") + private List excludeFileIds; +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dto/ExpandUserFileDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/ExpandUserFileDTO.java new file mode 100644 index 0000000..87ebc8f --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/ExpandUserFileDTO.java @@ -0,0 +1,32 @@ +package com.senmesh.sfile.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; + +/** + * 扩展用户文件DTO + */ +@ApiModel("扩展用户文件DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ExpandUserFileDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("文件夹信息") + private UserFileDTO folder; + + @ApiModelProperty("文件列表") + private List files; + +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dto/FileCategoryCreateDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/FileCategoryCreateDTO.java new file mode 100644 index 0000000..4d0d6ea --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/FileCategoryCreateDTO.java @@ -0,0 +1,34 @@ +package com.senmesh.sfile.dto; + +import com.senmesh.common.dto.BaseOperateDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; + +/** + * 文件种类创建DTO + */ +@ApiModel("文件种类创建DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class FileCategoryCreateDTO extends BaseOperateDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("文件种类") + @NotEmpty(message = "文件种类不能为空") + private String fileCategory; + + @ApiModelProperty("文件后缀") + private String fileSuffix; +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dto/FileCategoryDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/FileCategoryDTO.java new file mode 100644 index 0000000..aad1bce --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/FileCategoryDTO.java @@ -0,0 +1,31 @@ +package com.senmesh.sfile.dto; + +import com.senmesh.common.dto.BaseDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 文件种类 + */ +@ApiModel("文件种类") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class FileCategoryDTO extends BaseDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("文件种类") + private String fileCategory; + + @ApiModelProperty("文件后缀") + private String fileSuffix; +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dto/FileCategoryModifyDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/FileCategoryModifyDTO.java new file mode 100644 index 0000000..a632b65 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/FileCategoryModifyDTO.java @@ -0,0 +1,39 @@ +package com.senmesh.sfile.dto; + +import com.senmesh.common.dto.BaseOperateDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 文件种类修改DTO + */ +@ApiModel("文件种类修改DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class FileCategoryModifyDTO extends BaseOperateDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("主键ID") + @NotNull(message = "主键ID不能为空") + private Long id; + + @ApiModelProperty("文件种类") + @NotEmpty(message = "文件种类不能为空") + private String fileCategory; + + @ApiModelProperty("文件后缀") + private String fileSuffix; +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dto/FileCategoryQueryDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/FileCategoryQueryDTO.java new file mode 100644 index 0000000..b699dca --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/FileCategoryQueryDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.sfile.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 文件种类查询DTO + */ +@ApiModel("文件种类查询DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class FileCategoryQueryDTO extends PageQueryDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("主键ID") + private Long id; + + @ApiModelProperty("文件种类") + private String fileCategory; + + @ApiModelProperty("文件后缀") + private String fileSuffix; +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dto/FileRiskCreateDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/FileRiskCreateDTO.java new file mode 100644 index 0000000..660d265 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/FileRiskCreateDTO.java @@ -0,0 +1,31 @@ +package com.senmesh.sfile.dto; + +import com.senmesh.common.dto.BaseOperateDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; + +/** + * 文件风险创建DTO + */ +@ApiModel("文件风险创建DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class FileRiskCreateDTO extends BaseOperateDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("文件编码") + @NotEmpty(message = "文件编码不能为空") + private String fileCode; +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dto/FileRiskDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/FileRiskDTO.java new file mode 100644 index 0000000..50117d5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/FileRiskDTO.java @@ -0,0 +1,37 @@ +package com.senmesh.sfile.dto; + +import com.senmesh.common.dto.BaseDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 文件风险DTO + */ +@ApiModel("文件风险") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class FileRiskDTO extends BaseDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("文件编码") + private String fileCode; + + @ApiModelProperty("最高风险等级:1重度/2中度/3轻度") + private String maxRiskLevel; + + @ApiModelProperty("风险详情JSON") + private String riskJson; + + @ApiModelProperty("Dify文件上传响应JSON") + private String difyFileJson; +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dto/FileRiskQueryDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/FileRiskQueryDTO.java new file mode 100644 index 0000000..386c1d5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/FileRiskQueryDTO.java @@ -0,0 +1,34 @@ +package com.senmesh.sfile.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 文件风险查询DTO + */ +@ApiModel("文件风险查询DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class FileRiskQueryDTO extends PageQueryDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("主键ID") + private Long id; + + @ApiModelProperty("文件编码") + private String fileCode; + + @ApiModelProperty("最高风险等级:1重度/2中度/3轻度") + private String maxRiskLevel; +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dto/FileSecurityDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/FileSecurityDTO.java new file mode 100644 index 0000000..93253c0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/FileSecurityDTO.java @@ -0,0 +1,54 @@ +package com.senmesh.sfile.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.senmesh.common.dto.BaseDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +/** + * 文件安全检测记录DTO + */ +@ApiModel("文件安全检测记录") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class FileSecurityDTO extends BaseDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("文件编码") + private String fileCode; + + @ApiModelProperty("MeshSafe检测任务ID") + private String taskId; + + @ApiModelProperty("检测状态:1检测中/2通过/3不通过/4检测失败") + private String scanStatus; + + @ApiModelProperty("MeshSafe处置动作:pass/manual_review/reject") + private String action; + + @ApiModelProperty("检测结论说明") + private String reason; + + @ApiModelProperty("检测完整结果JSON") + private String resultJson; + + @ApiModelProperty("人工复核说明(人工改判时有值)") + private String reviewComment; + + @ApiModelProperty("检测时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; +} diff --git a/backend/src/main/java/com/senmesh/sfile/dto/FileSecurityReviewDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/FileSecurityReviewDTO.java new file mode 100644 index 0000000..be9df65 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/FileSecurityReviewDTO.java @@ -0,0 +1,36 @@ +package com.senmesh.sfile.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; + +/** + * 文件安全检测人工复核DTO + */ +@ApiModel("文件安全检测人工复核") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FileSecurityReviewDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("文件编码") + @NotBlank(message = "文件编码不能为空") + private String fileCode; + + @ApiModelProperty("复核结论:pass通过/reject不通过") + @NotBlank(message = "复核结论不能为空") + private String decision; + + @ApiModelProperty("复核说明(审计要求,必填)") + @NotBlank(message = "复核说明不能为空") + private String comment; +} diff --git a/backend/src/main/java/com/senmesh/sfile/dto/FileSecurityShareCheckDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/FileSecurityShareCheckDTO.java new file mode 100644 index 0000000..65c5bf7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/FileSecurityShareCheckDTO.java @@ -0,0 +1,51 @@ +package com.senmesh.sfile.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 文件安全检测分享预检DTO + */ +@ApiModel("文件安全检测分享预检") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FileSecurityShareCheckDTO { + + @ApiModelProperty("用户文件ID") + private Long userFileId; + + @ApiModelProperty("文件大类:1文件/2文件夹") + private String fileType; + + @ApiModelProperty("目录内文件总数(不含目录)") + private Integer totalFileCount; + + @ApiModelProperty("检测不通过数量") + private Integer blockedCount; + + @ApiModelProperty("检测中数量") + private Integer scanningCount; + + @ApiModelProperty("检测失败数量") + private Integer failedCount; + + @ApiModelProperty("检测不通过文件名列表") + private List blockedFileNames; + + @ApiModelProperty("检测中文件名列表") + private List scanningFileNames; + + @ApiModelProperty("检测失败文件名列表") + private List failedFileNames; + + @ApiModelProperty("确认跳过时需排除的用户文件ID列表(不通过+检测中,fail-closed时含检测失败)") + private List excludeFileIds; +} diff --git a/backend/src/main/java/com/senmesh/sfile/dto/ShareUserFileCreateDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/ShareUserFileCreateDTO.java new file mode 100644 index 0000000..3a0e857 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/ShareUserFileCreateDTO.java @@ -0,0 +1,39 @@ +package com.senmesh.sfile.dto; + +import com.senmesh.common.dto.BaseOperateDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * 分享用户文件创建DTO + */ +@ApiModel("分享用户文件创建DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class ShareUserFileCreateDTO extends BaseOperateDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("用户文件ID") + @NotNull(message = "用户文件ID不能为空") + private Long userFileId; + + @ApiModelProperty("有效天数") + @NotNull(message = "有效天数不能为空") + private Integer validDays; + + @ApiModelProperty("文件夹内存在检测未通过文件时,确认后仅复制检测通过的内容") + private Boolean onlyPassed; + +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dto/TransferMetadataDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/TransferMetadataDTO.java new file mode 100644 index 0000000..ac592c1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/TransferMetadataDTO.java @@ -0,0 +1,36 @@ +package com.senmesh.sfile.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 传输元数据DTO + */ +@ApiModel("传输元数据DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TransferMetadataDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("扩展用户文件DTO") + private ExpandUserFileDTO expandUserFile; + + @ApiModelProperty("源端用户ID,仅用于日志追踪") + private Long sourceUserId; + + @ApiModelProperty("源端用户手机号") + private String sourceUserPhone; + + @ApiModelProperty("源端用户类型") + private Integer sourceUserType; + +} diff --git a/backend/src/main/java/com/senmesh/sfile/dto/TransferUserFileCreateDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/TransferUserFileCreateDTO.java new file mode 100644 index 0000000..07ae0ec --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/TransferUserFileCreateDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.sfile.dto; + +import com.senmesh.common.dto.BaseOperateDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * 传输用户文件创建DTO + */ +@ApiModel("传输用户文件创建DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class TransferUserFileCreateDTO extends BaseOperateDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("用户文件ID") + @NotNull(message = "用户文件ID不能为空") + private Long userFileId; + + @ApiModelProperty("文件夹内存在检测未通过文件时,确认后仅传输检测通过的内容") + private Boolean onlyPassed; + +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dto/UploadConfigDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/UploadConfigDTO.java new file mode 100644 index 0000000..a22a4dc --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/UploadConfigDTO.java @@ -0,0 +1,46 @@ +package com.senmesh.sfile.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; + +/** + * 机构上传配置DTO + * + * @author liu on 2026-09-14 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@ApiModel("机构上传配置") +public class UploadConfigDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("机构id") + private Long orgId; + + @ApiModelProperty("是否允许上传") + private Boolean uploadEnabled; + + @ApiModelProperty("是否允许全部类型") + private Boolean allowAllType; + + @ApiModelProperty("允许的文件后缀(小写,不含点),allow_all_type=false时生效") + private List allowedSuffixes; + + @ApiModelProperty("单文件大小上限(MB),空或0不限制") + private Long maxFileSize; + + @ApiModelProperty("机构是否已配置过(false表示使用默认策略:允许上传全部类型)") + private Boolean configured; + +} diff --git a/backend/src/main/java/com/senmesh/sfile/dto/UploadConfigModifyDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/UploadConfigModifyDTO.java new file mode 100644 index 0000000..4d33dd3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/UploadConfigModifyDTO.java @@ -0,0 +1,44 @@ +package com.senmesh.sfile.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; + +import javax.validation.constraints.NotNull; + +/** + * 机构上传配置修改DTO + * + * @author liu on 2026-09-14 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@ApiModel("机构上传配置修改") +public class UploadConfigModifyDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("是否允许上传") + @NotNull(message = "是否允许上传不能为空") + private Boolean uploadEnabled; + + @ApiModelProperty("是否允许全部类型") + @NotNull(message = "是否允许全部类型不能为空") + private Boolean allowAllType; + + @ApiModelProperty("允许的文件后缀(不含点,自动忽略大小写),allow_all_type=false时必填") + private List allowedSuffixes; + + @ApiModelProperty("单文件大小上限(MB),空或0不限制") + private Long maxFileSize; + +} diff --git a/backend/src/main/java/com/senmesh/sfile/dto/UserFileCreateDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/UserFileCreateDTO.java new file mode 100644 index 0000000..4af457d --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/UserFileCreateDTO.java @@ -0,0 +1,69 @@ +package com.senmesh.sfile.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.senmesh.common.dto.BaseOperateDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Builder.Default; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Date; + +/** + * 用户文件创建DTO + */ +@ApiModel("用户文件创建DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class UserFileCreateDTO extends BaseOperateDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("用户id") +// @NotNull(message = "用户id不能为空") + private Long userId; + + @ApiModelProperty("根类型:1普通/2内穿外/3外传内/4我的分享") +// @NotEmpty(message = "根类型不能为空") + private String rootType; + + @ApiModelProperty("文件大类:1文件/2文件夹") + @NotEmpty(message = "文件大类不能为空") + private String fileType; + + @ApiModelProperty("文件名") + @NotEmpty(message = "文件名不能为空") + private String fileName; + + @ApiModelProperty("父id") + @Default + private Long parentId = 0L; + + @ApiModelProperty("文件编码") + private String fileCode; + + @ApiModelProperty("文件状态:1正常2失效11解析中12待审核13传输中14失败") + private String fileStatus; + + @ApiModelProperty("父路径(可选,用于优化性能,避免查询父节点)") + private String parentPath; + + @ApiModelProperty("有效期") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date endTime; + + @ApiModelProperty("访问码") + private String accessCode; +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dto/UserFileDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/UserFileDTO.java new file mode 100644 index 0000000..80ab283 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/UserFileDTO.java @@ -0,0 +1,90 @@ +package com.senmesh.sfile.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.senmesh.common.dto.BaseDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +/** + * 用户文件 + */ +@ApiModel("用户文件") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class UserFileDTO extends BaseDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("用户id") + private Long userId; + + @ApiModelProperty("根类型:1普通/2内穿外/3外传内/4我的分享") + private String rootType; + + @ApiModelProperty("文件大类:1文件/2文件夹") + private String fileType; + + @ApiModelProperty("文件名") + private String fileName; + + @ApiModelProperty("父id") + private Long parentId; + + @ApiModelProperty("文件编码") + private String fileCode; + + @ApiModelProperty("文件大小") + private Long fileSize; + + @ApiModelProperty("文件状态:1正常2失效11解析中12待审核13传输中14失败") + private String fileStatus; + + @ApiModelProperty("路径") + private String path; + + @ApiModelProperty("有效期") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date endTime; + + @ApiModelProperty("访问码") + private String accessCode; + + @ApiModelProperty("文件种类") + private String fileCategory; + + @ApiModelProperty("最高风险等级:1重度/2中度/3轻度") + private String maxRiskLevel; + + @ApiModelProperty("风险详情JSON") + private String riskJson; + + @ApiModelProperty("安全检测状态:1检测中/2通过/3不通过/4检测失败(空为未检测)") + private String securityStatus; + + @ApiModelProperty("安全检测处置动作:pass/manual_review/reject") + private String securityAction; + + @ApiModelProperty("安全检测结论说明") + private String securityReason; + + @ApiModelProperty("安全检测人工复核说明") + private String securityReviewComment; + + @ApiModelProperty("安全检测时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date securityTime; +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dto/UserFileModifyDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/UserFileModifyDTO.java new file mode 100644 index 0000000..de9b296 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/UserFileModifyDTO.java @@ -0,0 +1,50 @@ +package com.senmesh.sfile.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.senmesh.common.dto.BaseOperateDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Date; + +/** + * 用户文件修改DTO + */ +@ApiModel("用户文件修改DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class UserFileModifyDTO extends BaseOperateDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("主键ID") + @NotNull(message = "主键ID不能为空") + private Long id; + + @ApiModelProperty("用户id") + private Long userId; + + @ApiModelProperty("根类型:1普通/2内穿外/3外传内/4我的分享") + @NotEmpty(message = "根类型不能为空") + private String rootType; + + @ApiModelProperty("文件名") + private String fileName; + + @ApiModelProperty("父id") + private Long parentId; + + +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dto/UserFileModifyStatusDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/UserFileModifyStatusDTO.java new file mode 100644 index 0000000..6e36348 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/UserFileModifyStatusDTO.java @@ -0,0 +1,41 @@ +package com.senmesh.sfile.dto; + +import com.senmesh.common.dto.BaseOperateDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 用户文件修改状态DTO + */ +@ApiModel("用户文件修改状态DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class UserFileModifyStatusDTO extends BaseOperateDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("主键ID") + @NotNull(message = "主键ID不能为空") + private Long id; + + @ApiModelProperty("老状态:1正常2失效11解析中12待审核13传输中14失败") + @NotEmpty(message = "老状态不能为空") + private String oldStatus; + + @ApiModelProperty("新状态:1正常2失效11解析中12待审核13传输中14失败") + @NotEmpty(message = "新状态不能为空") + private String newStatus; + +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dto/UserFileQueryDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/UserFileQueryDTO.java new file mode 100644 index 0000000..f5605fa --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/UserFileQueryDTO.java @@ -0,0 +1,67 @@ +package com.senmesh.sfile.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +import java.util.Set; + +/** + * 用户文件查询DTO + */ +@ApiModel("用户文件查询DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class UserFileQueryDTO extends PageQueryDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("主键ID") + private Long id; + + @ApiModelProperty("用户id") + private Long userId; + + @ApiModelProperty("根类型:1普通/2内穿外/3外传内/4我的分享") + private String rootType; + + @ApiModelProperty("文件大类:1文件/2文件夹") + private String fileType; + + @ApiModelProperty("文件名") + private String fileName; + + @ApiModelProperty("文件名(模糊查询)") + private String fileNameLike; + + @ApiModelProperty("父id") + private Long parentId; + + @ApiModelProperty("文件编码") + private String fileCode; + + @ApiModelProperty("文件状态:1正常2失效11解析中12待审核13传输中") + private String fileStatus; + + @ApiModelProperty("文件状态(多值查询)") + private Set fileStatusIn; + + @ApiModelProperty("路径(模糊查询,用于查询某个文件夹下的所有子文件)") + private String pathLike; + + @ApiModelProperty("文件种类") + private String fileCategory; + + @ApiModelProperty("关联查询上级不为INVALID") + private Boolean parentNotInvalid; +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dto/UserFileRecordDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/UserFileRecordDTO.java new file mode 100644 index 0000000..560a65f --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/UserFileRecordDTO.java @@ -0,0 +1,43 @@ +package com.senmesh.sfile.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 用户文件记录DTO(按手机号查询上传/发送/接收记录) + */ +@ApiModel("用户文件记录") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class UserFileRecordDTO extends UserFileDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("手机号") + private String phone; + + @ApiModelProperty("账号") + private String username; + + @ApiModelProperty("真实姓名") + private String realName; + + @ApiModelProperty("用户类型:1企业用户,2个人用户") + private Integer userType; + + @ApiModelProperty("记录类型:1上传记录/2发送记录/3接收记录") + private Integer recordType; + + @ApiModelProperty("记录类型描述") + private String recordTypeDesc; + +} diff --git a/backend/src/main/java/com/senmesh/sfile/dto/UserFileRecordQueryDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/UserFileRecordQueryDTO.java new file mode 100644 index 0000000..af24ccf --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/UserFileRecordQueryDTO.java @@ -0,0 +1,70 @@ +package com.senmesh.sfile.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.senmesh.common.dto.PageQueryDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; +import java.util.Set; + +/** + * 用户文件记录查询DTO(按手机号查询上传/发送/接收记录) + */ +@ApiModel("用户文件记录查询DTO(按手机号)") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class UserFileRecordQueryDTO extends PageQueryDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty(value = "手机号(必填,精确匹配)", required = true) + private String phone; + + @ApiModelProperty("记录类型:1上传记录/2发送记录/3接收记录(不传查全部)") + private Integer recordType; + + @ApiModelProperty("文件名(模糊查询)") + private String fileNameLike; + + @ApiModelProperty("文件状态:1正常2失效11解析中12待审核13传输中14失败") + private String fileStatus; + + @ApiModelProperty("文件类型:1文件/2文件夹") + private String fileType; + + @ApiModelProperty("创建时间起") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat( + shape = JsonFormat.Shape.STRING, + pattern = "yyyy-MM-dd HH:mm:ss", + timezone = "GMT+8" + ) + private Date createTimeBegin; + + @ApiModelProperty("创建时间止") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat( + shape = JsonFormat.Shape.STRING, + pattern = "yyyy-MM-dd HH:mm:ss", + timezone = "GMT+8" + ) + private Date createTimeEnd; + + @ApiModelProperty(hidden = true) + @JsonIgnore + private Set rootTypeIn; + +} diff --git a/backend/src/main/java/com/senmesh/sfile/dto/UserFileStatisticsDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/UserFileStatisticsDTO.java new file mode 100644 index 0000000..e609af4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/UserFileStatisticsDTO.java @@ -0,0 +1,33 @@ +package com.senmesh.sfile.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 用户文件统计DTO + */ +@ApiModel("用户文件统计DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class UserFileStatisticsDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("文件种类") + private String fileCategory; + + @ApiModelProperty("文件个数") + private Long fileCount; + + @ApiModelProperty("文件总大小(kb)") + private Long totalSize; +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dto/UserSpaceCreateDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/UserSpaceCreateDTO.java new file mode 100644 index 0000000..8c93b2a --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/UserSpaceCreateDTO.java @@ -0,0 +1,31 @@ +package com.senmesh.sfile.dto; + +import com.senmesh.common.dto.BaseOperateDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * 用户空间创建DTO + */ +@ApiModel("用户空间创建DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class UserSpaceCreateDTO extends BaseOperateDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("用户id") + @NotNull(message = "用户id不能为空") + private Long userId; +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dto/UserSpaceDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/UserSpaceDTO.java new file mode 100644 index 0000000..34f1c4c --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/UserSpaceDTO.java @@ -0,0 +1,34 @@ +package com.senmesh.sfile.dto; + +import com.senmesh.common.dto.BaseDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 用户空间 + */ +@ApiModel("用户空间") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class UserSpaceDTO extends BaseDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("用户id") + private Long userId; + + @ApiModelProperty("总容量") + private Long totalSize; + + @ApiModelProperty("已使用容量") + private Long usedSize; +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dto/UserSpaceModifyDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/UserSpaceModifyDTO.java new file mode 100644 index 0000000..5c803de --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/UserSpaceModifyDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.sfile.dto; + +import com.senmesh.common.dto.BaseOperateDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * 用户空间修改DTO + */ +@ApiModel("用户空间修改DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class UserSpaceModifyDTO extends BaseOperateDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("用户id") + @NotNull(message = "用户id不能为空") + private Long userId; + + @ApiModelProperty("已使用容量") + @NotNull(message = "已使用容量不能为空") + private Long usedSize; +} + diff --git a/backend/src/main/java/com/senmesh/sfile/dto/UserSpaceQueryDTO.java b/backend/src/main/java/com/senmesh/sfile/dto/UserSpaceQueryDTO.java new file mode 100644 index 0000000..a1b59f6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/dto/UserSpaceQueryDTO.java @@ -0,0 +1,32 @@ +package com.senmesh.sfile.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 用户空间查询DTO + */ +@ApiModel("用户空间查询DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class UserSpaceQueryDTO extends PageQueryDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("主键ID") + private Long id; + + @ApiModelProperty("用户id") + private Long userId; +} + diff --git a/backend/src/main/java/com/senmesh/sfile/entity/FileCategory.java b/backend/src/main/java/com/senmesh/sfile/entity/FileCategory.java new file mode 100644 index 0000000..bfec5cc --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/entity/FileCategory.java @@ -0,0 +1,34 @@ +package com.senmesh.sfile.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 文件种类 + */ +@TableName("x_file_category") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class FileCategory extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** + * 文件种类 + */ + private String fileCategory; + + /** + * 文件后缀 + */ + private String fileSuffix; +} + diff --git a/backend/src/main/java/com/senmesh/sfile/entity/FileRisk.java b/backend/src/main/java/com/senmesh/sfile/entity/FileRisk.java new file mode 100644 index 0000000..295590b --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/entity/FileRisk.java @@ -0,0 +1,44 @@ +package com.senmesh.sfile.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 文件风险 + */ +@TableName("x_file_risk") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class FileRisk extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** + * 文件编码 + */ + private String fileCode; + + /** + * 最高风险等级:1重度/2中度/3轻度 + */ + private String maxRiskLevel; + + /** + * 风险详情JSON + */ + private String riskJson; + + /** + * Dify文件上传响应JSON + */ + private String difyFileJson; +} + diff --git a/backend/src/main/java/com/senmesh/sfile/entity/FileSecurity.java b/backend/src/main/java/com/senmesh/sfile/entity/FileSecurity.java new file mode 100644 index 0000000..4b87e50 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/entity/FileSecurity.java @@ -0,0 +1,60 @@ +package com.senmesh.sfile.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 文件安全检测记录 + *

+ * 同一文件允许多条检测记录(人工复核/重新检测均新增),业务取最新一条生效。 + */ +@TableName("x_file_security") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class FileSecurity extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** + * 文件编码 + */ + private String fileCode; + + /** + * MeshSafe检测任务ID + */ + private String taskId; + + /** + * 检测状态:1检测中/2通过/3不通过/4检测失败 + */ + private String scanStatus; + + /** + * MeshSafe处置动作:pass/manual_review/reject + */ + private String action; + + /** + * 检测结论说明 + */ + private String reason; + + /** + * 检测完整结果JSON + */ + private String resultJson; + + /** + * 人工复核说明(人工改判时有值) + */ + private String reviewComment; +} diff --git a/backend/src/main/java/com/senmesh/sfile/entity/UploadConfig.java b/backend/src/main/java/com/senmesh/sfile/entity/UploadConfig.java new file mode 100644 index 0000000..0b58c05 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/entity/UploadConfig.java @@ -0,0 +1,43 @@ +package com.senmesh.sfile.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 机构上传配置 + * 一行对应一个机构,用于限制该机构用户在网盘中可上传的文件类型/大小 + * + * @author liu on 2026-09-14 + */ +@TableName("x_upload_config") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class UploadConfig extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** 机构id(唯一) */ + private Long orgId; + + /** 是否允许上传 */ + private Boolean uploadEnabled; + + /** 是否允许全部类型(false时按allowed_suffixes白名单校验) */ + private Boolean allowAllType; + + /** 允许的文件后缀(逗号分隔,小写存储),allow_all_type=false时生效 */ + private String allowedSuffixes; + + /** 单文件大小上限(MB),空或0不限制 */ + private Long maxFileSize; + +} diff --git a/backend/src/main/java/com/senmesh/sfile/entity/UserFile.java b/backend/src/main/java/com/senmesh/sfile/entity/UserFile.java new file mode 100644 index 0000000..4f86be9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/entity/UserFile.java @@ -0,0 +1,76 @@ +package com.senmesh.sfile.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +import java.util.Date; + +/** + * 用户文件 + */ +@TableName("x_user_file") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class UserFile extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** + * 用户id + */ + private Long userId; + + /** + * 根类型:1普通/2内穿外/3外传内/4我的分享 + */ + private String rootType; + + /** + * 文件大类:1文件/2文件夹 + */ + private String fileType; + + /** + * 文件名 + */ + private String fileName; + + /** + * 父id + */ + private Long parentId; + + /** + * 文件编码 + */ + private String fileCode; + + /** + * 文件状态:1正常2失效11解析中12待审核13传输中14失败 + */ + private String fileStatus; + + /** + * 路径 + */ + private String path; + + /** + * 有效期 + */ + private Date endTime; + + /** + * 访问码 + */ + private String accessCode; +} + diff --git a/backend/src/main/java/com/senmesh/sfile/entity/UserSpace.java b/backend/src/main/java/com/senmesh/sfile/entity/UserSpace.java new file mode 100644 index 0000000..dcb1e38 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/entity/UserSpace.java @@ -0,0 +1,39 @@ +package com.senmesh.sfile.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 用户空间 + */ +@TableName("x_user_space") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class UserSpace extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** + * 用户id + */ + private Long userId; + + /** + * 总容量 + */ + private Long totalSize; + + /** + * 已使用容量 + */ + private Long usedSize; +} + diff --git a/backend/src/main/java/com/senmesh/sfile/job/MeshSafeScanJob.java b/backend/src/main/java/com/senmesh/sfile/job/MeshSafeScanJob.java new file mode 100644 index 0000000..cacd347 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/job/MeshSafeScanJob.java @@ -0,0 +1,39 @@ +package com.senmesh.sfile.job; + +import com.senmesh.common.annotation.AlitaStopWatch; +import com.senmesh.common.util.MockUtils; +import com.senmesh.sfile.service.FileSecurityService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +/** + * MeshSafe文件安全检测轮询定时任务 + *

+ * 轮询检测中的任务直到拿到结论(MeshSafe异步模式/网络异常重试), + * 检测中的记录超过配置时长仍无结论则标记检测失败。 + */ +@Component +@Slf4j +public class MeshSafeScanJob { + + @Autowired + private FileSecurityService fileSecurityService; + + /** + * 定时轮询未完成的检测任务,默认每30秒执行一次 + */ + @Scheduled(cron = "${meshsafe.poll.cron:0 */30 * * * ?}") + @AlitaStopWatch + public void execute() { + try { + MockUtils.mockPlatUser(); + fileSecurityService.pollPendingScans(); + } catch (Exception e) { + log.error("MeshSafe检测轮询任务执行失败", e); + } finally { + MockUtils.clearUser(); + } + } +} diff --git a/backend/src/main/java/com/senmesh/sfile/job/TransferFileMonitorJob.java b/backend/src/main/java/com/senmesh/sfile/job/TransferFileMonitorJob.java new file mode 100644 index 0000000..eca4d04 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/job/TransferFileMonitorJob.java @@ -0,0 +1,43 @@ +package com.senmesh.sfile.job; + +import com.senmesh.common.annotation.AlitaStopWatch; +import com.senmesh.common.util.MockUtils; +import com.senmesh.component.file.config.FileProperties; +import com.senmesh.sfile.service.TransferFileMonitorService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +/** + * 传输文件监听定时任务 + */ +@Component +@Slf4j +public class TransferFileMonitorJob { + + @Autowired + private TransferFileMonitorService transferFileMonitorService; + + @Autowired + private FileProperties fileProperties; + + /** + * 定时扫描传输目录 + * 默认每分钟执行一次 + */ + @Scheduled(cron = "${file.transfer.monitor.cron:0 */1 * * * ?}") + @AlitaStopWatch + public void execute() { + try { + log.debug("开始扫描传输目录"); + MockUtils.mockPlatUser(); + transferFileMonitorService.scanAndProcess(); + } catch (Exception e) { + log.error("传输文件监听处理失败", e); + } finally { + MockUtils.clearUser(); + } + } +} + diff --git a/backend/src/main/java/com/senmesh/sfile/mapper/FileCategoryMapper.xml b/backend/src/main/java/com/senmesh/sfile/mapper/FileCategoryMapper.xml new file mode 100644 index 0000000..d660e99 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/mapper/FileCategoryMapper.xml @@ -0,0 +1,26 @@ + + + + + + + + + FROM x_file_category t + WHERE t.deleted = FALSE + + AND t.id = #{param.id} + + + AND t.file_category = #{param.fileCategory} + + + AND t.file_suffix = #{param.fileSuffix} + + + + diff --git a/backend/src/main/java/com/senmesh/sfile/mapper/FileRiskMapper.xml b/backend/src/main/java/com/senmesh/sfile/mapper/FileRiskMapper.xml new file mode 100644 index 0000000..33f2387 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/mapper/FileRiskMapper.xml @@ -0,0 +1,26 @@ + + + + + + + + FROM x_file_risk t + WHERE t.deleted = FALSE + + AND t.id = #{param.id} + + + AND t.file_code = #{param.fileCode} + + + AND t.max_risk_level = #{param.maxRiskLevel} + + + + + diff --git a/backend/src/main/java/com/senmesh/sfile/mapper/FileSecurityMapper.xml b/backend/src/main/java/com/senmesh/sfile/mapper/FileSecurityMapper.xml new file mode 100644 index 0000000..7ec9f5c --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/mapper/FileSecurityMapper.xml @@ -0,0 +1,53 @@ + + + + + + WHERE t.deleted = FALSE + + AND t.file_code = #{fileCode} + + + AND t.file_code IN + + #{item} + + + + + + + + + + + diff --git a/backend/src/main/java/com/senmesh/sfile/mapper/UserFileMapper.xml b/backend/src/main/java/com/senmesh/sfile/mapper/UserFileMapper.xml new file mode 100644 index 0000000..5b5ce50 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/mapper/UserFileMapper.xml @@ -0,0 +1,194 @@ + + + + + + + + + + + + + FROM x_user_file t + LEFT JOIN xs_file_record fr ON t.file_code = fr.file_code AND fr.deleted = FALSE + LEFT JOIN x_file_category fc ON fr.file_suffix = fc.file_suffix AND fc.deleted = FALSE + LEFT JOIN x_file_risk fk ON t.file_code = fk.file_code AND fk.deleted = FALSE + LEFT JOIN x_file_security fs ON t.file_code = fs.file_code AND fs.deleted = FALSE + AND fs.id = (SELECT MAX(fs2.id) FROM x_file_security fs2 + WHERE fs2.file_code = t.file_code AND fs2.deleted = FALSE) + + LEFT JOIN x_user_file parent ON t.parent_id = parent.id AND parent.deleted = FALSE + + WHERE t.deleted = FALSE + + AND t.id = #{param.id} + + + AND t.user_id = #{param.userId} + + + AND t.root_type = #{param.rootType} + + + AND t.file_type = #{param.fileType} + + + AND t.file_name = #{param.fileName} + + + + AND t.file_name LIKE #{fileNameLike} + + + AND t.parent_id = #{param.parentId} + + + AND t.file_code = #{param.fileCode} + + + AND t.file_status = #{param.fileStatus} + + + AND t.file_status IN + + #{item} + + + + + AND t.path like #{pathLike} + + + AND fc.file_category = #{param.fileCategory} + + + AND (t.parent_id = 0 OR parent.file_status != '2') + + + + + UPDATE x_user_file child + SET path = CASE + WHEN child.id = #{fileId} THEN + CASE + WHEN #{newParentId} = 0 THEN CAST(#{fileId} AS VARCHAR) + ELSE CONCAT(parent.path, ',', #{fileId}) + END + ELSE + REPLACE(child.path, + CONCAT(current.path, ','), + CASE + WHEN #{newParentId} = 0 THEN CONCAT(#{fileId}, ',') + ELSE CONCAT(parent.path, ',', #{fileId}, ',') + END) + END, + update_by = #{operateUserId}, + update_time = NOW() + FROM x_user_file current + LEFT JOIN x_user_file parent ON parent.id = #{newParentId} AND parent.deleted = FALSE + WHERE current.id = #{fileId} + AND current.deleted = FALSE + AND (child.id = #{fileId} OR child.path LIKE CONCAT(current.path, ',%')) + AND child.deleted = FALSE + AND child.user_id = current.user_id + AND child.root_type = current.root_type + + + + UPDATE x_user_file child + SET deleted = TRUE, + update_by = #{operateUserId}, + update_time = NOW() + FROM x_user_file current + WHERE current.id = #{fileId} + AND current.deleted = FALSE + AND (child.id = #{fileId} OR child.path LIKE CONCAT(current.path, ',%')) + AND child.deleted = FALSE + AND child.user_id = current.user_id + AND child.root_type = current.root_type + + + + UPDATE x_user_file child + SET file_status = #{newStatus}, + update_by = #{operateUserId}, + update_time = NOW() + FROM x_user_file current + WHERE current.id = #{fileId} + AND current.deleted = FALSE + AND current.file_status = #{oldStatus} + AND (child.id = #{fileId} OR child.path LIKE CONCAT(current.path, ',%')) + AND child.deleted = FALSE + AND child.user_id = current.user_id + AND child.root_type = current.root_type + + + diff --git a/backend/src/main/java/com/senmesh/sfile/mapper/UserSpaceMapper.xml b/backend/src/main/java/com/senmesh/sfile/mapper/UserSpaceMapper.xml new file mode 100644 index 0000000..94933af --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/mapper/UserSpaceMapper.xml @@ -0,0 +1,34 @@ + + + + + + + + + diff --git a/backend/src/main/java/com/senmesh/sfile/service/FileCategoryService.java b/backend/src/main/java/com/senmesh/sfile/service/FileCategoryService.java new file mode 100644 index 0000000..add8672 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/service/FileCategoryService.java @@ -0,0 +1,60 @@ +package com.senmesh.sfile.service; + +import com.senmesh.sfile.dto.FileCategoryCreateDTO; +import com.senmesh.sfile.dto.FileCategoryDTO; +import com.senmesh.sfile.dto.FileCategoryModifyDTO; +import com.senmesh.sfile.dto.FileCategoryQueryDTO; + +import java.util.List; + +/** + * 文件种类Service + */ +public interface FileCategoryService { + + /** + * 创建文件种类 + * + * @param createDTO 创建DTO + * @return 主键ID + */ + Long create(FileCategoryCreateDTO createDTO); + + /** + * 修改文件种类 + * + * @param modifyDTO 修改DTO + */ + void modify(FileCategoryModifyDTO modifyDTO); + + /** + * 删除文件种类 + * + * @param id 主键ID + */ + void remove(Long id); + + /** + * 列表查询 + * + * @param queryDTO 查询DTO + * @return List + */ + List list(FileCategoryQueryDTO queryDTO); + + /** + * 分页查询 + * + * @param queryDTO 查询DTO + */ + void page(FileCategoryQueryDTO queryDTO); + + /** + * 单个查询 + * + * @param queryDTO 查询DTO + * @return FileCategoryDTO + */ + FileCategoryDTO find(FileCategoryQueryDTO queryDTO); +} + diff --git a/backend/src/main/java/com/senmesh/sfile/service/FileRiskService.java b/backend/src/main/java/com/senmesh/sfile/service/FileRiskService.java new file mode 100644 index 0000000..a2c63c9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/service/FileRiskService.java @@ -0,0 +1,100 @@ +package com.senmesh.sfile.service; + +import com.senmesh.sfile.dto.FileRiskCreateDTO; +import com.senmesh.sfile.dto.FileRiskDTO; +import com.senmesh.sfile.dto.FileRiskQueryDTO; + +import java.util.List; + +/** + * 文件风险Service + */ +public interface FileRiskService { + + /** + * 创建文件风险(带锁) + * 根据fileCode查询,如果存在则直接返回,不存在则创建 + * + * @param createDTO 创建DTO + * @return 文件风险DTO + */ + FileRiskDTO create(FileRiskCreateDTO createDTO); + + /** + * 获取风险规则 + * + * @param orgId 机构ID + * @return 风险规则配置值 + */ + String getRiskRule(Long orgId); + + /** + * 保存风险规则 + * + * @param riskRule 风险规则配置值 + */ + void saveRiskRule(String riskRule); + + /** + * 获取最低审核风险等级 + * + * @param orgId 机构ID + * @return 最低审核风险等级配置值 + */ + String getMinAuditRiskLevel(Long orgId); + + /** + * 保存最低审核风险等级 + * + * @param minAuditRiskLevel 最低审核风险等级配置值 + */ + void saveMinAuditRiskLevel(String minAuditRiskLevel); + + /** + * 扫描文件风险 + * 1. 根据fileCode查询,如果存在则直接返回 + * 2. 如果不存在,则走扫描逻辑: + * - 拿到文件流调dify上传文件 + * - 调用获取风险规则 + * - 调用dify chat拿风险结果 + * - 获取结果中的max_risk_level + * - 保存数据 + * + * @param fileCode 文件编码 + * @return 文件风险DTO + */ + FileRiskDTO scanFileRisk(String fileCode); + + /** + * 获取 Dify 风险规则 + * 上传文件到 Dify 并调用规则生成 API,返回生成的风险规则 + * + * @param fileCode 文件编码 + * @return Dify 返回的 answer + */ + String getDifyRiskRule(String fileCode); + + /** + * 列表查询文件风险 + * + * @param queryDTO 查询条件 + * @return 文件风险DTO列表 + */ + List list(FileRiskQueryDTO queryDTO); + + /** + * 分页查询文件风险 + * + * @param queryDTO 查询条件 + */ + void page(FileRiskQueryDTO queryDTO); + + /** + * 单个查询文件风险 + * + * @param queryDTO 查询条件 + * @return 文件风险DTO + */ + FileRiskDTO find(FileRiskQueryDTO queryDTO); +} + diff --git a/backend/src/main/java/com/senmesh/sfile/service/FileSecurityService.java b/backend/src/main/java/com/senmesh/sfile/service/FileSecurityService.java new file mode 100644 index 0000000..11f9465 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/service/FileSecurityService.java @@ -0,0 +1,88 @@ +package com.senmesh.sfile.service; + +import java.util.List; + +import com.senmesh.sfile.dto.FileSecurityDTO; +import com.senmesh.sfile.dto.FileSecurityShareCheckDTO; +import com.senmesh.sfile.dto.FileSecurityReviewDTO; + +/** + * 文件安全检测Service + */ +public interface FileSecurityService { + + /** + * 异步提交MeshSafe检测(上传/解包落库后调用,失败仅标记不影响主流程) + * 已有检测中/通过/不通过记录时跳过 + * + * @param fileCode 文件编码 + * @param fileName 文件名 + */ + void submitScanAsync(String fileCode, String fileName); + + /** + * 异步重新提交MeshSafe检测(重新检测场景) + * 仅已有检测中记录时跳过 + * + * @param fileCode 文件编码 + * @param fileName 文件名 + */ + void resubmitScanAsync(String fileCode, String fileName); + + /** + * 查询文件最新检测记录 + * + * @param fileCode 文件编码 + * @return FileSecurityDTO 无记录返回null + */ + FileSecurityDTO latest(String fileCode); + + /** + * 校验文件(含文件夹子文件)是否允许分享/传输 + * 检测不通过或检测中则抛出业务异常 + * + * @param userFileId 用户文件id(普通文件) + */ + void checkShareable(Long userFileId); + + /** + * 分享/传输预检:统计文件(含文件夹子文件)的安全检测拦截情况,供前端弹窗提示 + * + * @param userFileId 用户文件id(普通文件) + * @return FileSecurityShareCheckDTO 检测关闭时返回全零结果 + */ + FileSecurityShareCheckDTO shareCheck(Long userFileId); + + /** + * 分享/传输前置处理:文件夹内存在检测未通过文件且用户确认跳过(onlyPassed)时, + * 返回需排除的用户文件ID列表;单文件被拦截或未确认跳过时抛业务异常 + * + * @param userFileId 用户文件id(普通文件) + * @param onlyPassed 用户是否确认仅分享/传输通过的内容 + * @param actionName 动作名(分享/传输,用于提示文案) + * @return List 需排除的用户文件ID,空列表表示无需排除 + */ + List resolveShareExclusions(Long userFileId, boolean onlyPassed, String actionName); + + /** + * 人工复核修改检测结果(超管/机构管理员) + * 新增一条检测记录留痕,并尽力回写MeshSafe + * + * @param reviewDTO 复核参数 + * @return FileSecurityDTO 新的检测结果 + */ + FileSecurityDTO review(FileSecurityReviewDTO reviewDTO); + + /** + * 重新提交检测(超管/机构管理员) + * + * @param fileCode 文件编码 + */ + void rescan(String fileCode); + + /** + * 轮询未完成的检测任务(定时任务调用): + * 无taskId的记录补提交,有taskId的轮询结论,超时标记检测失败 + */ + void pollPendingScans(); +} diff --git a/backend/src/main/java/com/senmesh/sfile/service/NormalUserFileService.java b/backend/src/main/java/com/senmesh/sfile/service/NormalUserFileService.java new file mode 100644 index 0000000..3e9f87a --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/service/NormalUserFileService.java @@ -0,0 +1,19 @@ +package com.senmesh.sfile.service; + +import com.senmesh.sfile.dto.UserFileCreateDTO; +import com.senmesh.sfile.dto.UserFileDTO; + +/** + * 普通用户文件Service + */ +public interface NormalUserFileService { + + /** + * 创建普通用户文件 + * + * @param createDTO 创建DTO + * @return UserFileDTO + */ + UserFileDTO create(UserFileCreateDTO createDTO); +} + diff --git a/backend/src/main/java/com/senmesh/sfile/service/ShareUserFileService.java b/backend/src/main/java/com/senmesh/sfile/service/ShareUserFileService.java new file mode 100644 index 0000000..736264c --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/service/ShareUserFileService.java @@ -0,0 +1,31 @@ +package com.senmesh.sfile.service; + +import com.senmesh.sfile.dto.ShareUserFileCreateDTO; +import com.senmesh.sfile.dto.UserFileDTO; +import java.util.List; + +/** + * 分享用户文件Service + */ +public interface ShareUserFileService { + + /** + * 创建分享用户文件 + * 根据普通文件ID创建分享文件夹,并复制其下所有文件类型的子文件 + * + * @param createDTO 创建DTO + * @return 分享文件夹ID + */ + Long create(ShareUserFileCreateDTO createDTO); + + /** + * 根据ID和访问码查询分享文件 + * + * @param id 分享文件ID + * @param accessCode 访问码 + * @param parentId 父文件夹ID(可选,不传则查询所有子文件) + * @return + */ + List list(Long id, String accessCode, Long parentId); +} + diff --git a/backend/src/main/java/com/senmesh/sfile/service/TransferFileMonitorService.java b/backend/src/main/java/com/senmesh/sfile/service/TransferFileMonitorService.java new file mode 100644 index 0000000..265ca73 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/service/TransferFileMonitorService.java @@ -0,0 +1,22 @@ +package com.senmesh.sfile.service; + +import java.nio.file.Path; + +/** + * 传输文件监听服务 + */ +public interface TransferFileMonitorService { + + /** + * 扫描并处理传输目录中的文件 + */ + void scanAndProcess(); + + /** + * 解包单个传输文件 + * + * @param zipFilePath zip文件路径 + */ + void unpackTransferFile(Path zipFilePath); +} + diff --git a/backend/src/main/java/com/senmesh/sfile/service/TransferUserFileService.java b/backend/src/main/java/com/senmesh/sfile/service/TransferUserFileService.java new file mode 100644 index 0000000..7fa2f24 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/service/TransferUserFileService.java @@ -0,0 +1,19 @@ +package com.senmesh.sfile.service; + +import com.senmesh.sfile.dto.TransferUserFileCreateDTO; + +/** + * 传输用户文件Service + */ +public interface TransferUserFileService { + + /** + * 创建传输用户文件 + * 根据 FileProperties#location 的类型决定是内穿外还是外传内 + * + * @param createDTO 创建DTO + * @return 主键ID + */ + Long create(TransferUserFileCreateDTO createDTO); +} + diff --git a/backend/src/main/java/com/senmesh/sfile/service/UploadConfigService.java b/backend/src/main/java/com/senmesh/sfile/service/UploadConfigService.java new file mode 100644 index 0000000..417f66d --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/service/UploadConfigService.java @@ -0,0 +1,38 @@ +package com.senmesh.sfile.service; + +import com.senmesh.sfile.dto.UploadConfigDTO; +import com.senmesh.sfile.dto.UploadConfigModifyDTO; + +/** + * 机构上传配置Service + * + * @author liu on 2026-09-14 + */ +public interface UploadConfigService { + + /** + * 查询当前登录机构的上传配置 + * 未配置时返回默认策略(允许上传全部类型,不限大小) + * + * @return UploadConfigDTO + */ + UploadConfigDTO info(); + + /** + * 保存当前登录机构的上传配置(机构管理员/平台超管) + * + * @param modifyDTO 修改DTO + * @return Boolean + */ + Boolean modify(UploadConfigModifyDTO modifyDTO); + + /** + * 校验文件是否满足当前登录机构的上传配置,不满足抛业务异常 + * 无登录机构(个人用户)或机构未配置时不限制 + * + * @param fileName 文件名 + * @param fileSize 文件大小(字节),为空时跳过大小校验 + */ + void check(String fileName, Long fileSize); + +} diff --git a/backend/src/main/java/com/senmesh/sfile/service/UserFileService.java b/backend/src/main/java/com/senmesh/sfile/service/UserFileService.java new file mode 100644 index 0000000..97b2ca5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/service/UserFileService.java @@ -0,0 +1,142 @@ +package com.senmesh.sfile.service; + +import com.senmesh.sfile.dto.ExpandUserFileCreateDTO; +import com.senmesh.sfile.dto.ExpandUserFileDTO; +import com.senmesh.sfile.dto.UserFileCreateDTO; +import com.senmesh.sfile.dto.UserFileDTO; +import com.senmesh.sfile.dto.UserFileModifyDTO; +import com.senmesh.sfile.dto.UserFileModifyStatusDTO; +import com.senmesh.sfile.dto.UserFileQueryDTO; +import com.senmesh.sfile.dto.UserFileRecordDTO; +import com.senmesh.sfile.dto.UserFileRecordQueryDTO; +import com.senmesh.sfile.dto.UserFileStatisticsDTO; + +import java.util.List; + +/** + * 用户文件Service + */ +public interface UserFileService { + + /** + * 创建用户文件 + * + * @param createDTO 创建DTO + * @return UserFileDTO + */ + UserFileDTO create(UserFileCreateDTO createDTO); + + /** + * 根据普通文件创建新的文件(复制) + * 创建一个文件夹,文件名为原文件名+时间戳,然后复制原文件下所有文件类型的子文件 + * + * @param expandCreateDTO 扩展创建DTO + * @return 扩展用户文件DTO(包含文件夹信息和文件列表) + */ + ExpandUserFileDTO create(ExpandUserFileCreateDTO expandCreateDTO); + + /** + * 根据文件夹和文件列表创建文件夹和文件(用于传输文件解包) + * 1. 从 folder 中获取 userId 和 rootType + * 2. 创建文件夹 + * 3. 遍历文件列表,通过 fileCode 获取文件流,上传文件获取新的 fileCode,然后创建用户文件记录 + * + * @param folder 文件夹信息(包含 userId、rootType、fileName 等) + * @param files 文件列表(每个文件包含 fileCode、fileName 等) + * @return 扩展用户文件DTO(包含创建后的文件夹信息和文件列表) + */ + ExpandUserFileDTO create(UserFileDTO folder, List files); + + /** + * 修改用户文件 + * + * @param modifyDTO 修改DTO + */ + void modify(UserFileModifyDTO modifyDTO); + + /** + * 修改用户文件状态 + * + * @param modifyStatusDTO 修改状态DTO + */ + void modifyStatus(UserFileModifyStatusDTO modifyStatusDTO); + + /** + * 修改用户文件状态(校验用户权限) + * + * @param modifyStatusDTO 修改状态DTO + * @param userId 用户ID + */ + void modifyStatus(UserFileModifyStatusDTO modifyStatusDTO, Long userId); + + /** + * 删除用户文件 + * + * @param id 主键ID + */ + void remove(Long id); + + /** + * 删除用户文件(校验用户权限) + * + * @param id 主键ID + * @param userId 用户ID + */ + void remove(Long id, Long userId); + + /** + * 批量删除用户文件(校验用户权限) + * + * @param ids 主键ID列表 + * @param userId 用户ID + */ + void removeByIds(List ids, Long userId); + + /** + * 列表查询 + * + * @param queryDTO 查询DTO + * @return List + */ + List list(UserFileQueryDTO queryDTO); + + /** + * 分页查询 + * + * @param queryDTO 查询DTO + */ + void page(UserFileQueryDTO queryDTO); + + /** + * 单个查询 + * + * @param queryDTO 查询DTO + * @return UserFileDTO + */ + UserFileDTO find(UserFileQueryDTO queryDTO); + + /** + * 单个查询(不存在抛异常) + * + * @param queryDTO 查询DTO + * @return UserFileDTO + */ + UserFileDTO findOne(UserFileQueryDTO queryDTO); + + /** + * 按文件种类统计文件个数和总大小 + * + * @param queryDTO 查询DTO + * @return List + */ + List statisticsByCategory(UserFileQueryDTO queryDTO); + + /** + * 按手机号分页查询文件记录(上传/发送/接收,系统管理员) + * 记录类型与本端部署位置有关:内网侧发送为内穿外(2)、接收为外传内(3);外网侧相反 + * + * @param queryDTO 查询DTO + */ + void pageRecordByPhone(UserFileRecordQueryDTO queryDTO); +} + diff --git a/backend/src/main/java/com/senmesh/sfile/service/UserSpaceService.java b/backend/src/main/java/com/senmesh/sfile/service/UserSpaceService.java new file mode 100644 index 0000000..6dff348 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/service/UserSpaceService.java @@ -0,0 +1,60 @@ +package com.senmesh.sfile.service; + +import com.senmesh.sfile.dto.UserSpaceCreateDTO; +import com.senmesh.sfile.dto.UserSpaceDTO; +import com.senmesh.sfile.dto.UserSpaceModifyDTO; +import com.senmesh.sfile.dto.UserSpaceQueryDTO; + +import java.util.List; + +/** + * 用户空间Service + */ +public interface UserSpaceService { + + /** + * 创建用户空间 + * + * @param createDTO 创建DTO + * @return 主键ID + */ + Long create(UserSpaceCreateDTO createDTO); + + /** + * 修改用户空间 + * + * @param modifyDTO 修改DTO + */ + void modify(UserSpaceModifyDTO modifyDTO); + + /** + * 删除用户空间 + * + * @param id 主键ID + */ + void remove(Long id); + + /** + * 列表查询 + * + * @param queryDTO 查询DTO + * @return List + */ + List list(UserSpaceQueryDTO queryDTO); + + /** + * 分页查询 + * + * @param queryDTO 查询DTO + */ + void page(UserSpaceQueryDTO queryDTO); + + /** + * 单个查询 + * + * @param queryDTO 查询DTO + * @return UserSpaceDTO + */ + UserSpaceDTO find(UserSpaceQueryDTO queryDTO); +} + diff --git a/backend/src/main/java/com/senmesh/sfile/service/impl/FileCategoryServiceImpl.java b/backend/src/main/java/com/senmesh/sfile/service/impl/FileCategoryServiceImpl.java new file mode 100644 index 0000000..1385115 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/service/impl/FileCategoryServiceImpl.java @@ -0,0 +1,67 @@ +package com.senmesh.sfile.service.impl; + +import com.senmesh.common.util.ListUtil; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.sfile.convert.FileCategoryConvert; +import com.senmesh.sfile.dao.FileCategoryMapper; +import com.senmesh.sfile.dto.FileCategoryCreateDTO; +import com.senmesh.sfile.dto.FileCategoryDTO; +import com.senmesh.sfile.dto.FileCategoryModifyDTO; +import com.senmesh.sfile.dto.FileCategoryQueryDTO; +import com.senmesh.sfile.entity.FileCategory; +import com.senmesh.sfile.service.FileCategoryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 文件种类ServiceImpl + */ +@Service +public class FileCategoryServiceImpl implements FileCategoryService { + + @Autowired + private FileCategoryMapper fileCategoryMapper; + + @Override + @Transactional + public Long create(FileCategoryCreateDTO createDTO) { + FileCategory fileCategory = FileCategoryConvert.INSTANCE.toEntity(createDTO); + fileCategoryMapper.saveEntity(fileCategory); + return fileCategory.getId(); + } + + @Override + @Transactional + public void modify(FileCategoryModifyDTO modifyDTO) { + FileCategory fileCategory = FileCategoryConvert.INSTANCE.toEntity(modifyDTO); + fileCategoryMapper.updateEntitySelective(fileCategory); + } + + @Override + @Transactional + public void remove(Long id) { + fileCategoryMapper.deleteEntity(FileCategory.builder().id(id).build(), + UserContextHolder.getLoginUserId()); + } + + @Override + public List list(FileCategoryQueryDTO queryDTO) { + queryDTO.disablePage(); + return fileCategoryMapper.list(queryDTO); + } + + @Override + public void page(FileCategoryQueryDTO queryDTO) { + fileCategoryMapper.list(queryDTO); + } + + @Override + public FileCategoryDTO find(FileCategoryQueryDTO queryDTO) { + List fileCategoryDTOs = this.list(queryDTO); + return ListUtil.first(fileCategoryDTOs); + } +} + diff --git a/backend/src/main/java/com/senmesh/sfile/service/impl/FileRiskServiceImpl.java b/backend/src/main/java/com/senmesh/sfile/service/impl/FileRiskServiceImpl.java new file mode 100644 index 0000000..c85aa52 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/service/impl/FileRiskServiceImpl.java @@ -0,0 +1,330 @@ +package com.senmesh.sfile.service.impl; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.common.util.ListUtil; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.component.file.entity.FileRecord; +import com.senmesh.component.file.service.FileRecordService; +import com.senmesh.component.file.service.FileService; +import com.senmesh.component.file.util.FileStorageUtils; +import com.senmesh.config.dto.ConfigDTO; +import com.senmesh.config.dto.ConfigOperatorDTO; +import com.senmesh.config.entity.Config; +import com.senmesh.config.service.ConfigService; +import com.senmesh.sdk.dify.dto.DifyChatRequest; +import com.senmesh.sdk.dify.dto.DifyChatResponse; +import com.senmesh.sdk.dify.dto.DifyFileUploadRequest; +import com.senmesh.sdk.dify.dto.DifyFileUploadResponse; +import com.senmesh.sdk.dify.service.DifyClient; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.frame.redis.dto.LockDTO; +import com.senmesh.frame.redis.redisson.RedissonUtils; +import com.senmesh.sfile.convert.FileRiskConvert; +import com.senmesh.sfile.dao.FileRiskMapper; +import com.senmesh.sfile.dto.FileRiskCreateDTO; +import com.senmesh.sfile.dto.FileRiskDTO; +import com.senmesh.sfile.dto.FileRiskQueryDTO; +import com.senmesh.sfile.entity.FileRisk; +import com.senmesh.sfile.service.FileRiskService; +import com.senmesh.usercenter.constants.OrgConstants; +import java.io.IOException; +import java.util.HashMap; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.assertj.core.util.Lists; +import org.springframework.aop.framework.AopContext; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.InputStream; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * 文件风险ServiceImpl + */ +@Slf4j +@Service +public class FileRiskServiceImpl implements FileRiskService { + + private static final String RISK_RULE_CONFIG_CODE = "risk_rule"; + private static final String MIN_AUDIT_RISK_LEVEL_CONFIG_CODE = "min_audit_risk_level"; + private static final String DIFY_USER_ID = "senmeshfile"; + + /** + * 规则生成 API Key + */ + @Value("${dify.risk.rule.api-key}") + private String riskRuleApiKey; + + /** + * 文件智能风险预警 API Key + */ + @Value("${dify.risk.scan.api-key}") + private String riskScanApiKey; + + @Autowired + private ConfigService configService; + + @Autowired + private FileRiskMapper fileRiskMapper; + + @Autowired + private FileService fileService; + + @Autowired + private FileRecordService fileRecordService; + + /** + * 获取文件风险锁DTO + * + * @param fileCode 文件编码 + * @return LockDTO + */ + public static LockDTO getLockDTO(String fileCode) { + Assert.notBlank(fileCode, "文件编码不能为空"); + return LockDTO.builder() + .methodName("filerisk") + .tryLockWaitTime(0L) + .lockTimeout(60 * 5L) + .arg(fileCode) + .failMsg("该文件风险正在被操作") + .build(); + } + + @Override + @Transactional + public FileRiskDTO create(FileRiskCreateDTO createDTO) { + String fileCode = createDTO.getFileCode(); + FileRiskQueryDTO queryDTO = FileRiskQueryDTO.builder().fileCode(fileCode).build(); + + return RedissonUtils.lockAndSave(getLockDTO(fileCode), + () -> this.find(queryDTO), () -> { + FileRisk fileRisk = FileRiskConvert.INSTANCE.toEntity(createDTO); + fileRiskMapper.saveEntity(fileRisk); + FileRiskDTO fileRiskDTO = new FileRiskDTO(); + BeanUtils.copyProperties(fileRisk, + fileRiskDTO); + return fileRiskDTO;//FileRiskConvert.INSTANCE.toDto(fileRisk); + }); + } + + @Override + public String getRiskRule(Long orgId) { + ConfigDTO configDTO = configService.queryOrgConfigByCode(orgId, RISK_RULE_CONFIG_CODE); + return configDTO == null ? null : configDTO.getConfigValue(); + } + + @Override + @Transactional + public void saveRiskRule(String riskRule) { + configService.createOrModify(UserContextHolder.getExistLoginOrgId(), RISK_RULE_CONFIG_CODE, riskRule); + } + + @Override + public String getMinAuditRiskLevel(Long orgId) { + ConfigDTO configDTO = configService.queryOrgConfigByCode(orgId, MIN_AUDIT_RISK_LEVEL_CONFIG_CODE); + return configDTO == null ? null : configDTO.getConfigValue(); + } + + @Override + @Transactional + public void saveMinAuditRiskLevel(String minAuditRiskLevel) { + configService.createOrModify(UserContextHolder.getExistLoginOrgId(), MIN_AUDIT_RISK_LEVEL_CONFIG_CODE, minAuditRiskLevel); + } + + + + @Override + public FileRiskDTO scanFileRisk(String fileCode) { + // 1. 查询或创建记录 + FileRiskQueryDTO queryDTO = FileRiskQueryDTO.builder().fileCode(fileCode).build(); + FileRiskDTO fileRiskDTO = this.find(queryDTO); + + if (fileRiskDTO == null) { + // 1.1 记录不存在,创建新记录 + log.info("文件风险不存在,创建新记录,fileCode: {}", fileCode); + FileRiskCreateDTO createDTO = FileRiskCreateDTO.builder() + .fileCode(fileCode) + .build(); + fileRiskDTO = ((FileRiskService) AopContext.currentProxy()).create(createDTO); + } + + if (StringUtils.isNotBlank(fileRiskDTO.getRiskJson())) { + return fileRiskDTO; + } + + // 2. 如果 difyFileJson 为空,则上传文件 + DifyFileUploadResponse uploadResponse = null; + if (StringUtils.isBlank(fileRiskDTO.getDifyFileJson())) { + uploadResponse = uploadFileToDify(fileCode, riskScanApiKey); + String difyFileJson = JsonUtils.toJsonString(uploadResponse); + // 3. 更新 difyFileJson 字段 + FileRisk updateFileRisk = FileRisk.builder() + .id(fileRiskDTO.getId()) + .difyFileJson(difyFileJson) + .build(); + fileRiskMapper.updateEntitySelective(updateFileRisk); + // 更新 DTO + fileRiskDTO.setDifyFileJson(difyFileJson); + } else { + // 从 difyFileJson 中解析 uploadFileId + uploadResponse = JsonUtils.toObject(fileRiskDTO.getDifyFileJson(), DifyFileUploadResponse.class); + } + + // 3. 如果 riskJson 为空,则调用 Dify Chat 分析 + Map inputs = new HashMap<>(); + inputs.put("gz", this.getRiskRule(OrgConstants.PLATFORM_ORG_ID)); + inputs.put("srwj", + Collections.singletonList( + DifyChatRequest.DifyFileInfo.builder() + .type("document") + .uploadFileId(uploadResponse.getId()) + .build() + )); + DifyChatRequest chatRequest = DifyChatRequest.builder() + .query("请分析这个文件的风险") + .user(DIFY_USER_ID) + .inputs(inputs) + .files(Lists.emptyList()) + .build(); + + AlitaResult chatResult = DifyClient.chatMessages(riskScanApiKey, chatRequest); + Assert.isTrue(chatResult.getSuccess() , + "调用 Dify Chat 失败,fileCode: " + fileCode + ", error: " + chatResult.getMsg()); + + DifyChatResponse chatResponse = chatResult.getData(); + String answer = chatResponse.getAnswer(); + + // 解析风险等级 + String maxRiskLevel = parseMaxRiskLevel(chatResponse); + if (StringUtils.isBlank(maxRiskLevel)) { + log.warn("未能从 Dify 返回结果中解析出 max_risk_level,fileCode: {}", fileCode); + maxRiskLevel = null; // 默认为空 + } + + // 更新 riskJson 和 maxRiskLevel + FileRisk updateFileRisk = FileRisk.builder() + .id(fileRiskDTO.getId()) + .maxRiskLevel(maxRiskLevel) + .riskJson(answer) + .build(); + fileRiskMapper.updateEntitySelective(updateFileRisk); + log.info("更新文件风险成功,fileCode: {}, maxRiskLevel: {}", fileCode, maxRiskLevel); + + // 更新 DTO + fileRiskDTO.setMaxRiskLevel(maxRiskLevel); + fileRiskDTO.setRiskJson(answer); + return fileRiskDTO; + } + + + + + /** + * 获取 Dify 风险规则 + * 上传文件到 Dify 并调用规则生成 API,返回生成的风险规则 + * + * @param fileCode 文件编码 + * @return Dify 返回的 answer + */ + public String getDifyRiskRule(String fileCode) { + // 1. 上传文件到 Dify + DifyFileUploadResponse uploadResponse = uploadFileToDify(fileCode, riskRuleApiKey); + String uploadFileId = uploadResponse.getId(); + Assert.notBlank(uploadFileId, "上传文件到 Dify 失败,fileCode: " + fileCode); + + // 2. 调用 Dify Chat API(规则生成) + Map inputs = new HashMap<>(); + inputs.put("file", + Collections.singletonList( + DifyChatRequest.DifyFileInfo.builder() + .type("document") + .uploadFileId(uploadResponse.getId()) + .build() + )); + DifyChatRequest chatRequest = DifyChatRequest.builder() + .query("请分析这个文件") + .user(DIFY_USER_ID) + .inputs(inputs) + .files(Lists.emptyList()) + .build(); + + + AlitaResult chatResult = DifyClient.chatMessages(riskRuleApiKey, chatRequest); + Assert.isTrue(chatResult.getSuccess(), + "调用 Dify Chat 失败,fileCode: " + fileCode + ", error: " + chatResult.getMsg()); + + DifyChatResponse chatResponse = chatResult.getData(); + return chatResponse.getAnswer(); + } + + @Override + public List list(FileRiskQueryDTO queryDTO) { + queryDTO.disablePage(); + return fileRiskMapper.list(queryDTO); + } + + @Override + public void page(FileRiskQueryDTO queryDTO) { + fileRiskMapper.list(queryDTO); + } + + @Override + public FileRiskDTO find(FileRiskQueryDTO queryDTO) { + List list = this.list(queryDTO); + return ListUtil.first(list); + } + + /** + * 上传文件到 Dify + * + * @param fileCode 文件编码 + * @param apiKey API密钥 + * @return DifyFileUploadResponse + */ + private DifyFileUploadResponse uploadFileToDify(String fileCode, String apiKey) { + // 1. 获取文件流 + FileRecord fileRecord = fileRecordService.find(FileRecord.builder().fileCode(fileCode).build()); + try(InputStream fileStream = FileStorageUtils.get().download(fileRecord.getFilePath())){ + Assert.notNull(fileStream, "获取文件流失败,fileCode: " + fileCode); + + // 2. 上传文件到 Dify + DifyFileUploadRequest uploadRequest = DifyFileUploadRequest.builder() + .inputStream(fileStream) + .fileName(fileRecord.getFileName()) + .user(DIFY_USER_ID) + .build(); + + AlitaResult uploadResult = DifyClient.uploadFile(apiKey, uploadRequest); + Assert.isTrue(uploadResult.getSuccess() , + "上传文件到 Dify 失败,fileCode: " + fileCode + ", error: " + uploadResult.getMsg()); + + DifyFileUploadResponse uploadResponse = uploadResult.getData(); + return uploadResponse; + } catch (Exception e) { + throw new BusinessException(e); + } + + } + + /** + * 从Dify返回的响应中解析最高风险等级 + * + * @param chatResponse Dify返回的响应 + * @return 最高风险等级:1重度/2中度/3轻度 + */ + private String parseMaxRiskLevel(DifyChatResponse chatResponse) { + Map resultMap = JsonUtils.toMap(chatResponse.getAnswer()); + Object level = resultMap.get("max_risk_level"); + return level == null ? null : String.valueOf(resultMap.get("max_risk_level")); + } +} + diff --git a/backend/src/main/java/com/senmesh/sfile/service/impl/FileSecurityServiceImpl.java b/backend/src/main/java/com/senmesh/sfile/service/impl/FileSecurityServiceImpl.java new file mode 100644 index 0000000..f43271f --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/service/impl/FileSecurityServiceImpl.java @@ -0,0 +1,529 @@ +package com.senmesh.sfile.service.impl; + +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.ListUtil; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.component.file.entity.FileRecord; +import com.senmesh.component.file.service.FileRecordService; +import com.senmesh.component.file.util.FileStorageUtils; +import com.senmesh.frame.redis.dto.LockDTO; +import com.senmesh.frame.redis.redisson.RedissonUtils; +import com.senmesh.sfile.client.MeshSafeClient; +import com.senmesh.sfile.client.MeshSafeScanResult; +import com.senmesh.sfile.config.MeshSafeProperties; +import com.senmesh.sfile.constant.FileTypeEnum; +import com.senmesh.sfile.constant.RootTypeEnum; +import com.senmesh.sfile.constant.SecurityScanStatusEnum; +import com.senmesh.sfile.dao.FileSecurityMapper; +import com.senmesh.sfile.dto.FileSecurityDTO; +import com.senmesh.sfile.dto.FileSecurityShareCheckDTO; +import com.senmesh.sfile.dto.FileSecurityReviewDTO; +import com.senmesh.sfile.dto.UserFileDTO; +import com.senmesh.sfile.dto.UserFileQueryDTO; +import com.senmesh.sfile.entity.FileSecurity; +import com.senmesh.sfile.service.FileSecurityService; +import com.senmesh.sfile.service.UserFileService; +import com.senmesh.usercenter.user.service.OrgUserService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.aop.framework.AopContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 文件安全检测ServiceImpl + *

+ * 对接 MeshSafe 文件安全检测服务:上传/传输接收解包后自动送检, + * 检测不通过的文件禁止分享与跨网传输(下载预览不受限), + * 管理员可人工复核修改检测结果(留痕)。 + */ +@Slf4j +@Service +public class FileSecurityServiceImpl implements FileSecurityService { + + private static final String MESHSAFE_ACTION_PASS = "pass"; + + private static final String MESHSAFE_ACTION_MANUAL_REVIEW = "manual_review"; + + private static final String MESHSAFE_ACTION_REJECT = "reject"; + + private static final String MESHSAFE_STATUS_COMPLETED = "completed"; + + private static final String MESHSAFE_STATUS_FAILED = "failed"; + + @Autowired + private MeshSafeProperties meshSafeProperties; + + @Autowired + private MeshSafeClient meshSafeClient; + + @Autowired + private FileSecurityMapper fileSecurityMapper; + + @Autowired + private FileRecordService fileRecordService; + + @Autowired + private UserFileService userFileService; + + @Autowired + private OrgUserService orgUserService; + + @Override + @Async("asyncExecutor") + public void submitScanAsync(String fileCode, String fileName) { + submitScanInternal(fileCode, fileName, false); + } + + @Override + @Async("asyncExecutor") + public void resubmitScanAsync(String fileCode, String fileName) { + submitScanInternal(fileCode, fileName, true); + } + + @Override + public FileSecurityDTO latest(String fileCode) { + Assert.notBlank(fileCode, "文件编码不能为空"); + List list = fileSecurityMapper.list(null, fileCode); + return ListUtil.first(list); + } + + @Override + public void checkShareable(Long userFileId) { + FileSecurityShareCheckDTO check = shareCheck(userFileId); + if (!check.getBlockedFileNames().isEmpty()) { + throw new BusinessException( + buildBlockedMessage(check.getBlockedFileNames(), "安全检测未通过,禁止分享与传输")); + } + if (!check.getScanningFileNames().isEmpty()) { + throw new BusinessException( + buildBlockedMessage(check.getScanningFileNames(), "正在安全检测中,请稍后再试")); + } + // 检测失败:降级策略为fail-closed时同样禁止 + if (!Boolean.TRUE.equals(meshSafeProperties.getFailOpen()) + && !check.getFailedFileNames().isEmpty()) { + throw new BusinessException( + buildBlockedMessage(check.getFailedFileNames(), "安全检测失败,请重新检测后再试")); + } + } + + @Override + public FileSecurityShareCheckDTO shareCheck(Long userFileId) { + FileSecurityShareCheckDTO result = FileSecurityShareCheckDTO.builder() + .userFileId(userFileId) + .totalFileCount(0) + .blockedCount(0) + .scanningCount(0) + .failedCount(0) + .blockedFileNames(new ArrayList<>()) + .scanningFileNames(new ArrayList<>()) + .failedFileNames(new ArrayList<>()) + .excludeFileIds(new ArrayList<>()) + .build(); + if (!isEnabled()) { + return result; + } + Assert.notNull(userFileId, "文件ID不能为空"); + UserFileDTO userFile = userFileService.findOne(UserFileQueryDTO.builder() + .id(userFileId) + .rootType(RootTypeEnum.NORMAL.getType()) + .build()); + result.setFileType(userFile.getFileType()); + + // 收集该文件及子文件(文件夹展开)的记录,pathLike为包含匹配,精确过滤自身与子孙节点 + UserFileQueryDTO queryDTO = UserFileQueryDTO.builder() + .userId(userFile.getUserId()) + .rootType(RootTypeEnum.NORMAL.getType()) + .fileType(FileTypeEnum.FILE.getType()) + .pathLike(userFile.getPath()) + .build(); + queryDTO.disablePage(); + List files = userFileService.list(queryDTO); + String pathPrefix = userFile.getPath() + ","; + Map> filesByCode = files.stream() + .filter(f -> StringUtils.isNotBlank(f.getFileCode())) + .filter(f -> f.getPath().equals(userFile.getPath()) || f.getPath().startsWith(pathPrefix)) + .collect(Collectors.groupingBy(UserFileDTO::getFileCode)); + result.setTotalFileCount(filesByCode.values().stream().mapToInt(List::size).sum()); + if (filesByCode.isEmpty()) { + return result; + } + + collectStatusFiles(result, filesByCode, SecurityScanStatusEnum.REJECTED.getStatus(), true); + collectStatusFiles(result, filesByCode, SecurityScanStatusEnum.SCANNING.getStatus(), true); + boolean excludeFailed = !Boolean.TRUE.equals(meshSafeProperties.getFailOpen()); + collectStatusFiles(result, filesByCode, SecurityScanStatusEnum.FAILED.getStatus(), excludeFailed); + + result.setBlockedCount(result.getBlockedFileNames().size()); + result.setScanningCount(result.getScanningFileNames().size()); + result.setFailedCount(result.getFailedFileNames().size()); + return result; + } + + @Override + public List resolveShareExclusions(Long userFileId, boolean onlyPassed, String actionName) { + FileSecurityShareCheckDTO check = shareCheck(userFileId); + boolean hasBlocked = !check.getBlockedFileNames().isEmpty(); + boolean hasScanning = !check.getScanningFileNames().isEmpty(); + boolean hasFailed = !Boolean.TRUE.equals(meshSafeProperties.getFailOpen()) + && !check.getFailedFileNames().isEmpty(); + if (!hasBlocked && !hasScanning && !hasFailed) { + return Collections.emptyList(); + } + boolean isFolder = FileTypeEnum.FOLDER.getType().equals(check.getFileType()); + if (!isFolder || !onlyPassed) { + // 单文件被拦截,或文件夹未确认跳过:维持整体拦截 + this.checkShareable(userFileId); + } + if (check.getTotalFileCount() <= check.getExcludeFileIds().size()) { + throw new BusinessException("文件夹内没有检测通过的文件,无法" + actionName); + } + return check.getExcludeFileIds(); + } + + /** + * 按检测状态收集命中的文件名与需排除的文件ID + */ + private void collectStatusFiles(FileSecurityShareCheckDTO result, + Map> filesByCode, String status, boolean exclude) { + List records = fileSecurityMapper.listLatestByStatusIn( + new ArrayList<>(filesByCode.keySet()), Collections.singletonList(status)); + for (FileSecurityDTO record : records) { + List matched = filesByCode.get(record.getFileCode()); + if (matched == null) { + continue; + } + for (UserFileDTO file : matched) { + if (SecurityScanStatusEnum.REJECTED.getStatus().equals(status)) { + result.getBlockedFileNames().add(file.getFileName()); + } else if (SecurityScanStatusEnum.SCANNING.getStatus().equals(status)) { + result.getScanningFileNames().add(file.getFileName()); + } else { + result.getFailedFileNames().add(file.getFileName()); + } + if (exclude) { + result.getExcludeFileIds().add(file.getId()); + } + } + } + } + + @Override + public FileSecurityDTO review(FileSecurityReviewDTO reviewDTO) { + Long operateUserId = UserContextHolder.getExistLoginUserId(); + Assert.isTrue(isEnabled(), "文件安全检测未开启"); + Assert.isTrue(UserContextHolder.isSuperior() || UserContextHolder.isAdministrator(), + "当前用户无操作权限"); + + String fileCode = reviewDTO.getFileCode(); + String decision = reviewDTO.getDecision(); + Assert.isTrue(MESHSAFE_ACTION_PASS.equals(decision) || MESHSAFE_ACTION_REJECT.equals(decision), + "复核结论不合法,仅支持pass/reject"); + + FileSecurityDTO latest = latest(fileCode); + Assert.notNull(latest, "该文件无安全检测记录"); + this.checkOrgScope(fileCode); + + FileSecurity record = FileSecurity.builder() + .fileCode(fileCode) + .taskId(latest.getTaskId()) + .scanStatus(MESHSAFE_ACTION_PASS.equals(decision) + ? SecurityScanStatusEnum.PASSED.getStatus() + : SecurityScanStatusEnum.REJECTED.getStatus()) + .action(MESHSAFE_ACTION_MANUAL_REVIEW) + .reason(reviewDTO.getComment()) + .reviewComment(reviewDTO.getComment()) + .build(); + fileSecurityMapper.saveEntity(record); + + // 尽力回写MeshSafe人工复核结论,失败仅告警不影响本地生效 + if (Boolean.TRUE.equals(meshSafeProperties.getReviewSyncToMeshSafe()) + && StringUtils.isNotBlank(latest.getTaskId())) { + try { + meshSafeClient.review(latest.getTaskId(), decision, reviewDTO.getComment()); + } catch (Exception e) { + log.warn("回写MeshSafe人工复核结论失败, fileCode: {}, taskId: {}", + fileCode, latest.getTaskId(), e); + } + } + + log.info("文件安全检测人工复核完成, fileCode: {}, decision: {}, operateUserId: {}", + fileCode, decision, operateUserId); + + FileSecurityDTO result = new FileSecurityDTO(); + result.setFileCode(record.getFileCode()); + result.setTaskId(record.getTaskId()); + result.setScanStatus(record.getScanStatus()); + result.setAction(record.getAction()); + result.setReason(record.getReason()); + result.setReviewComment(record.getReviewComment()); + return result; + } + + @Override + @Transactional + public void rescan(String fileCode) { + Assert.isTrue(isEnabled(), "文件安全检测未开启"); + Assert.isTrue(UserContextHolder.isSuperior() || UserContextHolder.isAdministrator(), + "当前用户无操作权限"); + Assert.notBlank(fileCode, "文件编码不能为空"); + + FileSecurityDTO latest = latest(fileCode); + Assert.isTrue(latest == null + || !SecurityScanStatusEnum.isScanning(latest.getScanStatus()), + "文件正在安全检测中,请勿重复操作"); + this.checkOrgScope(fileCode); + + FileRecord fileRecord = fileRecordService.find( + FileRecord.builder().fileCode(fileCode).build()); + Assert.notNull(fileRecord, "文件不存在"); + + // 事务使本方法成为advised方法,AopContext.currentProxy()才能取到本Service代理 + ((FileSecurityService) AopContext.currentProxy()) + .resubmitScanAsync(fileCode, fileRecord.getFileName()); + } + + @Override + public void pollPendingScans() { + if (!isEnabled()) { + return; + } + List scanningList = fileSecurityMapper.listScanning(); + if (scanningList.isEmpty()) { + return; + } + log.info("开始轮询未完成的文件安全检测任务, 数量: {}", scanningList.size()); + for (FileSecurityDTO scanning : scanningList) { + try { + if (isPollTimeout(scanning)) { + markFailed(scanning.getId(), "安全检测超时"); + continue; + } + if (StringUtils.isBlank(scanning.getTaskId())) { + // 定时兜底补提交(异步提交失败未落taskId的记录) + this.submitScanningRecord(scanning.getId()); + } else { + MeshSafeScanResult result = meshSafeClient.getScan(scanning.getTaskId()); + applyScanResult(scanning.getId(), result); + } + } catch (Exception e) { + log.warn("轮询文件安全检测任务失败, id: {}, fileCode: {}, taskId: {}", + scanning.getId(), scanning.getFileCode(), scanning.getTaskId(), e); + } + } + } + + /** + * 补提交指定检测中记录:仍为检测中且无taskId时才提交 + */ + private void submitScanningRecord(Long recordId) { + FileSecurity record = fileSecurityMapper.getById(recordId); + if (record == null + || !SecurityScanStatusEnum.isScanning(record.getScanStatus()) + || StringUtils.isNotBlank(record.getTaskId())) { + return; + } + if (!RedissonUtils.tryLock(getLockDTO(record.getFileCode()))) { + return; + } + try { + // 双重检查:拿到锁后记录可能已被其他实例处理 + record = fileSecurityMapper.getById(recordId); + if (record == null + || !SecurityScanStatusEnum.isScanning(record.getScanStatus()) + || StringUtils.isNotBlank(record.getTaskId())) { + return; + } + byte[] fileBytes = readFileBytes(record.getFileCode()); + MeshSafeScanResult result = meshSafeClient.scan(resolveFileName(record.getFileCode()), fileBytes); + applyScanResult(recordId, result); + } catch (Exception e) { + log.error("补提交文件安全检测失败, recordId: {}, fileCode: {}", recordId, record.getFileCode(), e); + } finally { + RedissonUtils.unlock(getLockDTO(record.getFileCode())); + } + } + + /** + * 提交检测(可在异步线程或轮询任务中执行) + * + * @param force false-已有检测中/通过/不通过记录时跳过; true-仅已有检测中记录时跳过(用于重新检测) + */ + private void submitScanInternal(String fileCode, String fileName, boolean force) { + try { + if (!isEnabled() || StringUtils.isBlank(fileCode)) { + return; + } + if (!RedissonUtils.tryLock(getLockDTO(fileCode))) { + return; + } + try { + FileSecurityDTO latest = latest(fileCode); + if (latest != null + && !SecurityScanStatusEnum.FAILED.getStatus().equals(latest.getScanStatus())) { + if (!force || SecurityScanStatusEnum.isScanning(latest.getScanStatus())) { + return; + } + } + FileSecurity record = FileSecurity.builder() + .fileCode(fileCode) + .scanStatus(SecurityScanStatusEnum.SCANNING.getStatus()) + .build(); + fileSecurityMapper.saveEntity(record); + + byte[] fileBytes = readFileBytes(fileCode); + MeshSafeScanResult result = meshSafeClient.scan( + StringUtils.defaultIfBlank(fileName, resolveFileName(fileCode)), fileBytes); + applyScanResult(record.getId(), result); + } finally { + RedissonUtils.unlock(getLockDTO(fileCode)); + } + } catch (Exception e) { + log.error("文件安全检测提交失败, fileCode: {}", fileCode, e); + markFailedQuietly(fileCode, "安全检测提交失败: " + e.getMessage()); + } + } + + /** + * 按MeshSafe结论回写检测记录 + * completed时manual_review与reject均判为不通过(保守不放行,由人工复核放行) + */ + private void applyScanResult(Long recordId, MeshSafeScanResult result) { + FileSecurity update = FileSecurity.builder().id(recordId).build(); + String status = result.getStatus(); + if (MESHSAFE_STATUS_COMPLETED.equals(status)) { + update.setTaskId(result.getTaskId()); + update.setAction(result.getAction()); + update.setReason(result.getReason()); + update.setResultJson(result.getRawJson()); + if (MESHSAFE_ACTION_PASS.equals(result.getAction())) { + update.setScanStatus(SecurityScanStatusEnum.PASSED.getStatus()); + } else { + update.setScanStatus(SecurityScanStatusEnum.REJECTED.getStatus()); + } + } else if (MESHSAFE_STATUS_FAILED.equals(status)) { + update.setTaskId(result.getTaskId()); + update.setScanStatus(SecurityScanStatusEnum.FAILED.getStatus()); + update.setReason(StringUtils.defaultIfBlank(result.getReason(), + StringUtils.defaultIfBlank(result.getMessage(), "安全检测失败"))); + update.setResultJson(result.getRawJson()); + } else { + // pending/running: 记录taskId等待轮询 + update.setTaskId(result.getTaskId()); + } + fileSecurityMapper.updateEntitySelective(update); + } + + private void markFailedQuietly(String fileCode, String reason) { + try { + FileSecurityDTO latest = latest(fileCode); + if (latest != null && SecurityScanStatusEnum.isScanning(latest.getScanStatus())) { + markFailed(latest.getId(), reason); + } + } catch (Exception e) { + log.error("标记检测失败状态异常, fileCode: {}", fileCode, e); + } + } + + private void markFailed(Long recordId, String reason) { + FileSecurity update = FileSecurity.builder() + .id(recordId) + .scanStatus(SecurityScanStatusEnum.FAILED.getStatus()) + .reason(reason) + .build(); + fileSecurityMapper.updateEntitySelective(update); + } + + private boolean isPollTimeout(FileSecurityDTO scanning) { + Integer timeoutMinutes = meshSafeProperties.getPollTimeoutMinutes(); + if (timeoutMinutes == null || timeoutMinutes <= 0) { + return false; + } + Date baseline = scanning.getUpdateTime() != null + ? scanning.getUpdateTime() : scanning.getCreateTime(); + if (baseline == null) { + return false; + } + return System.currentTimeMillis() - baseline.getTime() > timeoutMinutes * 60L * 1000L; + } + + private String resolveFileName(String fileCode) { + FileRecord fileRecord = fileRecordService.find( + FileRecord.builder().fileCode(fileCode).build()); + return fileRecord == null ? fileCode : fileRecord.getFileName(); + } + + private byte[] readFileBytes(String fileCode) { + FileRecord fileRecord = fileRecordService.find( + FileRecord.builder().fileCode(fileCode).build()); + Assert.notNull(fileRecord, "未找到对应文件, fileCode: " + fileCode); + try (InputStream inputStream = FileStorageUtils.get().download(fileRecord.getFilePath())) { + Assert.notNull(inputStream, "获取文件流失败, fileCode: " + fileCode); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] buffer = new byte[8192]; + int len; + while ((len = inputStream.read(buffer)) > 0) { + bos.write(buffer, 0, len); + } + return bos.toByteArray(); + } catch (BusinessException e) { + throw e; + } catch (Exception e) { + throw new BusinessException("读取待检测文件失败, fileCode: " + fileCode, e); + } + } + + /** + * 非平台超管(机构管理员)操作文件时,校验文件所属用户属于本机构 + */ + private void checkOrgScope(String fileCode) { + if (UserContextHolder.isSuperior()) { + return; + } + UserFileDTO ownerFile = userFileService.find(UserFileQueryDTO.builder() + .fileCode(fileCode) + .rootType(RootTypeEnum.NORMAL.getType()) + .build()); + Assert.notNull(ownerFile, "文件不存在"); + Assert.isTrue( + orgUserService.existOrgUser(UserContextHolder.getExistLoginOrgId(), ownerFile.getUserId()), + "只能操作本机构的文件"); + } + + private String buildBlockedMessage(List fileNames, String reasonSuffix) { + List distinct = fileNames.stream().distinct().limit(3).collect(Collectors.toList()); + String detail = String.join("、", distinct) + + (fileNames.size() > 3 ? " 等" : ""); + return "文件「" + detail + "」" + reasonSuffix; + } + + private boolean isEnabled() { + return Boolean.TRUE.equals(meshSafeProperties.getEnabled()) + && StringUtils.isNotBlank(meshSafeProperties.getBaseUrl()) + && StringUtils.isNotBlank(meshSafeProperties.getClientId()) + && StringUtils.isNotBlank(meshSafeProperties.getSecret()); + } + + public static LockDTO getLockDTO(String fileCode) { + Assert.notBlank(fileCode, "文件编码不能为空"); + return LockDTO.builder() + .methodName("filesecurity") + .tryLockWaitTime(0L) + .lockTimeout(60 * 5L) + .arg(fileCode) + .failMsg("该文件安全检测正在被操作") + .build(); + } +} diff --git a/backend/src/main/java/com/senmesh/sfile/service/impl/NormalUserFileServiceImpl.java b/backend/src/main/java/com/senmesh/sfile/service/impl/NormalUserFileServiceImpl.java new file mode 100644 index 0000000..0553098 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/service/impl/NormalUserFileServiceImpl.java @@ -0,0 +1,65 @@ +package com.senmesh.sfile.service.impl; + +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.component.file.entity.FileRecord; +import com.senmesh.component.file.service.FileRecordService; +import com.senmesh.sfile.constant.FileStatusEnum; +import com.senmesh.sfile.constant.FileTypeEnum; +import com.senmesh.sfile.constant.RootTypeEnum; +import com.senmesh.sfile.dto.UserFileCreateDTO; +import com.senmesh.sfile.dto.UserFileDTO; +import com.senmesh.sfile.service.FileSecurityService; +import com.senmesh.sfile.service.NormalUserFileService; +import com.senmesh.sfile.service.UploadConfigService; +import com.senmesh.sfile.service.UserFileService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * 普通用户文件ServiceImpl + */ +@Service +public class NormalUserFileServiceImpl implements NormalUserFileService { + + @Autowired + private UserFileService userFileService; + + @Autowired + private UploadConfigService uploadConfigService; + + @Autowired + private FileRecordService fileRecordService; + + @Autowired + private FileSecurityService fileSecurityService; + + @Override + @Transactional + public UserFileDTO create(UserFileCreateDTO createDTO) { + createDTO.setUserId(UserContextHolder.getExistLoginUserId()); + // 设置根类型为普通 + createDTO.setRootType(RootTypeEnum.NORMAL.getType()); + createDTO.setFileStatus(FileStatusEnum.NORMAL.getStatus()); + // 机构上传配置校验(仅校验文件,文件夹无后缀/大小概念) + if (FileTypeEnum.isFile(createDTO.getFileType())) { + Long fileSize = null; + if (StringUtils.isNotBlank(createDTO.getFileCode())) { + FileRecord fileRecord = fileRecordService + .find(FileRecord.builder().fileCode(createDTO.getFileCode()).build()); + fileSize = fileRecord == null ? null : fileRecord.getFileSize(); + } + uploadConfigService.check(createDTO.getFileName(), fileSize); + } + // 创建用户文件 + UserFileDTO userFileDTO = userFileService.create(createDTO); + // MeshSafe文件安全检测(异步送检,不影响主流程) + if (FileTypeEnum.isFile(createDTO.getFileType()) + && StringUtils.isNotBlank(createDTO.getFileCode())) { + fileSecurityService.submitScanAsync(createDTO.getFileCode(), createDTO.getFileName()); + } + return userFileDTO; + } +} + diff --git a/backend/src/main/java/com/senmesh/sfile/service/impl/ShareUserFileServiceImpl.java b/backend/src/main/java/com/senmesh/sfile/service/impl/ShareUserFileServiceImpl.java new file mode 100644 index 0000000..59c5de5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/service/impl/ShareUserFileServiceImpl.java @@ -0,0 +1,85 @@ +package com.senmesh.sfile.service.impl; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.RandomUtils; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.sfile.constant.FileStatusEnum; +import com.senmesh.sfile.constant.RootTypeEnum; +import com.senmesh.sfile.dto.ExpandUserFileCreateDTO; +import com.senmesh.sfile.dto.ShareUserFileCreateDTO; +import com.senmesh.sfile.dto.UserFileDTO; +import com.senmesh.sfile.dto.UserFileQueryDTO; +import com.senmesh.sfile.service.FileSecurityService; +import com.senmesh.sfile.service.ShareUserFileService; +import com.senmesh.sfile.service.UserFileService; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Calendar; +import java.util.Date; + +/** + * 分享用户文件ServiceImpl + */ +@Service +public class ShareUserFileServiceImpl implements ShareUserFileService { + + @Autowired + private UserFileService userFileService; + + @Autowired + private FileSecurityService fileSecurityService; + + @Override + @Transactional + public Long create(ShareUserFileCreateDTO createDTO) { + Long userFileId = createDTO.getUserFileId(); + Long userId = UserContextHolder.getExistLoginUserId(); + Integer validDays = createDTO.getValidDays(); + + // MeshSafe安全检测校验:单文件不通过直接拦截;文件夹确认跳过时仅分享通过的内容 + List excludeIds = fileSecurityService.resolveShareExclusions( + userFileId, Boolean.TRUE.equals(createDTO.getOnlyPassed()), "分享"); + + // 根据有效天数计算过期时间 + Calendar calendar = Calendar.getInstance(); + calendar.setTime(new Date()); + calendar.add(Calendar.DAY_OF_MONTH, validDays); + Date endTime = calendar.getTime(); + + // 生成随机6位数字访问码 + String accessCode = RandomUtils.nextSixVerificationCode(); + + // 调用UserFileService的重载create方法,根据普通文件创建分享文件 + ExpandUserFileCreateDTO expandCreateDTO = ExpandUserFileCreateDTO.builder() + .userFileId(userFileId) + .userId(userId) + .rootType(RootTypeEnum.SHARE.getType()) + .fileStatus(FileStatusEnum.NORMAL.getStatus()) + .accessCode(accessCode) + .endTime(endTime) + .excludeFileIds(excludeIds) + .build(); + return userFileService.create(expandCreateDTO).getFolder().getId(); + } + + @Override + public List list(Long id, String accessCode, Long parentId) { + UserFileDTO userFileDTO = userFileService.findOne(UserFileQueryDTO.builder() + .id(id) + .rootType(RootTypeEnum.SHARE.getType()) + .build()); + Assert.isTrue(userFileDTO.getAccessCode().equals(accessCode), "访问码不正确"); + + return userFileService.list(UserFileQueryDTO.builder() + .rootType(RootTypeEnum.SHARE.getType()) + .pathLike(userFileDTO.getPath()) + .parentId(parentId) + .build()); + } + + +} + diff --git a/backend/src/main/java/com/senmesh/sfile/service/impl/TransferFileMonitorServiceImpl.java b/backend/src/main/java/com/senmesh/sfile/service/impl/TransferFileMonitorServiceImpl.java new file mode 100644 index 0000000..57b8174 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/service/impl/TransferFileMonitorServiceImpl.java @@ -0,0 +1,598 @@ +package com.senmesh.sfile.service.impl; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.component.file.config.FileProperties; +import com.senmesh.component.file.service.FileService; +import com.senmesh.sfile.constant.FileLocationEnum; +import com.senmesh.sfile.constant.FileStatusEnum; +import com.senmesh.sfile.constant.RootTypeEnum; +import com.senmesh.sfile.dto.ExpandUserFileDTO; +import com.senmesh.sfile.dto.FileRiskDTO; +import com.senmesh.sfile.dto.TransferMetadataDTO; +import com.senmesh.sfile.dto.UserFileDTO; +import com.senmesh.sfile.dto.UserFileModifyStatusDTO; +import com.senmesh.sfile.service.FileRiskService; +import com.senmesh.sfile.service.FileSecurityService; +import com.senmesh.sfile.service.TransferFileMonitorService; +import com.senmesh.sfile.service.UserFileService; +import com.senmesh.usercenter.user.dto.UserDTO; +import com.senmesh.usercenter.user.service.UserService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.FileTime; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipInputStream; + +/** + * 传输文件监听服务实现 + */ +@Service +@Slf4j +public class TransferFileMonitorServiceImpl implements TransferFileMonitorService { + + @Autowired + private FileProperties fileProperties; + + @Autowired + private UserFileService userFileService; + + @Autowired + private FileService fileService; + + @Autowired + private FileRiskService fileRiskService; + + @Autowired + private FileSecurityService fileSecurityService; + + @Autowired + private UserService userService; + + @Override + public void scanAndProcess() { + String transferReceiveDir = fileProperties.getTransfer().getReceiveDir(); + Path receiveDir = Paths.get(transferReceiveDir); + + try { + if (!Files.exists(receiveDir)) { + Files.createDirectories(receiveDir); + log.info("创建接收目录: {}", receiveDir); + return; + } + + // 1. 扫描 .zip 文件(解包逻辑) + List zipFiles = Files.list(receiveDir) + .filter(Files::isRegularFile) + .filter(p -> p.toString().endsWith(".zip")) + .filter(p -> !p.toString().endsWith(".tmp")) + .sorted(Comparator.comparing(p -> { + try { + return Files.getLastModifiedTime(p); + } catch (IOException e) { + return FileTime.fromMillis(0); + } + })) + .limit(10) + .collect(Collectors.toList()); + + if (!zipFiles.isEmpty()) { + log.info("发现 {} 个待处理的传输文件", zipFiles.size()); + for (Path zipFile : zipFiles) { + processZipFile(zipFile); + } + } + + // 2. 扫描 .finish 文件(完成标记逻辑) + List finishFiles = Files.list(receiveDir) + .filter(Files::isRegularFile) + .filter(p -> p.toString().endsWith(".finish")) + .sorted(Comparator.comparing(p -> { + try { + return Files.getLastModifiedTime(p); + } catch (IOException e) { + return FileTime.fromMillis(0); + } + })) + .limit(10) + .collect(Collectors.toList()); + + if (!finishFiles.isEmpty()) { + log.info("发现 {} 个完成标记文件", finishFiles.size()); + for (Path finishFile : finishFiles) { + processFinishFile(finishFile); + } + } + + } catch (Exception e) { + log.error("扫描传输目录失败", e); + } + } + + /** + * 处理单个 ZIP 文件(解包逻辑) + */ + private void processZipFile(Path zipFile) { + String fileName = zipFile.getFileName().toString(); + + try { + // 1. 校验 ZIP 包内文件大小是否匹配,并返回元数据 + TransferMetadataDTO metadata = verifyFileMD5(zipFile); + if (metadata == null) { + // 校验不通过,跳过 + return; + } + + if (!resolveTargetUser(zipFile, metadata)) { + return; + } + + log.info("文件大小校验通过,开始解包: {}", fileName); + + // 2. 解包并创建用户文件(传入已解析的元数据,直接创建为正常状态) + ExpandUserFileDTO result = unpackTransferFileInternal(zipFile, metadata); + + // 3. MeshSafe文件安全检测(异步送检,不影响解包流程) + submitSecurityScan(result); + + // 4. 创建 .finish 文件到发送目录,告诉发送方处理完成 + createFinishFile(fileName); + + // 5. 删除已处理的 ZIP 文件 + Files.delete(zipFile); + log.info("处理完成,已删除 ZIP 文件: {}", fileName); + + } catch (Exception e) { + log.error("处理文件失败,跳过: {}", fileName, e); + } + } + + /** + * MeshSafe文件安全检测:解包产生的每个文件异步送检,失败不影响解包流程 + */ + private void submitSecurityScan(ExpandUserFileDTO expandUserFileDTO) { + if (expandUserFileDTO == null || expandUserFileDTO.getFiles() == null) { + return; + } + for (UserFileDTO file : expandUserFileDTO.getFiles()) { + if (StringUtils.isNotBlank(file.getFileCode())) { + fileSecurityService.submitScanAsync(file.getFileCode(), file.getFileName()); + } + } + } + + /** + * 根据源端用户手机号和用户类型映射目标端用户。映射失败时改名为 .error,避免定时任务重复解包。 + */ + private boolean resolveTargetUser(Path zipFile, TransferMetadataDTO metadata) { + String fileName = zipFile.getFileName().toString(); + String sourceUserPhone = StringUtils.trim(metadata.getSourceUserPhone()); + Integer sourceUserType = metadata.getSourceUserType(); + + if (StringUtils.isBlank(sourceUserPhone) || sourceUserType == null) { + renameToError(zipFile, "元数据缺少源端用户手机号或用户类型"); + return false; + } + + List users = userService.listUncanceledByExactPhoneAndType(sourceUserPhone, sourceUserType); + if (users.size() != 1) { + renameToError(zipFile, "目标端用户匹配数量异常: phone=" + maskPhone(sourceUserPhone) + + ", userType=" + sourceUserType + ", count=" + users.size()); + return false; + } + + Long targetUserId = users.get(0).getId(); + ExpandUserFileDTO expandUserFile = metadata.getExpandUserFile(); + if (expandUserFile == null || expandUserFile.getFolder() == null) { + renameToError(zipFile, "元数据缺少文件夹信息"); + return false; + } + + Long sourceUserId = metadata.getSourceUserId() == null + ? expandUserFile.getFolder().getUserId() + : metadata.getSourceUserId(); + expandUserFile.getFolder().setUserId(targetUserId); + if (expandUserFile.getFiles() != null) { + for (UserFileDTO file : expandUserFile.getFiles()) { + file.setUserId(targetUserId); + } + } + log.info("传输用户映射成功: file={}, sourceUserId={}, sourcePhone={}, sourceType={}, targetUserId={}", + fileName, sourceUserId, maskPhone(sourceUserPhone), sourceUserType, targetUserId); + return true; + } + + private void renameToError(Path zipFile, String reason) { + String fileName = zipFile.getFileName().toString(); + Path errorFile = zipFile.resolveSibling(fileName + ".error"); + try { + Files.move(zipFile, errorFile, StandardCopyOption.REPLACE_EXISTING); + log.error("传输文件停止解包并改名为 .error: file={}, errorFile={}, reason={}", + fileName, errorFile.getFileName(), reason); + } catch (Exception e) { + log.error("传输文件停止解包但改名 .error 失败: file={}, reason={}", fileName, reason, e); + } + } + + private String maskPhone(String phone) { + if (StringUtils.length(phone) < 7) { + return phone; + } + return phone.substring(0, 3) + "****" + phone.substring(phone.length() - 4); + } + + + + /** + * 校验文件大小(对比元数据中的大小) + * + * @param zipFile ZIP 文件路径 + * @return 校验通过返回 TransferMetadataDTO,否则返回 null + */ + private TransferMetadataDTO verifyFileMD5(Path zipFile) { + String fileName = zipFile.getFileName().toString(); + + try (ZipFile zf = new ZipFile(zipFile.toFile())) { + // 1. 读取元数据 + ZipEntry metadataEntry = zf.getEntry("transferMetadata.json"); + if (metadataEntry == null) { + log.debug("ZIP 文件缺少 transferMetadata.json,跳过(可能还在传输中): {}", fileName); + return null; + } + + TransferMetadataDTO metadata; + try (InputStream is = zf.getInputStream(metadataEntry)) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int len; + while ((len = is.read(buffer)) > 0) { + baos.write(buffer, 0, len); + } + String metadataJson = new String(baos.toByteArray(), StandardCharsets.UTF_8); + metadata = JsonUtils.toObject(metadataJson, TransferMetadataDTO.class); + } + + // 2. 检查是否包含 ExpandUserFileDTO + ExpandUserFileDTO expandUserFile = metadata.getExpandUserFile(); + if (expandUserFile == null || expandUserFile.getFiles() == null) { + log.debug("元数据中不包含文件信息,跳过(可能还在传输中): {}", fileName); + return null; + } + if (expandUserFile.getFiles().isEmpty()) { + log.debug("传输空文件夹: {}", fileName); + return metadata; + } + + // 3. 创建 userFileId -> fileSize 的映射 + Map expectedSizeMap = new HashMap<>(); + for (UserFileDTO file : expandUserFile.getFiles()) { + if (file.getFileSize() != null) { + expectedSizeMap.put(file.getId(), file.getFileSize()); + } + } + + log.info("开始校验文件大小: {}", fileName); + + // 4. 遍历 ZIP 中的文件,对比大小 + Enumeration entries = zf.entries(); + int fileCount = 0; + int successCount = 0; + + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + + // 跳过目录和元数据文件 + if (entry.isDirectory() || "transferMetadata.json".equals(entry.getName())) { + continue; + } + + fileCount++; + + // 提取 userFileId(去掉路径) + String entryName = entry.getName(); + String userFileIdStr = entryName.contains("/") + ? entryName.substring(entryName.lastIndexOf("/") + 1) + : entryName; + + // 解析 userFileId + Long userFileId; + try { + userFileId = Long.parseLong(userFileIdStr); + } catch (NumberFormatException e) { + log.warn("无法解析 userFileId: {}", userFileIdStr); + continue; + } + + // 获取期望的文件大小 + Long expectedSize = expectedSizeMap.get(userFileId); + if (expectedSize == null) { + log.warn("元数据中未找到文件大小信息: userFileId={}", userFileId); + continue; + } + + // 获取实际文件大小 + long actualSize = entry.getSize(); + + // 对比大小 + if (actualSize != expectedSize) { + log.error("文件大小不匹配: userFileId={}, 期望={} bytes, 实际={} bytes", + userFileId, expectedSize, actualSize); + return null; + } + + successCount++; + log.debug("文件大小校验通过: userFileId={} ({} bytes)", userFileId, actualSize); + } + + // 5. 检查文件数量是否匹配 + if (fileCount == 0 || successCount != expectedSizeMap.size()) { + log.debug("文件数量不匹配: 期望={}, 实际={}, 跳过(可能还在传输中): {}", + expectedSizeMap.size(), successCount, fileName); + return null; + } + + log.info("文件大小校验通过: {} (共 {} 个文件)", fileName, successCount); + return metadata; + + } catch (Exception e) { + log.error("文件大小校验失败: {}", fileName, e); + return null; + } + } + + + @Override + @Transactional + public void unpackTransferFile(Path zipFilePath) { + // 先校验并获取元数据 + TransferMetadataDTO metadata = verifyFileMD5(zipFilePath); + if (metadata == null) { + throw new RuntimeException("ZIP 文件校验失败或格式不正确"); + } + // 调用内部方法 + unpackTransferFileInternal(zipFilePath, metadata); + } + + /** + * 解包传输文件(内部方法,接收已解析的元数据) + * + * @return 解包后创建的文件夹和文件信息 + */ + private ExpandUserFileDTO unpackTransferFileInternal(Path zipFilePath, TransferMetadataDTO metadata) { + String fileName = zipFilePath.getFileName().toString(); + log.info("开始解包文件: {}", fileName); + + try { + // 1. 从元数据中获取文件夹和文件信息 + ExpandUserFileDTO expandUserFile = metadata.getExpandUserFile(); + Assert.notNull(expandUserFile, "metadata 缺少 expandUserFile"); + + UserFileDTO folder = expandUserFile.getFolder(); + List files = expandUserFile.getFiles(); + + // 2. 确定 rootType 并设置到 folder 中 + String location = fileProperties.getTransfer().getLocation(); + String rootType; + if (FileLocationEnum.INTERNAL.getLocation().equals(location)) { + rootType = RootTypeEnum.EXTERNAL_TO_INTERNAL.getType(); + } else { + rootType = RootTypeEnum.INTERNAL_TO_EXTERNAL.getType(); + } + folder.setRootType(rootType); + + // 3. 创建 userFileId -> UserFileDTO 的映射 + Map fileMap = new HashMap<>(); + for (UserFileDTO file : files) { + fileMap.put(file.getId(), file); + } + + // 4. 解析 ZIP 文件,上传文件并设置 fileCode + try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFilePath.toFile()))) { + ZipEntry entry; + while ((entry = zis.getNextEntry()) != null) { + // 跳过元数据文件和目录 + if ("transferMetadata.json".equals(entry.getName()) || entry.isDirectory()) { + zis.closeEntry(); + continue; + } + + // 提取 userFileId(去掉路径) + String entryName = entry.getName(); + String userFileIdStr = entryName.contains("/") + ? entryName.substring(entryName.lastIndexOf("/") + 1) + : entryName; + + // 解析 userFileId + Long userFileId; + try { + userFileId = Long.parseLong(userFileIdStr); + } catch (NumberFormatException e) { + log.warn("无法解析 userFileId,跳过: {}", userFileIdStr); + zis.closeEntry(); + continue; + } + + // 获取文件信息 + UserFileDTO fileInfo = fileMap.get(userFileId); + if (fileInfo == null) { + log.warn("元数据中未找到文件信息,跳过: userFileId={}", userFileId); + zis.closeEntry(); + continue; + } + + // 读取文件流到内存 + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buffer = new byte[8192]; + int len; + while ((len = zis.read(buffer)) > 0) { + baos.write(buffer, 0, len); + } + + // 上传文件获取 fileCode + String originalFileName = fileInfo.getFileName(); + log.debug("开始上传文件: userFileId={}, 文件名={}", userFileId, originalFileName); + ByteArrayInputStream fileStream = new ByteArrayInputStream(baos.toByteArray()); + String fileCode = fileService.upload(originalFileName, fileStream).getFileCode(); + log.debug("文件上传成功: userFileId={}, fileCode={}", userFileId, fileCode); + + // 设置 fileCode 到文件信息中 + fileInfo.setFileCode(fileCode); + + zis.closeEntry(); + } + } + + // 5. 检查是否开启解包风险校验 + String fileStatus = FileStatusEnum.NORMAL.getStatus(); + if (Boolean.TRUE.equals(fileProperties.getTransfer().getUnpackRiskCheck())) { + log.info("解包风险校验已开启,开始扫描文件: {}", fileName); + fileStatus = scanFilesForRisk(files, folder); + } + folder.setFileStatus(fileStatus); + + // 6. 调用 UserFileService 的重载方法创建文件夹和文件 + ExpandUserFileDTO result = userFileService.create(folder, files); + + log.info("文件解包成功: {}, 创建文件夹ID: {}", fileName, result.getFolder().getId()); + + return result; + + } catch (Exception e) { + log.error("解包文件失败: {}", fileName, e); + throw new RuntimeException("解包文件失败: " + e.getMessage(), e); + } + } + + /** + * 扫描文件风险 + * for循环文件扫描,拿到最高风险等级,跟最低审核风险等级比较,如果不小于则状态给审批中,否则给正常 + * + * @param files 文件列表 + * @param folder 文件夹信息 + * @return 文件状态 + */ + private String scanFilesForRisk(List files, UserFileDTO folder) { + // 1. 获取最低审核风险等级 + Long orgId = UserContextHolder.getExistLoginOrgId(); + String minAuditRiskLevel = fileRiskService.getMinAuditRiskLevel(orgId); + if (StringUtils.isBlank(minAuditRiskLevel)) { + log.info("未配置最低审核风险等级,默认不审核"); + return FileStatusEnum.NORMAL.getStatus(); + } + + // 2. for循环扫描文件,获取最高风险等级 + String maxRiskLevel = "3"; // 默认轻度风险 + for (UserFileDTO file : files) { + String fileCode = file.getFileCode(); + if (StringUtils.isBlank(fileCode)) { + continue; + } + + FileRiskDTO fileRiskDTO = fileRiskService.scanFileRisk(fileCode); + String riskLevel = fileRiskDTO.getMaxRiskLevel(); + if (StringUtils.isNotBlank(riskLevel) && riskLevel.compareTo(maxRiskLevel) < 0) { + maxRiskLevel = riskLevel; + } + } + + // 3. 比较最高风险等级和最低审核风险等级 + if (maxRiskLevel.compareTo(minAuditRiskLevel) <= 0) { + log.info("文件风险等级 {} 不小于最低审核风险等级 {},状态设置为待审核", maxRiskLevel, minAuditRiskLevel); + return FileStatusEnum.PENDING_REVIEW.getStatus(); + } else { + log.info("文件风险等级 {} 小于最低审核风险等级 {},状态设置为正常", maxRiskLevel, minAuditRiskLevel); + return FileStatusEnum.NORMAL.getStatus(); + } + } + + /** + * 创建 .finish 文件到发送目录,告诉对方处理完成 + * + * @param zipFileName ZIP 文件名(例如:123_456.zip) + */ + private void createFinishFile(String zipFileName) { + try { + // 获取发送目录 + String transferSendDir = fileProperties.getTransfer().getSendDir(); + Path sendPath = Paths.get(transferSendDir); + + // 确保发送目录存在 + if (!Files.exists(sendPath)) { + Files.createDirectories(sendPath); + } + + // 创建 .finish 文件 + Path finishFile = sendPath.resolve(zipFileName + ".finish"); + Files.createFile(finishFile); + + log.info("创建完成标记文件到发送目录: {}", finishFile); + } catch (Exception e) { + log.error("创建完成标记文件失败: {}", zipFileName, e); + } + } + + /** + * 处理 .finish 文件(发送方接收到对方的完成标记) + * + * @param finishFile .finish 文件路径(例如:123_456.zip.finish) + */ + private void processFinishFile(Path finishFile) { + String fileName = finishFile.getFileName().toString(); + log.info("处理完成标记文件: {}", fileName); + + try { + // 1. 解析文件名,获取 userFileId + // 文件名格式:123_456.zip.finish + String zipFileName = fileName.replace(".finish", ""); + String[] parts = zipFileName.replace(".zip", "").split("_"); + + if (parts.length != 2) { + log.warn("无法解析完成标记文件名,跳过: {}", fileName); + return; + } + + Long userId = Long.parseLong(parts[0]); + Long folderId = Long.parseLong(parts[1]); + + log.info("解析完成标记文件: folderId={}, userId={}", folderId, userId); + + // 2. 更新文件夹及其所有子文件状态为正常(modifyStatus 会自动更新所有子文件) + UserFileModifyStatusDTO statusDTO = UserFileModifyStatusDTO.builder() + .id(folderId) + .oldStatus(FileStatusEnum.TRANSFERRING.getStatus()) + .newStatus(FileStatusEnum.NORMAL.getStatus()) + .build(); + userFileService.modifyStatus(statusDTO); + log.info("更新文件夹及所有子文件状态为正常: folderId={}", folderId); + + // 3. 删除 .finish 文件 + Files.delete(finishFile); + log.info("处理完成,已删除完成标记文件: {}", fileName); + + } catch (Exception e) { + log.error("处理完成标记文件失败: {}", fileName, e); + } + } +} diff --git a/backend/src/main/java/com/senmesh/sfile/service/impl/TransferUserFileServiceImpl.java b/backend/src/main/java/com/senmesh/sfile/service/impl/TransferUserFileServiceImpl.java new file mode 100644 index 0000000..5a0c925 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/service/impl/TransferUserFileServiceImpl.java @@ -0,0 +1,168 @@ +package com.senmesh.sfile.service.impl; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.component.file.config.FileProperties; +import com.senmesh.component.file.service.FileService; +import com.senmesh.sfile.constant.FileLocationEnum; +import com.senmesh.sfile.constant.FileStatusEnum; +import com.senmesh.sfile.constant.RootTypeEnum; +import com.senmesh.sfile.dto.ExpandUserFileCreateDTO; +import com.senmesh.sfile.dto.ExpandUserFileDTO; +import com.senmesh.sfile.dto.TransferMetadataDTO; +import com.senmesh.sfile.dto.TransferUserFileCreateDTO; +import com.senmesh.sfile.dto.UserFileDTO; +import com.senmesh.sfile.service.FileSecurityService; +import com.senmesh.sfile.service.TransferUserFileService; +import com.senmesh.sfile.service.UserFileService; +import com.senmesh.usercenter.user.dto.UserDTO; +import com.senmesh.usercenter.user.service.UserService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +/** + * 传输用户文件ServiceImpl + */ +@Service +@Slf4j +public class TransferUserFileServiceImpl implements TransferUserFileService { + + @Autowired + private UserFileService userFileService; + + @Autowired + private FileProperties fileProperties; + + @Autowired + private FileService fileService; + + @Autowired + private UserService userService; + + @Autowired + private FileSecurityService fileSecurityService; + + @Override + @Transactional + public Long create(TransferUserFileCreateDTO createDTO) { + Long userId = UserContextHolder.getExistLoginUserId(); + + // MeshSafe安全检测校验:单文件不通过直接拦截;文件夹确认跳过时仅传输通过的内容 + List excludeIds = fileSecurityService.resolveShareExclusions( + createDTO.getUserFileId(), Boolean.TRUE.equals(createDTO.getOnlyPassed()), "传输"); + + // 根据 FileProperties#location 的类型决定是内穿外还是外传内 + String location = fileProperties.getTransfer().getLocation(); + String rootType; + if (FileLocationEnum.INTERNAL.getLocation().equals(location)) { + // 内网 -> 内穿外 + rootType = RootTypeEnum.INTERNAL_TO_EXTERNAL.getType(); + } else { + // 外网 -> 外传内 + rootType = RootTypeEnum.EXTERNAL_TO_INTERNAL.getType(); + } + + // 调用UserFileService的重载create方法 + ExpandUserFileCreateDTO expandCreateDTO = ExpandUserFileCreateDTO.builder() + .userFileId(createDTO.getUserFileId()) + .userId(userId) + .rootType(rootType) + .fileStatus(FileStatusEnum.TRANSFERRING.getStatus()) + .excludeFileIds(excludeIds) + .build(); + ExpandUserFileDTO expandUserFileDTO = userFileService.create(expandCreateDTO); + + // 打包传输文件 + try { + packTransferFiles(expandUserFileDTO); + } catch (Exception e) { + log.error("打包传输文件失败", e); + throw new RuntimeException("打包传输文件失败: " + e.getMessage()); + } + + return expandUserFileDTO.getFolder().getId(); + } + + /** + * 打包传输文件 + * 将文件夹和文件打包成压缩包,并添加transferMetadata.json文件信息 + * + * @param expandUserFileDTO 扩展用户文件DTO + */ + private void packTransferFiles(ExpandUserFileDTO expandUserFileDTO) throws IOException { + UserFileDTO folder = expandUserFileDTO.getFolder(); + List files = expandUserFileDTO.getFiles(); + UserDTO sourceUser = userService.get(folder.getUserId()); + Assert.notNull(sourceUser, "源端用户不存在"); + Assert.notBlank(sourceUser.getPhone(), "源端用户手机号不能为空"); + Assert.notNull(sourceUser.getType(), "源端用户类型不能为空"); + String sourceUserPhone = sourceUser.getPhone().trim(); + + // 1. 创建传输发送目录 + String transferSendDir = fileProperties.getTransfer().getSendDir(); + Path transferPath = Paths.get(transferSendDir); + if (!Files.exists(transferPath)) { + Files.createDirectories(transferPath); + } + + // 2. 创建最终传输包 + String finalFileName = folder.getUserId() + "_" + folder.getId() + ".zip"; + Path finalFilePath = transferPath.resolve(finalFileName); + + try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(finalFilePath.toFile()))) { + // 2.1 添加文件夹中的文件 + String folderName = folder.getFileName(); + for (UserFileDTO file : files) { + String fileCode = file.getFileCode(); + Long userFileId = file.getId(); + + // 创建 ZipEntry(使用 userFileId 命名) + String entryName = folderName + "/" + userFileId; + ZipEntry zipEntry = new ZipEntry(entryName); + zos.putNextEntry(zipEntry); + + // 边读边写 + try (InputStream inputStream = fileService.getFile(fileCode)) { + byte[] buffer = new byte[8192]; + int len; + while ((len = inputStream.read(buffer)) > 0) { + zos.write(buffer, 0, len); + } + } + zos.closeEntry(); + + log.debug("添加文件: userFileId={}, 原文件名={}, 大小={} bytes", + userFileId, file.getFileName(), file.getFileSize()); + } + + // 2.2 添加元数据文件 + TransferMetadataDTO metadata = TransferMetadataDTO.builder() + .expandUserFile(expandUserFileDTO) + .sourceUserId(sourceUser.getId()) + .sourceUserPhone(sourceUserPhone) + .sourceUserType(sourceUser.getType()) + .build(); + + String metadataJson = JsonUtils.toJsonString(metadata); + ZipEntry metadataEntry = new ZipEntry("transferMetadata.json"); + zos.putNextEntry(metadataEntry); + zos.write(metadataJson.getBytes("UTF-8")); + zos.closeEntry(); + } + + log.info("传输文件打包完成: {}", finalFilePath); + } +} diff --git a/backend/src/main/java/com/senmesh/sfile/service/impl/UploadConfigServiceImpl.java b/backend/src/main/java/com/senmesh/sfile/service/impl/UploadConfigServiceImpl.java new file mode 100644 index 0000000..29f2e0e --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/service/impl/UploadConfigServiceImpl.java @@ -0,0 +1,170 @@ +package com.senmesh.sfile.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.frame.redis.aop.annotation.AutoUnLock; +import com.senmesh.frame.redis.dto.LockDTO; +import com.senmesh.frame.redis.redisson.RedissonUtils; +import com.senmesh.sfile.dao.UploadConfigMapper; +import com.senmesh.sfile.dto.UploadConfigDTO; +import com.senmesh.sfile.dto.UploadConfigModifyDTO; +import com.senmesh.sfile.entity.UploadConfig; +import com.senmesh.sfile.service.UploadConfigService; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 机构上传配置ServiceImpl + * + * @author liu on 2026-09-14 + */ +@Service +public class UploadConfigServiceImpl implements UploadConfigService { + + @Autowired + private UploadConfigMapper uploadConfigMapper; + + @Override + public UploadConfigDTO info() { + Long orgId = UserContextHolder.getExistLoginOrgId(); + UploadConfig config = getByOrgId(orgId); + if (config == null) { + // 未配置:默认允许上传全部类型,不限大小 + return UploadConfigDTO.builder() + .orgId(orgId) + .uploadEnabled(Boolean.TRUE) + .allowAllType(Boolean.TRUE) + .configured(Boolean.FALSE) + .build(); + } + return UploadConfigDTO.builder() + .orgId(orgId) + .uploadEnabled(config.getUploadEnabled()) + .allowAllType(config.getAllowAllType()) + .allowedSuffixes(parseSuffixes(config.getAllowedSuffixes())) + .maxFileSize(config.getMaxFileSize()) + .configured(Boolean.TRUE) + .build(); + } + + @Override + @Transactional + @AutoUnLock + public Boolean modify(UploadConfigModifyDTO modifyDTO) { + Assert.isTrue(UserContextHolder.isSuperior() || UserContextHolder.isAdministrator(), + "当前用户无操作权限"); + Long orgId = UserContextHolder.getExistLoginOrgId(); + List suffixes = normalizeSuffixes(modifyDTO.getAllowedSuffixes()); + Assert.isTrue(Boolean.TRUE.equals(modifyDTO.getAllowAllType()) || CollectionUtils.isNotEmpty(suffixes), + "未允许全部类型时,允许的文件后缀不能为空"); + if (modifyDTO.getMaxFileSize() != null) { + Assert.isTrue(modifyDTO.getMaxFileSize() > 0, "单文件大小上限必须大于0"); + } + Assert.isTrue(RedissonUtils.tryLockAutomatically( + LockDTO.builder().methodName("uploadConfigModify").arg(String.valueOf(orgId)).build()), + "上传配置正在修改,请稍后重试"); + + UploadConfig config = getByOrgId(orgId); + boolean exists = config != null; + if (!exists) { + config = UploadConfig.builder().orgId(orgId).build(); + } + config.setUploadEnabled(modifyDTO.getUploadEnabled()); + config.setAllowAllType(modifyDTO.getAllowAllType()); + config.setAllowedSuffixes(CollectionUtils.isEmpty(suffixes) ? null : String.join(",", suffixes)); + config.setMaxFileSize(modifyDTO.getMaxFileSize()); + if (exists) { + return uploadConfigMapper.updateEntitySelective(config, UserContextHolder.getExistLoginUserId()) == 1; + } + uploadConfigMapper.saveEntity(config); + return true; + } + + @Override + public void check(String fileName, Long fileSize) { + Long orgId = UserContextHolder.getLoginOrgId(); + if (orgId == null) { + // 个人用户等无登录机构场景,不受机构配置限制 + return; + } + UploadConfig config = getByOrgId(orgId); + if (config == null) { + // 未配置:默认允许 + return; + } + if (!Boolean.TRUE.equals(config.getUploadEnabled())) { + throw new BusinessException("当前机构已禁止上传文件,请联系机构管理员"); + } + // 文件夹等无后缀场景由调用方跳过,此处后缀为空按白名单不含空处理 + String suffix = extractSuffix(fileName); + if (!Boolean.TRUE.equals(config.getAllowAllType())) { + List allowed = parseSuffixes(config.getAllowedSuffixes()); + if (allowed.isEmpty()) { + throw new BusinessException("当前机构未配置可上传的文件类型,请联系机构管理员"); + } + if (StringUtils.isEmpty(suffix) || !allowed.contains(suffix)) { + throw new BusinessException("仅允许上传后缀为 " + String.join("、", allowed) + " 的文件"); + } + } + if (config.getMaxFileSize() != null && config.getMaxFileSize() > 0 + && fileSize != null && fileSize > config.getMaxFileSize() * 1024 * 1024) { + throw new BusinessException("上传文件过大,单文件最大不得超过" + config.getMaxFileSize() + "MB"); + } + } + + private UploadConfig getByOrgId(Long orgId) { + return uploadConfigMapper.selectOne(new LambdaQueryWrapper() + .eq(UploadConfig::getOrgId, orgId) + .eq(UploadConfig::getDeleted, false)); + } + + /** + * 后缀规范化:去空格/去前导点/转小写/去空元素 + */ + private List normalizeSuffixes(List suffixes) { + if (CollectionUtils.isEmpty(suffixes)) { + return suffixes; + } + return suffixes.stream() + .filter(StringUtils::isNotBlank) + .map(s -> StringUtils.stripStart(s.trim(), ".").toLowerCase()) + .filter(StringUtils::isNotBlank) + .distinct() + .collect(Collectors.toList()); + } + + private List parseSuffixes(String allowedSuffixes) { + if (StringUtils.isBlank(allowedSuffixes)) { + return java.util.Collections.emptyList(); + } + return Arrays.stream(allowedSuffixes.split(",")) + .map(String::trim) + .filter(StringUtils::isNotBlank) + .collect(Collectors.toList()); + } + + /** + * 提取小写后缀(不含点),无后缀返回空串 + */ + private String extractSuffix(String fileName) { + if (StringUtils.isBlank(fileName)) { + return ""; + } + String name = fileName.trim(); + int dot = name.lastIndexOf('.'); + if (dot < 0 || dot == name.length() - 1) { + return ""; + } + return name.substring(dot + 1).toLowerCase(); + } + +} diff --git a/backend/src/main/java/com/senmesh/sfile/service/impl/UserFileServiceImpl.java b/backend/src/main/java/com/senmesh/sfile/service/impl/UserFileServiceImpl.java new file mode 100644 index 0000000..1505632 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/service/impl/UserFileServiceImpl.java @@ -0,0 +1,446 @@ +package com.senmesh.sfile.service.impl; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.ListUtil; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.component.file.config.FileProperties; +import com.senmesh.component.file.service.FileService; +import com.senmesh.component.file.util.FileUtils; +import com.senmesh.sfile.constant.FileLocationEnum; +import com.senmesh.sfile.constant.FileRecordTypeEnum; +import com.senmesh.sfile.constant.FileStatusEnum; +import com.senmesh.sfile.constant.FileTypeEnum; +import com.senmesh.sfile.constant.RootTypeEnum; +import com.senmesh.sfile.convert.UserFileConvert; +import com.senmesh.sfile.dao.UserFileMapper; +import com.senmesh.sfile.dto.ExpandUserFileCreateDTO; +import com.senmesh.sfile.dto.ExpandUserFileDTO; +import com.senmesh.sfile.dto.UserFileCreateDTO; +import com.senmesh.sfile.dto.UserFileDTO; +import com.senmesh.sfile.dto.UserFileModifyDTO; +import com.senmesh.sfile.dto.UserFileModifyStatusDTO; +import com.senmesh.sfile.dto.UserFileQueryDTO; +import com.senmesh.sfile.dto.UserFileRecordDTO; +import com.senmesh.sfile.dto.UserFileRecordQueryDTO; +import com.senmesh.sfile.dto.UserFileStatisticsDTO; +import com.senmesh.sfile.entity.UserFile; +import com.senmesh.sfile.service.UserFileService; +import com.google.common.collect.Sets; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.InputStream; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * 用户文件ServiceImpl + */ +@Slf4j +@Service +public class UserFileServiceImpl implements UserFileService { + + @Autowired + private UserFileMapper userFileMapper; + + @Autowired + private FileService fileService; + + @Autowired + private FileProperties fileProperties; + + @Override + @Transactional + public UserFileDTO create(UserFileCreateDTO createDTO) { + Long parentId = createDTO.getParentId(); + String parentPath = createDTO.getParentPath(); + Long userId = createDTO.getUserId(); + String rootType = createDTO.getRootType(); + + // 1. 校验 userId 和 rootType 不能为空 + Assert.notNull(userId, "用户ID不能为空"); + Assert.notBlank(rootType, "根类型不能为空"); + + // 2. 校验文件类型时fileCode不能为空 + if (FileTypeEnum.isFile(createDTO.getFileType())) { + Assert.notBlank(createDTO.getFileCode(), "文件编码不能为空"); + } + + // 3. 处理 parentPath(性能优化:如果提供了 parentPath,直接使用,避免查询) + if (StringUtils.isBlank(parentPath) && parentId != null && parentId != 0L) { + // 如果没有提供 parentPath,但提供了 parentId,需要查询父节点获取 parentPath + UserFileDTO parentFile = this.findOne(UserFileQueryDTO.builder() + .id(parentId) + .userId(userId) + .rootType(rootType) + .build()); + Assert.isTrue(FileTypeEnum.isFolder(parentFile.getFileType()), "父节点必须是文件夹"); + // 获取父路径用于后续拼接 + parentPath = parentFile.getPath(); + } + // 如果提供了 parentPath,直接信任调用方,不做校验 + + // 4. 插入数据获取ID + UserFile userFile = UserFileConvert.INSTANCE.toEntity(createDTO); + userFileMapper.saveEntity(userFile); + Long newId = userFile.getId(); + + // 5. 构建path + String path = StringUtils.isNotBlank(parentPath) + ? parentPath + CommonConstants.COMMA + newId + : String.valueOf(newId); + + // 6. 更新path + userFile.setPath(path); + userFileMapper.updateEntitySelective(userFile); + + // 7. 转换为DTO返回 + return UserFileConvert.INSTANCE.toDto(userFile); + } + + @Override + @Transactional + public ExpandUserFileDTO create(ExpandUserFileCreateDTO expandCreateDTO) { + Long userFileId = expandCreateDTO.getUserFileId(); + Long userId = expandCreateDTO.getUserId(); + String rootType = expandCreateDTO.getRootType(); + + // 1. 查询普通文件(限制rootType为普通) + UserFileDTO normalFile = this.findOne(UserFileQueryDTO.builder() + .id(userFileId) + .userId(userId) + .rootType(RootTypeEnum.NORMAL.getType()) + .build()); + + // 2. 创建文件夹,文件名 = 原文件名 + 当前时间 + String timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); + String baseFileName = FileTypeEnum.isFile(normalFile.getFileType()) ? FileUtils.getFileNameNoSuffix(normalFile.getFileName()) : normalFile.getFileName(); + String folderName = baseFileName + "_" + timestamp; + + UserFileCreateDTO folderCreateDTO = UserFileCreateDTO.builder() + .userId(userId) + .rootType(rootType) + .fileStatus(expandCreateDTO.getFileStatus()) + .fileType(FileTypeEnum.FOLDER.getType()) + .fileName(folderName) + .parentId(0L) + .endTime(expandCreateDTO.getEndTime()) + .accessCode(expandCreateDTO.getAccessCode()) + .build(); + UserFileDTO folderDTO = this.create(folderCreateDTO); + Long folderId = folderDTO.getId(); + String folderPath = String.valueOf(folderId); + + // 3. 查询需要复制的文件列表 + UserFileQueryDTO queryDTO = UserFileQueryDTO.builder() + .userId(userId) + .rootType(RootTypeEnum.NORMAL.getType()) + .fileType(FileTypeEnum.FILE.getType()) + .pathLike(normalFile.getPath()) + .build(); + queryDTO.disablePage(); + List filesToCopy = this.list(queryDTO); + List excludeFileIds = expandCreateDTO.getExcludeFileIds(); + + // 4. 在文件夹下创建文件对象(跳过需排除的文件,如安全检测未通过确认跳过分享) + List createdFiles = new java.util.ArrayList<>(); + for (UserFileDTO fileDTO : filesToCopy) { + if (excludeFileIds != null && excludeFileIds.contains(fileDTO.getId())) { + log.info("复制用户文件时跳过排除文件: id={}, fileName={}", fileDTO.getId(), fileDTO.getFileName()); + continue; + } + UserFileCreateDTO fileCreateDTO = UserFileCreateDTO.builder() + .userId(userId) + .rootType(rootType) + .fileStatus(expandCreateDTO.getFileStatus()) + .fileType(FileTypeEnum.FILE.getType()) + .fileName(fileDTO.getFileName()) + .fileCode(fileDTO.getFileCode()) + .parentId(folderId) + .parentPath(folderPath) + .build(); + UserFileDTO createdFile = this.create(fileCreateDTO); + createdFiles.add(createdFile); + } + + // 6. 返回结果 + return ExpandUserFileDTO.builder() + .folder(folderDTO) + .files(createdFiles) + .build(); + } + + @Override + @Transactional + public ExpandUserFileDTO create(UserFileDTO folder, List files) { + Long userId = folder.getUserId(); + String rootType = folder.getRootType(); + + // 3. 创建文件夹 + UserFileCreateDTO folderCreateDTO = UserFileCreateDTO.builder() + .userId(userId) + .rootType(rootType) + .fileType(FileTypeEnum.FOLDER.getType()) + .fileName(folder.getFileName()) + .parentId(0L) + .fileStatus(folder.getFileStatus()) + .build(); + UserFileDTO folderDTO = this.create(folderCreateDTO); + Long folderId = folderDTO.getId(); + String folderPath = String.valueOf(folderId); + + log.info("创建文件夹成功: folderId={}, 文件名={}", folderId, folder.getFileName()); + + // 4. 创建文件列表 + List createdFiles = new ArrayList<>(); + for (UserFileDTO fileInfo : files) { + + // 创建文件记录 + UserFileCreateDTO fileCreateDTO = UserFileCreateDTO.builder() + .userId(userId) + .rootType(rootType) + .fileType(FileTypeEnum.FILE.getType()) + .fileName(fileInfo.getFileName()) + .fileCode(fileInfo.getFileCode()) + .parentId(folderId) + .parentPath(folderPath) + .fileStatus(folder.getFileStatus()) + .build(); + + UserFileDTO createdFile = this.create(fileCreateDTO); + createdFiles.add(createdFile); + } + + // 5. 返回结果 + return ExpandUserFileDTO.builder() + .folder(folderDTO) + .files(createdFiles) + .build(); + } + + @Override + @Transactional + public void modify(UserFileModifyDTO modifyDTO) { + Long id = modifyDTO.getId(); + Long userId = modifyDTO.getUserId(); + Long newParentId = modifyDTO.getParentId(); + String rootType = modifyDTO.getRootType(); + + // 1. 根据id+userId+rootType查询文件是否存在 + UserFileDTO existFile = this.findOne(UserFileQueryDTO.builder() + .id(id) + .userId(userId) + .rootType(rootType) + .build()); + + // 2. 判断是否需要更新path(parentId有值且与现存的parentId不一致) + boolean needUpdatePath = newParentId != null + && !newParentId.equals(existFile.getParentId()); + + if (needUpdatePath) { + // 2.1 校验新父节点(如果不是根目录) + if (newParentId != 0L) { + UserFileDTO newParentFile = this.findOne(UserFileQueryDTO.builder() + .id(newParentId) + .userId(userId) + .rootType(rootType) + .build()); + Assert.isTrue(FileTypeEnum.isFolder(newParentFile.getFileType()), "父节点必须是文件夹"); + // 校验新父节点的rootType必须与当前文件相同 + Assert.isTrue(existFile.getRootType().equals(newParentFile.getRootType()), + "不能将文件移动到不同类型的文件夹"); + } + + // 2.2 在SQL中一次性更新当前节点和所有子孙节点的path(SQL内部会限制相同userId和rootType) + userFileMapper.updatePathByParentIdChange(id, newParentId, modifyDTO.getOperateUserId()); + } + + // 3. 更新文件信息 + UserFile userFile = UserFileConvert.INSTANCE.toEntity(modifyDTO); + userFileMapper.updateEntitySelective(userFile); + } + + @Override + @Transactional + public void modifyStatus(UserFileModifyStatusDTO modifyStatusDTO) { + Long id = modifyStatusDTO.getId(); + String oldStatus = modifyStatusDTO.getOldStatus(); + String newStatus = modifyStatusDTO.getNewStatus(); + Long operateUserId = UserContextHolder.getLoginUserId(); + + // 更新文件状态及其所有子文件状态(SQL内部会校验oldStatus并限制相同userId和rootType) + userFileMapper.updateStatusWithChildren(id, oldStatus, newStatus, operateUserId); + } + + @Override + @Transactional + public void modifyStatus(UserFileModifyStatusDTO modifyStatusDTO, Long userId) { + Assert.notNull(userId, "用户ID不能为空"); + Long id = modifyStatusDTO.getId(); + + // 校验文件是否存在且属于该用户 + this.findOne(UserFileQueryDTO.builder() + .id(id) + .userId(userId) + .build()); + + // 调用原方法修改状态 + modifyStatus(modifyStatusDTO); + } + + + @Override + @Transactional + public void remove(Long id) { + // 删除文件及其所有子文件(SQL内部会限制相同userId和rootType) + userFileMapper.deleteFileWithChildren(id, UserContextHolder.getLoginUserId()); + } + + @Override + @Transactional + public void remove(Long id, Long userId) { + Assert.notNull(id, "文件ID不能为空"); + Assert.notNull(userId, "用户ID不能为空"); + + // 校验文件是否存在且属于该用户 + this.findOne(UserFileQueryDTO.builder() + .id(id) + .userId(userId) + .build()); + + // 删除文件及其所有子文件(SQL内部会限制相同userId和rootType) + remove(id); + } + + @Override + @Transactional + public void removeByIds(List ids, Long userId) { + Assert.notEmpty(ids, "文件ID列表不能为空"); + Assert.notNull(userId, "用户ID不能为空"); + + // 循环删除每个文件 + for (Long id : ids) { + remove(id, userId); + } + } + + @Override + public List list(UserFileQueryDTO queryDTO) { + queryDTO.disablePage(); + return userFileMapper.list(queryDTO); + } + + @Override + public void page(UserFileQueryDTO queryDTO) { + userFileMapper.list(queryDTO); + } + + @Override + public UserFileDTO find(UserFileQueryDTO queryDTO) { + List userFileDTOs = this.list(queryDTO); + return ListUtil.first(userFileDTOs); + } + + @Override + public UserFileDTO findOne(UserFileQueryDTO queryDTO) { + UserFileDTO userFileDTO = this.find(queryDTO); + Assert.notNull(userFileDTO, "文件不存在"); + return userFileDTO; + } + + @Override + public List statisticsByCategory(UserFileQueryDTO queryDTO) { + queryDTO.disablePage(); + return userFileMapper.statisticsByCategory(queryDTO); + } + + @Override + public void pageRecordByPhone(UserFileRecordQueryDTO queryDTO) { + Assert.isTrue(UserContextHolder.isSuperior(), "当前用户无操作权限"); + Assert.notBlank(queryDTO.getPhone(), "手机号不能为空"); + queryDTO.setPhone(queryDTO.getPhone().trim()); + if (queryDTO.getRecordType() != null) { + Assert.notNull(FileRecordTypeEnum.getByType(queryDTO.getRecordType()), + "记录类型不合法,仅支持1上传/2发送/3接收"); + } + queryDTO.setRootTypeIn(resolveRootTypes(queryDTO.getRecordType())); + List records = userFileMapper.listRecordByPhone(queryDTO); + fillRecordType(records); + } + + /** + * 记录类型 -> root_type 条件 + * 上传记录固定为普通(1);发送/接收方向与本端部署位置有关: + * 内网侧发送为内穿外(2)、接收为外传内(3);外网侧相反 + * + * @param recordType 记录类型,为空查全部 + */ + private Set resolveRootTypes(Integer recordType) { + if (recordType == null) { + return Sets.newHashSet(RootTypeEnum.NORMAL.getType(), getSendRootType(), getReceiveRootType()); + } + switch (FileRecordTypeEnum.getByType(recordType)) { + case UPLOAD: + return Collections.singleton(RootTypeEnum.NORMAL.getType()); + case SEND: + return Collections.singleton(getSendRootType()); + case RECEIVE: + return Collections.singleton(getReceiveRootType()); + default: + return resolveRootTypes(null); + } + } + + /** + * 本端发送方向:内网侧为内穿外(2),外网侧为外传内(3),与TransferUserFileServiceImpl保持一致 + */ + private String getSendRootType() { + return FileLocationEnum.isInternal(fileProperties.getTransfer().getLocation()) + ? RootTypeEnum.INTERNAL_TO_EXTERNAL.getType() + : RootTypeEnum.EXTERNAL_TO_INTERNAL.getType(); + } + + /** + * 本端接收方向:内网侧为外传内(3),外网侧为内穿外(2),与TransferFileMonitorServiceImpl保持一致 + */ + private String getReceiveRootType() { + return FileLocationEnum.isInternal(fileProperties.getTransfer().getLocation()) + ? RootTypeEnum.EXTERNAL_TO_INTERNAL.getType() + : RootTypeEnum.INTERNAL_TO_EXTERNAL.getType(); + } + + /** + * 按本端部署位置回填记录类型与描述 + */ + private void fillRecordType(List records) { + if (records == null || records.isEmpty()) { + return; + } + for (UserFileRecordDTO record : records) { + String rootType = record.getRootType(); + if (RootTypeEnum.NORMAL.getType().equals(rootType)) { + record.setRecordType(FileRecordTypeEnum.UPLOAD.getType()); + } else if (getSendRootType().equals(rootType)) { + record.setRecordType(FileRecordTypeEnum.SEND.getType()); + } else if (getReceiveRootType().equals(rootType)) { + record.setRecordType(FileRecordTypeEnum.RECEIVE.getType()); + } + if (record.getRecordType() != null) { + record.setRecordTypeDesc(FileRecordTypeEnum.getByType(record.getRecordType()).getDesc()); + } else { + RootTypeEnum rootTypeEnum = RootTypeEnum.getByType(rootType); + record.setRecordTypeDesc(rootTypeEnum == null ? rootType : rootTypeEnum.getDesc()); + } + } + } +} + diff --git a/backend/src/main/java/com/senmesh/sfile/service/impl/UserSpaceServiceImpl.java b/backend/src/main/java/com/senmesh/sfile/service/impl/UserSpaceServiceImpl.java new file mode 100644 index 0000000..edff9e6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/sfile/service/impl/UserSpaceServiceImpl.java @@ -0,0 +1,101 @@ +package com.senmesh.sfile.service.impl; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.ListUtil; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.frame.redis.dto.LockDTO; +import com.senmesh.frame.redis.redisson.RedissonUtils; +import com.senmesh.sfile.convert.UserSpaceConvert; +import com.senmesh.sfile.dao.UserSpaceMapper; +import com.senmesh.sfile.dto.UserSpaceCreateDTO; +import com.senmesh.sfile.dto.UserSpaceDTO; +import com.senmesh.sfile.dto.UserSpaceModifyDTO; +import com.senmesh.sfile.dto.UserSpaceQueryDTO; +import com.senmesh.sfile.entity.UserSpace; +import com.senmesh.sfile.service.UserSpaceService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 用户空间ServiceImpl + */ +@Service +public class UserSpaceServiceImpl implements UserSpaceService { + + @Autowired + private UserSpaceMapper userSpaceMapper; + + /** + * 默认总容量:5GB + */ + private static final Long DEFAULT_TOTAL_SIZE = 5L * 1024 * 1024 * 1024; + + + public static LockDTO getLockDTO(Long userId) { + Assert.notNull(userId, "用户id不能为空"); + return LockDTO.builder().methodName("userspace").tryLockWaitTime(0L) + .arg(userId.toString()) + .failMsg("该用户空间正在被操作") + .build(); + } + + @Override + @Transactional + public Long create(UserSpaceCreateDTO createDTO) { + Long userId = createDTO.getUserId(); + UserSpaceQueryDTO queryDTO = UserSpaceQueryDTO.builder().userId(userId).build(); + + UserSpaceDTO userSpaceDTO = RedissonUtils.lockAndSave(getLockDTO(userId), + () -> this.find(queryDTO), () -> { + UserSpace userSpace = UserSpaceConvert.INSTANCE.toEntity(createDTO); + userSpace.setTotalSize(DEFAULT_TOTAL_SIZE); + userSpace.setUsedSize(0L); + userSpaceMapper.saveEntity(userSpace); + return UserSpaceConvert.INSTANCE.toDto(userSpace); + }); + return userSpaceDTO.getId(); + } + + @Override + @Transactional + public void modify(UserSpaceModifyDTO modifyDTO) { + Long userId = modifyDTO.getUserId(); + UserSpaceQueryDTO queryDTO = UserSpaceQueryDTO.builder().userId(userId).build(); + UserSpaceDTO userSpaceDTO = this.find(queryDTO); + Assert.notNull(userSpaceDTO, "用户空间不存在"); + + UserSpace userSpace = UserSpace.builder() + .id(userSpaceDTO.getId()) + .usedSize(modifyDTO.getUsedSize()) + .build(); + userSpaceMapper.updateEntitySelective(userSpace); + } + + @Override + @Transactional + public void remove(Long id) { + userSpaceMapper.deleteEntity(UserSpace.builder().id(id).build(), + UserContextHolder.getLoginUserId()); + } + + @Override + public List list(UserSpaceQueryDTO queryDTO) { + queryDTO.disablePage(); + return userSpaceMapper.list(queryDTO); + } + + @Override + public void page(UserSpaceQueryDTO queryDTO) { + userSpaceMapper.list(queryDTO); + } + + @Override + public UserSpaceDTO find(UserSpaceQueryDTO queryDTO) { + List userSpaceDTOs = this.list(queryDTO); + return ListUtil.first(userSpaceDTOs); + } +} + diff --git a/backend/src/main/java/com/senmesh/swagger/config/SwaggerConfig.java b/backend/src/main/java/com/senmesh/swagger/config/SwaggerConfig.java new file mode 100644 index 0000000..ca97a37 --- /dev/null +++ b/backend/src/main/java/com/senmesh/swagger/config/SwaggerConfig.java @@ -0,0 +1,58 @@ +package com.senmesh.swagger.config; + +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.Contact; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +//@Configuration +//@EnableSwagger2 +public class SwaggerConfig { + + @Value("${swagger.enable:false}") + private boolean swaggerEnable; + + /** 文档访问前缀 **/ + public static final String ACCESS_PREFIX = + "/swagger-resources/**,/swagger-ui.html**,/webjars/**,/v2/**"; + + public boolean isSwaggerEnable() { + return swaggerEnable; + } + + @Bean + public Docket docket() { + return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()) + // 设置是否开启swagger,生产环境关闭 + .enable(swaggerEnable).select() + // 当前包路径 + .apis(RequestHandlerSelectors.basePackage("com.senmesh")) + .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) + .paths(PathSelectors.any()).build(); + } + + /** + * 构建api文档的详细信息 + * @return + * @author sr on 2019-11-05 + */ + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + // 页面标题 + .title("接口文档") + // 创建人 + .contact(new Contact("ljp", "", "")) + // 版本号 + .version("1.0") + // 描述 + .description("接口文档").build(); + } +} diff --git a/backend/src/main/java/com/senmesh/tkmybatis/mybatis/MyMapper.java b/backend/src/main/java/com/senmesh/tkmybatis/mybatis/MyMapper.java new file mode 100644 index 0000000..c896de8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/tkmybatis/mybatis/MyMapper.java @@ -0,0 +1,226 @@ +package com.senmesh.tkmybatis.mybatis; + + +import java.util.Collection; +import java.util.Date; + +import org.apache.ibatis.annotations.Param; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.senmesh.common.entity.BaseEntity; +import com.senmesh.common.util.UserContextHolder; + +/** + * + * 定义自己的通用mapper + * + * @author guhong + * @date 2019/8/19 + */ +public interface MyMapper extends /*Mapper, ExistsMapper,*/BaseMapper { + + /** + * 设置新增属性值 + * @param entity + * @param operateUserId + * @author sr on 2019-11-05 + */ + default void setCreateProperty(T entity, Long operateUserId) { + entity.setCreateBy(operateUserId); + entity.setCreateTime(new Date()); + entity.setUpdateBy(null); + entity.setUpdateTime(null); + entity.setDeleted(false); + } + + /** + * 设置修改属性值 + * @param entity + * @param operateUserId + * @author sr on 2019-11-05 + */ + default void setUpdateProperty(T entity, Long operateUserId) { + entity.setUpdateBy(operateUserId); + entity.setUpdateTime(new Date()); + entity.setProxyBy(entity.getProxyBy()); + } + + /** + * 设置删除属性值 + * @param entity + * @param operateUserId + * @author sr on 2019-11-05 + */ + default void setDeleteProperty(T entity, Long operateUserId) { + setUpdateProperty(entity, operateUserId); + entity.setDeleted(true); + } + + + /** + * 新增 + * @param entity + * @param operateUserId 操作人 + * @author sr on 2019-10-12 + */ + default void saveEntity(T entity, Long operateUserId) { + setCreateProperty(entity, operateUserId); + insert(entity); + } + + /** + * 根据主键更新实体,null也会被更新 + * @param entity + * @param operateUserId 操作人 + * @return + * @author sr on 2019-10-12 + */ + default int updateEntity(T entity, Long operateUserId) { + setUpdateProperty(entity, operateUserId); + return alwaysUpdateSomeColumnById(entity); + } + + /** + * 根据主键更新实体,null不会被更新 + * @param entity + * @return + * @author sr on 2019-10-12 + */ + default int updateEntitySelective(T entity) { + return updateEntitySelective(entity, UserContextHolder.getLoginUserId()); + } + + /** + * 根据主键更新实体,null不会被更新 + * @param entity + * @return + * @author sr on 2019-10-12 + */ + default int updateEntitySelective(T entity, Long operateUserId) { + setUpdateProperty(entity, operateUserId); + // 创建人/时间不能修改 + entity.setCreateBy(null); + entity.setCreateTime(null); + return updateById(entity); + } + + + + /** + * 逻辑删除实体(实则根据主键更新实体,null不会更新) + * @param entity + * @param operateUserId + * @return + * @author sr on 2019-10-12 + */ + default int deleteEntity(T entity, Long operateUserId) { + setDeleteProperty(entity, operateUserId); + return updateById(entity); + } + + + /** + * 批量保存 + * @param entitys + * @param operateUserId + * @author sr on 2019-11-05 + */ + default void saveEntites(Collection entitys, Long operateUserId) { + entitys.forEach(entity -> saveEntity(entity, operateUserId)); + } + + /** + * 批量保存 + * @param entitys + * @param operateUserId + * @author sr on 2019-11-05 + */ + default void saveEntites(Collection entitys) { + this.saveEntites(entitys, UserContextHolder.getLoginUserId()); + } + + /** + * 批量修改(根据主键更新实体,null也会被更新) + * @param entitys + * @param operateUserId + * @author sr on 2019-11-05 + */ + default void updateEntites(Collection entitys, Long operateUserId) { + entitys.forEach(entity -> updateEntity(entity, operateUserId)); + } + + /** + * 批量删除(实则根据主键更新实体,null不会更新) + * @param entitys + * @param operateUserId + * @author sr on 2019-11-05 + */ + default void deleteEntites(Collection entitys, Long operateUserId) { + entitys.forEach(entity -> deleteEntity(entity, operateUserId)); + } + + /** + * 批量修改(根据主键更新实体,null不会被更新) + * @param entity + * @return + * @author sr on 2019-10-12 + */ + default void updateEntitysSelective(Collection entitys, Long operateUserId) { + entitys.forEach(entity -> updateEntitySelective(entity, operateUserId)); + } + + /** + * 根据id获取实体 + * @param id + * @return + * @author sr on 2019-11-05 + */ + default T getById(Long id) { + T entity = selectById(id); + return (entity == null || entity.getDeleted()) ? null : entity; + } + + + /** + * 判断是否存在相同属性其他实体(已设置deleted=0) + * @param record + * @return + * @author sr on 2019-12-09 + */ + boolean existsEntity(@Param(Constants.ENTITY)T record); + + + /** + * 新增(context取用户信息) + * @param entity + * @author sr on 2019-10-12 + */ + default void saveEntity(T entity) { + saveEntity(entity, UserContextHolder.getLoginUserId()); + } + + /** + * 根据主键更新实体,null也会被更新(context取用户信息) + * @param entity + * @return + * @author sr on 2019-10-12 + */ + default int updateEntity(T entity) { + return updateEntity(entity, UserContextHolder.getLoginUserId()); + } + + + /** + * 逻辑删除实体(实则根据主键更新实体,null不会更新,context取用户信息) + * @param entity + * @return + * @author sr on 2019-10-12 + */ + default int deleteEntity(T entity) { + return deleteEntity(entity, UserContextHolder.getLoginUserId()); + } + + int alwaysUpdateSomeColumnById(@Param(Constants.ENTITY)T entity); + +} diff --git a/backend/src/main/java/com/senmesh/tkmybatis/pojo/Page.java b/backend/src/main/java/com/senmesh/tkmybatis/pojo/Page.java new file mode 100644 index 0000000..416c8e9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/tkmybatis/pojo/Page.java @@ -0,0 +1,78 @@ +package com.senmesh.tkmybatis.pojo; + +import com.senmesh.common.dto.IPage; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 分页 + * + * @author guhong + * @date 2019/8/19 + */ +@Data +@AllArgsConstructor +@Builder +public class Page implements Serializable, IPage { + + /** **/ + private static final long serialVersionUID = -729078966440672920L; + + /** 第几页 **/ + private int pageNo; + /** 页宽 **/ + private int pageSize; + /** 一共的页数 **/ + private int pageCount; + /** 记录条数 **/ + private int totalCount; + /** 查询出来的对象实体 **/ + private List entityList; + + public Page() { + pageSize = 20; + pageNo = 1; + } + + public Page(int pageNo, int pageSize) { + super(); + this.pageNo = pageNo < 1 ? 1 : pageNo; + this.pageSize = pageSize < 1 ? 20 : pageSize; + } + + public void setTotalCount(int totalCount) { + pageCount = (int) Math.ceil((double) totalCount / pageSize); + this.totalCount = totalCount; + } + + public int getFirstEntityIndex() { + return (pageNo - 1) * pageSize; + } + + @Override + public Integer getPageNo() { + return pageNo; + } + + @Override + public Integer getPageSize() { + return pageSize; + } + + @Override + public void setPageResult(int totalCount, List results) { + this.entityList = results; + this.setTotalCount(totalCount); + } + + + @Override + public Boolean getNeedPage() { + return true; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/annex/controller/UserAnnexController.java b/backend/src/main/java/com/senmesh/usercenter/annex/controller/UserAnnexController.java new file mode 100644 index 0000000..e1e2cbe --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/annex/controller/UserAnnexController.java @@ -0,0 +1,110 @@ +package com.senmesh.usercenter.annex.controller; + + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.annex.dto.UserAnnexCreateDTO; +import com.senmesh.usercenter.annex.dto.UserAnnexDTO; +import com.senmesh.usercenter.annex.dto.UserAnnexOperateDTO; +import com.senmesh.usercenter.annex.dto.UserAnnexPageQueryDTO; +import com.senmesh.usercenter.annex.entity.UserAnnex; +import com.senmesh.usercenter.annex.service.IUserAnnexService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + *

+ * 用户附件表 前端控制器 + *

+ * + * @author Carlye + * @since 2021-01-12 + */ +@Api(tags = "用户附件") +@RestController +@RequestMapping("/annex") +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class UserAnnexController { + + private final IUserAnnexService userAnnexService; + + + /** + * 创建 + * + * @param userAnnexCreateDTO 用户附件创建dto + * @return {@link AlitaResult} + */ + @PostMapping("/create") + @ApiOperation("创建用户附件") + public AlitaResult create(@RequestBody UserAnnexCreateDTO userAnnexCreateDTO) { + return AlitaResult.success(userAnnexService.create(userAnnexCreateDTO)); + } + + /** + * 创建 + * + * @param userAnnexCreateDTO 用户附件创建dto + * @return {@link AlitaResult} + */ + @PostMapping("/modify") + @ApiOperation("更新用户附件") + public AlitaResult modify(@RequestBody UserAnnexOperateDTO userAnnexCreateDTO) { + return AlitaResult.success(userAnnexService.modify(userAnnexCreateDTO)); + } + + + /** + * 分页查询 + * + * @param queryDTO 查询dto + * @return {@link AlitaResult>} + */ + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(UserAnnexPageQueryDTO queryDTO) { + userAnnexService.page(queryDTO); + return AlitaResult.success(queryDTO.getPageResult()); + } + + /** + * 查询单个 + * @param userId 用户ID + * @param annexType 附件类别 + * @return + */ + @GetMapping("/get/{userId}/{annexType}") + @ApiOperation("单个查询") + public AlitaResult get(@PathVariable("userId") Long userId, @PathVariable("annexType") Integer annexType) { + UserAnnexPageQueryDTO userAnnexPageQueryDTO = new UserAnnexPageQueryDTO(); + userAnnexPageQueryDTO.setUserId(userId); + userAnnexPageQueryDTO.setAnnexType(annexType); + userAnnexPageQueryDTO.setNeedPage(false); + List list = userAnnexService.page(userAnnexPageQueryDTO); + return AlitaResult.success(CollectionUtils.isEmpty(list)?null:list.get(0)); + } + + /** + * 查询单个 + * @param userId 用户ID + * @param annexType 附件类别 + * @return + */ + @DeleteMapping("/remove/{userId}/{annexType}") + @ApiOperation("删除附件") + public AlitaResult remove(@PathVariable("userId") Long userId, @PathVariable("annexType") Integer annexType) { + return AlitaResult.success(userAnnexService.update(Wrappers.lambdaUpdate() + .eq(UserAnnex::getUserId, userId) + .eq(UserAnnex::getAnnexType, annexType) + .eq(UserAnnex::getDeleted, false) + .set(UserAnnex::getDeleted, true))); + } + +} + diff --git a/backend/src/main/java/com/senmesh/usercenter/annex/dao/UserAnnexDao.java b/backend/src/main/java/com/senmesh/usercenter/annex/dao/UserAnnexDao.java new file mode 100644 index 0000000..bde8b21 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/annex/dao/UserAnnexDao.java @@ -0,0 +1,29 @@ +package com.senmesh.usercenter.annex.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.senmesh.usercenter.annex.dto.UserAnnexDTO; +import com.senmesh.usercenter.annex.dto.UserAnnexPageQueryDTO; +import com.senmesh.usercenter.annex.entity.UserAnnex; + +import java.util.List; +import org.apache.ibatis.annotations.Param; + +/** + *

+ * 用户附件表 Mapper 接口 + *

+ * + * @author Carlye + * @since 2021-01-12 + */ +public interface UserAnnexDao extends BaseMapper { + + + /** + * 分页查询 + * + * @param userAnnexPageQueryDTO 用户附件页面查询dto + * @return {@link List} + */ + List page(@Param("param") UserAnnexPageQueryDTO userAnnexPageQueryDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/annex/dto/UserAnnexCreateDTO.java b/backend/src/main/java/com/senmesh/usercenter/annex/dto/UserAnnexCreateDTO.java new file mode 100644 index 0000000..ee8380e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/annex/dto/UserAnnexCreateDTO.java @@ -0,0 +1,48 @@ +package com.senmesh.usercenter.annex.dto; + +import com.senmesh.common.dto.BaseDTO; +import com.senmesh.common.validate.EnumValidator; +import com.senmesh.usercenter.annex.enums.AnnexTypeEnum; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.Accessors; +import lombok.experimental.SuperBuilder; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + *

+ * 用户附件实体 + *

+ * + * @author Carlye + * @since 2021-01-12 + */ +@ApiModel("用户附件创建DTO") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +public class UserAnnexCreateDTO extends BaseDTO { + + private static final long serialVersionUID = 6855183230684638997L; + + @ApiModelProperty("机构ID") + private Long orgId; + + @ApiModelProperty("用户ID") + private Long userId; + + @NotNull(message = "附件类型不能为空") + @EnumValidator(value = AnnexTypeEnum.class,message = "附件类型错误") + @ApiModelProperty("附件类型 1:身份证正面 2:身份证反面") + private Integer annexType; + + @NotEmpty(message = "fileCode不能为空") + @ApiModelProperty("附件fileCode") + private String annexFileCode; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/annex/dto/UserAnnexDTO.java b/backend/src/main/java/com/senmesh/usercenter/annex/dto/UserAnnexDTO.java new file mode 100644 index 0000000..1fbf245 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/annex/dto/UserAnnexDTO.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.annex.dto; + +import com.senmesh.common.dto.BaseDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.Accessors; +import lombok.experimental.SuperBuilder; + +/** + *

+ * 用户附件实体 + *

+ * + * @author Carlye + * @since 2021-01-12 + */ +@ApiModel("用户附件DTO") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +public class UserAnnexDTO extends BaseDTO { + + private static final long serialVersionUID = -1784620895307517063L; + + @ApiModelProperty("机构ID") + private Long orgId; + + @ApiModelProperty("用户ID") + private Long userId; + + @ApiModelProperty("附件类型 1:身份证正面 2:身份证反面") + private Integer annexType; + + @ApiModelProperty("附件fileCode") + private String annexFileCode; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/annex/dto/UserAnnexOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/annex/dto/UserAnnexOperateDTO.java new file mode 100644 index 0000000..24817a3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/annex/dto/UserAnnexOperateDTO.java @@ -0,0 +1,49 @@ +package com.senmesh.usercenter.annex.dto; + +import com.senmesh.common.dto.BaseDTO; +import com.senmesh.common.validation.Update; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import lombok.experimental.SuperBuilder; + +/** + *

+ * 用户附件实体 + *

+ * + * @author Carlye + * @since 2021-01-12 + */ +@ApiModel("用户附件操作DTO") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +public class UserAnnexOperateDTO extends BaseDTO { + + private static final long serialVersionUID = 6855183230684638997L; + + @ApiModelProperty("机构ID") + private Long orgId; + + @NotNull(message = "用户ID不能为空", groups = {Update.class}) + @ApiModelProperty("用户ID") + private Long userId; + + @NotNull(message = "附件类型不能为空", groups = {Update.class}) + @ApiModelProperty("附件类型 1:身份证正面 2:身份证反面") + private Integer annexType; + + @NotEmpty(message = "fileCode不能为空", groups = {Update.class}) + @ApiModelProperty("附件fileCode") + private String annexFileCode; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/annex/dto/UserAnnexPageQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/annex/dto/UserAnnexPageQueryDTO.java new file mode 100644 index 0000000..62fd9f9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/annex/dto/UserAnnexPageQueryDTO.java @@ -0,0 +1,57 @@ +package com.senmesh.usercenter.annex.dto; + +import com.google.common.collect.Sets; +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.Accessors; + +import java.util.Arrays; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +/** + *

+ * 用户附件实体 + *

+ * + * @author Carlye + * @since 2021-01-12 + */ +@ApiModel("用户附件查询DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +public class UserAnnexPageQueryDTO extends PageQueryDTO { + + private static final long serialVersionUID = -1784620895307517063L; + + @ApiModelProperty("机构ID") + private Long orgId; + + @ApiModelProperty("用户ID") + private Long userId; + + @ApiModelProperty("附件类型 1:身份证正面 2:身份证反面") + private Integer annexType; + + @ApiModelProperty("附件fileCode") + private String annexFileCode; + + @ApiModelProperty("附件类型, ','分割") + private String annexTypeStr; + + private Set annexTypes; + + public Set getAnnexTypes() { + return Optional.ofNullable(getAnnexTypeStr()) + .map(str -> Arrays.stream(str.split(",")) + .collect(Collectors.toSet())) + .orElse(Sets.newHashSet()); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/annex/entity/UserAnnex.java b/backend/src/main/java/com/senmesh/usercenter/annex/entity/UserAnnex.java new file mode 100644 index 0000000..a67bc6e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/annex/entity/UserAnnex.java @@ -0,0 +1,48 @@ +package com.senmesh.usercenter.annex.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; +import com.senmesh.usercenter.annex.enums.AnnexTypeEnum; +import lombok.*; +import lombok.experimental.Accessors; + +/** + *

+ * 用户附件表 + *

+ * + * @author Carlye + * @since 2021-01-12 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableName("xs_user_annex") +public class UserAnnex extends BaseEntity { + + private static final long serialVersionUID = -967369619441044008L; + /** + * 机构ID + */ + private Long orgId; + + /** + * 用户ID + */ + private Long userId; + + /** + * 附件类型 1:身份证正面 2:身份证反面 + */ + private AnnexTypeEnum annexType; + + /** + * 附件fileCode + */ + @TableField("annex_fileCode") + private String annexFileCode; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/annex/enums/AnnexTypeEnum.java b/backend/src/main/java/com/senmesh/usercenter/annex/enums/AnnexTypeEnum.java new file mode 100644 index 0000000..a421515 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/annex/enums/AnnexTypeEnum.java @@ -0,0 +1,39 @@ +package com.senmesh.usercenter.annex.enums; + +import com.baomidou.mybatisplus.annotation.EnumValue; +import com.senmesh.mybatis.handle.BaseEnum; + +/** + * 附件类型的枚举 + * + * @author Carlye + * @date 2021/01/12 + */ +public enum AnnexTypeEnum implements BaseEnum { + IDCARD_FRONT(1, "身份证正面"), + + IDCARD_REVERSE(2, "身份证反面"); + + @EnumValue + private final Integer type; + + private final String desc; + + AnnexTypeEnum(Integer type, String desc) { + this.type = type; + this.desc = desc; + } + + public Integer getType() { + return type; + } + + public String getDesc() { + return desc; + } + + @Override + public Integer getValue() { + return type; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/annex/mapper/UserAnnexMapper.xml b/backend/src/main/java/com/senmesh/usercenter/annex/mapper/UserAnnexMapper.xml new file mode 100644 index 0000000..a110ee1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/annex/mapper/UserAnnexMapper.xml @@ -0,0 +1,31 @@ + + + + + + + diff --git a/backend/src/main/java/com/senmesh/usercenter/annex/mapstruct/UserAnnexMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/annex/mapstruct/UserAnnexMapMapper.java new file mode 100644 index 0000000..d28da4d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/annex/mapstruct/UserAnnexMapMapper.java @@ -0,0 +1,38 @@ +package com.senmesh.usercenter.annex.mapstruct; + +import com.senmesh.common.util.EnumUtil; +import com.senmesh.usercenter.annex.dto.UserAnnexCreateDTO; +import com.senmesh.usercenter.annex.dto.UserAnnexDTO; +import com.senmesh.usercenter.annex.entity.UserAnnex; +import com.senmesh.usercenter.annex.enums.AnnexTypeEnum; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +import javax.validation.Valid; + + +/** + * 用户映射器附件地图 + * + * @author Carlye + * @date 2021/01/12 + */ +@Mapper +public interface UserAnnexMapMapper { + + UserAnnexMapMapper INSTANCE = Mappers.getMapper(UserAnnexMapMapper.class); + + UserAnnex exchange(@Valid UserAnnexCreateDTO userAnnex); + + @Mappings({ + @Mapping(target = "annexType", + source = "annexType.type") + }) + UserAnnexDTO exchange(UserAnnex userAnnex); + + default AnnexTypeEnum cover1(Integer type) { + return EnumUtil.resolve(AnnexTypeEnum::getType, type); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/annex/service/IUserAnnexService.java b/backend/src/main/java/com/senmesh/usercenter/annex/service/IUserAnnexService.java new file mode 100644 index 0000000..4fa6c68 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/annex/service/IUserAnnexService.java @@ -0,0 +1,49 @@ +package com.senmesh.usercenter.annex.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.senmesh.usercenter.annex.dto.UserAnnexCreateDTO; +import com.senmesh.usercenter.annex.dto.UserAnnexDTO; +import com.senmesh.usercenter.annex.dto.UserAnnexOperateDTO; +import com.senmesh.usercenter.annex.dto.UserAnnexPageQueryDTO; +import com.senmesh.usercenter.annex.entity.UserAnnex; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.groups.Default; +import java.util.List; + +/** + *

+ * 用户附件表 服务类 + *

+ * + * @author Carlye + * @since 2021-01-12 + */ +@Validated(Default.class) +public interface IUserAnnexService extends IService { + + /** + * 创建用户附件 + * + * @param userAnnexCreateDTO 用户附件创建dto + * @return {@link UserAnnexDTO} + * @throws RuntimeException 运行时异常 + */ + UserAnnexDTO create(@Valid UserAnnexCreateDTO userAnnexCreateDTO) throws RuntimeException; + + /** + * 用户附件分页查询 + * + * @param userAnnexPageQueryDTO 用户附件页面查询dto + * @return {@link List} + */ + List page(UserAnnexPageQueryDTO userAnnexPageQueryDTO); + + /** + * 修改用户福建 + * @param userAnnexCreateDTO 用户附件操作dto + * @return 是否成功 + */ + Boolean modify(UserAnnexOperateDTO userAnnexCreateDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/annex/service/impl/UserAnnexServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/annex/service/impl/UserAnnexServiceImpl.java new file mode 100644 index 0000000..66d4842 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/annex/service/impl/UserAnnexServiceImpl.java @@ -0,0 +1,84 @@ +package com.senmesh.usercenter.annex.service.impl; + +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.frame.redis.aop.annotation.AutoUnLock; +import com.senmesh.frame.redis.dto.LockDTO; +import com.senmesh.frame.redis.redisson.RedissonUtils; +import com.senmesh.usercenter.annex.dao.UserAnnexDao; +import com.senmesh.usercenter.annex.dto.UserAnnexCreateDTO; +import com.senmesh.usercenter.annex.dto.UserAnnexDTO; +import com.senmesh.usercenter.annex.dto.UserAnnexOperateDTO; +import com.senmesh.usercenter.annex.dto.UserAnnexPageQueryDTO; +import com.senmesh.usercenter.annex.entity.UserAnnex; +import com.senmesh.usercenter.annex.mapstruct.UserAnnexMapMapper; +import com.senmesh.usercenter.annex.service.IUserAnnexService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.validation.Valid; +import java.util.List; +import java.util.Optional; + + +/** + *

+ * 用户附件表 服务实现类 + *

+ * + * @author Carlye + * @since 2021-01-12 + */ +@Slf4j +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class UserAnnexServiceImpl extends ServiceImpl implements IUserAnnexService { + + @Override + @AutoUnLock + public UserAnnexDTO create(@Valid UserAnnexCreateDTO userAnnexCreateDTO) throws RuntimeException { + Long userId = Optional.ofNullable(userAnnexCreateDTO.getUserId()).orElse(UserContextHolder.getExistLoginUserId()); + Assert.isTrue(RedissonUtils.tryLockAutomatically(LockDTO.builder().methodName("userAnnexCreate").tryLockWaitTime(0L).arg(userId + "").arg(userAnnexCreateDTO.getAnnexType() + "").build()), + "用户附件正在处理中,请稍后再试哦!"); + userAnnexCreateDTO.setUserId(userId); + List userAnnexes = list(Wrappers.lambdaQuery().eq(UserAnnex::getUserId, userId).eq(UserAnnex::getAnnexType, userAnnexCreateDTO.getAnnexType()).eq(UserAnnex::getDeleted, false)); + if (CollectionUtils.isEmpty(userAnnexes)){ + UserAnnex userAnnex = UserAnnexMapMapper.INSTANCE.exchange(userAnnexCreateDTO); + Assert.isTrue(save(userAnnex), "新建用户附件异常"); + return UserAnnexMapMapper.INSTANCE.exchange(userAnnex); + }else if (userAnnexes.size() == 1){ + UserAnnex userAnnex = userAnnexes.get(0); + Assert.isTrue(update(Wrappers.lambdaUpdate().set(UserAnnex::getAnnexFileCode,userAnnexCreateDTO.getAnnexFileCode()).eq(UserAnnex::getId,userAnnex.getId())),"更新附件异常"); + userAnnex.setAnnexFileCode(userAnnexCreateDTO.getAnnexFileCode()); + return UserAnnexMapMapper.INSTANCE.exchange(userAnnex); + } + throw new RuntimeException("用户附件数据异常"); + } + + @Override + public List page(UserAnnexPageQueryDTO userAnnexPageQueryDTO) { + Long userId = Optional.ofNullable(userAnnexPageQueryDTO.getUserId()).orElse(UserContextHolder.getExistLoginUserId()); + userAnnexPageQueryDTO.setUserId(userId); + return getBaseMapper().page(userAnnexPageQueryDTO); + } + + @Override + public Boolean modify(UserAnnexOperateDTO userAnnexCreateDTO) { + LambdaUpdateWrapper lambdaUpdateWrapper = Wrappers.lambdaUpdate() + .eq(UserAnnex::getUserId, userAnnexCreateDTO.getUserId()) + .eq(UserAnnex::getAnnexType, userAnnexCreateDTO.getAnnexType()) + .eq(UserAnnex::getDeleted, false) + .set(UserAnnex::getAnnexFileCode, userAnnexCreateDTO.getAnnexFileCode()); + if(userAnnexCreateDTO.getOrgId() != null){ + lambdaUpdateWrapper.eq(UserAnnex::getOrgId, userAnnexCreateDTO.getOrgId()); + } + Assert.isTrue(update(lambdaUpdateWrapper), "修改用户附件失败"); + return Boolean.TRUE; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/constant/AuthClientConstants.java b/backend/src/main/java/com/senmesh/usercenter/auth/constant/AuthClientConstants.java new file mode 100644 index 0000000..df92a19 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/constant/AuthClientConstants.java @@ -0,0 +1,8 @@ +package com.senmesh.usercenter.auth.constant; + +/** + * @author sr on 2021-05-24 + */ +public interface AuthClientConstants { + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/constant/AuthDetailConstants.java b/backend/src/main/java/com/senmesh/usercenter/auth/constant/AuthDetailConstants.java new file mode 100644 index 0000000..7b59574 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/constant/AuthDetailConstants.java @@ -0,0 +1,8 @@ +package com.senmesh.usercenter.auth.constant; + +/** + * @author sr on 2021-05-24 + */ +public interface AuthDetailConstants { + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/constant/AuthDetailEntrypointConstants.java b/backend/src/main/java/com/senmesh/usercenter/auth/constant/AuthDetailEntrypointConstants.java new file mode 100644 index 0000000..d58ef48 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/constant/AuthDetailEntrypointConstants.java @@ -0,0 +1,19 @@ +package com.senmesh.usercenter.auth.constant; + +/** + * @author sr on 2021-05-24 + */ +public interface AuthDetailEntrypointConstants { + + /** + * 招聘用户状态 1未报名 2已报名 3已邀约 4已面试 5待入职 6在职中 7已离职 + */ + Integer USER_JOB_STATUS_NOT_REGISTERED = 1; + Integer USER_JOB_STATUS_ALREADY_REGISTERED = 2; + Integer USER_JOB_STATUS_INVITED = 3; + Integer USER_JOB_STATUS_INTERVIEWED = 4; + Integer USER_JOB_STATUS_TO_BE_HIRED = 5; + Integer USER_JOB_STATUS_ON_THE_JOB = 6; + Integer USER_JOB_STATUS_RESIGNED = 7; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/constant/AuthMainTypeEnum.java b/backend/src/main/java/com/senmesh/usercenter/auth/constant/AuthMainTypeEnum.java new file mode 100644 index 0000000..9339ced --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/constant/AuthMainTypeEnum.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.auth.constant; + +import java.util.Map; + +import com.google.common.collect.Maps; + +public enum AuthMainTypeEnum { + + /** 微信 **/ + WECHAT(1), + /** 支付宝 **/ + ALIPAY(2), + /** 字节 **/ + BYTE_DANCE(3), + /** 随申办 **/ + SSB(4), + ; + + private Integer type; + + private static Map typeMap = Maps.newHashMap(); + static { + for(AuthMainTypeEnum authTypeEnum : AuthMainTypeEnum.values()) { + typeMap.put(authTypeEnum.getType(), authTypeEnum); + } + } + + AuthMainTypeEnum(Integer type) { + this.type = type; + } + + public Integer getType() { + return type; + } + + public static AuthMainTypeEnum getByCode(Integer type) { + return typeMap.get(type); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/constant/AuthTypeEnum.java b/backend/src/main/java/com/senmesh/usercenter/auth/constant/AuthTypeEnum.java new file mode 100644 index 0000000..ba65ce8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/constant/AuthTypeEnum.java @@ -0,0 +1,55 @@ +package com.senmesh.usercenter.auth.constant; + +import java.util.Map; + +import com.google.common.collect.Maps; + +public enum AuthTypeEnum { + + /** 微信公众号 **/ + WECHAT(11, AuthMainTypeEnum.WECHAT.getType()), + /** 微信小程序 **/ + WECHAT_LITE(12, AuthMainTypeEnum.WECHAT.getType()), + /** 支付宝 **/ + ALIPAY(21, AuthMainTypeEnum.ALIPAY.getType()), + /** 支付宝小程序 **/ + ALIPAY_LITE(22, AuthMainTypeEnum.ALIPAY.getType()), + /** 字节跳动小程序 **/ + BYTE_DANCE_LITE(32, AuthMainTypeEnum.BYTE_DANCE.getType()), + /** 随申办app **/ + SSB_APP(41, AuthMainTypeEnum.SSB.getType()), + ; + + private Integer code; + + private Integer mainCode; + + private static Map AuthTypeMap = Maps.newHashMap(); + static { + for(AuthTypeEnum authTypeEnum : AuthTypeEnum.values()) { + AuthTypeMap.put(authTypeEnum.getCode(), authTypeEnum); + } + } + + AuthTypeEnum(Integer code, Integer mainCode) { + this.code = code; + this.mainCode = mainCode; + } + + public Integer getCode() { + return code; + } + + public Integer getMainCode() { + return mainCode; + } + + public static AuthTypeEnum getByCode(Integer code) { + return AuthTypeMap.get(code); + } + + public static Integer getAuthMainType(Integer code) { + return AuthTypeMap.get(code).getMainCode(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/constant/LiteCodeConfigEnum.java b/backend/src/main/java/com/senmesh/usercenter/auth/constant/LiteCodeConfigEnum.java new file mode 100644 index 0000000..91ddee2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/constant/LiteCodeConfigEnum.java @@ -0,0 +1,27 @@ +package com.senmesh.usercenter.auth.constant; + +/** + * @description: + * @author: guixinman + * @create: 2023-04-07 11:47 + **/ +public enum LiteCodeConfigEnum { + + /**首页**/ + HOME(1), + /**岗位明细**/ + POSITION_DETAIL(2), + /**新招聘**/ + RECRUITNEW(3); + + private Integer type; + + LiteCodeConfigEnum(Integer type) { + this.type = type; + } + + public Integer getType() { + return type; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/constant/LiteCodeConstant.java b/backend/src/main/java/com/senmesh/usercenter/auth/constant/LiteCodeConstant.java new file mode 100644 index 0000000..e411b51 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/constant/LiteCodeConstant.java @@ -0,0 +1,15 @@ +package com.senmesh.usercenter.auth.constant; + +/** + * 二维码 常量 + * + * @author Carlye + * @date 2022/03/29 + */ +public interface LiteCodeConstant { + + /** + * 来源 (PC端) + */ + Integer SOURCE_FROM_PC = 1; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/controller/AuthClientController.java b/backend/src/main/java/com/senmesh/usercenter/auth/controller/AuthClientController.java new file mode 100644 index 0000000..d0da237 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/controller/AuthClientController.java @@ -0,0 +1,83 @@ +package com.senmesh.usercenter.auth.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.dto.CasTokenDTO; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.auth.dto.AuthClientDTO; +import com.senmesh.usercenter.auth.dto.AuthClientOperateDTO; +import com.senmesh.usercenter.auth.dto.AuthClientQueryDTO; +import com.senmesh.usercenter.auth.dto.LitePhoneAuthDTO; +import com.senmesh.usercenter.auth.dto.LitePhoneLoginDTO; +import com.senmesh.usercenter.auth.service.AuthClientService; +import com.senmesh.usercenter.auth.service.impl.LitePhoneLoginProvider; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +/** + * @author sr on 2021-05-24 + */ +//@RestController +@Api(tags = "授权客户端") +public class AuthClientController { + + @Autowired + private AuthClientService authClientService; + + @Autowired + private LitePhoneLoginProvider litePhoneLoginProvider; + + @PostMapping("auth_client/create") + @ApiOperation("创建") + public AlitaResult create(@RequestBody AuthClientOperateDTO authClientOperateDTO) { + return AlitaResult.success(authClientService.create(authClientOperateDTO)); + } + + @PutMapping("auth_client/modify") + @ApiOperation("修改") + public AlitaResult modify(@RequestBody AuthClientOperateDTO authClientOperateDTO) { + authClientService.modify(authClientOperateDTO); + return AlitaResult.success(true); + } + + @DeleteMapping("auth_client/remove/{id}") + @ApiOperation("删除") + public AlitaResult remove(@PathVariable Long id) { + authClientService.remove(id); + return AlitaResult.success(true); + } + + @GetMapping("auth_client/page") + @ApiOperation("分页查询") + public AlitaResult> page(AuthClientQueryDTO authClientQueryDTO) { + authClientService.page(authClientQueryDTO); + return AlitaResult.success(authClientQueryDTO.getPageResult()); + } + + + @ApiOperation("获取访问token") + @PostMapping("anon/auth_client/access_token") + public AlitaResult getAccessToken(@RequestBody AuthClientQueryDTO authClientQueryDTO) { + return AlitaResult.success(authClientService.getAccessToken(authClientQueryDTO)); + } + + @ApiOperation("获取ticket") + @PostMapping("anon/auth_client/ticket") + public AlitaResult getJsApiTicket(@RequestBody AuthClientQueryDTO authClientQueryDTO) { + return AlitaResult.success(authClientService.getJsApiTicket(authClientQueryDTO)); + } + + @ApiOperation("小程序登录(手机号)") + @PostMapping("anon/auth_client/login_lite") + public AlitaResult loginLite(@Validated @RequestBody LitePhoneLoginDTO loginPhoneLoginDTO) { + return AlitaResult.success(litePhoneLoginProvider.loginLite(loginPhoneLoginDTO)); + } + + @ApiOperation("获取小程序授权手机号") + @PostMapping("anon/auth_client/get_phone") + public AlitaResult getPhone(@Validated @RequestBody LitePhoneAuthDTO litePhoneAuthDTO) { + return AlitaResult.success(authClientService.getPhone(litePhoneAuthDTO)); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/controller/AuthDetailController.java b/backend/src/main/java/com/senmesh/usercenter/auth/controller/AuthDetailController.java new file mode 100644 index 0000000..3b74bdc --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/controller/AuthDetailController.java @@ -0,0 +1,44 @@ +package com.senmesh.usercenter.auth.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.auth.dto.AuthDetailDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailQueryDTO; +import com.senmesh.usercenter.auth.service.AuthDetailService; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2021-05-24 + */ +@RestController +@RequestMapping("auth_detail") +@Api(tags = "授权明细") +public class AuthDetailController { + + @Autowired + private AuthDetailService authDetailService; + + @DeleteMapping("/remove/{id}") + @ApiOperation("删除") + public AlitaResult remove(@PathVariable Long id){ + authDetailService.remove(id); + return AlitaResult.success(true); + } + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(AuthDetailQueryDTO authDetailQueryDTO){ + authDetailService.list(authDetailQueryDTO); + return AlitaResult.success(authDetailQueryDTO.getPageResult()); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/controller/AuthDetailEntrypointController.java b/backend/src/main/java/com/senmesh/usercenter/auth/controller/AuthDetailEntrypointController.java new file mode 100644 index 0000000..8c71e56 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/controller/AuthDetailEntrypointController.java @@ -0,0 +1,95 @@ +package com.senmesh.usercenter.auth.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.auth.dto.*; +import com.senmesh.usercenter.auth.service.AuthDetailEntrypointService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * @author sr on 2022-01-06 + */ +//@RestController +@Api(tags = "授权明细入口") +public class AuthDetailEntrypointController { + + @Autowired + private AuthDetailEntrypointService authDetailEntrypointService; + + @PostMapping("anon/auth_detail_entrypoint/create") + @ApiOperation("创建") + public AlitaResult create( + @Validated @RequestBody AuthCodeDTO authCodeDTO){ + return AlitaResult.success(authDetailEntrypointService.create(authCodeDTO)); + } + + @DeleteMapping("auth_detail_entrypoint/remove/{id}") + @ApiOperation("删除") + public AlitaResult remove(@PathVariable Long id){ + authDetailEntrypointService.remove(id); + return AlitaResult.success(true); + } + + @GetMapping("auth_detail_entrypoint/page") + @ApiOperation("分页查询") + public AlitaResult> page(AuthDetailEntrypointQueryDTO authDetailEntrypointQueryDTO){ + authDetailEntrypointService.page(authDetailEntrypointQueryDTO); + return AlitaResult.success(authDetailEntrypointQueryDTO.getPageResult()); + } + + @GetMapping("auth_detail_entrypoint/invite_info_page") + @ApiOperation("分页查询邀请信息") + public AlitaResult> inviteInfoPage(InviteInfoPageQueryDTO queryDTO){ + authDetailEntrypointService.inviteInfoPage(queryDTO); + return AlitaResult.success(queryDTO.getPageResult()); + } + @GetMapping("auth_detail_entrypoint/invite_info_statistic") + @ApiOperation("查询邀请信息-统计") + public AlitaResult inviteInfoStatistic(InviteInfoPageQueryDTO queryDTO){ + return AlitaResult.success(authDetailEntrypointService.inviteInfoStatistic(queryDTO)); + } + + @GetMapping("auth_detail_entrypoint/invite_info_detail/{entrypointId}") + @ApiOperation("查询邀请信息详情") + public AlitaResult inviteInfoDetail(@PathVariable("entrypointId") Long entrypointId){ + InviteInfoPageQueryDTO queryDTO = InviteInfoPageQueryDTO.builder().entrypointId(entrypointId).build(); + List inviteInfoDTOS = authDetailEntrypointService.inviteInfoPage(queryDTO); + if (CollectionUtils.isNotEmpty(inviteInfoDTOS)){ + return AlitaResult.success(inviteInfoDTOS.get(0)); + } + return AlitaResult.success(null); + } + + @GetMapping("auth_detail_entrypoint/pc_invite_info_page") + @ApiOperation("pc端分页查询邀请信息") + public AlitaResult> pcInviteInfoPage(PcInviteInfoPageQueryDTO queryDTO){ + authDetailEntrypointService.pcInviteInfoPage(queryDTO); + return AlitaResult.success(queryDTO.getPageResult()); + } + + @GetMapping("auth_detail_entrypoint/pc_invite_info_detail/{userId}") + @ApiOperation("单个邀请信息明细") + public AlitaResult getInviteInfoDetail(@PathVariable("userId") Long userId){ + return AlitaResult.success( + authDetailEntrypointService.getInviteInfoDetail(PcInviteInfoPageQueryDTO.builder().userId(userId).build())); + } + + @GetMapping("auth_detail_entrypoint/pc_invite_statistic") + @ApiOperation("邀请统计信息(pc)") + public AlitaResult pcInviteStatisticQuery(InviteStatisticQueryDTO queryDTO){ + return AlitaResult.success(authDetailEntrypointService.pcInviteStatisticQuery(queryDTO)); + } + + @GetMapping("auth_detail_entrypoint/invite_statistic") + @ApiOperation("邀请统计信息") + public AlitaResult inviteStatisticQuery(InviteStatisticQueryDTO queryDTO){ + return AlitaResult.success(authDetailEntrypointService.inviteStatisticQuery(queryDTO)); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/controller/AuthSubscribeDetailController.java b/backend/src/main/java/com/senmesh/usercenter/auth/controller/AuthSubscribeDetailController.java new file mode 100644 index 0000000..0f79a90 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/controller/AuthSubscribeDetailController.java @@ -0,0 +1,44 @@ +package com.senmesh.usercenter.auth.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.auth.dto.AuthSubscribeDetailDTO; +import com.senmesh.usercenter.auth.dto.AuthSubscribeDetailQueryDTO; +import com.senmesh.usercenter.auth.service.AuthSubscribeDetailService; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2022-04-05 + */ +@RestController +@RequestMapping("auth_subscribe_detail") +@Api(tags = "授权订阅明细") +public class AuthSubscribeDetailController { + + @Autowired + private AuthSubscribeDetailService authSubscribeDetailService; + + @DeleteMapping("/remove/{id}") + @ApiOperation("删除") + public AlitaResult remove(@PathVariable Long id){ + authSubscribeDetailService.remove(id); + return AlitaResult.success(true); + } + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(AuthSubscribeDetailQueryDTO authSubscribeDetailQueryDTO){ + authSubscribeDetailService.page(authSubscribeDetailQueryDTO); + return AlitaResult.success(authSubscribeDetailQueryDTO.getPageResult()); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/controller/AuthTypeController.java b/backend/src/main/java/com/senmesh/usercenter/auth/controller/AuthTypeController.java new file mode 100644 index 0000000..f211e38 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/controller/AuthTypeController.java @@ -0,0 +1,38 @@ +package com.senmesh.usercenter.auth.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.auth.dto.AuthTypeDTO; +import com.senmesh.usercenter.auth.dto.AuthTypeOperateDTO; +import com.senmesh.usercenter.auth.dto.AuthTypeQueryDTO; +import com.senmesh.usercenter.auth.service.AuthTypeService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * @author sr on 2021-05-24 + */ +@RestController +@RequestMapping("auth_type") +@Api(tags = "授权客户端类型") +public class AuthTypeController { + + @Autowired + private AuthTypeService authTypeService; + + @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create(@RequestBody AuthTypeOperateDTO typeOperateDTO) { + return AlitaResult.success(authTypeService.create(typeOperateDTO)); + } + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(AuthTypeQueryDTO queryDTO) { + authTypeService.list(queryDTO); + return AlitaResult.success(queryDTO.getPageResult()); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/controller/LiteCodeConfigController.java b/backend/src/main/java/com/senmesh/usercenter/auth/controller/LiteCodeConfigController.java new file mode 100644 index 0000000..26abc76 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/controller/LiteCodeConfigController.java @@ -0,0 +1,65 @@ +package com.senmesh.usercenter.auth.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.PathVariable; + +import com.senmesh.common.validation.Update; +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.auth.dto.LiteCodeConfigQueryDTO; +import com.senmesh.usercenter.auth.service.LiteCodeConfigService; +import com.senmesh.usercenter.auth.dto.LiteCodeConfigDTO; +import com.senmesh.usercenter.auth.dto.LiteCodeConfigOperateDTO; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2021-12-21 + */ +@RestController +@RequestMapping("lite_code_config") +@Api(tags = "小程序码配置") +public class LiteCodeConfigController { + + @Autowired + private LiteCodeConfigService liteCodeConfigService; + + @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create( + @Validated @RequestBody LiteCodeConfigOperateDTO liteCodeConfigOperateDTO){ + return AlitaResult.success(liteCodeConfigService.create(liteCodeConfigOperateDTO)); + } + + @PutMapping("/modify") + @ApiOperation("修改") + public AlitaResult modify( + @Validated(Update.class) @RequestBody LiteCodeConfigOperateDTO liteCodeConfigOperateDTO){ + liteCodeConfigService.modify(liteCodeConfigOperateDTO); + return AlitaResult.success(true); + } + + @DeleteMapping("/remove/{id}") + @ApiOperation("删除") + public AlitaResult remove(@PathVariable Long id){ + liteCodeConfigService.remove(id); + return AlitaResult.success(true); + } + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(LiteCodeConfigQueryDTO liteCodeConfigQueryDTO){ + liteCodeConfigService.list(liteCodeConfigQueryDTO); + return AlitaResult.success(liteCodeConfigQueryDTO.getPageResult()); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/controller/LiteCodeController.java b/backend/src/main/java/com/senmesh/usercenter/auth/controller/LiteCodeController.java new file mode 100644 index 0000000..79094a9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/controller/LiteCodeController.java @@ -0,0 +1,51 @@ +package com.senmesh.usercenter.auth.controller; + +import com.senmesh.usercenter.auth.dto.LiteCodeModifyDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.auth.dto.LiteCodeCreateDTO; +import com.senmesh.usercenter.auth.dto.LiteCodeDTO; +import com.senmesh.usercenter.auth.dto.LiteCodeQueryDTO; +import com.senmesh.usercenter.auth.service.LiteCodeService; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2021-12-21 + */ +@RestController +@RequestMapping("lite_code") +@Api(tags = "小程序码") +public class LiteCodeController { + + @Autowired + private LiteCodeService liteCodeService; + + @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create( + @Validated @RequestBody LiteCodeCreateDTO liteCodeCreateDTO){ + return AlitaResult.success(liteCodeService.create(liteCodeCreateDTO)); + } + + @PutMapping("/modify") + @ApiOperation("修改") + public AlitaResult modify( + @Validated @RequestBody LiteCodeModifyDTO liteCodeModifyDTO){ + return AlitaResult.success(liteCodeService.modify(liteCodeModifyDTO)); + } + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(LiteCodeQueryDTO liteCodeQueryDTO){ + liteCodeService.page(liteCodeQueryDTO); + return AlitaResult.success(liteCodeQueryDTO.getPageResult()); + } + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dao/AuthClientMapper.java b/backend/src/main/java/com/senmesh/usercenter/auth/dao/AuthClientMapper.java new file mode 100644 index 0000000..5eb057a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dao/AuthClientMapper.java @@ -0,0 +1,29 @@ +package com.senmesh.usercenter.auth.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.auth.dto.AuthClientDTO; +import com.senmesh.usercenter.auth.dto.AuthClientQueryDTO; +import com.senmesh.usercenter.auth.entity.AuthClient; + +/** + * 授权客户端 + * + * @author sr on 2021-05-24 + */ +public interface AuthClientMapper extends MyMapper { + + /** + * 查询 + * + * @param authClientQueryDTO + * @return + * @author sr on 2021-05-24 + */ + List listAuthClientDTO(@Param("param") AuthClientQueryDTO authClientQueryDTO); + + List list(@Param("param") AuthClientQueryDTO authClientQueryDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dao/AuthDetailEntrypointMapper.java b/backend/src/main/java/com/senmesh/usercenter/auth/dao/AuthDetailEntrypointMapper.java new file mode 100644 index 0000000..93405d7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dao/AuthDetailEntrypointMapper.java @@ -0,0 +1,58 @@ +package com.senmesh.usercenter.auth.dao; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.auth.dto.*; +import com.senmesh.usercenter.auth.entity.AuthDetailEntrypoint; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Set; + +/** + * 授权明细入口 + * + * @author sr on 2022-01-06 + */ +public interface AuthDetailEntrypointMapper extends MyMapper { + + /** + * 查询 + * + * @param authDetailEntrypointQueryDTO + * @return + * @author sr on 2022-01-06 + */ + List listAuthDetailEntrypointDTO(@Param("param") AuthDetailEntrypointQueryDTO authDetailEntrypointQueryDTO); + + /** + * 邀请信息 + * + * @param queryDTO 查询dto + * @param existLoginUserId 存在登录用户id + * @param existLoginOrgId 存在登录org id + * @return {@link List}<{@link InviteInfoDTO}> + */ + List inviteInfoPage(@Param("param") InviteInfoPageQueryDTO queryDTO, @Param("userId") Long existLoginUserId,@Param("orgId") Long existLoginOrgId); + /** + * PC端机构下所有的 邀请信息 + * + * @param queryDTO 查询dto + */ + List pcInviteInfoPage(@Param("param") PcInviteInfoPageQueryDTO queryDTO,@Param("orgId") Long existLoginOrgId); + + + List inviteStatisticQuery(@Param("param") InviteStatisticQueryDTO queryDTO, @Param("orgId") Long existLoginOrgId); + + /** + * 邀请数统计查询 + * + * @param queryDTO 查询dto + * @param existLoginOrgId 存在登录org id + * @return int + */ + int countInviteStatisticQuery(@Param("param") InviteStatisticQueryDTO queryDTO, @Param("orgId") Long existLoginOrgId); + + int inviteRegisterCount(@Param("param") InviteStatisticQueryDTO queryDTO, @Param("orgId") Long existLoginOrgId); + + List registrationList(@Param("userIds") Set userIds); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dao/AuthDetailMapper.java b/backend/src/main/java/com/senmesh/usercenter/auth/dao/AuthDetailMapper.java new file mode 100644 index 0000000..febec80 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dao/AuthDetailMapper.java @@ -0,0 +1,27 @@ +package com.senmesh.usercenter.auth.dao; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.auth.dto.AuthDetailDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailQueryDTO; +import com.senmesh.usercenter.auth.entity.AuthDetail; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 授权明细 + * + * @author sr on 2021-05-24 + */ +public interface AuthDetailMapper extends MyMapper { + + /** + * 查询 + * + * @param authDetailQueryDTO + * @return + * @author sr on 2021-05-24 + */ + List listAuthDetailDTO(@Param("param") AuthDetailQueryDTO authDetailQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dao/AuthSubscribeDetailMapper.java b/backend/src/main/java/com/senmesh/usercenter/auth/dao/AuthSubscribeDetailMapper.java new file mode 100644 index 0000000..92a28c8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dao/AuthSubscribeDetailMapper.java @@ -0,0 +1,28 @@ +package com.senmesh.usercenter.auth.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.usercenter.auth.dto.AuthSubscribeDetailDTO; +import com.senmesh.usercenter.auth.dto.AuthSubscribeDetailQueryDTO; +import com.senmesh.usercenter.auth.entity.AuthSubscribeDetail; +import com.senmesh.tkmybatis.mybatis.MyMapper; + +/** + * 授权订阅明细 + * + * @author sr on 2022-04-05 + */ +public interface AuthSubscribeDetailMapper extends MyMapper { + + /** + * 查询 + * + * @param authSubscribeDetailQueryDTO + * @return + * @author sr on 2022-04-05 + */ + List listAuthSubscribeDetailDTO(@Param("param") AuthSubscribeDetailQueryDTO authSubscribeDetailQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dao/AuthTypeMapper.java b/backend/src/main/java/com/senmesh/usercenter/auth/dao/AuthTypeMapper.java new file mode 100644 index 0000000..d5f3377 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dao/AuthTypeMapper.java @@ -0,0 +1,19 @@ +package com.senmesh.usercenter.auth.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.senmesh.usercenter.auth.dto.AuthTypeDTO; +import com.senmesh.usercenter.auth.dto.AuthTypeQueryDTO; +import com.senmesh.usercenter.auth.entity.AuthType; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 授权客户端 + * + * @author sr on 2021-05-24 + */ +public interface AuthTypeMapper extends BaseMapper { + + List list(@Param("param") AuthTypeQueryDTO queryDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dao/LiteCodeConfigMapper.java b/backend/src/main/java/com/senmesh/usercenter/auth/dao/LiteCodeConfigMapper.java new file mode 100644 index 0000000..d8e80da --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dao/LiteCodeConfigMapper.java @@ -0,0 +1,28 @@ +package com.senmesh.usercenter.auth.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.usercenter.auth.dto.LiteCodeConfigDTO; +import com.senmesh.usercenter.auth.dto.LiteCodeConfigQueryDTO; +import com.senmesh.usercenter.auth.entity.LiteCodeConfig; +import com.senmesh.tkmybatis.mybatis.MyMapper; + +/** + * 小程序码配置 + * + * @author sr on 2021-12-21 + */ +public interface LiteCodeConfigMapper extends MyMapper { + + /** + * 查询 + * + * @param liteCodeConfigQueryDTO + * @return + * @author sr on 2021-12-21 + */ + List listLiteCodeConfigDTO(@Param("param") LiteCodeConfigQueryDTO liteCodeConfigQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dao/LiteCodeMapper.java b/backend/src/main/java/com/senmesh/usercenter/auth/dao/LiteCodeMapper.java new file mode 100644 index 0000000..1db3239 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dao/LiteCodeMapper.java @@ -0,0 +1,28 @@ +package com.senmesh.usercenter.auth.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.usercenter.auth.dto.LiteCodeDTO; +import com.senmesh.usercenter.auth.dto.LiteCodeQueryDTO; +import com.senmesh.usercenter.auth.entity.LiteCode; +import com.senmesh.tkmybatis.mybatis.MyMapper; + +/** + * 小程序码 + * + * @author sr on 2021-12-21 + */ +public interface LiteCodeMapper extends MyMapper { + + /** + * 查询 + * + * @param liteCodeQueryDTO + * @return + * @author sr on 2021-12-21 + */ + List listLiteCodeDTO(@Param("param") LiteCodeQueryDTO liteCodeQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthClientDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthClientDTO.java new file mode 100644 index 0000000..4be83b8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthClientDTO.java @@ -0,0 +1,38 @@ +package com.senmesh.usercenter.auth.dto; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-05-24 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "授权客户端") +public class AuthClientDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + /** + * 授权类型名称 + */ + private String authTypeName; + /** + * 客户端名称 + */ + private String clientName; + /** 授权类型标识 */ + private Integer authTypeCode ; + /** 配置数据 */ + private String paramData ; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthClientDataDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthClientDataDTO.java new file mode 100644 index 0000000..c1893fe --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthClientDataDTO.java @@ -0,0 +1,32 @@ +package com.senmesh.usercenter.auth.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(description = "授权客户端配置数据信息") +public class AuthClientDataDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 285993673369713207L; + + @ApiModelProperty("授权客户端id") + private Long authClientId; + + @ApiModelProperty("授权类型标识") + private Integer authTypeCode ; + + @ApiModelProperty("第三方id") + private String clientId; + + @ApiModelProperty("第三方密钥") + private String clientSecret; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthClientOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthClientOperateDTO.java new file mode 100644 index 0000000..5209aaf --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthClientOperateDTO.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.auth.dto; + +import com.senmesh.common.dto.BaseDTO; +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import javax.validation.constraints.NotNull; + +/** + * @author sr on 2021-05-24 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@ApiModel(description = "授权客户端操作") +public class AuthClientOperateDTO extends BaseDTO { + + /** + * + **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("授权类型标识") + @NotNull(message = "授权类型标识不能为空", groups = {Create.class, Update.class}) + private Integer authTypeCode; + @ApiModelProperty("授权应用名称") + @NotNull(message = "授权应用名称不能为空", groups = {Create.class, Update.class}) + private String clientName; + @ApiModelProperty("授权应用配置") + @NotNull(message = "授权应用配置不能为空", groups = {Create.class, Update.class}) + private String paramData; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthClientQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthClientQueryDTO.java new file mode 100644 index 0000000..9b09c47 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthClientQueryDTO.java @@ -0,0 +1,34 @@ +package com.senmesh.usercenter.auth.dto; + +import java.io.Serializable; + +import com.senmesh.common.dto.PageQueryDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2021-05-24 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "授权客户端查询条件") +public class AuthClientQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + @ApiModelProperty("域名或ip") + private String domainOrIp; + @ApiModelProperty("授权类型标识") + private Integer authTypeCode ; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthCodeDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthCodeDTO.java new file mode 100644 index 0000000..a1e7661 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthCodeDTO.java @@ -0,0 +1,38 @@ +package com.senmesh.usercenter.auth.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2022-01-06 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(description = "授权码信息") +public class AuthCodeDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 5013108110519909949L; + + @ApiModelProperty("授权类型标识") + @NotNull(message = "授权类型标识不能为空") + private Integer authTypeCode; + @ApiModelProperty("小程序授权码") + @NotBlank(message = "小程序授权码不能为空") + private String code; + @ApiModelProperty("请求域名或ip") + private String domainOrIp; + @ApiModelProperty("注册邀请码") + private String registerCode; + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailBindDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailBindDTO.java new file mode 100644 index 0000000..dba43d2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailBindDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.auth.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotNull; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-05-24 + */ +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@Data +@ApiModel(description = "授权明细(绑定)") +public class AuthDetailBindDTO extends AuthDetailCreateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("用户类型") + @NotNull(message = "用户类型不能为空") + private Integer userType; + @ApiModelProperty("用户id") + @NotNull(message = "用户id不能为空") + private Long userId; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailCreateDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailCreateDTO.java new file mode 100644 index 0000000..a4a958e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailCreateDTO.java @@ -0,0 +1,53 @@ +package com.senmesh.usercenter.auth.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-05-24 + */ +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@Data +@ApiModel(description = "授权明细创建") +public class AuthDetailCreateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @NotNull(message = "授权客户端id不能为空") + @ApiModelProperty("授权客户端id") + private Long authClientId ; + @NotNull(message = "授权类型不能为空") + @ApiModelProperty("授权类型标识") + private Integer authTypeCode ; + @ApiModelProperty("昵称") + private String nickname ; + @ApiModelProperty("头像") + private String avatar ; + @ApiModelProperty("性别") + private String gender ; + @ApiModelProperty("国家") + private String country ; + @ApiModelProperty("省份") + private String province ; + @ApiModelProperty("城市") + private String city ; + @ApiModelProperty("open_id") + private String openId ; + @NotBlank(message = "授权唯一id不能为空") + @ApiModelProperty("授权唯一id") + private String uniqueId ; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailDTO.java new file mode 100644 index 0000000..8cc2022 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailDTO.java @@ -0,0 +1,50 @@ +package com.senmesh.usercenter.auth.dto; + +import com.senmesh.common.dto.BaseDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import java.util.Date; + +/** + * @author sr on 2021-05-24 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "授权明细") +public class AuthDetailDTO extends BaseDTO { + + private static final long serialVersionUID = -6031622340021565040L; + @ApiModelProperty("授权客户端id") + private Long authClientId; + @ApiModelProperty("授权应用名称") + private String authClientName; + @ApiModelProperty("授权类型标识") + private Integer authTypeCode; + @ApiModelProperty("授权类型名称") + private String authTypeName; + @ApiModelProperty("昵称") + private String nickname; + @ApiModelProperty("头像") + private String avatar; + @ApiModelProperty("性别") + private String gender; + @ApiModelProperty("国家") + private String country; + @ApiModelProperty("省份") + private String province; + @ApiModelProperty("城市") + private String city; + @ApiModelProperty("open_id") + private String openId; + @ApiModelProperty("授权唯一id") + private String uniqueId; + @ApiModelProperty("创建时间") + private Date createTime; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailEntrypointCreateDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailEntrypointCreateDTO.java new file mode 100644 index 0000000..c2070c9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailEntrypointCreateDTO.java @@ -0,0 +1,39 @@ +package com.senmesh.usercenter.auth.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2022-01-06 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "授权明细入口操作") +public class AuthDetailEntrypointCreateDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("授权类型标识") + private Integer authTypeCode; + @ApiModelProperty("授权码") + @NotBlank(message = "授权码不能为空") + private String code; + @ApiModelProperty("请求域名或ip") + private String domainOrIp; + @ApiModelProperty("注册邀请码") + private String registerCode; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailEntrypointCreateRes.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailEntrypointCreateRes.java new file mode 100644 index 0000000..335754e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailEntrypointCreateRes.java @@ -0,0 +1,26 @@ +package com.senmesh.usercenter.auth.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "授权明细入口操作结果") +public class AuthDetailEntrypointCreateRes implements Serializable{ + + /** **/ + private static final long serialVersionUID = 8730408984340728312L; + + @ApiModelProperty("是否订阅") + private Boolean subscribe; + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailEntrypointDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailEntrypointDTO.java new file mode 100644 index 0000000..f3404a9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailEntrypointDTO.java @@ -0,0 +1,33 @@ +package com.senmesh.usercenter.auth.dto; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2022-01-06 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "授权明细入口") +public class AuthDetailEntrypointDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("授权客户端id") + private Long authDetailId; + @ApiModelProperty("关联id(小程序码id)") + private Long unionId; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailEntrypointQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailEntrypointQueryDTO.java new file mode 100644 index 0000000..7e972fc --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailEntrypointQueryDTO.java @@ -0,0 +1,34 @@ +package com.senmesh.usercenter.auth.dto; + +import java.io.Serializable; + +import com.senmesh.common.dto.PageQueryDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2022-01-06 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "授权明细入口查询条件") +public class AuthDetailEntrypointQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + @ApiModelProperty("授权客户端id") + private Long authDetailId; + @ApiModelProperty("关联id(小程序码id)") + private Long unionId; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailLoginDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailLoginDTO.java new file mode 100644 index 0000000..e03a533 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailLoginDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.auth.dto; + +import javax.validation.constraints.NotNull; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-05-24 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +@ApiModel(description = "授权明细(登录)") +public class AuthDetailLoginDTO extends AuthDetailCreateDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("用户类型") + @NotNull(message = "用户类型不能为空") + private Integer userType; + @ApiModelProperty("注册邀请码") + private String registerCode; + @ApiModelProperty("入口点") + private String entrypoint; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailQueryDTO.java new file mode 100644 index 0000000..6640d4b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthDetailQueryDTO.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.auth.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * @author sr on 2021-05-24 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "授权明细查询条件") +public class AuthDetailQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + @ApiModelProperty("授权客户端id") + private Long authClientId; + @ApiModelProperty("授权类型标识") + private Integer authTypeCode ; + @ApiModelProperty("open_id") + private String openId ; + @ApiModelProperty("用户id") + private Long userId; + @ApiModelProperty("授权唯一id") + private String uniqueId; + @ApiModelProperty("昵称") + private String nickname ; +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthSubscribeDetailCreateDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthSubscribeDetailCreateDTO.java new file mode 100644 index 0000000..27cc3c0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthSubscribeDetailCreateDTO.java @@ -0,0 +1,41 @@ +package com.senmesh.usercenter.auth.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; +import javax.validation.constraints.NotNull; +import com.senmesh.common.validation.Update; + +import com.senmesh.common.dto.BaseOperateDTO; + +/** + * @author sr on 2022-04-05 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "授权订阅明细操作") +public class AuthSubscribeDetailCreateDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + @NotNull(message = "id不能为空", groups = {Update.class}) + private Long id; + + @ApiModelProperty("授权客户端id") + @NotNull(message = "授权客户端id不能为空") + private Long authClientId ; + @NotNull(message = "openId不能为空") + private String openId ; + @NotNull(message = "uniqueId不能为空") + private String uniqueId ; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthSubscribeDetailDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthSubscribeDetailDTO.java new file mode 100644 index 0000000..e487703 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthSubscribeDetailDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.auth.dto; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2022-04-05 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "授权订阅明细") +public class AuthSubscribeDetailDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 授权客户端id */ + @ApiModelProperty("授权客户端id") + private Long authClientId ; + @ApiModelProperty("open_id") + private String openId ; + @ApiModelProperty("授权唯一id") + private String uniqueId ; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthSubscribeDetailQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthSubscribeDetailQueryDTO.java new file mode 100644 index 0000000..e5240dd --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthSubscribeDetailQueryDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.auth.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; + +import com.senmesh.common.dto.PageQueryDTO; + +/** + * @author sr on 2022-04-05 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "授权订阅明细查询条件") +public class AuthSubscribeDetailQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + /** 授权客户端id */ + @ApiModelProperty("授权客户端id") + private Long authClientId ; + @ApiModelProperty("授权唯一id") + private String uniqueId ; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthTypeDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthTypeDTO.java new file mode 100644 index 0000000..50c6e32 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthTypeDTO.java @@ -0,0 +1,32 @@ +package com.senmesh.usercenter.auth.dto; + +import com.senmesh.common.dto.BaseDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-05-24 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "授权客户端类型") +public class AuthTypeDTO extends BaseDTO { + + /** + * + **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("授权大类:1微信,2支付宝") + private Integer authMainType; + @ApiModelProperty("授权类型标识") + private Integer authTypeCode; + @ApiModelProperty("名称") + private String name; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthTypeOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthTypeOperateDTO.java new file mode 100644 index 0000000..d4b32f5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthTypeOperateDTO.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.auth.dto; + +import com.senmesh.common.dto.BaseDTO; +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import javax.validation.constraints.NotNull; + +/** + * @author sr on 2021-05-24 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@ApiModel(description = "授权客户端类型操作") +public class AuthTypeOperateDTO extends BaseDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("授权大类:1微信,2支付宝") + @NotNull(message = "授权大类不能为空", groups = {Create.class, Update.class}) + private Integer authMainType; + @ApiModelProperty("授权类型标识") + @NotNull(message = "授权类型标识不能为空", groups = {Create.class, Update.class}) + private Integer authTypeCode; + @ApiModelProperty("名称") + @NotNull(message = "授权名称不能为空", groups = {Create.class, Update.class}) + private String name; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthTypeQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthTypeQueryDTO.java new file mode 100644 index 0000000..b3f9c53 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/AuthTypeQueryDTO.java @@ -0,0 +1,24 @@ +package com.senmesh.usercenter.auth.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import lombok.*; + +import java.io.Serializable; + +/** + * @author sr on 2021-05-24 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@Builder +@ApiModel(description = "授权客户端查询条件") +public class AuthTypeQueryDTO extends PageQueryDTO implements Serializable { + + /** + * + **/ + private static final long serialVersionUID = 1L; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/CodeToSessionDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/CodeToSessionDTO.java new file mode 100644 index 0000000..55294e2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/CodeToSessionDTO.java @@ -0,0 +1,32 @@ +package com.senmesh.usercenter.auth.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2022-01-06 + */ +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Data +@ApiModel(description = "通用code换session对象") +public class CodeToSessionDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 6510677813408678455L; + + @ApiModelProperty("用户在当前小程序的 ID") + private String openId; + @ApiModelProperty("会话密钥") + private String unionId; + @ApiModelProperty("唯一标识符") + private String sessionKey; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/InviteInfoDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/InviteInfoDTO.java new file mode 100644 index 0000000..7a91250 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/InviteInfoDTO.java @@ -0,0 +1,78 @@ +package com.senmesh.usercenter.auth.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serializable; +import java.util.Date; + +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Data +@ApiModel(description = "邀请人信息") +public class InviteInfoDTO implements Serializable { + private static final long serialVersionUID = -5127886750745608146L; + + @ApiModelProperty("邀请记录ID") + private Long entrypointId; + + @ApiModelProperty("用户昵称") + private String userNickName; + + @ApiModelProperty("用户姓名") + private String userRealName; + + @ApiModelProperty("头像地址") + private String userAvatar; + + @ApiModelProperty("手机号") + private String userPhone; + + @ApiModelProperty("注册时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date userRegisterTime; + + @ApiModelProperty("用户ID") + private Long userId; + + @ApiModelProperty("简历-姓名") + private String resumePersonName; + + @ApiModelProperty("简历-身份证号") + private String resumeCardNo; + + @ApiModelProperty("简历 - 性别:0女 1男") + private Integer resumeSex; + + @ApiModelProperty("简历 - 年龄") + private Integer resumeAge; + + @ApiModelProperty("简历 - 文化程度:0学历不限、1初中、2高中、3专科、4本科、5硕士、6博士") + private Integer resumeEducation; + + @ApiModelProperty("简历 - 求职意向") + private String resumeJobIntention; + + @ApiModelProperty("简历 - 求职意向名称") + private String resumeJobIntentionName; + + @ApiModelProperty("简历 - 数据来源:1BOSS直聘、2猎聘...") + private Integer resumeSource; + + @ApiModelProperty("简历 - 简历附件") + private String resumeFileCode; + + @ApiModelProperty("简历 - 备注") + private String resumeRemark; + + @ApiModelProperty("简历 - 招聘负责人") + private Long resumePersonInCharge; + + @ApiModelProperty("当前用户的状态") + private Integer status; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/InviteInfoPageQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/InviteInfoPageQueryDTO.java new file mode 100644 index 0000000..fb7b803 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/InviteInfoPageQueryDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.auth.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Data +@ApiModel(description = "邀请人信息 - 分页查询DTO") +public class InviteInfoPageQueryDTO extends PageQueryDTO { + + private static final long serialVersionUID = -7603359054944420315L; + @ApiModelProperty("二维码ID") + private Long lifeCodeId; + @ApiModelProperty("邀请记录ID") + private Long entrypointId; + + /** + * 查询类型 1: 需要查询在职人数 2:查今日邀请 + */ + private Integer queryType; + + @ApiModelProperty("开始时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date startTime; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/InviteStatisticDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/InviteStatisticDTO.java new file mode 100644 index 0000000..2d95a4f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/InviteStatisticDTO.java @@ -0,0 +1,19 @@ +package com.senmesh.usercenter.auth.dto; + +import io.swagger.annotations.ApiModel; +import lombok.*; + +import java.io.Serializable; + +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Data +@ApiModel(description = "统计数据") +public class InviteStatisticDTO implements Serializable { + private static final long serialVersionUID = 366340705953671571L; + + private Long authDetailId; + + private Long userAuthId; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/InviteStatisticInfoDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/InviteStatisticInfoDTO.java new file mode 100644 index 0000000..386502c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/InviteStatisticInfoDTO.java @@ -0,0 +1,51 @@ +package com.senmesh.usercenter.auth.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Objects; + +@ApiModel("合伙人统计-查询DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InviteStatisticInfoDTO implements Serializable { + + private static final long serialVersionUID = -5588108740516901862L; + + @ApiModelProperty("总邀请数量") + private Integer totalInviteNumber; + + @ApiModelProperty("今日邀请数量") + private Integer todayInviteNumber; + + @ApiModelProperty("在职数量") + private Integer onTheJobNumber; + + public Integer getTotalInviteNumber() { + if (Objects.isNull(totalInviteNumber)){ + totalInviteNumber = 0; + } + return totalInviteNumber; + } + + public Integer getTodayInviteNumber() { + if (Objects.isNull(todayInviteNumber)){ + todayInviteNumber = 0; + } + return todayInviteNumber; + } + + public Integer getOnTheJobNumber() { + if (Objects.isNull(onTheJobNumber)){ + onTheJobNumber = 0; + } + return onTheJobNumber; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/InviteStatisticQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/InviteStatisticQueryDTO.java new file mode 100644 index 0000000..bd62d57 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/InviteStatisticQueryDTO.java @@ -0,0 +1,44 @@ +package com.senmesh.usercenter.auth.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serializable; +import java.util.Date; + +@ApiModel("合伙人统计-查询DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InviteStatisticQueryDTO implements Serializable { + + private static final long serialVersionUID = -5588108740516901862L; + + @ApiModelProperty("开始时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date startTime; + + @ApiModelProperty("结束时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date endTime; + + @ApiModelProperty("用户ID") + private Long userId; + + @ApiModelProperty("PC端调用默认pc") + private String clientType; + + /** + * 查询类型 1: 需要查询在职人数 + */ + private Integer queryType; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/LiteCodeConfigDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/LiteCodeConfigDTO.java new file mode 100644 index 0000000..0072499 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/LiteCodeConfigDTO.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.auth.dto; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-12-21 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "小程序码配置") +public class LiteCodeConfigDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("授权客户端id") + private Long authClientId; + @ApiModelProperty("小程序码业务类型") + private Integer bizType; + @ApiModelProperty("路径") + private String path; + @ApiModelProperty("参数键-逗号分隔") + private String paramKey; + @ApiModelProperty("内置环境参数键-逗号分隔") + private String envParamKey; + @ApiModelProperty("平台编码") + private Integer platformCode; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/LiteCodeConfigOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/LiteCodeConfigOperateDTO.java new file mode 100644 index 0000000..1b49849 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/LiteCodeConfigOperateDTO.java @@ -0,0 +1,33 @@ +package com.senmesh.usercenter.auth.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; +import javax.validation.constraints.NotNull; +import com.senmesh.common.validation.Update; + +import com.senmesh.common.dto.BaseOperateDTO; + +/** + * @author sr on 2021-12-21 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "小程序码配置操作") +public class LiteCodeConfigOperateDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + @NotNull(message = "id不能为空", groups = {Update.class}) + private Long id; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/LiteCodeConfigQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/LiteCodeConfigQueryDTO.java new file mode 100644 index 0000000..ac3f777 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/LiteCodeConfigQueryDTO.java @@ -0,0 +1,34 @@ +package com.senmesh.usercenter.auth.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; + +import com.senmesh.common.dto.PageQueryDTO; + +/** + * @author sr on 2021-12-21 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "小程序码配置查询条件") +public class LiteCodeConfigQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + @ApiModelProperty("授权客户端id") + private Long authClientId; + @ApiModelProperty("小程序码业务类型") + private Integer bizType; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/LiteCodeCreateDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/LiteCodeCreateDTO.java new file mode 100644 index 0000000..a0f109e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/LiteCodeCreateDTO.java @@ -0,0 +1,50 @@ +package com.senmesh.usercenter.auth.dto; + +import com.google.common.collect.Maps; +import com.senmesh.common.dto.BaseOperateDTO; +import com.senmesh.usercenter.auth.constant.AuthTypeEnum; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.Builder.Default; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Map; + +/** + * @author sr on 2021-12-21 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "小程序码操作") +public class LiteCodeCreateDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("小程序码业务类型") + @NotNull(message = "小程序码业务类型不能为空") + private Integer bizType; + @ApiModelProperty("名称") + @NotBlank(message = "名称不能为空") + private String name; + @ApiModelProperty("请求域名或ip") +// @NotBlank(message = "请求域名或ip不能为空") + private String domainOrIp; + @ApiModelProperty("授权类型:默认微信小程序") + @Default + private Integer authTypeCode = AuthTypeEnum.WECHAT_LITE.getCode(); + @ApiModelProperty("参数值") + @Default + private Map paramData = Maps.newHashMap(); + + /** + * 来源 + */ + private Integer sourceFrom; +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/LiteCodeDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/LiteCodeDTO.java new file mode 100644 index 0000000..e0e1eeb --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/LiteCodeDTO.java @@ -0,0 +1,48 @@ +package com.senmesh.usercenter.auth.dto; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-12-21 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "小程序码") +public class LiteCodeDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("小程序码配置id") + private Long liteCodeConfigId; + @ApiModelProperty("唯一码-uuid") + private String uniqueCode; + @ApiModelProperty("参数值(按参数键升序排列)(格式:**&**)") + private String paramValue; + @ApiModelProperty("query参数值(格式:**=**&**=**)") + private String queryValue; + @ApiModelProperty("小程序码文件编码") + private String fileCode; + @ApiModelProperty("小程序scheme码") + private String urlScheme; + @ApiModelProperty("名称") + private String name; + @ApiModelProperty("用户id") + private Long userId; + @ApiModelProperty("机构id") + private Long orgId; + @ApiModelProperty("平台编码") + private Integer platformCode; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/LiteCodeModifyDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/LiteCodeModifyDTO.java new file mode 100644 index 0000000..4ba015e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/LiteCodeModifyDTO.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.auth.dto; + +import com.senmesh.common.dto.BaseOperateDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + * @description: 小程序码修改操作 + * @author: guixinman + * @create: 2023-02-20 16:08 + **/ +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "小程序码操作") +public class LiteCodeModifyDTO extends BaseOperateDTO implements Serializable { + + @ApiModelProperty("小程序码业务类型") + //@NotNull(message = "小程序码业务类型不能为空") + private Integer bizType; + + @NotNull(message = "id不能为空") + private Long id; + + + @NotBlank(message = "名称不能为空") + private String name; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/LiteCodeQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/LiteCodeQueryDTO.java new file mode 100644 index 0000000..40a277b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/LiteCodeQueryDTO.java @@ -0,0 +1,43 @@ +package com.senmesh.usercenter.auth.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * @author sr on 2021-12-21 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "小程序码查询条件") +public class LiteCodeQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + @ApiModelProperty("小程序码配置id") + private Long liteCodeConfigId; + @ApiModelProperty("参数值(按参数键升序排列)(格式:**&**)") + private String paramValue; + @ApiModelProperty("小程序码名称") + private String name; + @ApiModelProperty("小程序码名称(模糊匹配)") + private String nameLike; + @ApiModelProperty("用户id") + private Long userId; + @ApiModelProperty("机构id") + private Long orgId; + @ApiModelProperty("业务类型") + private Integer bizType; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/LitePhoneAuthDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/LitePhoneAuthDTO.java new file mode 100644 index 0000000..66c1b20 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/LitePhoneAuthDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.auth.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-05-12 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(description = "小程序手机号授权信息") +public class LitePhoneAuthDTO extends AuthCodeDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 2022092915168090246L; + + @ApiModelProperty("包括敏感数据在内的完整用户信息的加密数据") +// @NotBlank(message = "加密数据不能为空") + private String encryptedData; + @ApiModelProperty("加密算法的初始向量") +// @NotBlank(message = "加密向量不能为空") + private String iv; + @ApiModelProperty("获取手机号的code(微信小程序)") + private String phoneCode; + + @ApiModelProperty("手机号(加密信息换取的)") + private String phone; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/LitePhoneLoginDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/LitePhoneLoginDTO.java new file mode 100644 index 0000000..5181c6e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/LitePhoneLoginDTO.java @@ -0,0 +1,32 @@ +package com.senmesh.usercenter.auth.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotNull; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-05-12 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(description = "小程序登录") +public class LitePhoneLoginDTO extends LitePhoneAuthDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 2022092915168090246L; + + @ApiModelProperty("用户类型") + @NotNull(message = "用户类型不能为空") + private Integer userType; + @ApiModelProperty("入口点") + private String entrypoint; + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/PcInviteInfoDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/PcInviteInfoDTO.java new file mode 100644 index 0000000..f66ff46 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/PcInviteInfoDTO.java @@ -0,0 +1,65 @@ +package com.senmesh.usercenter.auth.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Data +@ApiModel(description = "邀请人信息") +public class PcInviteInfoDTO implements Serializable { + private static final long serialVersionUID = -5127886750745608146L; + + @ApiModelProperty("用户id") + private Long userId; + + @ApiModelProperty("姓名") + private String personName; + + @ApiModelProperty("昵称") + private String nickname; + + @ApiModelProperty("身份证号") + private String cardNo; + + @ApiModelProperty("性别:2女 1男 3 其它") + private String gender; + + @ApiModelProperty("年龄") + private Integer age; + + @ApiModelProperty("手机号") + private String phone; + + @ApiModelProperty("文化程度:0学历不限、1初中、2高中、3专科、4本科、5硕士、6博士") + private String education; + + @ApiModelProperty("求职意向") + private String jobIntention; + + @ApiModelProperty("邀请人id") + private String inviterId; + + @ApiModelProperty("邀请人名称") + private String inviterName; + + @ApiModelProperty("邀请时间") + private String inviterTime; + + @ApiModelProperty("注册时间") + private String registerTime; + + @ApiModelProperty("二维码名称") + private String liteName; + + @ApiModelProperty("备注") + private String remark; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/PcInviteInfoPageQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/PcInviteInfoPageQueryDTO.java new file mode 100644 index 0000000..42d02b1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/PcInviteInfoPageQueryDTO.java @@ -0,0 +1,60 @@ +package com.senmesh.usercenter.auth.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Data +@ApiModel(description = "PC端邀请人信息 - 分页查询DTO") +public class PcInviteInfoPageQueryDTO extends PageQueryDTO { + + private static final long serialVersionUID = -7603359054944420315L; + + @ApiModelProperty("用户id") + private Long userId; + + @ApiModelProperty("姓名") + private String personNameLike; + + @ApiModelProperty("昵称") + private String nicknameLike; + + @ApiModelProperty("性别:2女 1男 3 其它") + private Integer gender; + + @ApiModelProperty("年龄") + private Integer age; + + @ApiModelProperty("手机号") + private String phone; + + @ApiModelProperty("邀请人id") + private String inviterId; + + @ApiModelProperty("邀请时间开始") + private String inviterTimeStart; + @ApiModelProperty("邀请时间结束") + private String inviterTimeEnd; + + @ApiModelProperty("注册时间开始") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date registerTimeStart; + @ApiModelProperty("注册时间结束") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date registerTimeEnd; + + @ApiModelProperty("二维码名称") + private String liteNameLike; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/PcInviteStatisticInfoDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/PcInviteStatisticInfoDTO.java new file mode 100644 index 0000000..4e0682a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/PcInviteStatisticInfoDTO.java @@ -0,0 +1,51 @@ +package com.senmesh.usercenter.auth.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Objects; + +@ApiModel("合伙人统计 - pc 查询DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PcInviteStatisticInfoDTO implements Serializable { + + private static final long serialVersionUID = -5588108740516901862L; + + @ApiModelProperty("邀请数量") + private Integer inviteNumber; + + @ApiModelProperty("未注册数量") + private Integer unRegisterNumber; + + @ApiModelProperty("注册数量") + private Integer registerNumber; + + public Integer getInviteNumber() { + if (Objects.isNull(inviteNumber)) { + inviteNumber = 0; + } + return inviteNumber; + } + + public Integer getUnRegisterNumber() { + if (Objects.isNull(unRegisterNumber)) { + unRegisterNumber = 0; + } + return unRegisterNumber; + } + + public Integer getRegisterNumber() { + if (Objects.isNull(registerNumber)) { + registerNumber = 0; + } + return registerNumber; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/dto/RegistrationInfoDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/dto/RegistrationInfoDTO.java new file mode 100644 index 0000000..b4f9b59 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/dto/RegistrationInfoDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.auth.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class RegistrationInfoDTO implements Serializable { + private static final long serialVersionUID = -3240224698154801738L; + + /** + * 用户id + */ + private Long userId; + + /** + * 岗位ID + */ + private Long positionId; + + /** + * 状态 + */ + private Integer status; + + /** + * 终止 + */ + private Boolean termination; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/entity/AuthClient.java b/backend/src/main/java/com/senmesh/usercenter/auth/entity/AuthClient.java new file mode 100644 index 0000000..43f805e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/entity/AuthClient.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.auth.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 授权客户端 + * + * @author sr on 2021-05-24 + */ +@TableName("uc_auth_client") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class AuthClient extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + /** + * 授权应用名称 + */ + private String clientName; + /** 授权类型标识 */ + private Integer authTypeCode ; + /** 配置数据 */ + private String paramData ; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/entity/AuthDetail.java b/backend/src/main/java/com/senmesh/usercenter/auth/entity/AuthDetail.java new file mode 100644 index 0000000..6bab5b8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/entity/AuthDetail.java @@ -0,0 +1,49 @@ +package com.senmesh.usercenter.auth.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 授权明细 + * + * @author sr on 2021-05-24 + */ +@TableName("uc_auth_detail") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class AuthDetail extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 授权客户端id */ + private Long authClientId ; + /** 授权类型标识 */ + private Integer authTypeCode ; + /** 昵称 */ + private String nickname ; + /** 头像 */ + private String avatar ; + /** 性别 */ + private String gender ; + /** 国家 */ + private String country ; + /** 省份 */ + private String province ; + /** 城市 */ + private String city ; + /** open_id */ + private String openId ; + /** 授权唯一id */ + private String uniqueId ; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/entity/AuthDetailEntrypoint.java b/backend/src/main/java/com/senmesh/usercenter/auth/entity/AuthDetailEntrypoint.java new file mode 100644 index 0000000..f3b32dc --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/entity/AuthDetailEntrypoint.java @@ -0,0 +1,33 @@ +package com.senmesh.usercenter.auth.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 授权明细入口 + * + * @author sr on 2022-01-06 + */ +@TableName("uc_auth_detail_entrypoint") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class AuthDetailEntrypoint extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 授权客户端id **/ + private Long authDetailId; + /** 关联id(小程序码id) **/ + private Long unionId; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/entity/AuthSubscribeDetail.java b/backend/src/main/java/com/senmesh/usercenter/auth/entity/AuthSubscribeDetail.java new file mode 100644 index 0000000..1839df1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/entity/AuthSubscribeDetail.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.auth.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 授权订阅明细 + * + * @author sr on 2022-04-05 + */ +@TableName("uc_auth_subscribe_detail") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class AuthSubscribeDetail extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 授权客户端id */ + private Long authClientId ; + /** open_id */ + private String openId ; + /** 授权唯一id */ + private String uniqueId ; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/entity/AuthType.java b/backend/src/main/java/com/senmesh/usercenter/auth/entity/AuthType.java new file mode 100644 index 0000000..a38b384 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/entity/AuthType.java @@ -0,0 +1,34 @@ +package com.senmesh.usercenter.auth.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 授权类型 + * + * @author sr on 2021-05-24 + */ +@TableName("uc_auth_type") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class AuthType extends BaseEntity { + + /** + * 授权大类:1微信,2支付宝 + */ + private Integer authMainType; + /** 授权类型标识 */ + private Integer authTypeCode ; + /** 名称 */ + private String name ; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/entity/LiteCode.java b/backend/src/main/java/com/senmesh/usercenter/auth/entity/LiteCode.java new file mode 100644 index 0000000..4cdb585 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/entity/LiteCode.java @@ -0,0 +1,49 @@ +package com.senmesh.usercenter.auth.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 小程序码 + * + * @author sr on 2021-12-21 + */ +@TableName("uc_lite_code") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class LiteCode extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 小程序码配置id **/ + private Long liteCodeConfigId; + /** 唯一码-uuid **/ + private String uniqueCode; + /** 参数值(按参数键升序排列)(格式:**&**) **/ + private String paramValue; + /** query参数值(格式:**=**&**=**) **/ + private String queryValue; + /** 小程序码文件编码 **/ + private String fileCode; + /** 小程序scheme码 **/ + private String urlScheme; + /** 名称 **/ + private String name; + /** 用户id **/ + private Long userId; + /** 机构id **/ + private Long orgId; + /** 平台编码 **/ + private Integer platformCode; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/entity/LiteCodeConfig.java b/backend/src/main/java/com/senmesh/usercenter/auth/entity/LiteCodeConfig.java new file mode 100644 index 0000000..ff31cf6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/entity/LiteCodeConfig.java @@ -0,0 +1,41 @@ +package com.senmesh.usercenter.auth.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 小程序码配置 + * + * @author sr on 2021-12-21 + */ +@TableName("uc_lite_code_config") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class LiteCodeConfig extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 授权客户端id **/ + private Long authClientId; + /** 小程序码业务类型 **/ + private Integer bizType; + /** 路径 **/ + private String path; + /** 参数键-逗号分隔 **/ + private String paramKey; + /** 内置环境参数键-逗号分隔 **/ + private String envParamKey; + /** 平台编码 **/ + private Integer platformCode; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/mapper/AuthClientMapper.xml b/backend/src/main/java/com/senmesh/usercenter/auth/mapper/AuthClientMapper.xml new file mode 100644 index 0000000..2c6805f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/mapper/AuthClientMapper.xml @@ -0,0 +1,42 @@ + + + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/mapper/AuthDetailEntrypointMapper.xml b/backend/src/main/java/com/senmesh/usercenter/auth/mapper/AuthDetailEntrypointMapper.xml new file mode 100644 index 0000000..b533a81 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/mapper/AuthDetailEntrypointMapper.xml @@ -0,0 +1,245 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/mapper/AuthDetailMapper.xml b/backend/src/main/java/com/senmesh/usercenter/auth/mapper/AuthDetailMapper.xml new file mode 100644 index 0000000..164fb32 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/mapper/AuthDetailMapper.xml @@ -0,0 +1,47 @@ + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/mapper/AuthSubscribeDetailMapper.xml b/backend/src/main/java/com/senmesh/usercenter/auth/mapper/AuthSubscribeDetailMapper.xml new file mode 100644 index 0000000..3e6f373 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/mapper/AuthSubscribeDetailMapper.xml @@ -0,0 +1,22 @@ + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/mapper/AuthTypeMapper.xml b/backend/src/main/java/com/senmesh/usercenter/auth/mapper/AuthTypeMapper.xml new file mode 100644 index 0000000..ea29a04 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/mapper/AuthTypeMapper.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/mapper/LiteCodeConfigMapper.xml b/backend/src/main/java/com/senmesh/usercenter/auth/mapper/LiteCodeConfigMapper.xml new file mode 100644 index 0000000..936607d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/mapper/LiteCodeConfigMapper.xml @@ -0,0 +1,23 @@ + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/mapper/LiteCodeMapper.xml b/backend/src/main/java/com/senmesh/usercenter/auth/mapper/LiteCodeMapper.xml new file mode 100644 index 0000000..3895154 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/mapper/LiteCodeMapper.xml @@ -0,0 +1,39 @@ + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/mapstruct/AuthClientMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/auth/mapstruct/AuthClientMapMapper.java new file mode 100644 index 0000000..966f648 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/mapstruct/AuthClientMapMapper.java @@ -0,0 +1,48 @@ +package com.senmesh.usercenter.auth.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.sdk.bytedance.model.Code2SessionDataDTO; +import com.senmesh.sdk.wechat.model.Code2SessionDTO; +import com.senmesh.usercenter.auth.dto.AuthClientDTO; +import com.senmesh.usercenter.auth.dto.AuthClientOperateDTO; +import com.senmesh.usercenter.auth.dto.AuthTypeOperateDTO; +import com.senmesh.usercenter.auth.dto.CodeToSessionDTO; +import com.senmesh.usercenter.auth.entity.AuthClient; +import com.senmesh.usercenter.auth.entity.AuthType; + +/** + * @author sr on 2021-05-24 + */ +@Mapper +public interface AuthClientMapMapper { + + AuthClientMapMapper INSTANCE = + Mappers.getMapper(AuthClientMapMapper.class); + + /** + * dto to entity + * + * @param authClientDto + * @return + * @author sr on 2021-05-24 + */ + AuthClient toEntity( + AuthClientDTO authClientDto); + + + /** + * @param authClientOperateDTO + * @return + * @author sr on 2021-05-24 + */ + AuthClient toEntity(AuthClientOperateDTO authClientOperateDTO); + + AuthType exchange(AuthTypeOperateDTO operateDTO); + + CodeToSessionDTO to(Code2SessionDTO dto); + + CodeToSessionDTO to(Code2SessionDataDTO dto); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/mapstruct/AuthDetailEntrypointMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/auth/mapstruct/AuthDetailEntrypointMapMapper.java new file mode 100644 index 0000000..d6ea234 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/mapstruct/AuthDetailEntrypointMapMapper.java @@ -0,0 +1,29 @@ +package com.senmesh.usercenter.auth.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.auth.dto.AuthDetailEntrypointDTO; +import com.senmesh.usercenter.auth.entity.AuthDetailEntrypoint; + +/** + * @author sr on 2022-01-06 + */ +@Mapper +public interface AuthDetailEntrypointMapMapper { + + AuthDetailEntrypointMapMapper INSTANCE = + Mappers.getMapper(AuthDetailEntrypointMapMapper.class); + + /** + * dto to entity + * + * @param authDetailEntrypointDto + * @return + * @author sr on 2022-01-06 + */ + AuthDetailEntrypoint toEntity( + AuthDetailEntrypointDTO authDetailEntrypointDto); + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/mapstruct/AuthDetailMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/auth/mapstruct/AuthDetailMapMapper.java new file mode 100644 index 0000000..573be11 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/mapstruct/AuthDetailMapMapper.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.auth.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.auth.dto.AuthDetailCreateDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailLoginDTO; +import com.senmesh.usercenter.auth.dto.LitePhoneLoginDTO; +import com.senmesh.usercenter.auth.entity.AuthDetail; +import com.senmesh.usercenter.user.login.dto.LoginPhoneDTO; + +/** + * @author sr on 2021-05-24 + */ +@Mapper +public interface AuthDetailMapMapper { + + AuthDetailMapMapper INSTANCE = + Mappers.getMapper(AuthDetailMapMapper.class); + + /** + * dto to entity + * + * @param authDetailDto + * @return + * @author sr on 2021-05-24 + */ + AuthDetail toEntity(AuthDetailCreateDTO authDetailCreateDTO); + + @Mapping(target = "withoutCode", constant = "true") + LoginPhoneDTO to(LitePhoneLoginDTO litePhoneLoginDTO); + + AuthDetailLoginDTO toDto(LitePhoneLoginDTO loginPhoneLoginDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/mapstruct/AuthSubscribeDetailMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/auth/mapstruct/AuthSubscribeDetailMapMapper.java new file mode 100644 index 0000000..7983641 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/mapstruct/AuthSubscribeDetailMapMapper.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.auth.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.auth.dto.AuthSubscribeDetailDTO; +import com.senmesh.usercenter.auth.entity.AuthSubscribeDetail; +import com.senmesh.usercenter.auth.dto.AuthSubscribeDetailCreateDTO; + +/** + * @author sr on 2022-04-05 + */ +@Mapper +public interface AuthSubscribeDetailMapMapper { + + AuthSubscribeDetailMapMapper INSTANCE = + Mappers.getMapper(AuthSubscribeDetailMapMapper.class); + + /** + * dto to entity + * + * @param authSubscribeDetailDto + * @return + * @author sr on 2022-04-05 + */ + AuthSubscribeDetail toEntity( + AuthSubscribeDetailDTO authSubscribeDetailDto); + + + /** + * @param authSubscribeDetailCreateDTO + * @return + * @author sr on 2022-04-05 + */ + AuthSubscribeDetail toEntity(AuthSubscribeDetailCreateDTO authSubscribeDetailCreateDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/mapstruct/LiteCodeConfigMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/auth/mapstruct/LiteCodeConfigMapMapper.java new file mode 100644 index 0000000..0f0a5ee --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/mapstruct/LiteCodeConfigMapMapper.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.auth.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.auth.dto.LiteCodeConfigDTO; +import com.senmesh.usercenter.auth.entity.LiteCodeConfig; +import com.senmesh.usercenter.auth.dto.LiteCodeConfigOperateDTO; + +/** + * @author sr on 2021-12-21 + */ +@Mapper +public interface LiteCodeConfigMapMapper { + + LiteCodeConfigMapMapper INSTANCE = + Mappers.getMapper(LiteCodeConfigMapMapper.class); + + /** + * dto to entity + * + * @param liteCodeConfigDto + * @return + * @author sr on 2021-12-21 + */ + LiteCodeConfig toEntity( + LiteCodeConfigDTO liteCodeConfigDto); + + + /** + * @param liteCodeConfigOperateDTO + * @return + * @author sr on 2021-12-21 + */ + LiteCodeConfig toEntity(LiteCodeConfigOperateDTO liteCodeConfigOperateDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/mapstruct/LiteCodeMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/auth/mapstruct/LiteCodeMapMapper.java new file mode 100644 index 0000000..aa23add --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/mapstruct/LiteCodeMapMapper.java @@ -0,0 +1,39 @@ +package com.senmesh.usercenter.auth.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.auth.dto.LiteCodeDTO; +import com.senmesh.usercenter.auth.entity.LiteCode; +import com.senmesh.usercenter.auth.dto.LiteCodeCreateDTO; + +/** + * @author sr on 2021-12-21 + */ +@Mapper +public interface LiteCodeMapMapper { + + LiteCodeMapMapper INSTANCE = + Mappers.getMapper(LiteCodeMapMapper.class); + + /** + * dto to entity + * + * @param liteCodeDto + * @return + * @author sr on 2021-12-21 + */ + LiteCode toEntity( + LiteCodeDTO liteCodeDto); + + + /** + * @param liteCodeOperateDTO + * @return + * @author sr on 2021-12-21 + */ + LiteCode toEntity(LiteCodeCreateDTO liteCodeOperateDTO); + + LiteCodeDTO toDto(LiteCode liteCode); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/service/AuthClientService.java b/backend/src/main/java/com/senmesh/usercenter/auth/service/AuthClientService.java new file mode 100644 index 0000000..ff995eb --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/service/AuthClientService.java @@ -0,0 +1,191 @@ +package com.senmesh.usercenter.auth.service; + +import java.util.List; + +import javax.validation.Valid; + +import org.springframework.validation.annotation.Validated; + +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; +import com.senmesh.sdk.wechat.model.SubscibeMessageReq; +import com.senmesh.sdk.wechat.model.UnionDTO; +import com.senmesh.sdk.wechat.model.UrlSchemeReq; +import com.senmesh.sdk.wechat.model.WxacodeReq; +import com.senmesh.usercenter.auth.dto.AuthClientDTO; +import com.senmesh.usercenter.auth.dto.AuthClientDataDTO; +import com.senmesh.usercenter.auth.dto.AuthClientOperateDTO; +import com.senmesh.usercenter.auth.dto.AuthClientQueryDTO; +import com.senmesh.usercenter.auth.dto.CodeToSessionDTO; +import com.senmesh.usercenter.auth.dto.LitePhoneAuthDTO; +import com.senmesh.usercenter.auth.wechat.dto.WechatSignatureReqDTO; +import com.senmesh.usercenter.auth.wechat.dto.WechatSignatureResDTO; + +/** + * 授权客户端 + * + * @author sr on 2021-05-24 + */ +@Validated +public interface AuthClientService { + + /** + * 新增 + * + * @param authClientOperateDTO + * @return + * @author sr on 2021-05-24 + */ + @Validated(Create.class) + Long create(@Valid AuthClientOperateDTO authClientOperateDTO); + + /** + * 修改 + * + * @param authClientOperateDTO + * @author sr on 2021-05-24 + */ + @Validated(Update.class) + void modify(@Valid AuthClientOperateDTO authClientOperateDTO); + + /** + * 删除 + * + * @param id + * @author sr on 2021-05-24 + */ + void remove(Long id); + + /** + * 查询 + * + * @param authClientQueryDTO + * @return + * @author sr on 2021-05-24 + */ + List list(AuthClientQueryDTO authClientQueryDTO); + + /** + * 分页查询 + * @param authClientQueryDTO + * @author sr on 2022-01-04 + */ + void page(AuthClientQueryDTO authClientQueryDTO); + + /** + * 查询单个授权配置 + * @param authClientQueryDTO + * @return + * @author sr on 2021-06-24 + */ + AuthClientDTO findAuthClientDTO(AuthClientQueryDTO authClientQueryDTO); + + /** + * 查询单个授权配置数据对象 + * @param authClientQueryDTO + * @return + * @author sr on 2021-07-07 + */ + AuthClientDataDTO findClientData(AuthClientQueryDTO authClientQueryDTO); + + /** + * 获取授权配置数据对象 + * @param authClientDTO + * @return + * @author sr on 2022-04-06 + */ + AuthClientDataDTO toClientData(AuthClientDTO authClientDTO); + + + /** + * 获取accessToken + * + * @param clientRegistrationId + * @return + * @author sr on 2021-01-15 + */ + String getAccessToken(AuthClientQueryDTO authClientQueryDTO); + + /** + * 获取ticket + * + * @param clientRegistrationId + * @return + * @author sr on 2021-01-15 + */ + String getJsApiTicket(AuthClientQueryDTO authClientQueryDTO); + + /** + * 签名 + * + * @param wechatSignatureDTO + * @return + * @author sr on 2021-01-15 + */ + WechatSignatureResDTO signature(WechatSignatureReqDTO wechatSignatureDTO); + + /** + * 根据授权配置获取accessToken + * @param authClientDataDTO + * @return + * @author sr on 2021-12-24 + */ + String getAccessToken(AuthClientDataDTO authClientDataDTO); + + /** + * 获取小程序码 + * @param authClientDataDTO + * @param wxacodeRequestParam + * @return + * @author sr on 2021-12-24 + */ + byte[] getWxacode(AuthClientDataDTO authClientDataDTO, WxacodeReq wxacodeRequestParam); + + /** + * 获取小程序scheme码 + * @param authClientDataDTO + * @param urlSchemeRequestParam + * @return + * @author sr on 2021-12-24 + */ + String getUrlscheme(AuthClientDataDTO authClientDataDTO, + UrlSchemeReq urlSchemeRequestParam); + + /** + * 发送小程序订阅消息 + * @param authClientDataDTO + * @param subscibeMessageReq + * @author sr on 2022-01-04 + */ + void subscibeMessage(AuthClientDataDTO authClientDataDTO, SubscibeMessageReq subscibeMessageReq); + + /** + * code换session + * @param authClientDataDTO + * @param code + * @return + * @author sr on 2022-01-06 + */ + CodeToSessionDTO getCodeToSessionDTO(AuthClientDataDTO authClientDataDTO, String code); + + String getPhone(LitePhoneAuthDTO litePhoneAuthDTO); + + /** + * 订阅用户列表 + * @return openIds + * @author sr on 2022-04-05 + */ + List subscribeUser(AuthClientDataDTO authClientDataDTO); + + /** + * 批量openid换unionid + * @param authClientDataDTO + * @param openIds + * @return + * @author sr on 2022-04-05 + */ + List batchUnion(AuthClientDataDTO authClientDataDTO, List openIds); + + String getPhone(AuthClientDataDTO authClientDataDTO, String phoneCode); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/service/AuthDetailEntrypointService.java b/backend/src/main/java/com/senmesh/usercenter/auth/service/AuthDetailEntrypointService.java new file mode 100644 index 0000000..444d38d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/service/AuthDetailEntrypointService.java @@ -0,0 +1,97 @@ +package com.senmesh.usercenter.auth.service; + +import com.senmesh.usercenter.auth.dto.*; + +import com.senmesh.usercenter.auth.dto.AuthCodeDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailEntrypointDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailEntrypointQueryDTO; +import java.util.List; + +/** + * 授权明细入口 + * + * @author sr on 2022-01-06 + */ +public interface AuthDetailEntrypointService { + + /** + * 新增 + * + * @param authCodeDTO + * @return + * @author sr on 2022-01-06 + */ + AuthDetailEntrypointCreateRes create(AuthCodeDTO authCodeDTO); + + /** + * 删除 + * + * @param id + * @author sr on 2022-01-06 + */ + void remove(Long id); + + /** + * 查询 + * + * @param authDetailEntrypointQueryDTO + * @return + * @author sr on 2022-01-06 + */ + List list(AuthDetailEntrypointQueryDTO authDetailEntrypointQueryDTO); + + /** + * 分页查询 + * + * @param authDetailEntrypointQueryDTO + * @return + * @author sr on 2022-01-06 + */ + void page(AuthDetailEntrypointQueryDTO authDetailEntrypointQueryDTO); + + /** + * 单个查询 + * + * @param authDetailEntrypointQueryDTO + * @return + * @author sr on 2022-01-06 + */ + AuthDetailEntrypointDTO find(AuthDetailEntrypointQueryDTO authDetailEntrypointQueryDTO); + + /** + * 分页查询邀请人列表 + * 默认查询当前登录人 + * 只查询已注册的邀请人列表 + * + * @param queryDTO 查询dto + * @return {@link List}<{@link InviteInfoDTO}> + */ + List inviteInfoPage(InviteInfoPageQueryDTO queryDTO); + InviteStatisticInfoDTO inviteInfoStatistic(InviteInfoPageQueryDTO queryDTO); + + /** + * pc端查询邀请列表 + * @param queryDTO + * @return + */ + List pcInviteInfoPage(PcInviteInfoPageQueryDTO queryDTO); + + /** + * 请统计查询(pc) + * + * @param queryDTO 查询dto + * @return {@link InviteStatisticInfoDTO} + */ + PcInviteStatisticInfoDTO pcInviteStatisticQuery(InviteStatisticQueryDTO queryDTO); + + + /** + * 请统计查询 + * + * @param queryDTO 查询dto + * @return {@link InviteStatisticInfoDTO} + */ + InviteStatisticInfoDTO inviteStatisticQuery(InviteStatisticQueryDTO queryDTO); + + PcInviteInfoDTO getInviteInfoDetail(PcInviteInfoPageQueryDTO queryDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/service/AuthDetailService.java b/backend/src/main/java/com/senmesh/usercenter/auth/service/AuthDetailService.java new file mode 100644 index 0000000..a3b1c5d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/service/AuthDetailService.java @@ -0,0 +1,48 @@ +package com.senmesh.usercenter.auth.service; + +import java.util.List; + +import com.senmesh.usercenter.auth.dto.AuthDetailCreateDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailQueryDTO; + +/** + * 授权明细 + * + * @author sr on 2021-05-24 + */ +public interface AuthDetailService { + + /** + * 创建(幂等) + * @param authDetailCreateDTO + * @return + * @author sr on 2022-01-06 + */ + Long create(AuthDetailCreateDTO authDetailCreateDTO); + + /** + * 删除 + * + * @param id + * @author sr on 2021-05-24 + */ + void remove(Long id); + + /** + * 查询 + * + * @param authDetailQueryDTO + * @return + * @author sr on 2021-05-24 + */ + List list(AuthDetailQueryDTO authDetailQueryDTO); + + /** + * 分页查询 + * @param authDetailQueryDTO + * @author sr on 2022-01-04 + */ + void page(AuthDetailQueryDTO authDetailQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/service/AuthSubscribeDetailService.java b/backend/src/main/java/com/senmesh/usercenter/auth/service/AuthSubscribeDetailService.java new file mode 100644 index 0000000..605a9c0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/service/AuthSubscribeDetailService.java @@ -0,0 +1,62 @@ +package com.senmesh.usercenter.auth.service; + +import java.util.List; + +import com.senmesh.usercenter.auth.dto.AuthSubscribeDetailQueryDTO; +import com.senmesh.usercenter.auth.dto.AuthSubscribeDetailCreateDTO; +import com.senmesh.usercenter.auth.dto.AuthSubscribeDetailDTO; + +/** + * 授权订阅明细 + * + * @author sr on 2022-04-05 + */ +public interface AuthSubscribeDetailService { + + /** + * 新增 + * + * @param authSubscribeDetailCreateDTO + * @return + * @author sr on 2022-04-05 + */ + void create(AuthSubscribeDetailCreateDTO authSubscribeDetailCreateDTO); + + /** + * 删除 + * + * @param id + * @author sr on 2022-04-05 + */ + void remove(Long id); + + /** + * 查询 + * + * @param authSubscribeDetailQueryDTO + * @return + * @author sr on 2022-04-05 + */ + List list(AuthSubscribeDetailQueryDTO authSubscribeDetailQueryDTO); + + /** + * 分页查询 + * + * @param authSubscribeDetailQueryDTO + * @return + * @author sr on 2022-04-05 + */ + void page(AuthSubscribeDetailQueryDTO authSubscribeDetailQueryDTO); + + /** + * 单个查询 + * + * @param authSubscribeDetailQueryDTO + * @return + * @author sr on 2022-04-05 + */ + AuthSubscribeDetailDTO find(AuthSubscribeDetailQueryDTO authSubscribeDetailQueryDTO); + + void loadAllClient(); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/service/AuthTypeService.java b/backend/src/main/java/com/senmesh/usercenter/auth/service/AuthTypeService.java new file mode 100644 index 0000000..60de762 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/service/AuthTypeService.java @@ -0,0 +1,41 @@ +package com.senmesh.usercenter.auth.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.senmesh.common.validation.Create; +import com.senmesh.usercenter.auth.dto.AuthTypeDTO; +import com.senmesh.usercenter.auth.dto.AuthTypeOperateDTO; +import com.senmesh.usercenter.auth.dto.AuthTypeQueryDTO; +import com.senmesh.usercenter.auth.entity.AuthType; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.List; + +/** + * 授权客户端 + * + * @author sr on 2021-05-24 + */ +@Validated +public interface AuthTypeService extends IService { + + /** + * 新增 + * + * @param operateDTO + * @return + * @author sr on 2021-05-24 + */ + @Validated(Create.class) + Long create(@Valid AuthTypeOperateDTO operateDTO); + + /** + * 查询 + * + * @param queryDTO + * @return + * @author sr on 2021-05-24 + */ + List list(AuthTypeQueryDTO queryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/service/LiteCodeConfigService.java b/backend/src/main/java/com/senmesh/usercenter/auth/service/LiteCodeConfigService.java new file mode 100644 index 0000000..28745fd --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/service/LiteCodeConfigService.java @@ -0,0 +1,68 @@ +package com.senmesh.usercenter.auth.service; + +import java.util.List; + +import com.senmesh.usercenter.auth.dto.LiteCodeConfigQueryDTO; +import com.senmesh.usercenter.auth.dto.LiteCodeConfigOperateDTO; +import com.senmesh.usercenter.auth.dto.LiteCodeConfigDTO; + +/** + * 小程序码配置 + * + * @author sr on 2021-12-21 + */ +public interface LiteCodeConfigService { + + /** + * 新增 + * + * @param liteCodeConfigOperateDTO + * @return + * @author sr on 2021-12-21 + */ + Long create(LiteCodeConfigOperateDTO liteCodeConfigOperateDTO); + + /** + * 修改 + * + * @param liteCodeConfigOperateDTO + * @author sr on 2021-12-21 + */ + void modify(LiteCodeConfigOperateDTO liteCodeConfigOperateDTO); + + /** + * 删除 + * + * @param id + * @author sr on 2021-12-21 + */ + void remove(Long id); + + /** + * 查询 + * + * @param liteCodeConfigQueryDTO + * @return + * @author sr on 2021-12-21 + */ + List list(LiteCodeConfigQueryDTO liteCodeConfigQueryDTO); + + /** + * 分页查询 + * + * @param liteCodeConfigQueryDTO + * @return + * @author sr on 2021-12-21 + */ + void page(LiteCodeConfigQueryDTO liteCodeConfigQueryDTO); + + /** + * 单个查询 + * + * @param liteCodeConfigQueryDTO + * @return + * @author sr on 2021-12-21 + */ + LiteCodeConfigDTO findOne(LiteCodeConfigQueryDTO liteCodeConfigQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/service/LiteCodeService.java b/backend/src/main/java/com/senmesh/usercenter/auth/service/LiteCodeService.java new file mode 100644 index 0000000..d997e6f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/service/LiteCodeService.java @@ -0,0 +1,54 @@ +package com.senmesh.usercenter.auth.service; + +import java.util.List; + +import com.senmesh.usercenter.auth.dto.LiteCodeModifyDTO; +import com.senmesh.usercenter.auth.dto.LiteCodeQueryDTO; +import com.senmesh.usercenter.auth.dto.LiteCodeCreateDTO; +import com.senmesh.usercenter.auth.dto.LiteCodeDTO; + +/** + * 小程序码 + * + * @author sr on 2021-12-21 + */ +public interface LiteCodeService { + + /** + * 新增 + * + * @param liteCodeCreateDTO + * @return + * @author sr on 2021-12-21 + */ + LiteCodeDTO create(LiteCodeCreateDTO liteCodeCreateDTO); + + /** + * 查询 + * + * @param liteCodeQueryDTO + * @return + * @author sr on 2021-12-21 + */ + List list(LiteCodeQueryDTO liteCodeQueryDTO); + + /** + * 分页查询 + * + * @param liteCodeQueryDTO + * @return + * @author sr on 2021-12-21 + */ + void page(LiteCodeQueryDTO liteCodeQueryDTO); + + /** + * 单个查询 + * + * @param liteCodeQueryDTO + * @return + * @author sr on 2021-12-21 + */ + LiteCodeDTO find(LiteCodeQueryDTO liteCodeQueryDTO); + + LiteCodeDTO modify(LiteCodeModifyDTO liteCodeModifyDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/AuthClientServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/AuthClientServiceImpl.java new file mode 100644 index 0000000..2ed7b43 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/AuthClientServiceImpl.java @@ -0,0 +1,311 @@ +package com.senmesh.usercenter.auth.service.impl; + +import java.util.List; + +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.google.common.collect.Lists; +import com.senmesh.common.AlitaResult; +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.common.util.RandomUtils; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.frame.redis.util.RedisUtils; +import com.senmesh.sdk.bytedance.ByteDanceUtils; +import com.senmesh.sdk.bytedance.model.Code2SessionDataDTO; +import com.senmesh.sdk.bytedance.model.Code2SessionReqDTO; +import com.senmesh.sdk.common.dto.LiteUserPhoneDTO; +import com.senmesh.sdk.common.util.LiteEncryptor; +import com.senmesh.sdk.wechat.WechatClient; +import com.senmesh.sdk.wechat.model.AbstractAccessTokenReq; +import com.senmesh.sdk.wechat.model.AccessTokenDTO; +import com.senmesh.sdk.wechat.model.BaseWeChatDTO; +import com.senmesh.sdk.wechat.model.BatchUnionDTO; +import com.senmesh.sdk.wechat.model.BatchUnionReq; +import com.senmesh.sdk.wechat.model.BufferDTO; +import com.senmesh.sdk.wechat.model.Code2SessionDTO; +import com.senmesh.sdk.wechat.model.JsApiTicketDTO; +import com.senmesh.sdk.wechat.model.PhoneNumberDTO; +import com.senmesh.sdk.wechat.model.PhoneNumberReq; +import com.senmesh.sdk.wechat.model.SubscibeMessageReq; +import com.senmesh.sdk.wechat.model.SubscibeUserDTO; +import com.senmesh.sdk.wechat.model.SubscibeUserReq; +import com.senmesh.sdk.wechat.model.UnionDTO; +import com.senmesh.sdk.wechat.model.UnionUser; +import com.senmesh.sdk.wechat.model.UrlSchemeDTO; +import com.senmesh.sdk.wechat.model.UrlSchemeReq; +import com.senmesh.sdk.wechat.model.WxacodeReq; +import com.senmesh.usercenter.auth.constant.AuthTypeEnum; +import com.senmesh.usercenter.auth.dao.AuthClientMapper; +import com.senmesh.usercenter.auth.dto.AuthClientDTO; +import com.senmesh.usercenter.auth.dto.AuthClientDataDTO; +import com.senmesh.usercenter.auth.dto.AuthClientOperateDTO; +import com.senmesh.usercenter.auth.dto.AuthClientQueryDTO; +import com.senmesh.usercenter.auth.dto.CodeToSessionDTO; +import com.senmesh.usercenter.auth.dto.LitePhoneAuthDTO; +import com.senmesh.usercenter.auth.entity.AuthClient; +import com.senmesh.usercenter.auth.mapstruct.AuthClientMapMapper; +import com.senmesh.usercenter.auth.service.AuthClientService; +import com.senmesh.usercenter.auth.util.AuthClientUtils; +import com.senmesh.usercenter.auth.wechat.dto.WechatSignatureReqDTO; +import com.senmesh.usercenter.auth.wechat.dto.WechatSignatureResDTO; +import com.senmesh.usercenter.sys.util.DomainUtils; + +/** + * @author sr on 2021-05-24 + */ +@Service +public class AuthClientServiceImpl implements AuthClientService { + + @Autowired + private AuthClientMapper authClientMapper; + + @Override + public Long create(AuthClientOperateDTO authClientOperateDTO) { + AuthClient authClient = AuthClientMapMapper.INSTANCE.toEntity(authClientOperateDTO); + authClientMapper.saveEntity(authClient); + return authClient.getId(); + } + + @Override + public void modify(AuthClientOperateDTO authClientOperateDTO) { + AuthClient authClient = AuthClientMapMapper.INSTANCE.toEntity(authClientOperateDTO); + authClientMapper.updateEntitySelective(authClient); + } + + @Override + public void remove(Long id) { + authClientMapper.deleteEntity(AuthClient.builder().id(id).build(), + UserContextHolder.getLoginUserId()); + } + + @Override + public void page(AuthClientQueryDTO authClientQueryDTO) { + authClientMapper.list(authClientQueryDTO); + } + + @Override + public List list(AuthClientQueryDTO authClientQueryDTO) { + authClientQueryDTO.disablePage(); + return authClientMapper.list(authClientQueryDTO); + } + + @Override + public AuthClientDTO findAuthClientDTO(AuthClientQueryDTO authClientQueryDTO) { + authClientQueryDTO.disablePage(); + List authClientDTOs = authClientMapper.listAuthClientDTO(authClientQueryDTO); + Assert.isTrue(!authClientDTOs.isEmpty(), "未找到对应匹配的授权配置信息"); + Assert.isTrue(authClientDTOs.size() == 1, "找到多个匹配的授权配置信息"); + return authClientDTOs.get(0); + } + + @Override + public AuthClientDataDTO findClientData(AuthClientQueryDTO authClientQueryDTO) { + AuthClientDTO authClientDTO = findAuthClientDTO(authClientQueryDTO); + return toClientData(authClientDTO); + } + + @Override + public AuthClientDataDTO toClientData(AuthClientDTO authClientDTO) { + String paramDataStr = authClientDTO.getParamData(); + Assert.isTrue(StringUtils.isNotBlank(paramDataStr), "授权客户端缺少第三方配置"); + AuthClientDataDTO authClientDataDTO = JsonUtils.toObject(paramDataStr, AuthClientDataDTO.class); + authClientDataDTO.setAuthClientId(authClientDTO.getId()); + authClientDataDTO.setAuthTypeCode(authClientDTO.getAuthTypeCode()); + return authClientDataDTO; + } + + @Override + public String getAccessToken(AuthClientQueryDTO authClientQueryDTO) { + AuthClientDataDTO authClientDataDTO = this.findClientData(authClientQueryDTO); + return this.getAccessToken(authClientDataDTO); + } + + @Override + public String getAccessToken(AuthClientDataDTO authClientDataDTO) { + Long authClientId = authClientDataDTO.getAuthClientId(); + String redisKey = AuthClientUtils.getRedisAccessTokenKey(authClientId); + String token = (String) RedisUtils.get(redisKey); + if (StringUtils.isNotBlank(token)) { + return token; + } + WechatClient client = + new WechatClient(authClientDataDTO.getClientId(), authClientDataDTO.getClientSecret()); + + AlitaResult tokenResult = client.getAccessToken(); + Assert.isTrue(tokenResult.getSuccess(), "微信token获取失败:" + tokenResult.getMsg()); + token = tokenResult.getData().getAccessToken(); + RedisUtils.add(redisKey, token, AuthClientUtils.DEFAULT_EXPIRE_TIME); + return token; + } + + @Override + public String getJsApiTicket(AuthClientQueryDTO authClientQueryDTO) { + AuthClientDataDTO authClientDataDTO = this.findClientData(authClientQueryDTO); + return this.getJsApiTicket(authClientDataDTO); + } + + private String getJsApiTicket(AuthClientDataDTO authClientDataDTO) { + Long authClientId = authClientDataDTO.getAuthClientId(); + String redisKey = AuthClientUtils.getRedisAccessTokenKey(authClientId); + // 判断缓存是否存在,不存在调接口 + String ticket = (String) RedisUtils.get(redisKey); + if (StringUtils.isNotBlank(ticket)) { + return ticket; + } + String accessToken = this.getAccessToken(authClientDataDTO); + AlitaResult ticketResult = WechatClient.getJsApiTicket(accessToken); + Assert.isTrue(ticketResult.getSuccess(), "微信ticket获取失败:" + ticketResult.getMsg()); + ticket = ticketResult.getData().getTicket(); + RedisUtils.add(redisKey, ticket, AuthClientUtils.DEFAULT_EXPIRE_TIME); + return ticket; + } + + @Override + public WechatSignatureResDTO signature(WechatSignatureReqDTO wechatSignatureDTO) { + AuthClientDataDTO authClientDataDTO = this.findClientData(wechatSignatureDTO); + // 当前时间戳 + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + // 数据字符串 + String nonceStr = RandomUtils.generateUUID().substring(0, 16); + // ticket + String ticket = this.getJsApiTicket(authClientDataDTO); + String str = String.format("jsapi_ticket=%s&noncestr=%s×tamp=%s&url=%s", ticket, nonceStr, + timestamp, wechatSignatureDTO.getUrl()); + // 签名 + String signature = DigestUtils.sha1Hex(str); + return WechatSignatureResDTO.builder().nonceStr(nonceStr).timestamp(timestamp) + .signature(signature).appId(authClientDataDTO.getClientId()).build(); + } + + /** + * 处理accessToken + * @param authClientDataDTO + * @param param + * @author sr on 2021-12-24 + */ + private void dealAccessToken(AuthClientDataDTO authClientDataDTO, Object param) { + if (param instanceof AbstractAccessTokenReq) { + AbstractAccessTokenReq req = (AbstractAccessTokenReq) param; + String accessToken = req.getAccessToken(); + if (StringUtils.isBlank(accessToken)) { + Assert.notNull(authClientDataDTO, "授权客户端配置为空"); + req.setAccessToken(getAccessToken(authClientDataDTO)); + } + } + } + + @Override + public byte[] getWxacode(AuthClientDataDTO authClientDataDTO, WxacodeReq wxacodeRequestParam) { + dealAccessToken(authClientDataDTO, wxacodeRequestParam); + AlitaResult wxacodeResult = WechatClient.getWxacode(wxacodeRequestParam); + Assert.isTrue(wxacodeResult.getSuccess(), "获取微信小程序码失败:" + wxacodeResult.getMsg()); + return wxacodeResult.getData().getBuffer(); + } + + @Override + public String getUrlscheme(AuthClientDataDTO authClientDataDTO, UrlSchemeReq urlSchemeRequestParam) { + dealAccessToken(authClientDataDTO, urlSchemeRequestParam); + AlitaResult urlSchemeResult = WechatClient.getUrlscheme(urlSchemeRequestParam); + Assert.isTrue(urlSchemeResult.getSuccess(), "获取微信小程序scheme码失败:" + urlSchemeResult.getMsg()); + return urlSchemeResult.getData().getOpenlink(); + } + + @Override + public void subscibeMessage(AuthClientDataDTO authClientDataDTO, SubscibeMessageReq subscibeMessageReq) { + dealAccessToken(authClientDataDTO, subscibeMessageReq); + AlitaResult subscibeMessagResult = WechatClient.subscibeMessage(subscibeMessageReq); + Assert.isTrue(subscibeMessagResult.getSuccess(), "发送微信小程序订阅消息失败:" + subscibeMessagResult.getMsg()); + } + + @Override + public CodeToSessionDTO getCodeToSessionDTO(AuthClientDataDTO authClientDataDTO, String code) { + Integer authTypeCode = authClientDataDTO.getAuthTypeCode(); + String clientId = authClientDataDTO.getClientId(); + String clientSecret = authClientDataDTO.getClientSecret(); + + if (AuthTypeEnum.WECHAT_LITE.getCode().equals(authTypeCode)) { + WechatClient client = + new WechatClient(clientId, clientSecret); + AlitaResult sessionResult = client.code2Session(code); + Assert.isTrue(sessionResult.getSuccess(), "获取小程序用户信息失败:" + sessionResult.getMsg()); + return AuthClientMapMapper.INSTANCE.to(sessionResult.getData()); + } else if (AuthTypeEnum.BYTE_DANCE_LITE.getCode().equals(authTypeCode)) { + AlitaResult sessionResult = ByteDanceUtils + .execute(Code2SessionReqDTO.builder().appId(clientId).secret(clientSecret) + .code(code).build()); + Assert.isTrue(sessionResult.getSuccess(), "获取小程序用户信息失败:" + sessionResult.getMsg()); + return AuthClientMapMapper.INSTANCE.to(sessionResult.getData()); + } else { + throw new BusinessException("授权类型有误"); + } + } + + @Override + public String getPhone(LitePhoneAuthDTO litePhoneAuthDTO) { + String domainOrIp = DomainUtils.getOrDefault(litePhoneAuthDTO.getDomainOrIp()); + Integer authTypeCode = litePhoneAuthDTO.getAuthTypeCode(); + AuthClientDataDTO authClientDataDTO = this + .findClientData(AuthClientQueryDTO.builder().domainOrIp(domainOrIp) + .authTypeCode(authTypeCode).build()); + String phoneCode = litePhoneAuthDTO.getPhoneCode(); + String phone = null; + if (AuthTypeEnum.WECHAT_LITE.getCode().equals(authTypeCode) + && StringUtils.isNotBlank(phoneCode)) { + phone = this.getPhone(authClientDataDTO, phoneCode); + } else { + Assert.isTrue( + StringUtils.isNotBlank(litePhoneAuthDTO.getEncryptedData()) && StringUtils.isNotBlank( + litePhoneAuthDTO.getIv()), "加密数据不能为空"); + CodeToSessionDTO codeToSessionDTO = + this.getCodeToSessionDTO(authClientDataDTO, litePhoneAuthDTO.getCode()); + LiteUserPhoneDTO liteUserPhoneDTO = LiteEncryptor.decrypt(litePhoneAuthDTO.getEncryptedData(), + litePhoneAuthDTO.getIv(), codeToSessionDTO.getSessionKey(), LiteUserPhoneDTO.class); + phone = liteUserPhoneDTO.getPhoneNumber(); + } + return phone; + } + + @Override + public List subscribeUser(AuthClientDataDTO authClientDataDTO) { + String accessToken = getAccessToken(authClientDataDTO); + AlitaResult result = + WechatClient.getSubscibeUser(SubscibeUserReq.builder().accessToken(accessToken).build()); + Assert.isTrue(result.getSuccess(), "获取订阅用户列表失败:" + result.getMsg()); + // TODO 待关注人数超1w时,修复分页 + return result.getData().getData().getOpenId(); + } + + @Override + public List batchUnion(AuthClientDataDTO authClientDataDTO, List openIds) { + String accessToken = getAccessToken(authClientDataDTO); + List partUser = Lists.newArrayListWithExpectedSize(100); + int totalSize = openIds.size(); + List totalUnionDTO = Lists.newArrayListWithExpectedSize(totalSize); + for (int i = 0; i< totalSize; i++) { + partUser.add(UnionUser.builder().openId(openIds.get(i)).build()); + if (i % 99 == 0 || i == totalSize -1) { + // 整百/最后一个 + AlitaResult batchUnionResult = WechatClient.batchUnion(BatchUnionReq.builder().accessToken(accessToken).users(partUser).build()); + Assert.isTrue(batchUnionResult.getSuccess(), "获取订阅用户unionid失败:" + batchUnionResult.getMsg()); + totalUnionDTO.addAll(batchUnionResult.getData().getUserInfoList()); + partUser = Lists.newArrayListWithExpectedSize(100); + } + } + return totalUnionDTO; + } + + @Override + public String getPhone(AuthClientDataDTO authClientDataDTO, String phoneCode) { + AlitaResult phoneResult = WechatClient.phoneNumber(PhoneNumberReq.builder() + .accessToken(getAccessToken(authClientDataDTO)).code(phoneCode).build()); + Assert.isTrue(phoneResult.getSuccess(), "获取授权手机号失败:" + phoneResult.getMsg()); + return phoneResult.getData().getPhoneInfo().getPhoneNumber(); + } + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/AuthDetailEntrypointServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/AuthDetailEntrypointServiceImpl.java new file mode 100644 index 0000000..84005df --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/AuthDetailEntrypointServiceImpl.java @@ -0,0 +1,328 @@ +package com.senmesh.usercenter.auth.service.impl; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.google.common.collect.Maps; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.IdcardUtils; +import com.senmesh.common.util.ListUtil; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.auth.constant.AuthDetailEntrypointConstants; +import com.senmesh.usercenter.auth.constant.AuthTypeEnum; +import com.senmesh.usercenter.auth.dao.AuthDetailEntrypointMapper; +import com.senmesh.usercenter.auth.dao.AuthSubscribeDetailMapper; +import com.senmesh.usercenter.auth.dto.AuthClientDataDTO; +import com.senmesh.usercenter.auth.dto.AuthClientQueryDTO; +import com.senmesh.usercenter.auth.dto.AuthCodeDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailCreateDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailEntrypointCreateRes; +import com.senmesh.usercenter.auth.dto.AuthDetailEntrypointDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailEntrypointQueryDTO; +import com.senmesh.usercenter.auth.dto.CodeToSessionDTO; +import com.senmesh.usercenter.auth.dto.InviteInfoDTO; +import com.senmesh.usercenter.auth.dto.InviteInfoPageQueryDTO; +import com.senmesh.usercenter.auth.dto.InviteStatisticDTO; +import com.senmesh.usercenter.auth.dto.InviteStatisticInfoDTO; +import com.senmesh.usercenter.auth.dto.InviteStatisticQueryDTO; +import com.senmesh.usercenter.auth.dto.PcInviteInfoDTO; +import com.senmesh.usercenter.auth.dto.PcInviteInfoPageQueryDTO; +import com.senmesh.usercenter.auth.dto.PcInviteStatisticInfoDTO; +import com.senmesh.usercenter.auth.dto.RegistrationInfoDTO; +import com.senmesh.usercenter.auth.entity.AuthDetailEntrypoint; +import com.senmesh.usercenter.auth.entity.AuthSubscribeDetail; +import com.senmesh.usercenter.auth.service.AuthClientService; +import com.senmesh.usercenter.auth.service.AuthDetailEntrypointService; +import com.senmesh.usercenter.auth.service.AuthDetailService; +import com.senmesh.usercenter.sys.util.DomainUtils; +import com.senmesh.usercenter.user.constant.UserTypeEnum; +import com.senmesh.usercenter.user.dao.UserMapper; +import com.senmesh.usercenter.user.dto.UserAuthQueryDTO; +import com.senmesh.usercenter.user.dto.UserRegisterCodeInfoDTO; +import com.senmesh.usercenter.user.login.dto.UserDetailDTO; +import com.senmesh.usercenter.user.service.UserRegisterService; + +import cn.hutool.core.date.DateUtil; + +/** + * @author sr on 2022-01-06 + */ +@Service +public class AuthDetailEntrypointServiceImpl implements AuthDetailEntrypointService { + + @Autowired + private AuthDetailEntrypointMapper authDetailEntrypointMapper; + + @Autowired + private AuthClientService authClientService; + + @Autowired + private AuthDetailService authDetailService; + + @Autowired + private UserRegisterService userRegisterService; + + @Autowired + private UserMapper userMapper; + + @Autowired + private AuthSubscribeDetailMapper authSubscribeDetailMapper; + + @Override + @Transactional + public AuthDetailEntrypointCreateRes create(AuthCodeDTO authCodeDTO) { + String domainOrIp = DomainUtils.getOrDefault(authCodeDTO.getDomainOrIp()); + Integer authTypeCode = authCodeDTO.getAuthTypeCode(); + AuthClientDataDTO authClientDataDTO = authClientService + .findClientData(AuthClientQueryDTO.builder().domainOrIp(domainOrIp) + .authTypeCode(authTypeCode).build()); + CodeToSessionDTO codeToSessionDTO = + authClientService.getCodeToSessionDTO(authClientDataDTO, authCodeDTO.getCode()); + String authUnionId = codeToSessionDTO.getUnionId(); + // 是否关注公众号 + boolean subscribe = authSubscribeDetailMapper + .existsEntity(AuthSubscribeDetail.builder().uniqueId(authUnionId).build()); + AuthDetailEntrypointCreateRes createRes = AuthDetailEntrypointCreateRes.builder().subscribe(subscribe).build(); + // 判断授权用户是否已注册用户 + UserAuthQueryDTO userAuthQueryDTO = (UserAuthQueryDTO) UserAuthQueryDTO.builder() + .authMainType(AuthTypeEnum.getAuthMainType(authTypeCode)) + .uniqueId(authUnionId) + .userType(UserTypeEnum.PERSON.getType()) + .build() + .disablePage(); + List userDetailDTOs = + userMapper.listAuthUserDetailDTO(userAuthQueryDTO); + if(!userDetailDTOs.isEmpty()) { + return createRes; + } + // 获取创建授权信息 + long authDetailId = authDetailService.create(AuthDetailCreateDTO.builder() + .authClientId(authClientDataDTO.getAuthClientId()).authTypeCode(authTypeCode) + .openId(codeToSessionDTO.getOpenId()).uniqueId(authUnionId).build()); + String registerCode = authCodeDTO.getRegisterCode(); + Long unionId = null; + if (StringUtils.isNotBlank(registerCode)) { + UserRegisterCodeInfoDTO infoDto = userRegisterService.analyRegisterCode(registerCode); + if (infoDto != null) { + unionId = infoDto.getUnionId(); + } + } + // 是否已存在 + AuthDetailEntrypointDTO authDetailEntrypointDTO = find( + AuthDetailEntrypointQueryDTO.builder().authDetailId(authDetailId).unionId(unionId).build()); + if (authDetailEntrypointDTO != null) { + return createRes; + } + AuthDetailEntrypoint authDetailEntrypoint = + AuthDetailEntrypoint.builder().authDetailId(authDetailId).unionId(unionId).build(); + authDetailEntrypointMapper.saveEntity(authDetailEntrypoint); + return createRes; + } + + @Override + @Transactional + public void remove(Long id) { + authDetailEntrypointMapper.deleteEntity(AuthDetailEntrypoint.builder().id(id).build(), + UserContextHolder.getLoginUserId()); + } + + @Override + public List list( + AuthDetailEntrypointQueryDTO authDetailEntrypointQueryDTO) { + authDetailEntrypointQueryDTO.disablePage(); + return authDetailEntrypointMapper.listAuthDetailEntrypointDTO(authDetailEntrypointQueryDTO); + } + + @Override + public void page(AuthDetailEntrypointQueryDTO authDetailEntrypointQueryDTO) { + authDetailEntrypointMapper.listAuthDetailEntrypointDTO(authDetailEntrypointQueryDTO); + } + + @Override + public AuthDetailEntrypointDTO find(AuthDetailEntrypointQueryDTO authDetailEntrypointQueryDTO) { + List authDetailEntrypointDTOs = + this.list(authDetailEntrypointQueryDTO); + return authDetailEntrypointDTOs.isEmpty() ? null : ListUtil.first(authDetailEntrypointDTOs); + } + + @Override + public List inviteInfoPage(InviteInfoPageQueryDTO queryDTO) { + if (queryDTO.getQueryType() != null && queryDTO.getQueryType() == 2) { + queryDTO.setStartTime(DateUtil.beginOfDay(DateUtil.date())); + }else { + queryDTO.setStartTime(null); + } + List inviteInfoDTOS = authDetailEntrypointMapper.inviteInfoPage(queryDTO, UserContextHolder.getExistLoginUserId() + , UserContextHolder.getExistLoginOrgId()); + if (CollectionUtils.isNotEmpty(inviteInfoDTOS)){ + Set userIds = inviteInfoDTOS.stream().map(InviteInfoDTO::getUserId).collect(Collectors.toSet()); + List registrationInfoDTOS = authDetailEntrypointMapper.registrationList(userIds); + Map statusMap = statusMap(registrationInfoDTOS); + return inviteInfoDTOS.stream().peek(inviteInfoDTO -> { + inviteInfoDTO.setStatus(statusMap.get(inviteInfoDTO.getUserId())); + }).collect(Collectors.toList()); + } + return inviteInfoDTOS; + } + + @Override + public InviteStatisticInfoDTO inviteInfoStatistic(InviteInfoPageQueryDTO queryDTO) { + + InviteStatisticInfoDTO infoDTO = new InviteStatisticInfoDTO(); + + queryDTO.setStartTime(null); + queryDTO.setQueryType(null); + infoDTO.setTotalInviteNumber(authDetailEntrypointMapper.inviteInfoPage(queryDTO, UserContextHolder.getExistLoginUserId() + , UserContextHolder.getExistLoginOrgId()).size()); + + queryDTO.setStartTime(DateUtil.beginOfDay(DateUtil.date())); + infoDTO.setTodayInviteNumber(authDetailEntrypointMapper.inviteInfoPage(queryDTO, UserContextHolder.getExistLoginUserId() + , UserContextHolder.getExistLoginOrgId()).size()); + + queryDTO.setStartTime(null); + queryDTO.setQueryType(1); + infoDTO.setOnTheJobNumber(authDetailEntrypointMapper.inviteInfoPage(queryDTO, UserContextHolder.getExistLoginUserId() + , UserContextHolder.getExistLoginOrgId()).size()); + return infoDTO; + } + + /** + * 状态图hh + * + * @param registrationInfoDTOS 注册信息dto + * @return {@link Map}<{@link Long}, {@link Integer}> + */ + private Map statusMap(List registrationInfoDTOS){ + Map statusMap = Maps.newHashMap(); + if (CollectionUtils.isEmpty(registrationInfoDTOS)){ + return statusMap; + } + for (RegistrationInfoDTO registrationInfoDTO : registrationInfoDTOS) { + Long userId = registrationInfoDTO.getUserId(); + Integer status = registrationInfoDTO.getStatus(); + Boolean termination = registrationInfoDTO.getTermination(); + Integer existStatus = statusMap.get(userId); + Integer newStatus = mergeStatus(status, termination); + if (Objects.isNull(existStatus)){ + statusMap.put(userId,newStatus); + }else { + if (AuthDetailEntrypointConstants.USER_JOB_STATUS_RESIGNED.equals(existStatus)){ + statusMap.put(userId,newStatus); + }else { + if (!(AuthDetailEntrypointConstants.USER_JOB_STATUS_RESIGNED.equals(newStatus) || Objects.isNull(newStatus))){ + if (newStatus > existStatus){ + statusMap.put(userId,newStatus); + } + } + } + } + } + return statusMap; + } + + /** + * 合并状态 + * + * @param originStatus 起源地位 + * @param termination 终止 + * @return {@link Integer} + */ + private Integer mergeStatus(Integer originStatus,Boolean termination){ + if (AuthDetailEntrypointConstants.USER_JOB_STATUS_ON_THE_JOB.equals(originStatus)){ + // 在职中 + return AuthDetailEntrypointConstants.USER_JOB_STATUS_ON_THE_JOB; + }else if (AuthDetailEntrypointConstants.USER_JOB_STATUS_ALREADY_REGISTERED.equals(originStatus) + || AuthDetailEntrypointConstants.USER_JOB_STATUS_INVITED.equals(originStatus) + || AuthDetailEntrypointConstants.USER_JOB_STATUS_INTERVIEWED.equals(originStatus) + || AuthDetailEntrypointConstants.USER_JOB_STATUS_TO_BE_HIRED.equals(originStatus) + ){ + // 已报名 + return AuthDetailEntrypointConstants.USER_JOB_STATUS_ALREADY_REGISTERED; + }else if (!Boolean.TRUE.equals(termination) || AuthDetailEntrypointConstants.USER_JOB_STATUS_NOT_REGISTERED.equals(originStatus)){ + // 未报名 + return AuthDetailEntrypointConstants.USER_JOB_STATUS_NOT_REGISTERED; + }else if (AuthDetailEntrypointConstants.USER_JOB_STATUS_RESIGNED.equals(originStatus)){ + // 已离职 + return AuthDetailEntrypointConstants.USER_JOB_STATUS_RESIGNED; + } + return null; + } + + @Override + public List pcInviteInfoPage(PcInviteInfoPageQueryDTO queryDTO) { + List result = authDetailEntrypointMapper.pcInviteInfoPage(queryDTO, UserContextHolder.getExistLoginOrgId()); + result.stream().forEach(exportDTO -> { + // 解析身份证性别、年龄 + if(StringUtils.isNotBlank(exportDTO.getCardNo())){ + exportDTO.setGender(IdcardUtils.judgeGender(exportDTO.getCardNo())); + exportDTO.setAge(IdcardUtils.getAgeByIDNumber(exportDTO.getCardNo())); + } + }); + return result; + } + + @Override + public PcInviteInfoDTO getInviteInfoDetail(PcInviteInfoPageQueryDTO queryDTO){ + List result = this.pcInviteInfoPage(queryDTO); + Assert.isTrue(result.size() == 1, "邀请人信息不唯一"); + return result.get(0); + } + + @Override + public PcInviteStatisticInfoDTO pcInviteStatisticQuery(InviteStatisticQueryDTO queryDTO) { + // PC端调用去除查询条件 + if(!"pc".equals(queryDTO.getClientType())){ + queryDTO.setUserId(UserContextHolder.getExistLoginUserId()); + if (Objects.isNull(queryDTO.getStartTime()) && Objects.isNull(queryDTO.getEndTime())) { + //日期转换 + ZoneId zone = ZoneId.systemDefault(); + Date startTime = Date.from(LocalDateTime.of(LocalDate.now(), LocalTime.MIN).atZone(zone).toInstant()); + Date endTime = Date.from(LocalDateTime.now().atZone(zone).toInstant()); + queryDTO.setStartTime(startTime); + queryDTO.setEndTime(endTime); + } + } + PcInviteStatisticInfoDTO infoDTO = new PcInviteStatisticInfoDTO(); + //查询邀请数 未注册数 + List inviteStatisticDTOS = authDetailEntrypointMapper.inviteStatisticQuery(queryDTO, UserContextHolder.getExistLoginOrgId()); + if (CollectionUtils.isNotEmpty(inviteStatisticDTOS)){ + for (InviteStatisticDTO inviteStatisticDTO : inviteStatisticDTOS) { + infoDTO.setInviteNumber(infoDTO.getInviteNumber() + 1); + if (Objects.isNull(inviteStatisticDTO.getUserAuthId())){ + infoDTO.setUnRegisterNumber(infoDTO.getUnRegisterNumber() + 1); + } + } + } + //查询注册数 + int count = authDetailEntrypointMapper.inviteRegisterCount(queryDTO, UserContextHolder.getExistLoginOrgId()); + infoDTO.setRegisterNumber(count); + return infoDTO; + } + + @Override + public InviteStatisticInfoDTO inviteStatisticQuery(InviteStatisticQueryDTO queryDTO) { + queryDTO.setUserId(UserContextHolder.getExistLoginUserId()); + InviteStatisticInfoDTO infoDTO = new InviteStatisticInfoDTO(); + infoDTO.setTotalInviteNumber(authDetailEntrypointMapper.countInviteStatisticQuery(queryDTO,UserContextHolder.getExistLoginOrgId())); + queryDTO.setStartTime(DateUtil.beginOfDay(DateUtil.date())); + infoDTO.setTodayInviteNumber(authDetailEntrypointMapper.countInviteStatisticQuery(queryDTO,UserContextHolder.getExistLoginOrgId())); + queryDTO.setStartTime(null); + queryDTO.setQueryType(1); + infoDTO.setOnTheJobNumber(authDetailEntrypointMapper.countInviteStatisticQuery(queryDTO,UserContextHolder.getExistLoginOrgId())); + return infoDTO; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/AuthDetailServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/AuthDetailServiceImpl.java new file mode 100644 index 0000000..fe2c13c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/AuthDetailServiceImpl.java @@ -0,0 +1,91 @@ +package com.senmesh.usercenter.auth.service.impl; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.frame.redis.dto.LockDTO; +import com.senmesh.frame.redis.redisson.RedissonUtils; +import com.senmesh.usercenter.auth.constant.AuthTypeEnum; +import com.senmesh.usercenter.auth.dao.AuthDetailMapper; +import com.senmesh.usercenter.auth.dto.AuthDetailCreateDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailQueryDTO; +import com.senmesh.usercenter.auth.entity.AuthDetail; +import com.senmesh.usercenter.auth.mapstruct.AuthDetailMapMapper; +import com.senmesh.usercenter.auth.service.AuthDetailService; + +/** + * @author sr on 2021-05-24 + */ +@Service +public class AuthDetailServiceImpl implements AuthDetailService { + + private static final String AUTH_DETAIL_LOCK_NAME = "auth:detail"; + + @Autowired + private AuthDetailMapper authDetailMapper; + + private LockDTO getAuthDetailLockDTO(String openId) { + Assert.notBlank(openId, "第三方授权信息id不能为空"); + return LockDTO.builder().methodName(AUTH_DETAIL_LOCK_NAME).tryLockWaitTime(0L) + .arg(AUTH_DETAIL_LOCK_NAME) + .build(); + } + + @Override + @Transactional + public Long create(AuthDetailCreateDTO authDetailCreateDTO) { + Integer authTypeCode = authDetailCreateDTO.getAuthTypeCode(); + String openId = authDetailCreateDTO.getOpenId(); + // TODO 暂只支持微信公众号+小程序|字节小程序 + if (AuthTypeEnum.WECHAT.getCode().equals(authTypeCode) + || AuthTypeEnum.WECHAT_LITE.getCode().equals(authTypeCode) + || AuthTypeEnum.BYTE_DANCE_LITE.getCode().equals(authTypeCode)) { + // 上锁 + LockDTO lockDTO = getAuthDetailLockDTO(openId); + try { + Assert.isTrue(RedissonUtils.tryLock(lockDTO), "该授权信息正在被操作"); + List authDetailDTOs = + authDetailMapper.listAuthDetailDTO((AuthDetailQueryDTO) AuthDetailQueryDTO.builder() + .authTypeCode(authTypeCode).openId(openId).build().disablePage()); + int num = authDetailDTOs.size(); + Assert.isTrue(num <= 1, openId + "授权信息异常,请联系管理员"); + if (num == 0) { + // 无则创建 + AuthDetail authDetail = AuthDetailMapMapper.INSTANCE.toEntity(authDetailCreateDTO); + authDetailMapper.saveEntity(authDetail); + return authDetail.getId(); + } else { + return authDetailDTOs.get(0).getId(); + } + } finally { + RedissonUtils.unlock(lockDTO); + } + } else { + throw new BusinessException("暂不支持该类型授权信息"); + } + + } + + @Override + public void remove(Long id) { + + } + + @Override + public List list(AuthDetailQueryDTO authDetailQueryDTO) { + authDetailQueryDTO.disablePage(); + return authDetailMapper.listAuthDetailDTO(authDetailQueryDTO); + } + + @Override + public void page(AuthDetailQueryDTO authDetailQueryDTO) { + authDetailMapper.listAuthDetailDTO(authDetailQueryDTO); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/AuthSubscribeDetailServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/AuthSubscribeDetailServiceImpl.java new file mode 100644 index 0000000..e3d1a11 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/AuthSubscribeDetailServiceImpl.java @@ -0,0 +1,94 @@ +package com.senmesh.usercenter.auth.service.impl; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.common.util.ListUtil; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.sdk.wechat.model.UnionDTO; +import com.senmesh.usercenter.auth.constant.AuthTypeEnum; +import com.senmesh.usercenter.auth.dao.AuthSubscribeDetailMapper; +import com.senmesh.usercenter.auth.dto.AuthClientDTO; +import com.senmesh.usercenter.auth.dto.AuthClientDataDTO; +import com.senmesh.usercenter.auth.dto.AuthClientQueryDTO; +import com.senmesh.usercenter.auth.dto.AuthSubscribeDetailCreateDTO; +import com.senmesh.usercenter.auth.dto.AuthSubscribeDetailDTO; +import com.senmesh.usercenter.auth.dto.AuthSubscribeDetailQueryDTO; +import com.senmesh.usercenter.auth.entity.AuthSubscribeDetail; +import com.senmesh.usercenter.auth.mapstruct.AuthSubscribeDetailMapMapper; +import com.senmesh.usercenter.auth.service.AuthClientService; +import com.senmesh.usercenter.auth.service.AuthSubscribeDetailService; + +/** + * @author sr on 2022-04-05 + */ +@Service +public class AuthSubscribeDetailServiceImpl implements AuthSubscribeDetailService { + + @Autowired + private AuthSubscribeDetailMapper authSubscribeDetailMapper; + + @Autowired + private AuthClientService authClientService; + + @Override + @Transactional + public void create(AuthSubscribeDetailCreateDTO createDto) { + Long authClientId = createDto.getAuthClientId(); + String openId = createDto.getOpenId(); + boolean exist = authSubscribeDetailMapper + .existsEntity(AuthSubscribeDetail.builder().authClientId(authClientId).openId(openId).build()); + if (exist) { + return; + } + authSubscribeDetailMapper.saveEntity(AuthSubscribeDetailMapMapper.INSTANCE.toEntity(createDto)); + } + + @Override + @Transactional + public void remove(Long id) { + authSubscribeDetailMapper.deleteEntity(AuthSubscribeDetail.builder().id(id).build(), + UserContextHolder.getLoginUserId()); + } + + @Override + public List list(AuthSubscribeDetailQueryDTO authSubscribeDetailQueryDTO) { + authSubscribeDetailQueryDTO.disablePage(); + return authSubscribeDetailMapper.listAuthSubscribeDetailDTO(authSubscribeDetailQueryDTO); + } + + @Override + public void page(AuthSubscribeDetailQueryDTO authSubscribeDetailQueryDTO) { + authSubscribeDetailMapper.listAuthSubscribeDetailDTO(authSubscribeDetailQueryDTO); + } + + @Override + public AuthSubscribeDetailDTO find(AuthSubscribeDetailQueryDTO authSubscribeDetailQueryDTO) { + List authSubscribeDetailDTOs = this.list(authSubscribeDetailQueryDTO); + return authSubscribeDetailDTOs.isEmpty() ? null : ListUtil.first(authSubscribeDetailDTOs); + } + + @Override + public void loadAllClient() { + List authClients = authClientService + .list(AuthClientQueryDTO.builder().authTypeCode(AuthTypeEnum.WECHAT.getCode()).build()); + if (authClients.isEmpty()) { + return ; + } + authClients.forEach(client -> { + // 获取订阅列表 + AuthClientDataDTO authClientDataDTO = authClientService.toClientData(client); + List openIds = authClientService.subscribeUser(authClientDataDTO); + List unionDtos = authClientService.batchUnion(authClientDataDTO, openIds); + unionDtos.stream().filter(d -> d.getSubscribe().equals(1)).forEach( + dto -> create(AuthSubscribeDetailCreateDTO.builder() + .authClientId(client.getId()) + .openId(dto.getOpenId()) + .uniqueId(dto.getUnionId()).build())); + }); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/AuthTypeServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/AuthTypeServiceImpl.java new file mode 100644 index 0000000..8d30ff6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/AuthTypeServiceImpl.java @@ -0,0 +1,39 @@ +package com.senmesh.usercenter.auth.service.impl; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.usercenter.auth.dao.AuthTypeMapper; +import com.senmesh.usercenter.auth.dto.AuthTypeDTO; +import com.senmesh.usercenter.auth.dto.AuthTypeOperateDTO; +import com.senmesh.usercenter.auth.dto.AuthTypeQueryDTO; +import com.senmesh.usercenter.auth.entity.AuthType; +import com.senmesh.usercenter.auth.mapstruct.AuthClientMapMapper; +import com.senmesh.usercenter.auth.service.AuthTypeService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @author sr on 2021-05-24 + */ +@Service +public class AuthTypeServiceImpl extends ServiceImpl implements AuthTypeService { + + + @Override + public Long create(AuthTypeOperateDTO operateDTO) { + AuthType authType = AuthClientMapMapper.INSTANCE.exchange(operateDTO); + Assert.isTrue(count(Wrappers.lambdaQuery() + .eq(AuthType::getDeleted,false) + .eq(AuthType::getAuthTypeCode,authType.getAuthTypeCode()) + ) == 0,"授权类型标识重复"); + save(authType); + return authType.getId(); + } + + @Override + public List list(AuthTypeQueryDTO queryDTO) { + return getBaseMapper().list(queryDTO); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/LiteCodeConfigServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/LiteCodeConfigServiceImpl.java new file mode 100644 index 0000000..a331122 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/LiteCodeConfigServiceImpl.java @@ -0,0 +1,67 @@ +package com.senmesh.usercenter.auth.service.impl; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.usercenter.auth.dao.LiteCodeConfigMapper; +import com.senmesh.usercenter.auth.service.LiteCodeConfigService; +import com.senmesh.usercenter.auth.dto.LiteCodeConfigQueryDTO; +import com.senmesh.usercenter.auth.dto.LiteCodeConfigDTO; +import com.senmesh.usercenter.auth.dto.LiteCodeConfigOperateDTO; +import com.senmesh.usercenter.auth.entity.LiteCodeConfig; + +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.ListUtil; + +/** + * @author sr on 2021-12-21 + */ +@Service +public class LiteCodeConfigServiceImpl implements LiteCodeConfigService { + + @Autowired + private LiteCodeConfigMapper liteCodeConfigMapper; + + @Override + @Transactional + public Long create(LiteCodeConfigOperateDTO liteCodeConfigOperateDTO) { + // TODO Auto-generated method stub + return null; + } + + @Override + @Transactional + public void modify(LiteCodeConfigOperateDTO liteCodeConfigOperateDTO) { + // TODO Auto-generated method stub + + } + + @Override + @Transactional + public void remove(Long id) { + liteCodeConfigMapper.deleteEntity(LiteCodeConfig.builder().id(id).build(), + UserContextHolder.getLoginUserId()); + } + + @Override + public List list(LiteCodeConfigQueryDTO liteCodeConfigQueryDTO) { + liteCodeConfigQueryDTO.disablePage(); + return liteCodeConfigMapper.listLiteCodeConfigDTO(liteCodeConfigQueryDTO); + } + + @Override + public void page(LiteCodeConfigQueryDTO liteCodeConfigQueryDTO) { + liteCodeConfigMapper.listLiteCodeConfigDTO(liteCodeConfigQueryDTO); + } + + @Override + public LiteCodeConfigDTO findOne(LiteCodeConfigQueryDTO liteCodeConfigQueryDTO) { + List liteCodeConfigDTOs = this.list(liteCodeConfigQueryDTO); + Assert.isTrue(liteCodeConfigDTOs.size() == 1, "未找到唯一匹配小程序码配置"); + return ListUtil.first(liteCodeConfigDTOs); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/LiteCodeServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/LiteCodeServiceImpl.java new file mode 100644 index 0000000..5e96034 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/LiteCodeServiceImpl.java @@ -0,0 +1,180 @@ +package com.senmesh.usercenter.auth.service.impl; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.ListUtil; +import com.senmesh.common.util.RandomUtils; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.component.file.service.FileService; +import com.senmesh.frame.redis.aop.annotation.AutoUnLock; +import com.senmesh.frame.redis.dto.LockDTO; +import com.senmesh.frame.redis.redisson.RedissonUtils; +import com.senmesh.sdk.wechat.model.JumpWxa; +import com.senmesh.sdk.wechat.model.UrlSchemeReq; +import com.senmesh.sdk.wechat.model.WxacodeReq; +import com.senmesh.usercenter.auth.constant.AuthTypeEnum; +import com.senmesh.usercenter.auth.constant.LiteCodeConstant; +import com.senmesh.usercenter.auth.dao.LiteCodeMapper; +import com.senmesh.usercenter.auth.dto.*; +import com.senmesh.usercenter.auth.entity.LiteCode; +import com.senmesh.usercenter.auth.mapstruct.LiteCodeMapMapper; +import com.senmesh.usercenter.auth.service.AuthClientService; +import com.senmesh.usercenter.auth.service.LiteCodeConfigService; +import com.senmesh.usercenter.auth.service.LiteCodeService; +import com.senmesh.usercenter.auth.util.AuthClientUtils; +import com.senmesh.usercenter.auth.util.LiteCodeUtils; +import com.senmesh.usercenter.sys.dao.DomainMapper; +import com.senmesh.usercenter.sys.dto.DomainDTO; +import com.senmesh.usercenter.sys.dto.DomainQueryDTO; +import com.senmesh.usercenter.sys.util.DomainUtils; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +/** + * @author sr on 2021-12-21 + */ +@Service +public class LiteCodeServiceImpl implements LiteCodeService { + + /** 小程序码文件名称 **/ + public static final String CODE_FILE_NAME = "wxacode.png"; + private static final String LOCK_NAME = "lite:code"; + + @Autowired + private LiteCodeMapper liteCodeMapper; + + @Autowired + private AuthClientService authClientService; + + @Autowired + private LiteCodeConfigService liteCodeConfigService; + + @Autowired + private FileService fileService; + + @Autowired + private DomainMapper domainMapper; + + public static LockDTO getLockDTO(Long liteCodeConfigId, String name, String paramValue, Long userId, + Long orgId) { + Assert.isTrue(liteCodeConfigId != null && StringUtils.isNotBlank(name), "小程序码配置不能为空"); + return LockDTO.builder().methodName(LOCK_NAME).tryLockWaitTime(0L) + .arg(liteCodeConfigId.toString()) + .arg(name) + .arg(paramValue) + .arg(Optional.ofNullable(userId).orElse(0L).toString()) + .arg(Optional.ofNullable(orgId).orElse(0L).toString()) + .build(); + } + + + @Override + @Transactional + @AutoUnLock + public LiteCodeDTO create(LiteCodeCreateDTO liteCodeCreateDTO) { + String domainOrIp = DomainUtils.getOrDefault(liteCodeCreateDTO.getDomainOrIp()); + + //只有PC端的才需要这个校验 + if (Objects.nonNull(liteCodeCreateDTO.getSourceFrom()) + && LiteCodeConstant.SOURCE_FROM_PC.equals(liteCodeCreateDTO.getSourceFrom())){ + List domainDTOS = domainMapper.listDomainDTO(DomainQueryDTO.builder() + .orgId(UserContextHolder.getExistLoginOrgId()) + .domainOrIp(domainOrIp) + .build()); + Assert.isTrue(CollectionUtils.size(domainDTOS) == 1,"当前域名无法生成邀请二维码,请登录机构绑定域名操作"); + } + + Integer authTypeCode = liteCodeCreateDTO.getAuthTypeCode(); + Assert.isTrue(AuthTypeEnum.WECHAT_LITE.getCode().equals(authTypeCode), "暂只处理微信小程序码"); + AuthClientDataDTO authClientDataDTO = authClientService + .findClientData(AuthClientQueryDTO.builder().domainOrIp(domainOrIp) + .authTypeCode(authTypeCode).build()); + // 查询小程序码配置 + LiteCodeConfigDTO liteCodeConfigDTO = liteCodeConfigService.findOne( + LiteCodeConfigQueryDTO.builder().authClientId(authClientDataDTO.getAuthClientId()) + .bizType(liteCodeCreateDTO.getBizType()).build()); + Long liteCodeConfigId = liteCodeConfigDTO.getId(); + Map paramData = liteCodeCreateDTO.getParamData(); + String paramValue = LiteCodeUtils.buildParamValue(liteCodeConfigDTO, paramData); + + Long userId = MapUtils.getLong(paramData, LiteCodeUtils.USER_ID_KEY); + Long orgId = MapUtils.getLong(paramData, LiteCodeUtils.ORG_ID_KEY); + String name = liteCodeCreateDTO.getName(); + LiteCodeQueryDTO liteCodeQueryDTO = + LiteCodeQueryDTO.builder().liteCodeConfigId(liteCodeConfigId).name(name) + .paramValue(paramValue).userId(userId).orgId(orgId).build(); + LiteCodeDTO liteCodeDTO = find(liteCodeQueryDTO); + if (liteCodeDTO != null) { + return liteCodeDTO; + } + // 上锁 + LockDTO lockDTO = getLockDTO(liteCodeConfigId, name, paramValue, userId, orgId); + Assert.isTrue(RedissonUtils.tryLockAutomatically(lockDTO), "小程序码正在被生成"); + liteCodeDTO = find(liteCodeQueryDTO); + if (liteCodeDTO != null) { + return liteCodeDTO; + } + LiteCode liteCode = LiteCode.builder().liteCodeConfigId(liteCodeConfigId) + .uniqueCode(RandomUtils.generateUUID()).paramValue(paramValue).name(name) + .userId(userId) + .orgId(orgId) + .platformCode(liteCodeConfigDTO.getPlatformCode()) + .build(); + liteCodeMapper.saveEntity(liteCode); + Long liteCodeId = liteCode.getId(); + String queryValue = LiteCodeUtils.buildQueryValue(liteCodeId, liteCodeConfigDTO, paramData); + + String fileCode = null; + String path = liteCodeConfigDTO.getPath(); + // 小程序码 + WxacodeReq wxacodeRequestParam = WxacodeReq.builder() + .path(path + CommonConstants.QUESTION + queryValue).build(); + fileCode = fileService + .upload(CODE_FILE_NAME, + AuthClientUtils.getService().getWxacode(authClientDataDTO, wxacodeRequestParam)) + .getFileCode(); + // 小程序scheme码 + UrlSchemeReq urlSchemeRequestParam = + UrlSchemeReq.builder() + .jumpWxa( + JumpWxa.builder().path(path).query(queryValue) + .envVersion(LiteCodeUtils.getEnvVersion()).build()) + .build(); + String urlScheme = AuthClientUtils.getService().getUrlscheme(authClientDataDTO, urlSchemeRequestParam); + liteCode.setQueryValue(queryValue); + liteCode.setFileCode(fileCode); + liteCode.setUrlScheme(urlScheme); + liteCodeMapper.updateEntity(liteCode); + return LiteCodeMapMapper.INSTANCE.toDto(liteCode); + } + + @Override + public List list(LiteCodeQueryDTO liteCodeQueryDTO) { + liteCodeQueryDTO.disablePage(); + return liteCodeMapper.listLiteCodeDTO(liteCodeQueryDTO); + } + + @Override + public void page(LiteCodeQueryDTO liteCodeQueryDTO) { + liteCodeMapper.listLiteCodeDTO(liteCodeQueryDTO); + } + + @Override + public LiteCodeDTO find(LiteCodeQueryDTO liteCodeQueryDTO) { + List liteCodeDTOs = this.list(liteCodeQueryDTO); + return liteCodeDTOs.isEmpty() ? null : ListUtil.first(liteCodeDTOs); + } + + @Override + public LiteCodeDTO modify(LiteCodeModifyDTO liteCodeModifyDTO) { + liteCodeMapper.updateEntitySelective( + LiteCode.builder().id(liteCodeModifyDTO.getId()).name(liteCodeModifyDTO.getName()).build()); + return this.find(LiteCodeQueryDTO.builder().id(liteCodeModifyDTO.getId()).build()); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/LitePhoneLoginProvider.java b/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/LitePhoneLoginProvider.java new file mode 100644 index 0000000..26fbd05 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/service/impl/LitePhoneLoginProvider.java @@ -0,0 +1,122 @@ +package com.senmesh.usercenter.auth.service.impl; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.senmesh.common.dto.CasTokenDTO; +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.exception.WithResultException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.sdk.common.dto.LiteUserPhoneDTO; +import com.senmesh.sdk.common.util.LiteEncryptor; +import com.senmesh.security.expection.BadLoginException; +import com.senmesh.security.jwt.JwtTokenUtils; +import com.senmesh.security.mapstruct.UserMapMapper; +import com.senmesh.usercenter.auth.constant.AuthTypeEnum; +import com.senmesh.usercenter.auth.dto.AuthClientDataDTO; +import com.senmesh.usercenter.auth.dto.AuthClientQueryDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailBindDTO; +import com.senmesh.usercenter.auth.dto.CodeToSessionDTO; +import com.senmesh.usercenter.auth.dto.LitePhoneLoginDTO; +import com.senmesh.usercenter.auth.mapstruct.AuthDetailMapMapper; +import com.senmesh.usercenter.auth.service.AuthClientService; +import com.senmesh.usercenter.sys.util.DomainUtils; +import com.senmesh.usercenter.user.login.dto.LoginPhoneDTO; +import com.senmesh.usercenter.user.login.dto.UserDetailDTO; +import com.senmesh.usercenter.user.login.service.UserLoginService; +import com.senmesh.usercenter.user.service.UserService; + +import lombok.extern.slf4j.Slf4j; + + +/** + * 小程序登录提供者 + * @author sr on 2022-01-04 + */ +@Service +@Slf4j +public class LitePhoneLoginProvider { + + @Autowired + private AuthClientService authClientService; + + @Autowired + private UserLoginService userLoginService; + + @Autowired + private UserService userService; + + public CasTokenDTO loginLite(LitePhoneLoginDTO litePhoneLoginDTO) { + Assert.notNull(litePhoneLoginDTO.getAuthTypeCode(), "授权类型不能为空"); + AuthDetailBindDTO authDetailBindDTO = this.toAuthDetailDTO(litePhoneLoginDTO); + LoginPhoneDTO loginPhoneDTO = AuthDetailMapMapper.INSTANCE.to(litePhoneLoginDTO); + try { + UserDetailDTO userDetailDTO = userLoginService.loadUser(loginPhoneDTO); + String token = JwtTokenUtils.generateToken(UserMapMapper.INSTANCE.dtoToDto(userDetailDTO)); + // 指定用户id + authDetailBindDTO.setUserId(userDetailDTO.getId()); + if (StringUtils.isBlank(authDetailBindDTO.getUniqueId())) { + log.debug(authDetailBindDTO.getAuthClientId() + "-小程序未挂载开放平台"); + // RobotUtils.sendDevops(authDetailBindDTO.getAuthClientId() + "-小程序未挂载开放平台"); + } else { + try { + userService.bindUserAuth(authDetailBindDTO); + } catch (Exception e) { + // 现在都没看,也就没必要发了 + /*RobotUtils.sendDevops("微信小程序登录绑定授权信息失败:authClientId=" + authDetailBindDTO.getAuthClientId() + + ",unionId=" + authDetailBindDTO.getUniqueId() + + ",openId=" + authDetailBindDTO.getOpenId());*/ + log.info("auth login bind error:{},clientId:{},openId:{},unionId:{}", e.getMessage(), + authDetailBindDTO.getAuthClientId(), authDetailBindDTO.getOpenId(), + authDetailBindDTO.getUniqueId()); + } + } + return CasTokenDTO.builder().token(token).register(userDetailDTO.getRegister()).build(); + } catch (BadLoginException be) { + throw new WithResultException(be.getResult(), be); + } catch (BusinessException be) { + throw be; + } catch (Exception e) { + throw new BusinessException(e.getMessage(), e); + } + } + + /** + * 获取授权绑定对象 + * 手机号,openId,unionId等 + * @param litePhoneLoginDTO + * @return + * @author sr on 2022-03-15 + */ + private AuthDetailBindDTO toAuthDetailDTO(LitePhoneLoginDTO litePhoneLoginDTO) { + Integer authTypeCode = litePhoneLoginDTO.getAuthTypeCode(); + AuthClientDataDTO authClientDataDTO = authClientService + .findClientData(AuthClientQueryDTO.builder() + .domainOrIp(DomainUtils.getOrDefault(litePhoneLoginDTO.getDomainOrIp())) + .authTypeCode(authTypeCode).build()); + CodeToSessionDTO codeToSessionDTO = + authClientService.getCodeToSessionDTO(authClientDataDTO, litePhoneLoginDTO.getCode()); + String phoneCode = litePhoneLoginDTO.getPhoneCode(); + String phone = null; + if (AuthTypeEnum.WECHAT_LITE.getCode().equals(authTypeCode) + && StringUtils.isNotBlank(phoneCode)) { + phone = authClientService.getPhone(authClientDataDTO, phoneCode); + } else { + Assert.isTrue( + StringUtils.isNotBlank(litePhoneLoginDTO.getEncryptedData()) && StringUtils.isNotBlank( + litePhoneLoginDTO.getIv()), "加密数据不能为空"); + LiteUserPhoneDTO liteUserPhoneDTO = LiteEncryptor.decrypt(litePhoneLoginDTO.getEncryptedData(), + litePhoneLoginDTO.getIv(), codeToSessionDTO.getSessionKey(), LiteUserPhoneDTO.class); + phone = liteUserPhoneDTO.getPhoneNumber(); + } + + litePhoneLoginDTO.setPhone(phone); + return AuthDetailBindDTO.builder().authClientId(authClientDataDTO.getAuthClientId()) + .userType(litePhoneLoginDTO.getUserType()) + .authTypeCode(authTypeCode) + .openId(codeToSessionDTO.getOpenId()) + .uniqueId(codeToSessionDTO.getUnionId()).build(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/util/AuthClientUtils.java b/backend/src/main/java/com/senmesh/usercenter/auth/util/AuthClientUtils.java new file mode 100644 index 0000000..7322339 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/util/AuthClientUtils.java @@ -0,0 +1,56 @@ +package com.senmesh.usercenter.auth.util; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.usercenter.auth.service.AuthClientService; + +/** + * @author sr on 2021-01-15 + */ +@Component +public class AuthClientUtils { + + public static final String REDIS_KEY_WX_ACCESS_TOKEN_PREFIX = "uc:auth:accesstoken:"; + public static final String REDIS_KEY_WX_JSAPI_TICKET_PREFIX = "uc:auth:jsapiticket:"; + + private static AuthClientService authClientService; + + /** redis key默认过期时间 **/ + public static final Long DEFAULT_EXPIRE_TIME = 6000L; + + @Autowired + public void setWechatUtils(AuthClientService authClientService) { + AuthClientUtils.authClientService = authClientService; + } + + /** + * 获取缓存accesstoken的键 + * + * @param authClientId + * @return + * @author sr on 2021-01-15 + */ + public static String getRedisAccessTokenKey(Long authClientId) { + return REDIS_KEY_WX_ACCESS_TOKEN_PREFIX + authClientId; + } + + /** + * 获取缓存jsapiticket的键 + * + * @param authClientId + * @return + * @author sr on 2021-01-15 + */ + public static String getRedisJsApiTicketKey(Long authClientId) { + return REDIS_KEY_WX_JSAPI_TICKET_PREFIX + authClientId; + } + + public static AuthClientService getService() { + Assert.notNull(authClientService, "无法获取acessToken,请检查配置"); + return authClientService; + } + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/util/AuthDetailUtils.java b/backend/src/main/java/com/senmesh/usercenter/auth/util/AuthDetailUtils.java new file mode 100644 index 0000000..e8d2fe0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/util/AuthDetailUtils.java @@ -0,0 +1,8 @@ +package com.senmesh.usercenter.auth.util; + +/** + * @author sr on 2021-05-24 + */ +public class AuthDetailUtils { + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/util/LiteCodeUtils.java b/backend/src/main/java/com/senmesh/usercenter/auth/util/LiteCodeUtils.java new file mode 100644 index 0000000..b472dec --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/util/LiteCodeUtils.java @@ -0,0 +1,151 @@ +package com.senmesh.usercenter.auth.util; + +import java.util.Arrays; +import java.util.Map; + +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.constant.ProjectProfileEnum; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.common.util.SpringContextHolder; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.auth.dto.LiteCodeConfigDTO; +import com.senmesh.usercenter.dto.IUserDetail; +import com.senmesh.usercenter.user.constant.UserTypeEnum; +import com.senmesh.usercenter.user.dto.UserRegisterCodeInfoDTO; +import com.senmesh.usercenter.user.service.UserRegisterService; + +/** + * @author sr on 2021-12-21 + */ +public class LiteCodeUtils { + + /** 内置环境参数键:注册码 **/ + public static final String REGISTER_CODE_KEY = "registerCode"; + + public static final String USER_ID_KEY = "userId"; + public static final String USER_TYPE_KEY = "userType"; + public static final String ORG_ID_KEY = "orgId"; + public static final String PLATFORM_CODE_KEY = "platformCode"; + + private static UserRegisterService userRegisterService; + + /** + * 构建参数值(按参数键升序排列)(格式:**&**) + * @param paramData + * @return + * @author sr on 2021-12-21 + */ + public static String buildParamValue(LiteCodeConfigDTO liteCodeConfigDTO, Map paramData) { + String paramKey = liteCodeConfigDTO.getParamKey(); + dealEnv(liteCodeConfigDTO, paramData); + if (StringUtils.isBlank(paramKey)) { + return null; + } + String[] paramKeyArray = paramKey.split(CommonConstants.AND); + // 排序 + Arrays.sort(paramKeyArray); + StringBuilder paramstr = new StringBuilder(); + for (String key : paramKeyArray) { + Object paramValue = paramData.get(key); + Assert.notNull(paramValue, "获取小程序码参数不全"); + paramstr.append(key).append(CommonConstants.EQUAL).append(paramValue.toString()) + .append(CommonConstants.AND); + } + return paramstr.toString(); + } + + public static UserRegisterService getUserRegisterService() { + if (userRegisterService == null) { + userRegisterService = SpringContextHolder.getBean(UserRegisterService.class); + } + return userRegisterService; + } + + public static void dealEnv(LiteCodeConfigDTO liteCodeConfigDTO, + Map paramData) { + String envParamKey = liteCodeConfigDTO.getEnvParamKey(); + if (StringUtils.isBlank(envParamKey)) { + return ; + } + String[] envParamKeyArray = envParamKey.split(CommonConstants.AND); + for (String envKey : envParamKeyArray) { + if (REGISTER_CODE_KEY.equals(envKey)) { + Long userId = MapUtils.getLong(paramData, USER_ID_KEY); + Long orgId = MapUtils.getLong(paramData, ORG_ID_KEY); + paramData.put(PLATFORM_CODE_KEY, liteCodeConfigDTO.getPlatformCode()); + if (userId != null) { + if (orgId != null) { + paramData.put(USER_TYPE_KEY, UserTypeEnum.ORG.getType()); + } else { + paramData.put(USER_TYPE_KEY, UserTypeEnum.PERSON.getType()); + } + } else { + IUserDetail userDetail = UserContextHolder.getExistLoginUser(); + paramData.put(USER_ID_KEY, userDetail.getId()); + paramData.put(USER_TYPE_KEY, userDetail.getType()); + paramData.put(ORG_ID_KEY, userDetail.getOrgId()); + } + } + } + } + + /** + * 组装query值 + * @param paramKey + * @param envParamKey + * @param paramData + * @return + * @author sr on 2021-12-22 + */ + public static String buildQueryValue(Long liteCodeId, LiteCodeConfigDTO liteCodeConfigDTO, + Map paramData) { + String paramKey = liteCodeConfigDTO.getParamKey(); + String envParamKey = liteCodeConfigDTO.getEnvParamKey(); + StringBuilder paramBuilder = new StringBuilder(); + if (StringUtils.isNotBlank(paramKey)) { + String[] paramKeyArray = paramKey.split(CommonConstants.AND); + for (String key : paramKeyArray) { + paramBuilder.append(key).append(CommonConstants.EQUAL) + .append(MapUtils.getString(paramData, key)).append(CommonConstants.AND); + } + } + if (StringUtils.isBlank(envParamKey)) { + return paramBuilder.toString(); + } + String[] envParamKeyArray = envParamKey.split(CommonConstants.AND); + for (String envKey : envParamKeyArray) { + if (REGISTER_CODE_KEY.equals(envKey)) { + Integer inviterType = MapUtils.getInteger(paramData, USER_TYPE_KEY); + Long inviterId = MapUtils.getLong(paramData, USER_ID_KEY); + Long inviterOrgId = MapUtils.getLong(paramData, ORG_ID_KEY); + Integer platformCode = MapUtils.getInteger(paramData, PLATFORM_CODE_KEY); + String registerCode = getUserRegisterService() + .getCode(UserRegisterCodeInfoDTO.builder().inviterId(inviterId).inviterType(inviterType) + .inviterOrgId(inviterOrgId).platformCode(platformCode).unionId(liteCodeId).build()); + paramBuilder.append(envKey).append(CommonConstants.EQUAL) + .append(registerCode).append(CommonConstants.AND); + } + } + int length = paramBuilder.length(); + return length > 0 ? paramBuilder.substring(0, length - 1) : null; + } + + + /** + * 获取小程序版本 + * @return + * @author sr on 2021-12-22 + */ + public static String getEnvVersion() { + String profile = EnvironmentUtils.getProfile(); + if (ProjectProfileEnum.UAT.getValue().equals(profile)) { + return "trial"; + } + return "release"; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/wechat/controller/UcWechatController.java b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/controller/UcWechatController.java new file mode 100644 index 0000000..b61c288 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/controller/UcWechatController.java @@ -0,0 +1,58 @@ +package com.senmesh.usercenter.auth.wechat.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.dto.CasTokenDTO; +import com.senmesh.usercenter.auth.service.AuthClientService; +import com.senmesh.usercenter.auth.wechat.dto.WechatLiteLoginDTO; +import com.senmesh.usercenter.auth.wechat.dto.WechatLiteSubMsgDTO; +import com.senmesh.usercenter.auth.wechat.dto.WechatSignatureReqDTO; +import com.senmesh.usercenter.auth.wechat.dto.WechatSignatureResDTO; +import com.senmesh.usercenter.auth.wechat.service.WechatService; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +//@RestController +@Api(tags = "微信操作") +public class UcWechatController { + + @Autowired + private WechatService wechatService; + + @Autowired + private AuthClientService authClientService; + + @ApiOperation("获取signature") + @PostMapping("anon/wechat/signature") + public AlitaResult signature(@Validated @RequestBody WechatSignatureReqDTO wechatSignatureDTO){ + return AlitaResult.success(authClientService.signature(wechatSignatureDTO)); + } + + @ApiOperation("小程序登录(授权信息)") + @PostMapping("anon/wechat/login_lite") + public AlitaResult loginLite(@Validated @RequestBody WechatLiteLoginDTO wechatLiteLoginDTO) { + return AlitaResult.success(wechatService.loginLite(wechatLiteLoginDTO)); + } + + @ApiOperation("绑定小程序") + @PostMapping("unac/wechat/bind_lite") + public AlitaResult bindLite(@Validated @RequestBody WechatLiteLoginDTO wechatLiteLoginDTO) { + wechatService.bindLite(wechatLiteLoginDTO); + return AlitaResult.success(); + } + + @ApiOperation("发送小程序订阅消息") + @PostMapping("wechat/send_lite_sub_msg") + public AlitaResult sendLiteSubMsg(@Validated @RequestBody WechatLiteSubMsgDTO wechatLiteSubMsgDTO) { + wechatService.sendLiteSubMsg(wechatLiteSubMsgDTO); + return AlitaResult.success(); + } + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/BaseWeChatDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/BaseWeChatDTO.java new file mode 100644 index 0000000..c7b1503 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/BaseWeChatDTO.java @@ -0,0 +1,23 @@ +package com.senmesh.usercenter.auth.wechat.dto; + +import lombok.Data; + +import java.io.Serializable; + +/** + * @author leijiaping + */ +@Data +public class BaseWeChatDTO implements Serializable { + + /** + * 错误编码 + */ + private String errcode; + + /** + * 错误信息 + */ + private String errmsg; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/WechatAuthUserInfoDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/WechatAuthUserInfoDTO.java new file mode 100644 index 0000000..ce3d4a9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/WechatAuthUserInfoDTO.java @@ -0,0 +1,71 @@ +package com.senmesh.usercenter.auth.wechat.dto; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-05-12 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +public class WechatAuthUserInfoDTO extends BaseWeChatDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 2022092915168090246L; + + /** + * 用户的唯一标识 + */ + @JsonProperty("openid") + private String openId; + + /** + * 用户昵称 + */ + private String nickname; + + /** + * 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知 + */ + private Integer sex; + + /** + * 用户个人资料填写的省份 + */ + private String province; + + /** + * 普通用户个人资料填写的城市 + */ + private String city; + + /** + * 国家,如中国为CN + */ + private String country; + + /** + * 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。 + */ + private String headimgurl; + + /** + * 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段 + */ + private String unionid; + + private String encryptedData; + + private String iv; + + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/WechatLiteAccessTokenDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/WechatLiteAccessTokenDTO.java new file mode 100644 index 0000000..4538a18 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/WechatLiteAccessTokenDTO.java @@ -0,0 +1,31 @@ +package com.senmesh.usercenter.auth.wechat.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * @author leijiaping + */ +@EqualsAndHashCode(callSuper = true) +@Data +@AllArgsConstructor +@NoArgsConstructor +public class WechatLiteAccessTokenDTO extends BaseWeChatDTO implements Serializable { + + /** + * 授权用户唯一标识 + */ + private String openid; + + /** + * 当且仅当该网站应用已获得该用户的userinfo授权时,才会出现该字段 + */ + private String unionid; + + + private String session_key; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/WechatLiteCodeReqDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/WechatLiteCodeReqDTO.java new file mode 100644 index 0000000..d8f4c84 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/WechatLiteCodeReqDTO.java @@ -0,0 +1,31 @@ +package com.senmesh.usercenter.auth.wechat.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class WechatLiteCodeReqDTO implements Serializable{ + + @ApiModelProperty("请求域名或ip") + @NotBlank(message = "请求域名或ip不能为空") + private String domainOrIp; + @ApiModelProperty("唯一标识") + @NotBlank(message = "唯一标识") + private String uniqueCode; + @ApiModelProperty("小程序路径") + @NotBlank(message = "小程序路径不能为空") + private String path; + @ApiModelProperty("小程序路径参数") +// @NotBlank(message = "小程序路径参数不能为空") + private String query; + @ApiModelProperty("码类型:1小程序码,2.urlscheme") + private Integer type; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/WechatLiteLoginDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/WechatLiteLoginDTO.java new file mode 100644 index 0000000..f02cadd --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/WechatLiteLoginDTO.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.auth.wechat.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-05-12 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(description = "小程序登录") +public class WechatLiteLoginDTO extends WechatAuthUserInfoDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 2022092915168090246L; + @ApiModelProperty("小程序授权码") + @NotBlank(message = "小程序授权码不能为空") + private String code; + @ApiModelProperty("用户类型") + @NotNull(message = "用户类型不能为空") + private Integer userType; + @ApiModelProperty("请求域名或ip") + private String domainOrIp; + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/WechatLiteSubMsgDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/WechatLiteSubMsgDTO.java new file mode 100644 index 0000000..d45e49d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/WechatLiteSubMsgDTO.java @@ -0,0 +1,43 @@ +package com.senmesh.usercenter.auth.wechat.dto; + +import java.io.Serializable; +import java.util.Map; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import com.google.common.collect.Maps; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2022-01-04 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(description = "小程序消息") +@Builder +public class WechatLiteSubMsgDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 2022092915168090246L; + @ApiModelProperty("请求域名或ip") + private String domainOrIp; + @ApiModelProperty("用户id") + @NotNull(message = "用户id不能为空") + private Long userId; + @ApiModelProperty("微信订阅消息模版id") + @NotBlank(message = "微信订阅消息模版id不能为空") + private String templateId; + @ApiModelProperty("消息参数") + private Map paramData = Maps.newHashMap(); + @ApiModelProperty("点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar") + private String page; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/WechatSignatureReqDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/WechatSignatureReqDTO.java new file mode 100644 index 0000000..1972095 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/WechatSignatureReqDTO.java @@ -0,0 +1,26 @@ +package com.senmesh.usercenter.auth.wechat.dto; + +import javax.validation.constraints.NotBlank; + +import com.senmesh.usercenter.auth.dto.AuthClientQueryDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(description = "微信签名链接") +public class WechatSignatureReqDTO extends AuthClientQueryDTO{ + + /** **/ + private static final long serialVersionUID = -1042268580628180555L; + + @ApiModelProperty("链接") + @NotBlank(message = "链接不能为空") + private String url; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/WechatSignatureResDTO.java b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/WechatSignatureResDTO.java new file mode 100644 index 0000000..51a5f95 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/dto/WechatSignatureResDTO.java @@ -0,0 +1,26 @@ +package com.senmesh.usercenter.auth.wechat.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "微信签名链接返回") +public class WechatSignatureResDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = -1042268580628180555L; + + private String nonceStr; + private String timestamp; + private String signature; + private String appId; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/wechat/mapstruct/WechatMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/mapstruct/WechatMapMapper.java new file mode 100644 index 0000000..bd321f7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/mapstruct/WechatMapMapper.java @@ -0,0 +1,39 @@ +package com.senmesh.usercenter.auth.wechat.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.auth.dto.AuthDetailBindDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailLoginDTO; +import com.senmesh.usercenter.auth.wechat.dto.WechatLiteLoginDTO; +import com.senmesh.usercenter.user.login.dto.LoginPhoneDTO; + +/** + * @author sr on 2021-11-23 + */ +@Mapper +public interface WechatMapMapper { + + WechatMapMapper INSTANCE = + Mappers.getMapper(WechatMapMapper.class); + + @Mapping(target = "withoutCode", constant = "true") + LoginPhoneDTO toDto(AuthDetailLoginDTO authDetailLoginDTO); + + @Mappings(value = { + @Mapping(target = "avatar", source = "headimgurl"), + @Mapping(target = "gender", source = "sex"), + @Mapping(target = "uniqueId", source = "unionid"), + }) + AuthDetailLoginDTO toLoginDto(WechatLiteLoginDTO wechatLiteLoginDTO); + + @Mappings(value = { + @Mapping(target = "avatar", source = "headimgurl"), + @Mapping(target = "gender", source = "sex"), + @Mapping(target = "uniqueId", source = "unionid"), + }) + AuthDetailBindDTO toBindDto(WechatLiteLoginDTO wechatLiteLoginDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/wechat/service/WechatService.java b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/service/WechatService.java new file mode 100644 index 0000000..ae00eec --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/service/WechatService.java @@ -0,0 +1,34 @@ +package com.senmesh.usercenter.auth.wechat.service; + +import com.senmesh.common.dto.CasTokenDTO; +import com.senmesh.usercenter.auth.wechat.dto.WechatLiteLoginDTO; +import com.senmesh.usercenter.auth.wechat.dto.WechatLiteSubMsgDTO; + +/** + * @author sr on 2021-01-15 + */ +public interface WechatService { + + /** + * 小程序登录 + * @param wechatLiteLoginDTO + * @return + * @author sr on 2021-07-09 + */ + CasTokenDTO loginLite(WechatLiteLoginDTO wechatLiteLoginDTO); + + /** + * 绑定微信小程序 + * @param wechatLiteLoginDTO + * @author sr on 2021-08-23 + */ + void bindLite(WechatLiteLoginDTO wechatLiteLoginDTO); + + /** + * 小程序订阅消息 + * @param wechatLiteSubMsgDTO + * @author sr on 2022-01-04 + */ + void sendLiteSubMsg(WechatLiteSubMsgDTO wechatLiteSubMsgDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/auth/wechat/service/impl/WechatServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/service/impl/WechatServiceImpl.java new file mode 100644 index 0000000..8188da4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/auth/wechat/service/impl/WechatServiceImpl.java @@ -0,0 +1,118 @@ +package com.senmesh.usercenter.auth.wechat.service.impl; + +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.senmesh.common.dto.CasTokenDTO; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.ListUtil; +import com.senmesh.sdk.wechat.model.SubscibeMessageReq; +import com.senmesh.sdk.wechat.util.MessageParamUtils; +import com.senmesh.security.expection.BadLoginException; +import com.senmesh.security.jwt.JwtTokenUtils; +import com.senmesh.security.mapstruct.UserMapMapper; +import com.senmesh.usercenter.auth.constant.AuthTypeEnum; +import com.senmesh.usercenter.auth.dto.AuthClientDataDTO; +import com.senmesh.usercenter.auth.dto.AuthClientQueryDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailBindDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailCreateDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailLoginDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailQueryDTO; +import com.senmesh.usercenter.auth.dto.CodeToSessionDTO; +import com.senmesh.usercenter.auth.service.AuthClientService; +import com.senmesh.usercenter.auth.service.AuthDetailService; +import com.senmesh.usercenter.auth.util.AuthClientUtils; +import com.senmesh.usercenter.auth.util.LiteCodeUtils; +import com.senmesh.usercenter.auth.wechat.dto.WechatLiteLoginDTO; +import com.senmesh.usercenter.auth.wechat.dto.WechatLiteSubMsgDTO; +import com.senmesh.usercenter.auth.wechat.mapstruct.WechatMapMapper; +import com.senmesh.usercenter.auth.wechat.service.WechatService; +import com.senmesh.usercenter.sys.util.DomainUtils; +import com.senmesh.usercenter.user.login.dto.UserDetailDTO; +import com.senmesh.usercenter.user.login.service.UserLoginService; +import com.senmesh.usercenter.user.service.UserService; + +import lombok.extern.slf4j.Slf4j; + +@Service +@Slf4j +public class WechatServiceImpl implements WechatService { + + @Autowired + private AuthClientService authClientService; + + @Autowired + private UserLoginService userLoginService; + + @Autowired + private UserService userService; + + @Autowired + private AuthDetailService authDetailService; + + @Override + public CasTokenDTO loginLite(WechatLiteLoginDTO wechatLiteLoginDTO) { + try { + AuthDetailLoginDTO authDetailLoginDTO = WechatMapMapper.INSTANCE.toLoginDto(wechatLiteLoginDTO); + analyCode(wechatLiteLoginDTO, authDetailLoginDTO); + UserDetailDTO userDetailDTO = userLoginService.findUserDetailDTO(authDetailLoginDTO); + String token = JwtTokenUtils.generateToken(UserMapMapper.INSTANCE.dtoToDto(userDetailDTO)); + return CasTokenDTO.builder().token(token).register(userDetailDTO.getRegister()).build(); + } catch (BadLoginException be) { + log.info("silence login:{}", be.getMessage()); + } catch (Exception e) { + log.info("silence login:{}", e.getMessage()); + } + return new CasTokenDTO(); + } + + private void analyCode(WechatLiteLoginDTO wechatLiteLoginDTO, AuthDetailCreateDTO authDetailCreateDTO) { + AuthClientDataDTO authClientDataDTO = authClientService + .findClientData(AuthClientQueryDTO.builder() + .domainOrIp(DomainUtils.getOrDefault(wechatLiteLoginDTO.getDomainOrIp())) + .authTypeCode(AuthTypeEnum.WECHAT_LITE.getCode()).build()); + CodeToSessionDTO codeToSessionDTO = + authClientService.getCodeToSessionDTO(authClientDataDTO, wechatLiteLoginDTO.getCode()); + authDetailCreateDTO.setUniqueId(codeToSessionDTO.getUnionId()); + authDetailCreateDTO.setOpenId(codeToSessionDTO.getOpenId()); + authDetailCreateDTO.setAuthClientId(authClientDataDTO.getAuthClientId()); + authDetailCreateDTO.setAuthTypeCode(AuthTypeEnum.WECHAT_LITE.getCode()); + log.debug("code2SessionDTO:{},", codeToSessionDTO); + } + + @Override + public void bindLite(WechatLiteLoginDTO wechatLiteLoginDTO) { + AuthDetailBindDTO authDetailBindDTO = WechatMapMapper.INSTANCE.toBindDto(wechatLiteLoginDTO); + analyCode(wechatLiteLoginDTO, authDetailBindDTO); + Assert.isTrue(StringUtils.isNotBlank(authDetailBindDTO.getUniqueId()), + //new DevopsException(authDetailBindDTO.getAuthClientId() + "-小程序未挂载开放平台") + authDetailBindDTO.getAuthClientId() + "-小程序未挂载开放平台" + ); + userService.bindUserAuth(authDetailBindDTO); + } + + @Override + public void sendLiteSubMsg(WechatLiteSubMsgDTO wechatLiteMsgDTO) { + String domainOrIp = DomainUtils.getOrDefault(wechatLiteMsgDTO.getDomainOrIp()); + AuthClientDataDTO authClientDataDTO = authClientService + .findClientData(AuthClientQueryDTO.builder().domainOrIp(domainOrIp) + .authTypeCode(AuthTypeEnum.WECHAT_LITE.getCode()).build()); + List authDetails = authDetailService + .list(AuthDetailQueryDTO.builder().authClientId(authClientDataDTO.getAuthClientId()) + .userId(wechatLiteMsgDTO.getUserId()).build()); + Assert.isTrue(authDetails.size() == 1, "未找到唯一匹配的用户授权信息"); + SubscibeMessageReq subscibeMessageReq = SubscibeMessageReq.builder() + .touser(ListUtil.first(authDetails).getOpenId()) + .templateId(wechatLiteMsgDTO.getTemplateId()) + .data(MessageParamUtils.dealData(wechatLiteMsgDTO.getParamData())) + .page(wechatLiteMsgDTO.getPage()) + .miniprogramState(LiteCodeUtils.getEnvVersion()) + .build(); + AuthClientUtils.getService().subscibeMessage(authClientDataDTO, subscibeMessageReq); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/constants/PermissionConstants.java b/backend/src/main/java/com/senmesh/usercenter/authority/constants/PermissionConstants.java new file mode 100644 index 0000000..3e83420 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/constants/PermissionConstants.java @@ -0,0 +1,16 @@ +package com.senmesh.usercenter.authority.constants; + +/** + * 角色权限常量类 + * @author sr on 2019-10-16 + */ +public class PermissionConstants { + + /** 资源类型: 菜单**/ + public static final String RESOURCE_TYPE_URL = "1"; + /** 资源类型: 组件 **/ + public static final String RESOURCE_TYPE_COMPONENT = "2"; + /** 资源类型: 接口 **/ + public static final String RESOURCE_TYPE_INTERFACE = "3"; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/controller/UcPermissionController.java b/backend/src/main/java/com/senmesh/usercenter/authority/controller/UcPermissionController.java new file mode 100644 index 0000000..0b4e85a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/controller/UcPermissionController.java @@ -0,0 +1,33 @@ +package com.senmesh.usercenter.authority.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.senmesh.common.AlitaResult; +import com.senmesh.usercenter.authority.dto.PermissionQueryDTO; +import com.senmesh.usercenter.authority.dto.UrlPermissionDTO; +import com.senmesh.usercenter.authority.service.UcPermissionService; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +@Api(tags = "角色权限操作") +@RestController +@RequestMapping("/permission") +public class UcPermissionController { + + @Autowired + private UcPermissionService ucPermissionService; + + @ApiOperation("查询角色权限分配菜单接口") + @GetMapping("/list_url") + public AlitaResult> listUrl(PermissionQueryDTO permissionQueryDTO) { + return ucPermissionService.listUrl(permissionQueryDTO); + + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/controller/UcRoleController.java b/backend/src/main/java/com/senmesh/usercenter/authority/controller/UcRoleController.java new file mode 100644 index 0000000..5b54eb2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/controller/UcRoleController.java @@ -0,0 +1,178 @@ +package com.senmesh.usercenter.authority.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.common.validation.Check; +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.authority.dto.*; +import com.senmesh.usercenter.authority.service.UcRoleAllocationService; +import com.senmesh.usercenter.authority.service.UcRoleService; +import com.senmesh.usercenter.cache.SecurityCacheUtils; +import com.senmesh.usercenter.dto.*; +import com.senmesh.usercenter.query.RoleQuery; +import com.senmesh.usercenter.resource.service.UcUrlService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Objects; + +/** + * 角色操作 + * + * @author sr on 2019-11-05 + */ +@Api(tags = "角色操作") +@RestController +@RequestMapping("/role") +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class UcRoleController { + + private final UcRoleService roleService; + + private final UcRoleAllocationService ucRoleAllocationService; + + private final UcUrlService urlService; + + @ApiOperation("创建普通机构角色") + @PostMapping("/create") + public AlitaResult createOrgRole(@Validated(Create.class) @RequestBody RoleDTO roleDTO) { + roleService.createOrgRole(UserContextHolder.getExistLoginOrgId(), roleDTO); + return AlitaResult.success(roleDTO); + } + + @ApiOperation("修改普通机构角色") + @PostMapping("/update") + public AlitaResult updateOrgRole(@Validated(Update.class) @RequestBody RoleDTO roleDTO) { + roleService.updateOrgRole(UserContextHolder.getExistLoginOrgId(), roleDTO); + return AlitaResult.success(roleDTO); + } + + @ApiOperation("删除普通机构角色") + @DeleteMapping("/delete/{id}") + public AlitaResult deleteOrgRole(@PathVariable("id") Long roleId) { + roleService.deleteOrgRole(UserContextHolder.getExistLoginOrgId(), roleId); + return AlitaResult.success(true); + } + + @ApiOperation("获取普通机构角色列表") + @GetMapping("/list") + public AlitaResult> query(Page page, RoleDTO roleDTO) { + roleService.queryOrgRole(UserContextHolder.getExistLoginOrgId(), roleDTO, page); + return AlitaResult.success(page); + } + + @ApiOperation("获取机构招聘负责人角色列表") + @GetMapping("/listPersonCharge") + public AlitaResult> queryByPersonCharge(Long orgId) { + return AlitaResult.success(roleService.queryOrgRole(orgId)); + } + + @ApiOperation("获取机构角色列表") + @PostMapping("/page") + public AlitaResult> page(@RequestBody RoleQuery query) { + query.setOrgId(UserContextHolder.getExistLoginOrgId()); + roleService.queryPlatformAdminRoleList(query); + return AlitaResult.success(query.getPageResult()); + } + + @ApiOperation("根据用户ID查询可分配的角色列表") + @PostMapping("/page_allocation_role_list") + public AlitaResult queryAllocationRoleList(@RequestBody RoleQuery query) { + if (Objects.isNull(query.getOrgId())){ + query.setOrgId(UserContextHolder.getExistLoginOrgId()); + } + return roleService.queryUserAllocationRoleList(query); + } + + @ApiOperation("获取普通机构角色已选分配权限") + @GetMapping("/check_key/list") + public AlitaResult> queryCheckedKeys() { + List checkedKeysByRoleIds = roleService + .findCheckedKeysByRoleIds(UserContextHolder.getExistLoginOrgId()); + return AlitaResult.success(checkedKeysByRoleIds); + } + + @ApiOperation("角色权限分配") + @PostMapping("/url_allocation") + public AlitaResult roleUrlAllocation( + @RequestBody PermissionOperateDTO permissionOptionDTO) { + //保存菜单 + roleService.roleUrlAllocation(permissionOptionDTO, UserContextHolder.getExistLoginOrgId()); + //清理已删除菜单下相关接口/组件 + roleService.cleanRoleComponentAndInterface(); + // 刷新缓存 + SecurityCacheUtils.flushAll(); + return AlitaResult.success(Boolean.TRUE); + } + + @ApiOperation("用户分配角色") + @PostMapping("/user_allocation_role") + public AlitaResult userAllocationRole(@RequestBody AllocationRoleDTO allocationRoleDTO) { + return roleService.userAllocationRole(allocationRoleDTO, UserContextHolder.getLoginUserId()); + } + + @ApiOperation("角色分配用户") + @PostMapping("/role_allocation_user") + public AlitaResult roleAllocationUser(@RequestBody AllocationRoleUserDTO dto) { + roleService.roleAllocationUser(dto); + return AlitaResult.success(Boolean.TRUE); + } + + @ApiOperation("分配角色删除用户") + @PostMapping("/remove_allocation_role") + public AlitaResult removelocationRole(@RequestBody AllocationRoleUserDTO allocationRoleDTO) { + roleService.removelocationRole(allocationRoleDTO); + return AlitaResult.success(Boolean.TRUE); + } + + @ApiOperation("角色是否启用") + @PostMapping("/enable") + public AlitaResult roleEnable(@RequestBody RoleDTO roleDTO) { + return roleService.roleEnable(roleDTO.getId(), roleDTO.getEnabled(), UserContextHolder.getExistLoginUserId()); + } + + @ApiOperation("查询指定机构下用户业务角色(已分配/未分配)列表") + @GetMapping("/getBusinessRoles/{orgId}/{userId}") + public AlitaResult> getBusinessRoles(@PathVariable("orgId") Long orgId, @PathVariable("userId") Long userId) { + return AlitaResult.success(ucRoleAllocationService.getBusinessRoles(orgId, userId)); + } + + + @ApiOperation("指定用户角色分配(新分配/取消分配)") + @PostMapping("/allocateBusinessRoles/{orgId}/{userId}") + public AlitaResult allocateBusinessRoles(@PathVariable("orgId") Long orgId, @PathVariable("userId") Long userId, @RequestBody UserAllocateRoleDTO userAllocateRoleDTO) { + ucRoleAllocationService.allocateBusinessRoles(orgId, userId, userAllocateRoleDTO, UserContextHolder.getExistLoginUserId()); + return AlitaResult.success(); + } + + @ApiOperation("获取角色菜单下相关组件/接口列表") + @GetMapping("/get_url_resources") + public AlitaResult> getAllResourceList(@Validated(Check.class) + PermissionPageQueryDTO permissionPageQueryDTO) { + permissionPageQueryDTO.setOrgId(UserContextHolder.getExistLoginOrgId()); + urlService.queryAllResourceList(permissionPageQueryDTO); + return AlitaResult.success(permissionPageQueryDTO.getPageResult()); + } + + @ApiOperation("保存角色对应菜单下组件/接口列表") + @PostMapping("/save_url_resources") + public AlitaResult saveUrlResourcesOperateDTO( + @Validated(Create.class) @RequestBody PermissionResourcesDTO permissionResourcesDTO) { + urlService.saveUrlResourcesOperateDTO(permissionResourcesDTO); + SecurityCacheUtils.flushAll(); + return AlitaResult.success(Boolean.TRUE); + } + + @ApiOperation("查询指定机构、指定用户、指定平台的已分配角色列表") + @GetMapping("/getAllocatedBusinessRoles") + public AlitaResult> getAllocatedBusinessRoles(@Validated AllocatedBusinessRoleQueryDTO queryDTO) { + return AlitaResult.success(ucRoleAllocationService.getAllocatedBusinessRoles(queryDTO)); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/dao/UcPermissionMapper.java b/backend/src/main/java/com/senmesh/usercenter/authority/dao/UcPermissionMapper.java new file mode 100644 index 0000000..259d1f7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/dao/UcPermissionMapper.java @@ -0,0 +1,108 @@ +package com.senmesh.usercenter.authority.dao; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.authority.dto.*; +import com.senmesh.usercenter.authority.entity.Permission; +import com.senmesh.usercenter.dto.CheckKeyDTO; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * 权限mapper + * @author sr on 2019-10-07 + */ +@Component(UcPermissionMapper.BEAN_ID) +public interface UcPermissionMapper extends MyMapper { + + String BEAN_ID = "security.permissionMapper"; + + /** + * 查询所有组件权限 + * + * @return + * @author sr on 2019-10-17 + */ + List findComponent(@Param("param") PermissionQueryDTO permissionQueryDTO); + + /** + * 查询所有菜单权限 + * + * @return + * @author sr on 2019-10-17 + */ + List findUrl(@Param("param") PermissionQueryDTO permissionQueryDTO); + + /** + * 查询指定角色指定类型拥有权限的资源id列表 + * @param roleId + * @param resourceType + * @return + * @author sr on 2019-10-17 + */ + @Select("select distinct p.resource_id from xs_permission p, xs_url r " + + "where p.role_id = #{roleId} and p.resource_type = #{resourceType} and p.deleted = 0 " + + "and p.resource_id = r.id and r.deleted=0 order by p.resource_id") + Set findResourceIdByRoleId(Long roleId, Integer resourceType); + + @Select("select distinct p.resource_id from xs_permission p, xs_url r " + + "where p.role_id = #{roleId} and p.resource_type = #{resourceType} and p.deleted = 0 " + + "and p.resource_id = r.id order by p.resource_id") + Set selectResourceIdByRoleId(Long roleId, String resourceType); + + /** + * 查询指定角色拥有权限的所有资源id+type + * @param roleIds + * @return + * @author sr on 2019-10-17 + */ + List> listResourceIdTypeByRoleId(List roleIds); + + + /** + * 查询指定用户拥有的权限列表 + * @param roleId + * @return + * @author sr on 2019-10-17 + */ + @Select("select * from xs_permission where role_id = #{roleId} and deleted = 0 ") + List findByRoleId(Long roleId); + + + /** + * 查询指定角色的checkedKeys + * @param roleIds + * @return + */ + List findCheckedKeysByRoleIds(@Param("roleIds") Set roleIds); + + /** + * 逻辑删除角色分配资源 + * + * @param roleId + * @param resourceId + * @return + */ + @Update("update xs_permission set deleted = 1, update_by = #{operateUserId} where role_id = #{roleId} and resource_id = #{resourceId}") + int deletePermissionByRoleIdAndResourceId(Long operateUserId, Long roleId, Long resourceId); + + /** + * 逻辑删除角色分配资源 + * + * @param roleId + * @return + */ + @Update("update xs_permission set deleted = 1, update_by = #{operateUserId} where role_id = #{roleId}") + int deletePermissionByRoleId(Long operateUserId, Long roleId); + + List urlComponentList( + @Param("param") PermissionPageQueryDTO permissionPageQueryDTO); + + List urlInterfaceList( + @Param("param") PermissionPageQueryDTO permissionPageQueryDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/dao/UcRoleAllocationMapper.java b/backend/src/main/java/com/senmesh/usercenter/authority/dao/UcRoleAllocationMapper.java new file mode 100644 index 0000000..afd6d60 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/dao/UcRoleAllocationMapper.java @@ -0,0 +1,101 @@ +package com.senmesh.usercenter.authority.dao; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.authority.dto.RoleAllocationDTO; +import com.senmesh.usercenter.authority.entity.RoleAllocation; +import com.senmesh.usercenter.dto.AllocatedBusinessRoleQueryDTO; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; + +import java.util.List; +import java.util.Set; +import com.senmesh.usercenter.dto.RoleDTO; + +/** + * @author Jerry.li + * @description 角色分配 + * @date 2020/3/24 + */ +@Mapper +public interface UcRoleAllocationMapper extends MyMapper { + + /** + * 查询角色分配列表 + * @param allocationType + * @param allocationId + * @return + */ + List selectAllocationList(@Param("allocationType") String allocationType, @Param("allocationId") Long allocationId); + + /** + * 查询角色ID列表 + * @param allocationType + * @param allocationId + * @return + */ + Set selectRoleIds(@Param("allocationType") String allocationType, @Param("allocationId") Long allocationId); + + /** + * 批量删除角色 + * @param allocationType + * @param allocationId + * @param deleteRoleIds + * @param operateUserId + */ + void deleteByRoleIds(@Param("allocationType") String allocationType, @Param("allocationId") Long allocationId, @Param("roleIds") List deleteRoleIds, @Param("operateUserId") Long operateUserId); + + /** + * 根据账号查询角色分配列表 + * @param username + * @return + */ + List selectAllocationListByUsername(String username); + + /** + * 查询指定分配类型id的分配列表 + * @param allocationType + * @param allocationId + * @return + * @author sr on 2019-10-17 + */ + @Select("select * from xs_role_allocation where allocation_type = #{allocationType} and allocation_id = #{allocationId} and deleted = 0 ") + List findByAllocationId(@Param("allocationType") String allocationType, @Param("allocationId") Long allocationId); + + /** + * 查询指定分配类型id的分配角色id列表 + * @param allocationType + * @param allocationId + * @return + * @author sr on 2019-10-17 + */ + @Select("select distinct role_id from xs_role_allocation where allocation_type = #{allocationType} and allocation_id = #{allocationId} and deleted = 0 ") + Set findRoleIds(@Param("allocationType") String allocationType, @Param("allocationId") Long allocationId); + + /** + * 查询指定用户的角色分配列表 + * @param userId + * @return + * @author sr on 2021-08-05 + */ + List findByUserId(Long userId); + + /** + * 取消用户已分配的角色 + * @param operateUserId + * @param roleId + * @param userId + * @return + */ + @Update("update xs_role_allocation set deleted = 1, update_by = #{operateUserId} where role_id = #{roleId} and allocation_id = #{userId} and deleted = 0") + int deleteUserAllocatedRole(Long operateUserId, Long roleId, Long userId); + /** + * @description: 查询指定机构、指定用户、指定平台的已分配角色 + * @return: + * @author: guixinman + * @param: + */ + List getAllocatedBusinessRoles(@Param("param") AllocatedBusinessRoleQueryDTO queryDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/dao/UcRoleMapper.java b/backend/src/main/java/com/senmesh/usercenter/authority/dao/UcRoleMapper.java new file mode 100644 index 0000000..673b271 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/dao/UcRoleMapper.java @@ -0,0 +1,144 @@ +package com.senmesh.usercenter.authority.dao; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.authority.entity.Role; +import com.senmesh.usercenter.dto.RoleDTO; +import com.senmesh.usercenter.query.RoleQuery; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; +import java.util.Set; + +/** + * @author Jerry.li + * @description 角色 + * @date 2020/3/24 + */ +@Mapper +public interface UcRoleMapper extends MyMapper { + + /** + * 根据角色类型查询角色ID + * @param roleType + * @return + */ + @Select("select id from xs_role where type = #{roleType} and deleted = 0 ") + Long selectRoleIdByRoleType(String roleType); + + /** + * + * @param orgId + * @param roleDTO + * @return + */ + List selectOrgRoleList(@Param("orgId") Long orgId, @Param("param") RoleDTO roleDTO); + + /** + * 查询指定机构的角色列表 + * @param orgId + * @param roleDTO + * @param page + * @return + * @author sr on 2019-10-14 + */ + List queryOrgRoles(@Param("orgId")Long orgId, @Param("param") RoleDTO roleDTO, Page page); + + /** + * 查询指定机构的角色列表 + * @param orgId + * @return + * @author sr on 2019-10-14 + */ + @Select("select * from xs_role where org_id = #{orgId} and deleted = 0") + List queryOrgRoleList(@Param("orgId")Long orgId); + + /** + * 校验指定机构下是否存在对应角色类型角色 + * @param orgId + * @param roleId + * @param roleType + * @return + * @author sr on 2019-10-17 + */ + @Select("select count(*) from xs_role where org_id = #{orgId} and id = #{roleId} and type = #{roleType} and deleted = 0") + int existRole(@Param("orgId") Long orgId, @Param("roleId") Long roleId, @Param("roleType") String roleType); + + /** + * 查询机构下角色id列表 + * @param orgId + * @param roleDTO + * @return + * @author sr on 2019-10-17 + */ + Set queryOrgRoleIds(@Param("orgId")Long orgId, @Param("param") RoleDTO roleDTO); + + /** + * 根据类型查询角色id(内置的系统角色) + * @param roleType + * @return + * @author sr on 2019-10-19 + */ + @Select("select id from xs_role where type = #{roleType} and deleted = 0 ") + Long queryRoleId(String roleType); + + /** + * 校验角色名是否存在 + * @param orgId + * @param roleName + * @param roleId 为空则判断所有角色(新增),不为空代表判断除该角色id之外的角色(修改) + * @return + * @author sr on 2019-11-18 + */ + int existRoleName(@Param("orgId") Long orgId, @Param("roleName") String roleName, @Param("roleId") Long roleId); + + /** + * 分页查询平台级角色列表 + * @param page + * @return + */ + List selectPlatformAdminRoleList(@Param("param") RoleQuery roleQuery); + + /** + * 查询用户已分配的角色ID + * @param query + * @return + */ + List selectAllocatedRoleIdListByUserId(RoleQuery query); + + /** + * 查询平台用户可分配的角色列表 + */ + List selectPlatformUserUnallocatedRoleList(RoleQuery query); + + /** + * 查询机构用户可分配的角色列表 + * + * @param query + * @return + */ + List selectOrgUserUnallocatedRoleList(RoleQuery query); + + /** + * 获取所有不能删除的销售角色 + * + * @return {@link Set} + */ + Set getSellerRoleCanNotBeDeleted(@Param("userId") Long userId); + + /** + * 清理已删除菜单的组件 + * @param loginUserId + */ + void cleanRoleComponent(Long loginUserId); + + /** + * 清理已删除菜单的接口 + * @param loginUserId + */ + void cleanRoleInterface(Long loginUserId); + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/dto/ComponentPermissionDTO.java b/backend/src/main/java/com/senmesh/usercenter/authority/dto/ComponentPermissionDTO.java new file mode 100644 index 0000000..2f927a2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/dto/ComponentPermissionDTO.java @@ -0,0 +1,50 @@ +package com.senmesh.usercenter.authority.dto; + +import org.apache.commons.lang3.StringUtils; + +import com.senmesh.security.access.provider.IConfigAttribute; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-09-07 + */ +@Data +@NoArgsConstructor +public class ComponentPermissionDTO implements IConfigAttribute { + + /** **/ + private static final long serialVersionUID = -451031464850427393L; + + /** 角色ID **/ + private Long roleId; + + /** 资源类型:1菜单3接口 **/ + private String resourceType; + + /** 资源ID **/ + private Long resourceId; + + /** 权限鉴别属性,默认格式:ROLE_{roleId} **/ + private String attribute; + + @Override + /** + * 权限鉴别属性,默认格式:ROLE_{roleId} + * + * @return attribute + */ + public String getAttribute() { + if (StringUtils.isBlank(attribute)) { + return "ROLE_" + roleId; + } + return attribute; + } + + @Override + public Long getKey() { + return resourceId; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/dto/PermissionDTO.java b/backend/src/main/java/com/senmesh/usercenter/authority/dto/PermissionDTO.java new file mode 100644 index 0000000..29c61cc --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/dto/PermissionDTO.java @@ -0,0 +1,66 @@ +package com.senmesh.usercenter.authority.dto; + +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseDTO; +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 权限信息 + * + * @author on 2019-11-05 + */ +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public class PermissionDTO extends BaseDTO { + + private static final long serialVersionUID = -8945833162881931804L; + + @ApiModelProperty("角色ID") + private Long roleId; + + @ApiModelProperty("资源类型:1菜单2组件3接口") + private String resourceType; + + @ApiModelProperty("资源ID,如菜单和组件,以及用户定义的资源") + private Long resourceId; + + @ApiModelProperty("所属菜单ID") + private Long urlId; + + @ApiModelProperty("机构ID") + private Long orgId; + + @ApiModelProperty("权限鉴别属性,默认格式:ROLE_{roleId},可以扩展") + private String attribute; + + @ApiModelProperty("组件/接口名称") + private String name; + + @ApiModelProperty("接口地址") + private String link; + + @ApiModelProperty("组件编码") + private String code; + + @ApiModelProperty("描述") + private String description; + + @ApiModelProperty("平台编码") + private Integer platformCode; + + @ApiModelProperty("是否授权") + @NotNull(message = "是否选中标识不能为空", groups = { + Create.class, Update.class}) + private Boolean selected; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/dto/PermissionOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/authority/dto/PermissionOperateDTO.java new file mode 100644 index 0000000..2e6b50d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/dto/PermissionOperateDTO.java @@ -0,0 +1,53 @@ +package com.senmesh.usercenter.authority.dto; + +import java.io.Serializable; +import java.util.List; + +import javax.validation.constraints.NotNull; + +import com.senmesh.common.validation.Update; +import com.senmesh.usercenter.resource.dto.UrlDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 角色权限 + * + * @author sr on 2019-11-05 + */ +@ApiModel("角色权限") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PermissionOperateDTO implements Serializable { + + /** + * + **/ + private static final long serialVersionUID = 4898248691495623567L; + + @ApiModelProperty("角色id") + @NotNull(message = "角色id不能为空", groups = {Update.class}) + private Long roleId; + + /** + * 平台编码 + */ + private Integer platformCode; + + @ApiModelProperty("资源树") + List urlDTOs; + + @ApiModelProperty("分配资源id(type_id)") + List resourceIds; + + @ApiModelProperty("已分配的资源列表") + List resourceIdList; + + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/dto/PermissionPageQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/authority/dto/PermissionPageQueryDTO.java new file mode 100644 index 0000000..ceac093 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/dto/PermissionPageQueryDTO.java @@ -0,0 +1,47 @@ +package com.senmesh.usercenter.authority.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.PageQueryDTO; +import com.senmesh.common.validation.Check; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author yzq + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class PermissionPageQueryDTO extends PageQueryDTO implements Serializable { + + @ApiModelProperty("应用编码 1.业务系统 2.运营中台 3.用户中心 4.支付系统 5.在线培训 6.转发器 7.风控 8.网关 9.发号器 10.基础框架") + @NotNull(message = "平台编码不能为空", groups = {Check.class}) + private Integer platformCode; + + @ApiModelProperty("角色ID") + @NotNull(message = "角色不能为空", groups = {Check.class}) + private Long roleId; + + @ApiModelProperty("机构ID") + private Long orgId; + + @ApiModelProperty("资源类型:1菜单 2组件 3接口") + @NotNull(message = "资源类型不能为空", groups = {Check.class}) + private String resourceType; + + @ApiModelProperty("父菜单Id") + @NotNull(message = "父菜单id不能为空s", groups = {Check.class}) + private Long urlId; + + @ApiModelProperty("是否已授权 1.已授权 2.未授权 ") + private Boolean selected; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/dto/PermissionQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/authority/dto/PermissionQueryDTO.java new file mode 100644 index 0000000..0320d3e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/dto/PermissionQueryDTO.java @@ -0,0 +1,27 @@ +package com.senmesh.usercenter.authority.dto; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-09-07 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class PermissionQueryDTO implements Serializable { + + /** **/ + private static final long serialVersionUID = -3670302869701791296L; + + /** 应用 **/ + private Integer systemCode; + /** 机构id **/ + private Long orgId; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/dto/PermissionResourcesDTO.java b/backend/src/main/java/com/senmesh/usercenter/authority/dto/PermissionResourcesDTO.java new file mode 100644 index 0000000..52129a4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/dto/PermissionResourcesDTO.java @@ -0,0 +1,24 @@ +package com.senmesh.usercenter.authority.dto; + +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; + + +/** + * @author yzhq + */ +@ApiModel("角色资源保存DTO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PermissionResourcesDTO extends PermissionPageQueryDTO implements Serializable { + + private List PermissionDTOList; + +} + diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/dto/RoleAllocationDTO.java b/backend/src/main/java/com/senmesh/usercenter/authority/dto/RoleAllocationDTO.java new file mode 100644 index 0000000..9f0d549 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/dto/RoleAllocationDTO.java @@ -0,0 +1,51 @@ +package com.senmesh.usercenter.authority.dto; + +import com.senmesh.common.dto.BaseDTO; +import com.senmesh.usercenter.constants.SecurityConstants; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import org.springframework.security.core.GrantedAuthority; + +/** + * 角色分配表 + * + * @author on 2019-11-05 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@SuperBuilder +public class RoleAllocationDTO extends BaseDTO implements GrantedAuthority { + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** + * 角色id + */ + private Long roleId; + + /** + * 角色具体分配类型对应的id + */ + private Long allocationId; + + /** + * 角色分配类型:1个人2部门3组 + */ + private String allocationType; + + @Override + public String getAuthority() { + if (roleId != null && roleId != 0L) { + return SecurityConstants.ROLE_PERMISSION_PREFIX + roleId; + } + return null; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/dto/UrlPermissionDTO.java b/backend/src/main/java/com/senmesh/usercenter/authority/dto/UrlPermissionDTO.java new file mode 100644 index 0000000..216f116 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/dto/UrlPermissionDTO.java @@ -0,0 +1,57 @@ +package com.senmesh.usercenter.authority.dto; + +import org.apache.commons.lang3.StringUtils; + +import com.senmesh.security.access.provider.IUrlConfigAttribute; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-09-07 + */ +@Data +@NoArgsConstructor +public class UrlPermissionDTO implements IUrlConfigAttribute{ + + private static final long serialVersionUID = 9030470489046670169L; + + /** 角色ID **/ + private Long roleId; + + /** 资源类型:1菜单3接口 **/ + private String resourceType; + + /** 资源ID **/ + private Long resourceId; + + /** 权限鉴别属性,默认格式:ROLE_{roleId} **/ + private String attribute; + + /** 链接 **/ + private String link; + + @Override + /** + * 权限鉴别属性,默认格式:ROLE_{roleId} + * + * @return attribute + */ + public String getAttribute() { + if (StringUtils.isBlank(attribute)) { + return "ROLE_" + roleId; + } + return attribute; + } + + @Override + public Long getKey() { + return resourceId; + } + + @Override + public String getUrl() { + return link; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/entity/Permission.java b/backend/src/main/java/com/senmesh/usercenter/authority/entity/Permission.java new file mode 100644 index 0000000..16b3475 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/entity/Permission.java @@ -0,0 +1,80 @@ +package com.senmesh.usercenter.authority.entity; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.data.annotation.Transient; +import org.springframework.security.access.ConfigAttribute; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 权限信息 + * + * @author on 2019-11-05 + */ +@TableName("xs_permission") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@EqualsAndHashCode(callSuper = true) +public class Permission extends BaseEntity implements ConfigAttribute { + + private static final long serialVersionUID = 1L; + + /** + * 角色ID + **/ + private Long roleId; + + /** + * 资源类型:1菜单2组件 + **/ + private String resourceType; + + /** + * 资源ID,如菜单和组件,以及用户定义的资源 + **/ + private Long resourceId; + + /** + * 权限鉴别属性,默认格式:ROLE_{roleId},可以扩展 + **/ + private String attribute; + + /** + * 机构ID + */ + private Long orgId; + + /** + * 平台编码 + */ + private Integer platformCode; + + /** + * 菜单地址,为收集菜单权限 + **/ + @Transient + private String resourceLink; + + @Override + /** + * 权限鉴别属性,默认格式:ROLE_{roleId} + * + * @return attribute + */ + public String getAttribute() { + if (StringUtils.isBlank(attribute)) { + return "ROLE_" + roleId; + } + return attribute; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/entity/Role.java b/backend/src/main/java/com/senmesh/usercenter/authority/entity/Role.java new file mode 100644 index 0000000..d40f846 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/entity/Role.java @@ -0,0 +1,64 @@ +package com.senmesh.usercenter.authority.entity; + +import java.io.Serializable; +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author Jerry.li + * @description 角色 + * @date 2020/3/24 + */ +@Data +@TableName("xs_role") +@AllArgsConstructor +@NoArgsConstructor +public class Role extends BaseEntity implements Serializable { + + private static final long serialVersionUID = 4976697243964672402L; + + /** 机构id **/ + private Long orgId; + + /** 名称 **/ + private String name; + + /** 类型:0业务角色、1系统角色-渠道代理商、2系统角色-普通机构 **/ + private String type; + + /** 是否启用 **/ + private Boolean enabled; + + /** 描述 **/ + private String description; + + /** 标准角色类型:见role_standard_type **/ + private String standardType; + + /** + * 所属平台 + */ + private Integer platformCode; + + @Builder + public Role(Long id, Boolean deleted, Long createBy, Date createTime, Long updateBy, + Date updateTime, Long proxyBy, Long orgId, String name, String type, Boolean enabled, + String description, String standardType, Integer platformCode) { + super(id, deleted, createBy, createTime, updateBy, updateTime, proxyBy); + this.orgId = orgId; + this.name = name; + this.type = type; + this.enabled = enabled; + this.description = description; + this.standardType = standardType; + this.platformCode = platformCode; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/entity/RoleAllocation.java b/backend/src/main/java/com/senmesh/usercenter/authority/entity/RoleAllocation.java new file mode 100644 index 0000000..7cb1770 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/entity/RoleAllocation.java @@ -0,0 +1,48 @@ +package com.senmesh.usercenter.authority.entity; + +import java.io.Serializable; + +import org.springframework.data.annotation.Transient; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author Jerry.li + * @description 角色分配 + * @date 2020/3/24 + */ +@TableName("xs_role_allocation") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public class RoleAllocation extends BaseEntity implements Serializable { + + private static final long serialVersionUID = 5399518985159547780L; + + /** 机构id **/ + @Transient + private Long orgId; + + /** + * 角色id + */ + private Long roleId; + + /** + * 角色具体分配类型对应的id + */ + private Long allocationId; + + /** + * 角色分配类型:1-个人 2-部门 3-组 + */ + private String allocationType; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/mapper/UcPermissionMapper.xml b/backend/src/main/java/com/senmesh/usercenter/authority/mapper/UcPermissionMapper.xml new file mode 100644 index 0000000..7f5fd91 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/mapper/UcPermissionMapper.xml @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/mapper/UcRoleAllocationMapper.xml b/backend/src/main/java/com/senmesh/usercenter/authority/mapper/UcRoleAllocationMapper.xml new file mode 100644 index 0000000..27b7e65 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/mapper/UcRoleAllocationMapper.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + update + xs_role_allocation + set + deleted = TRUE, + update_by = #{operateUserId}, + update_time = now() + where + allocation_type = #{allocationType} + and allocation_id = #{allocationId} + and deleted = FALSE + and role_id in + + #{roleId} + + + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/mapper/UcRoleMapper.xml b/backend/src/main/java/com/senmesh/usercenter/authority/mapper/UcRoleMapper.xml new file mode 100644 index 0000000..a70dacc --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/mapper/UcRoleMapper.xml @@ -0,0 +1,181 @@ + + + + + FROM xs_role + + org_id = #{orgId} and deleted = FALSE + + + AND name like #{nameLike} + + + and enabled = #{param.enabled} + + + and type = #{param.type} + + + and standard_type = #{param.standardType} + + + order by id desc + + + -- 菜单已删除,组件还存在 + UPDATE + xs_permission xp + LEFT JOIN xs_component xc ON + xp.resource_id = xc.id + AND xc.deleted = FALSE + LEFT JOIN xs_permission xp2 ON + xp2.resource_id = xc.url_id + AND xp2.role_id = xp.role_id + AND xp2.deleted = FALSE + SET xp.deleted = TRUE,xp.update_by = #{loginUserId}, xp.update_time = now() + WHERE + xp.deleted = FALSE + AND xp2.id IS null + AND xp.resource_type = '2' + + + + -- 菜单已删除,接口还存在 + UPDATE + xs_permission xp + LEFT JOIN xs_url xc ON + xp.resource_id = xc.id + AND xc.type = 2 + AND xc.deleted = FALSE + LEFT JOIN xs_permission xp2 ON + xp2.resource_id = xc.parent_id + AND xp2.role_id = xp.role_id + AND xp2.deleted = FALSE + SET xp.deleted = TRUE,xp.update_by = #{loginUserId} , xp.update_time = now() + WHERE + xp.deleted = FALSE + AND xp2.id IS NULL + AND xp.resource_type = '3' + + + + + + + + + + + + + + + + + + + + diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/service/UcPermissionService.java b/backend/src/main/java/com/senmesh/usercenter/authority/service/UcPermissionService.java new file mode 100644 index 0000000..ce8144a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/service/UcPermissionService.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.authority.service; + + +import java.util.List; +import java.util.Map; + +import com.senmesh.security.service.IPermissionSecurityService; +import com.senmesh.usercenter.authority.dto.ComponentPermissionDTO; +import com.senmesh.usercenter.authority.dto.PermissionQueryDTO; + +/** + * @author chenyun + * @description + * @date 2020/9/3 17:52 + */ +public interface UcPermissionService extends IPermissionSecurityService { + + /** + * 查询角色下所有组件 + * + * @return + */ + List listComponent(PermissionQueryDTO permissionQueryDTO); + + /** + * 查询指定角色拥有权限的所有资源id+type + * + * @param roleIds + * @return + * @author sr on 2020-09-07 + */ + List> listResourceIdTypeByRoleId(List roleIds); + + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/service/UcRoleAllocationService.java b/backend/src/main/java/com/senmesh/usercenter/authority/service/UcRoleAllocationService.java new file mode 100644 index 0000000..6066fd2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/service/UcRoleAllocationService.java @@ -0,0 +1,48 @@ +package com.senmesh.usercenter.authority.service; + +import com.senmesh.security.service.IRoleAllocationSecurityService; +import com.senmesh.usercenter.dto.AllocatedBusinessRoleQueryDTO; +import com.senmesh.usercenter.dto.AllocationDTO; +import com.senmesh.usercenter.dto.RoleDTO; +import com.senmesh.usercenter.dto.UserAllocateRoleDTO; + +import java.util.List; + +/** + * 角色分配 + * + * @author sr on 2019-10-17 + */ +public interface UcRoleAllocationService extends IRoleAllocationSecurityService{ + + /** + * 查询指定机构下用户业务角色(已分配/未分配)列表 + * + * @param orgId + * @param userId + * @return + * @author sr on 2019-10-17 + */ + AllocationDTO getBusinessRoles(Long orgId, Long userId); + + /** + * @description: 查询指定机构、指定用户、指定平台的已分配角色 + * @return: + * @author: guixinman + * @param: + */ + List getAllocatedBusinessRoles(AllocatedBusinessRoleQueryDTO queryDTO); + + /** + * 指定用户角色分配(新分配/取消分配) + * + * @param orgId + * @param userId + * @param userAllocateRoleDTO + * @param operateUserId + * @author sr on 2019-10-17 + */ + void allocateBusinessRoles(Long orgId, Long userId, UserAllocateRoleDTO userAllocateRoleDTO, + Long operateUserId); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/service/UcRoleService.java b/backend/src/main/java/com/senmesh/usercenter/authority/service/UcRoleService.java new file mode 100644 index 0000000..ae059e7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/service/UcRoleService.java @@ -0,0 +1,132 @@ +package com.senmesh.usercenter.authority.service; + +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.authority.dto.PermissionOperateDTO; +import com.senmesh.usercenter.dto.AllocationRoleDTO; +import com.senmesh.usercenter.dto.AllocationRoleUserDTO; +import com.senmesh.usercenter.dto.CheckKeyDTO; +import com.senmesh.usercenter.dto.RoleDTO; +import com.senmesh.usercenter.query.RoleQuery; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; +import javax.validation.groups.Default; +import java.util.List; + +/** + * @author Jerry.li + * @description 角色服务类 + * @date 2020/3/26 + */ +@Validated(Default.class) +public interface UcRoleService { + + /** + * 创建普通机构角色(type=0) + * + * @param orgId 机构id 不能为空 + * @param roleDTO + * @return + * @author sr on 2019-10-14 + */ + void createOrgRole(Long orgId, RoleDTO roleDTO); + + /** + * 修改普通机构角色(type=0) + * + * @param orgId 机构id 不能为空 + * @param roleDTO + * @author sr on 2019-10-14 + */ + void updateOrgRole(@NotNull Long orgId, @NotNull RoleDTO roleDTO); + + /** + * 删除普通机构角色(type=0) + * + * @param orgId 机构id 不能为空 + * @param roleId + * @author sr on 2019-10-14 + */ + void deleteOrgRole(Long orgId, Long roleId); + + /** + * 获取普通机构角色列表(type=0) + * + * @param orgId 机构id 不能为空 + * @param roleDTO + * @param page + * @author sr on 2019-10-14 + */ + void queryOrgRole(Long orgId, RoleDTO roleDTO, Page page); + + /** + * 获取标准角色为招聘负责人的列表 + * + */ + List queryOrgRole(Long orgId); + + /** + * 获取当前登录机构下角色的权限数据 + * + * @param orgId + * @return + */ + List findCheckedKeysByRoleIds(Long orgId); + + /** + * 分页查询平台管理员的角色列表 + * @param page + * @param query + */ + void queryPlatformAdminRoleList(RoleQuery query); + + /** + * 角色资源分配 + * @param permissionDTO + * @param operateUserId + */ + void roleUrlAllocation(PermissionOperateDTO permissionDTO, Long operateUserId); + + /** + * 用户分配角色 + * @param allocationRoleDTO + * @param operateUserId + * @return + */ + AlitaResult userAllocationRole(AllocationRoleDTO allocationRoleDTO, Long operateUserId); + + /** + * 角色分配用户 + * @param dto + * @return + */ + AlitaResult roleAllocationUser(AllocationRoleUserDTO dto); + + + /** + * 分配角色删除用户 + * @param allocationRoleDTO + */ + void removelocationRole(AllocationRoleUserDTO allocationRoleDTO); + + /** + * 角色启用 + * @param roleId + * @param enable + * @param operateUserId + * @return + */ + AlitaResult roleEnable(Long roleId, Boolean enable, Long operateUserId); + + /** + * 根据用户ID查询可分配的角色列表 + * @param query + */ + AlitaResult queryUserAllocationRoleList(RoleQuery query); + + /** + * 清理已已删除菜单下的组件和接口 + */ + void cleanRoleComponentAndInterface(); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/service/impl/ResourceSecurityServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/authority/service/impl/ResourceSecurityServiceImpl.java new file mode 100644 index 0000000..26c9663 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/service/impl/ResourceSecurityServiceImpl.java @@ -0,0 +1,184 @@ +package com.senmesh.usercenter.authority.service.impl; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.security.decision.manager.SecurityDecisionManager; +import com.senmesh.security.dto.SecurityUserDTO; +import com.senmesh.security.service.IResourceSecurityService; +import com.senmesh.usercenter.authority.constants.PermissionConstants; +import com.senmesh.usercenter.authority.dao.UcRoleMapper; +import com.senmesh.usercenter.authority.dto.PermissionQueryDTO; +import com.senmesh.usercenter.authority.service.UcPermissionService; +import com.senmesh.usercenter.constants.OrgConstants; +import com.senmesh.usercenter.constants.SecurityConstants; +import com.senmesh.usercenter.constants.UrlConstants; +import com.senmesh.usercenter.dto.IUserDetail; +import com.senmesh.usercenter.query.RoleQuery; +import com.senmesh.usercenter.resource.dao.UcComponentMapper; +import com.senmesh.usercenter.resource.dao.UcUrlMapper; +import com.senmesh.usercenter.resource.dto.ComponentDTO; +import com.senmesh.usercenter.resource.dto.UrlDTO; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +@Slf4j +public class ResourceSecurityServiceImpl implements IResourceSecurityService { + + private final UcUrlMapper ucUrlMapper; + + private final UcComponentMapper ucComponentMapper; + + private final SecurityDecisionManager securityDecisionManager; + + private final UcPermissionService ucPermissionService; + + private final UcRoleMapper ucRoleMapper; + + @Override + @Transactional(rollbackFor = RuntimeException.class) + @Cacheable(cacheNames = SecurityConstants.CacheName.RESOURCE_TREE_CACHE_KEY, + key = SecurityConstants.CACHE_KEY_ORG_SYSTEM_USER) + public List listResource(Integer systemCode, IUserDetail iUserDetail) { + return listResource(systemCode, iUserDetail, null); + } + + @Override + @Cacheable(cacheNames = SecurityConstants.CacheName.RESOURCE_TREE_CACHE_KEY, + key = SecurityConstants.CACHE_KEY_ORG_SYSTEM_USER_ROLE) + public List listResource(Integer systemCode, IUserDetail iUserDetail, Long roleId) { + // 当前登录人资源 + // 角色id不为空,已选角色资源列表 + Set urlIds = Sets.newHashSet(); + Set componentIds = Sets.newHashSet(); + if (roleId != null) { + distinctResource(roleId, urlIds, componentIds); + } + boolean isManager = UserContextHolder.isAdministrator(iUserDetail); + Long orgId = iUserDetail.getOrgId(); + Assert.notNull(orgId, "暂只支持查询企业用户资源列表,个人用户待处理"); + // 查询机构拥有资源 + List urls = this.listUrlDTO(systemCode, orgId); + Map urlMap = urls.stream() + .collect(Collectors.toMap(UrlDTO::getId, url -> url)); + List urlDTOs = Lists.newArrayList(); + PermissionQueryDTO permissionQueryDTO = + PermissionQueryDTO.builder().orgId(orgId).systemCode(systemCode).build(); + // 保证菜单顺序 + urls.stream().forEach(url -> { + // 决策权限 + if (!isManager && !securityDecisionManager.decide((SecurityUserDTO)iUserDetail, url, permissionQueryDTO)) { + return; + } + Long urlId = url.getId(); + UrlDTO uDto = urlMap.get(urlId); + + // 顶级菜单 + if (UrlConstants.URL_TOP_PARENT_ID.equals(url.getParentId())) { + urlDTOs.add(uDto); + return; + } + // 找父url,然后把自己加入其子集合 + UrlDTO pDto = urlMap.get(url.getParentId()); + if (pDto == null) { + log.error("️**************菜单数据异常,需修复数据*****************"); + return; + } + pDto.getChildren().add(uDto); + // 判断roleId是否拥有权限 + if (roleId != null && urlIds.contains(urlId)) { + uDto.setSelected(true); + } + }); + + // 将组件加入树中 + List components = this.listComponentDTO(systemCode, orgId); + components.stream().forEach(component -> { + // 决策权限 + if (!isManager && !securityDecisionManager.decide(component, permissionQueryDTO)) { + return; + } + UrlDTO url = urlMap.get(component.getUrlId()); + if (url == null) { + return; + } + url.getComponents().add(component); + + // 判断roleId是否拥有权限 + if (roleId != null && componentIds.contains(component.getId())) { + component.setSelected(true); + } + }); + return urlDTOs; + } + + /** + * 分类角色拥有的资源id(菜单/组件), + * + * @param roleId + * @param urlIds + * @param componentIds + * @author sr on 2019-10-16 + */ + private void distinctResource(Long roleId, Set urlIds, Set componentIds) { + List allocatedRoleIdList = Lists.newLinkedList(); + allocatedRoleIdList.add(roleId); + if (roleId == null) { + //当前登录人 + Long loginUserId = UserContextHolder.getLoginUserId(); + //查询当前用户已分配的角色 + RoleQuery roleQuery = RoleQuery.builder().userId(loginUserId).build(); + allocatedRoleIdList = ucRoleMapper.selectAllocatedRoleIdListByUserId(roleQuery); + } + if (CollectionUtils.isNotEmpty(allocatedRoleIdList)) { + List> resources = + ucPermissionService.listResourceIdTypeByRoleId(allocatedRoleIdList); + resources.forEach(resource -> { + if (PermissionConstants.RESOURCE_TYPE_URL + .equals(MapUtils.getString(resource, SecurityConstants.MAP_KEY_RESOURCE_TYPE))) { + urlIds.add(MapUtils.getLong(resource, SecurityConstants.MAP_KEY_RESOURCE_ID)); + return; + } + if (PermissionConstants.RESOURCE_TYPE_COMPONENT + .equals(MapUtils.getString(resource, SecurityConstants.MAP_KEY_RESOURCE_TYPE))) { + componentIds.add(MapUtils.getLong(resource, SecurityConstants.MAP_KEY_RESOURCE_ID)); + return; + } + }); + } + } + + @Override + public List listUrlDTO(Integer systemCode, Long orgId) { + /*Assert.notNull( + Arrays.stream(SystemCodeEnum.values()).filter(code -> code.getCode().equals(systemCode)) + .findFirst().orElse(null), + "应用不存在");*/ + return ucUrlMapper.listUrlDTO(systemCode, + OrgConstants.PLATFORM_ORG_ID.equals(orgId) ? null : orgId); + } + + @Override + public List listComponentDTO(Integer systemCode, Long orgId) { + /*Assert.notNull( + Arrays.stream(SystemCodeEnum.values()).filter(code -> code.getCode().equals(systemCode)) + .findFirst().orElse(null), + "应用不存在");*/ + return ucComponentMapper.listComponentDTO(systemCode, + OrgConstants.PLATFORM_ORG_ID.equals(orgId) ? null : orgId); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/service/impl/UcPermissionServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/authority/service/impl/UcPermissionServiceImpl.java new file mode 100644 index 0000000..1f8e672 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/service/impl/UcPermissionServiceImpl.java @@ -0,0 +1,38 @@ +package com.senmesh.usercenter.authority.service.impl; + +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.senmesh.common.AlitaResult; +import com.senmesh.usercenter.authority.dao.UcPermissionMapper; +import com.senmesh.usercenter.authority.dto.ComponentPermissionDTO; +import com.senmesh.usercenter.authority.dto.PermissionQueryDTO; +import com.senmesh.usercenter.authority.dto.UrlPermissionDTO; +import com.senmesh.usercenter.authority.service.UcPermissionService; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class UcPermissionServiceImpl implements UcPermissionService { + + private final UcPermissionMapper ucPermissionMapper; + + @Override + public List listComponent(PermissionQueryDTO permissionQueryDTO) { + return ucPermissionMapper.findComponent(permissionQueryDTO); + } + + @Override + public AlitaResult> listUrl(PermissionQueryDTO permissionQueryDTO) { + return AlitaResult.success(ucPermissionMapper.findUrl(permissionQueryDTO)); + } + + @Override + public List> listResourceIdTypeByRoleId(List roleIds) { + return ucPermissionMapper.listResourceIdTypeByRoleId(roleIds); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/service/impl/UcRoleAllocationServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/authority/service/impl/UcRoleAllocationServiceImpl.java new file mode 100644 index 0000000..6eb1d12 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/service/impl/UcRoleAllocationServiceImpl.java @@ -0,0 +1,117 @@ +package com.senmesh.usercenter.authority.service.impl; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.google.common.collect.Lists; +import com.senmesh.common.AlitaResult; +import com.senmesh.common.exception.util.ExceptionUtils; +import com.senmesh.usercenter.authority.dao.UcRoleAllocationMapper; +import com.senmesh.usercenter.authority.dao.UcRoleMapper; +import com.senmesh.usercenter.authority.dto.RoleAllocationDTO; +import com.senmesh.usercenter.authority.entity.RoleAllocation; +import com.senmesh.usercenter.authority.service.UcRoleAllocationService; +import com.senmesh.usercenter.constants.SecurityConstants; +import com.senmesh.usercenter.constants.SecurityExceptionMsg; +import com.senmesh.usercenter.dto.AllocatedBusinessRoleQueryDTO; +import com.senmesh.usercenter.dto.AllocationDTO; +import com.senmesh.usercenter.dto.RoleDTO; +import com.senmesh.usercenter.dto.UserAllocateRoleDTO; +import com.senmesh.usercenter.user.service.OrgUserService; +import com.senmesh.usercenter.utils.RoleUtils; + +import lombok.RequiredArgsConstructor; + +/** + * 角色分配 + * + * @author sr on 2019-10-17 + */ +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class UcRoleAllocationServiceImpl implements UcRoleAllocationService { + + private final UcRoleMapper ucRoleMapper; + + private final OrgUserService orgUserService; + + private final UcRoleAllocationMapper ucRoleAllocationMapper; + + @Override + @Transactional(rollbackFor = RuntimeException.class) + public AllocationDTO getBusinessRoles(Long orgId, Long userId) { + // 校验机构下是否存在用户 + ExceptionUtils.throwBusinessException(orgUserService.existOrgUser(orgId, userId), + SecurityExceptionMsg.ORG_USER_NOT_EXIST); + // 查询用户已经分配的角色id + Set roleIds = + ucRoleAllocationMapper.findRoleIds(SecurityConstants.ALLOCATION_TYPE_USER, userId); + // 查询机构下的角色(启用/业务角色)列表 + List roleDTOs = + ucRoleMapper.queryOrgRoles(orgId, RoleUtils.getBusinessRoleDTO(), null); + Map> roleDTOMap = roleDTOs.stream() + .collect(Collectors.partitioningBy(roleDTO -> roleIds.contains(roleDTO.getId()))); + return new AllocationDTO<>(roleDTOMap.get(true), roleDTOMap.get(false)); + } + + @Override + public List getAllocatedBusinessRoles(AllocatedBusinessRoleQueryDTO queryDTO) { + // 校验机构下是否存在用户 + ExceptionUtils.throwBusinessException(orgUserService.existOrgUser(queryDTO.getOrgId(), queryDTO.getAllocationId()), + SecurityExceptionMsg.ORG_USER_NOT_EXIST); + return ucRoleAllocationMapper.getAllocatedBusinessRoles(queryDTO); + } + + @Override + @Transactional(rollbackFor = RuntimeException.class) + public void allocateBusinessRoles(Long orgId, Long userId, + UserAllocateRoleDTO userAllocateRoleDTO, + Long operateUserId) { + // 校验机构下是否存在用户 + ExceptionUtils.throwBusinessException(orgUserService.existOrgUser(orgId, userId), + SecurityExceptionMsg.ORG_USER_NOT_EXIST); + boolean allocated = Boolean.TRUE.equals(userAllocateRoleDTO.getAllocated()); + // 查询机构下的角色(启用/业务角色)id列表 + Set orgRoleIds = ucRoleMapper.queryOrgRoleIds(orgId, RoleUtils.getBusinessRoleDTO()); + // 过滤掉不在范围的id + List roleAllocations = allocated ? Lists.newArrayList() : null; + List deleteRoleIds = allocated ? null : Lists.newArrayList(); + + // 查询用户已经分配的角色id + Set allocationRoleIds = + ucRoleAllocationMapper.findRoleIds(SecurityConstants.ALLOCATION_TYPE_USER, userId); + + userAllocateRoleDTO.getRoleIds().stream().filter(roleId -> orgRoleIds.contains(roleId)) + .forEach(roleId -> { + if (allocated && !allocationRoleIds.contains(roleId)) { + roleAllocations + .add(RoleAllocation.builder().orgId(orgId).roleId(roleId).allocationId(userId) + .allocationType(SecurityConstants.ALLOCATION_TYPE_USER).build()); + } else if ((!allocated && allocationRoleIds.contains(roleId))) { + deleteRoleIds.add(roleId); + } + }); + if (allocated) { + ExceptionUtils.throwBusinessException(CollectionUtils.isEmpty(roleAllocations), + SecurityExceptionMsg.ALLOCATE_ROLES_EMPTY); + ucRoleAllocationMapper.saveEntites(roleAllocations, operateUserId); + } else { + ExceptionUtils.throwBusinessException(CollectionUtils.isEmpty(deleteRoleIds), + SecurityExceptionMsg.UNALLOCATE_ROLES_EMPTY); + ucRoleAllocationMapper.deleteByRoleIds(SecurityConstants.ALLOCATION_TYPE_USER, userId, + deleteRoleIds, operateUserId); + } + } + + @Override + public AlitaResult> findByUserId(Long userId) { + return AlitaResult.success(ucRoleAllocationMapper.findByUserId(userId)); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/authority/service/impl/UcRoleServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/authority/service/impl/UcRoleServiceImpl.java new file mode 100644 index 0000000..ea05f75 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/authority/service/impl/UcRoleServiceImpl.java @@ -0,0 +1,381 @@ +package com.senmesh.usercenter.authority.service.impl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.authority.dao.UcPermissionMapper; +import com.senmesh.usercenter.authority.dao.UcRoleAllocationMapper; +import com.senmesh.usercenter.authority.dao.UcRoleMapper; +import com.senmesh.usercenter.authority.dto.PermissionOperateDTO; +import com.senmesh.usercenter.authority.entity.Permission; +import com.senmesh.usercenter.authority.entity.Role; +import com.senmesh.usercenter.authority.entity.RoleAllocation; +import com.senmesh.usercenter.authority.service.UcRoleService; +import com.senmesh.usercenter.cache.SecurityCacheUtils; +import com.senmesh.usercenter.constants.RoleConstants; +import com.senmesh.usercenter.constants.SecurityConstants; +import com.senmesh.usercenter.constants.SecurityExceptionMsg; +import com.senmesh.usercenter.dto.AllocationRoleDTO; +import com.senmesh.usercenter.dto.AllocationRoleUserDTO; +import com.senmesh.usercenter.dto.CheckKeyDTO; +import com.senmesh.usercenter.dto.RoleDTO; +import com.senmesh.usercenter.enums.ResourceType; +import com.senmesh.usercenter.query.RoleQuery; +import com.senmesh.usercenter.resource.dao.UcUrlMapper; +import com.senmesh.usercenter.utils.RoleUtils; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * @author Jerry.li + * @description 角色服务 + * @date 2020/3/26 + */ +@Slf4j +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +// TODO 目前只有本地引用,需提供cloud调用,然后放开注释 +// @ConditionalOnProperty(name = SecurityConstants.PROP_KEY_SECURITY_USELOCAL, havingValue = "true", +// matchIfMissing = true) +public class UcRoleServiceImpl implements UcRoleService { + + private final UcUrlMapper ucUrlMapper; + + private final UcRoleMapper ucRoleMapper; + + private final UcPermissionMapper ucPermissionMapper; + + private final UcRoleAllocationMapper ucRoleAllocationMapper; + + @Override + @Transactional(rollbackFor = RuntimeException.class) + public void createOrgRole(Long orgId, RoleDTO roleDTO) { + // 校验机构下角色名称 + Assert.isTrue( + ucRoleMapper.existRoleName(orgId, roleDTO.getName(), null) == 0, + SecurityExceptionMsg.ROLE_NAME_EXIST); + if (StringUtils.isBlank(roleDTO.getStandardType())) { + roleDTO.setStandardType(RoleConstants.STANDARD_ROLE_TYPE_ELSE); + } + Role role = RoleUtils.toCreateRole(orgId, roleDTO, RoleConstants.ROLE_TYPE_BUSINESS); + + ucRoleMapper.saveEntity(role, UserContextHolder.getExistLoginUserId()); + + roleDTO.setId(role.getId()); + roleDTO.setCreateTime(role.getCreateTime()); + // 刷新缓存 + SecurityCacheUtils.flushAll(); + } + + @Override + @Transactional(rollbackFor = RuntimeException.class) + public void updateOrgRole(Long orgId, RoleDTO roleDTO) { + Role byId = ucRoleMapper.getById(roleDTO.getId()); + Assert.isTrue(byId != null && orgId.equals(byId.getOrgId()), "角色信息不存在"); + + if (!StringUtils.equals(roleDTO.getName(), byId.getName())) { + // 校验机构下角色名称 + Assert.isTrue( + ucRoleMapper.existRoleName(orgId, roleDTO.getName(), roleDTO.getId()) == 0, + SecurityExceptionMsg.ROLE_NAME_EXIST); + } + + if (StringUtils.isBlank(roleDTO.getStandardType())) { + roleDTO.setStandardType(RoleConstants.STANDARD_ROLE_TYPE_ELSE); + } + + Assert.isTrue( + ucRoleMapper.updateEntitySelective( + RoleUtils.toUpdateRole(roleDTO), UserContextHolder.getExistLoginUserId()) + == 1, + SecurityExceptionMsg.UPDATE_NOT_EXIST); + // 刷新缓存 + SecurityCacheUtils.flushAll(); + } + + @Override + @Transactional(rollbackFor = RuntimeException.class) + public void deleteOrgRole(Long orgId, Long roleId) { + Assert.isTrue( + ucRoleMapper.deleteEntity( + Role.builder().id(roleId).build(), UserContextHolder.getExistLoginUserId()) + == 1, + SecurityExceptionMsg.UPDATE_NOT_EXIST); + // 刷新缓存 + SecurityCacheUtils.flushAll(); + } + + @Override + @Transactional(rollbackFor = RuntimeException.class) + public void queryOrgRole(Long orgId, RoleDTO roleDTO, Page page) { + roleDTO.setType(RoleConstants.ROLE_TYPE_BUSINESS); + ucRoleMapper.queryOrgRoles(orgId, roleDTO, page); + } + + @Override + public List queryOrgRole(Long orgId) { + RoleDTO roleDTO = RoleDTO.builder().standardType(RoleConstants.STANDARD_ROLE_TYPE_PERSONCHARGE).build(); + return ucRoleMapper.queryOrgRoles(orgId, roleDTO, null); + } + + @Override + public List findCheckedKeysByRoleIds(Long orgId) { + List roleDTOS = ucRoleMapper.queryOrgRoleList(orgId); + List rs = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(roleDTOS)) { + Set roleIds = roleDTOS.stream().map(RoleDTO::getId).collect(Collectors.toSet()); + rs = ucPermissionMapper.findCheckedKeysByRoleIds(roleIds); + } + return rs; + } + + @Override + public void queryPlatformAdminRoleList(RoleQuery query) { + ucRoleMapper.selectPlatformAdminRoleList(query); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void roleUrlAllocation( + PermissionOperateDTO permissionDTO, Long operateUserId) { + Long roleId = permissionDTO.getRoleId(); + String attribute = "ROLE_" + roleId; + //本次所有选择的菜单 + List selectedIdList = permissionDTO.getResourceIdList(); + if(CollectionUtils.isEmpty(selectedIdList)){ + // 取消之前全部分配资源列表并退出 + ucPermissionMapper.deletePermissionByRoleId(operateUserId, roleId); + return; + } + // 查询出该角色已分配的资源ID列表 + Set oldResourceIdSet = + ucPermissionMapper.selectResourceIdByRoleId(roleId, + RoleConstants.ROLE_TYPE_BUSINESS); + //过滤出需要删除的(原本已存在,不在本次所选菜单中) + Set removeIdList= + oldResourceIdSet.stream().filter(resourceId ->!selectedIdList.contains(resourceId)).collect(Collectors.toSet()); + //过滤出新增的 + selectedIdList.removeAll(oldResourceIdSet); + // 本次新增 + if (CollectionUtils.isNotEmpty(selectedIdList)) { + // 查询出父级菜单ID + Set parentIds = ucUrlMapper.selectParentIdByResourceIds(selectedIdList); + parentIds.addAll(selectedIdList); + log.info("-------本次新增资源ID:{}", parentIds.toString()); + parentIds.forEach( + resourceId -> { + Permission permission = + Permission.builder() + .roleId(roleId) + .resourceId(resourceId) + .attribute(attribute) + .platformCode(permissionDTO.getPlatformCode()) + .orgId(UserContextHolder.getLoginOrgId()) + .resourceType(ResourceType.RESOURCE_MENU_TYPE.getType()) + .build(); + ucPermissionMapper.saveEntity(permission, operateUserId); + }); + } + if(CollectionUtils.isNotEmpty(removeIdList)){ + this.removeResource(removeIdList,roleId,UserContextHolder.getLoginUserId()); + } + } + + /** + * 检查分配角色 + * + * @param oldRoles 旧的角色 + * @param newRoles 新角色 + * @param cannotDeletedRoles 不能删除角色 + */ + private void checkAllocationRole(List oldRoles, List newRoles, Set cannotDeletedRoles) { + Assert.isTrue(!(CollectionUtils.containsAny(oldRoles, cannotDeletedRoles) && !CollectionUtils.containsAny(newRoles, cannotDeletedRoles)), + "当前操作包含的销售角色不是无关联状态"); + } + + @Override + public AlitaResult userAllocationRole( + AllocationRoleDTO allocationRoleDTO, Long operateUserId) { + Long userId = allocationRoleDTO.getUserId(); + // 查询用户已分配的角色ID + RoleQuery query = RoleQuery.builder() + .userId(userId) + .platformCode(allocationRoleDTO.getPlatformCode()) + .build(); + List allocatedRoleIdList = ucRoleMapper.selectAllocatedRoleIdListByUserId(query); + + // 本次分配 + List tempRoleIdList = allocationRoleDTO.getAllocatedRoleIdList(); + + checkAllocationRole(allocatedRoleIdList, tempRoleIdList, ucRoleMapper.getSellerRoleCanNotBeDeleted(userId)); + + if (CollectionUtils.isEmpty(tempRoleIdList)) { + // 取消已分配的全部权限 + removeAllocatedRole(allocatedRoleIdList, userId, operateUserId); + return AlitaResult.success(true); + } + + // 筛选出本次取消和新分配的角色ID + if (CollectionUtils.isNotEmpty(allocatedRoleIdList)) { + List cancelAllocationRoleIdList = new ArrayList<>(); + allocatedRoleIdList.forEach( + oldRoleId -> { + if (!tempRoleIdList.contains(oldRoleId)) { + cancelAllocationRoleIdList.add(oldRoleId); + } + }); + + removeAllocatedRole(cancelAllocationRoleIdList, userId, operateUserId); + // 过滤掉本次取消的角色ID + allocatedRoleIdList.removeAll(cancelAllocationRoleIdList); + // 过滤已分配有效的角色ID + tempRoleIdList.removeAll(allocatedRoleIdList); + } + + // 本次新增 + if (CollectionUtils.isNotEmpty(tempRoleIdList)) { + tempRoleIdList.forEach( + roleId -> { + RoleAllocation allocation = + RoleAllocation.builder() + .roleId(roleId) + .allocationId(userId) + .createBy(operateUserId) + .allocationType(SecurityConstants.ALLOCATION_TYPE_USER) // TODO: 其他类型待确认 + .build(); + ucRoleAllocationMapper.saveEntity(allocation, operateUserId); + }); + } + // 刷新缓存 + SecurityCacheUtils.flushAll(); + return AlitaResult.success(true); + } + + + @Override + public AlitaResult roleAllocationUser(AllocationRoleUserDTO dto ) { + for (Long userId : dto.getUserIds()) { + // 查询用户已分配的角色ID + RoleQuery query = RoleQuery.builder() + .userId(userId) + .platformCode(dto.getPlatformCode()) + .build(); + List allocatedRoleIdList = ucRoleMapper.selectAllocatedRoleIdListByUserId(query); + // 已分配过则跳过 + if(allocatedRoleIdList.contains(dto.getRoleId())){ + continue; + } + // 检查分配角色 + checkAllocationRole(allocatedRoleIdList, Arrays.asList(dto.getRoleId()), ucRoleMapper.getSellerRoleCanNotBeDeleted(userId)); + // 本次新增 + RoleAllocation allocation = + RoleAllocation.builder() + .roleId(dto.getRoleId()) + .allocationId(userId) + .allocationType(SecurityConstants.ALLOCATION_TYPE_USER) // TODO: 其他类型待确认 + .build(); + ucRoleAllocationMapper.saveEntity(allocation); + } + // 刷新缓存 + SecurityCacheUtils.flushAll(); + return AlitaResult.success(true); + } + + + @Override + public void removelocationRole(AllocationRoleUserDTO allocationRoleDTO) { + // 取消已分配的权限 + allocationRoleDTO.getUserIds().stream().forEach( userId -> { + removeAllocatedRole(Arrays.asList(allocationRoleDTO.getRoleId()), userId, UserContextHolder.getExistLoginOrgId()); + }); + SecurityCacheUtils.flushAll(); + } + + @Override + public AlitaResult roleEnable(Long roleId, Boolean enable, Long operateUserId) { + Role role = Role.builder().id(roleId).enabled(enable).build(); + int count = ucRoleMapper.updateEntitySelective(role, operateUserId); + // 刷新缓存 + SecurityCacheUtils.flushAll(); + return AlitaResult.success(count > 0); + } + + @Override + public AlitaResult queryUserAllocationRoleList(RoleQuery query) { + Long userId = query.getUserId(); + AllocationRoleDTO allocationRoleDTO = new AllocationRoleDTO(); + // 查询已分配的角色ID + List allocatedRoleIdList = ucRoleMapper.selectAllocatedRoleIdListByUserId(query); + allocationRoleDTO.setAllocatedRoleIdList(allocatedRoleIdList); + + // 查询用户对应的机构信息 +// OrganizeDTO organizeDTO = ucOrgMapper.selectOrgInfoByUserId(userId); +// ExceptionUtils.throwBusinessException(organizeDTO == null, SecurityExceptionMsg.ORG_NOT_EXIST); + + List roleDTOList = ucRoleMapper.selectPlatformUserUnallocatedRoleList(query); + allocationRoleDTO.setUnallocatedRoleList(roleDTOList); + return AlitaResult.success(allocationRoleDTO); + } + + @Override + public void + cleanRoleComponentAndInterface() { + ucRoleMapper.cleanRoleComponent(UserContextHolder.getLoginUserId()); + ucRoleMapper.cleanRoleInterface(UserContextHolder.getLoginUserId()); + } + + /** + * 移除已分配的资源 + * + * @param resourceIdSet + * @param roleId + * @param operateUserId + */ + private void removeResource(Set resourceIdSet, Long roleId, Long operateUserId) { + resourceIdSet.forEach( + resourceId -> { + log.info( + "-------本次取消的资源分配信息roleId:{}, resourceId: {}, operateUserId:{}", + roleId, + resourceId, + operateUserId); + ucPermissionMapper.deletePermissionByRoleIdAndResourceId( + operateUserId, roleId, resourceId); + }); + } + + /** + * 取消已分配的角色 + * + * @param roleIdList + * @param userId + * @param operateUserId + */ + private void removeAllocatedRole(List roleIdList, Long userId, Long operateUserId) { + if (CollectionUtils.isNotEmpty(roleIdList)) { + roleIdList.forEach( + roleId -> { + log.info( + "-------本次取消的角色分配roleId:{}, userId: {}, operateUserId:{}", + roleId, + userId, + operateUserId); + ucRoleAllocationMapper.deleteUserAllocatedRole(operateUserId, roleId, userId); + }); + } + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/cache/CacheConfig.java b/backend/src/main/java/com/senmesh/usercenter/cache/CacheConfig.java new file mode 100644 index 0000000..c41fe39 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/cache/CacheConfig.java @@ -0,0 +1,14 @@ +package com.senmesh.usercenter.cache; + +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Configuration; + +/** + * 缓存配置类 + * @author sr on 2019-09-11 + */ +@Configuration +@EnableCaching +public class CacheConfig { + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/cache/SecurityCacheAllEvict.java b/backend/src/main/java/com/senmesh/usercenter/cache/SecurityCacheAllEvict.java new file mode 100644 index 0000000..c0aa22f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/cache/SecurityCacheAllEvict.java @@ -0,0 +1,32 @@ +package com.senmesh.usercenter.cache; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Caching; + +import com.senmesh.usercenter.constants.SecurityConstants; + +/** + * 清除所有security缓存 + * + * @author on 2019-11-05 + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Caching(evict = { + @CacheEvict(cacheNames = { + SecurityConstants.CacheName.RESOURCE_TREE_CACHE_KEY, + SecurityConstants.CacheName.USER_GRANTED_AUTHORITY_CACHE_KEY, + SecurityConstants.CacheName.URL_FILTER_ATTRIBUTE_MAP_CACHE_KEY, + SecurityConstants.CacheName.URL_ATTRIBUTE_MAP_CACHE_KEY, + SecurityConstants.CacheName.COMPONENT_ATTRIBUTE_MAP_CACHE_KEY + }, allEntries = true) +}) +public @interface SecurityCacheAllEvict { + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/cache/SecurityCacheEvict.java b/backend/src/main/java/com/senmesh/usercenter/cache/SecurityCacheEvict.java new file mode 100644 index 0000000..0daa0b6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/cache/SecurityCacheEvict.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.cache; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Caching; + +import com.senmesh.usercenter.constants.SecurityConstants; + +/** + * 清除缓存 + * + * @author on 2019-11-05 + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Caching(evict = { + @CacheEvict(cacheNames = SecurityConstants.CacheName.RESOURCE_TREE_CACHE_KEY, + key = SecurityCacheEvict.SYSTEM_ORG_ALL), + @CacheEvict(cacheNames = SecurityConstants.CacheName.USER_GRANTED_AUTHORITY_CACHE_KEY, + key = SecurityCacheEvict.ORG_ALL), + @CacheEvict(cacheNames = SecurityConstants.CacheName.URL_FILTER_ATTRIBUTE_MAP_CACHE_KEY, + key = SecurityCacheEvict.SYSTEM_ALL), + @CacheEvict(cacheNames = SecurityConstants.CacheName.URL_ATTRIBUTE_MAP_CACHE_KEY, + key = SecurityCacheEvict.SYSTEM_ORG), + @CacheEvict(cacheNames = SecurityConstants.CacheName.COMPONENT_ATTRIBUTE_MAP_CACHE_KEY, + key = SecurityCacheEvict.SYSTEM_ORG), +}) +public @interface SecurityCacheEvict { + + String SYSTEM_ORG = "#systemCode + ':' + #orgId"; + String SYSTEM_ORG_ALL = "#systemCode + ':' + #orgId + '*'"; + String SYSTEM_ALL = "#systemCode + '*'"; + String ORG_ALL = "#orgId + '*'"; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/cache/SecurityCacheService.java b/backend/src/main/java/com/senmesh/usercenter/cache/SecurityCacheService.java new file mode 100644 index 0000000..0a237ef --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/cache/SecurityCacheService.java @@ -0,0 +1,17 @@ +package com.senmesh.usercenter.cache; + +import org.springframework.stereotype.Service; + +@Service +public class SecurityCacheService { + + @SecurityCacheEvict + public void evictSystemOrg(Integer systemCode, Long orgId) { + // do nothing... + } + + @SecurityCacheAllEvict + public void evictAll() { + // do nothing... + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/cache/SecurityCacheUtils.java b/backend/src/main/java/com/senmesh/usercenter/cache/SecurityCacheUtils.java new file mode 100644 index 0000000..2d7c186 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/cache/SecurityCacheUtils.java @@ -0,0 +1,67 @@ +package com.senmesh.usercenter.cache; + +import java.util.Set; + +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import com.google.common.collect.Sets; +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.common.util.UserContextHolder; + +/** + * security缓存工具类 + * + * @author sr on 2020-09-15 + */ +@Component +public class SecurityCacheUtils { + + private static SecurityCacheService securityCacheService; + + SecurityCacheUtils(SecurityCacheService securityCacheService) { + SecurityCacheUtils.securityCacheService = securityCacheService; + } + + /** + * 清除当前系统机构级缓存 + * + * @author sr on 2020-09-15 + */ + public static void flushCurrentSystemOrg() { + flushSystemOrg(null, UserContextHolder.getLoginOrgId()); + } + + /** + * 清除系统机构级缓存 + * + * @param systemCode + * @param orgId + * @author sr on 2020-09-15 + */ + public static void flushSystemOrg(Integer systemCode, Long orgId) { + flushSystemOrgs(systemCode, Sets.newHashSet(orgId)); + } + + + public static void flushSystemOrgs(Integer systemCode, Set orgIds) { + if (CollectionUtils.isEmpty(orgIds)) { + return; + } + if (systemCode == null) { + systemCode = EnvironmentUtils.getSystemCode(); + } + for (Long orgId : orgIds) { + securityCacheService.evictSystemOrg(systemCode, orgId); + } + } + + /** + * 清除所有缓存 + * @author sr on 2020-09-15 + */ + public static void flushAll() { + securityCacheService.evictAll(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/common/constant/CodeTypeEnum.java b/backend/src/main/java/com/senmesh/usercenter/common/constant/CodeTypeEnum.java new file mode 100644 index 0000000..0859a96 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/common/constant/CodeTypeEnum.java @@ -0,0 +1,24 @@ +package com.senmesh.usercenter.common.constant; + +import com.senmesh.codegenerator.pojo.CodeParam; + +/** + * 编码类型 + * @author sr on 2019-12-06 + */ +public enum CodeTypeEnum { + + ORG(CodeParam.builder().type("O").build()), + + ; + private CodeParam codeParam; + + private CodeTypeEnum(CodeParam codeParam) { + this.codeParam = codeParam; + } + + public CodeParam getCodeParam() { + return this.codeParam; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/common/constant/XxlJobHandlerConstants.java b/backend/src/main/java/com/senmesh/usercenter/common/constant/XxlJobHandlerConstants.java new file mode 100644 index 0000000..09dd221 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/common/constant/XxlJobHandlerConstants.java @@ -0,0 +1,24 @@ +package com.senmesh.usercenter.common.constant; + +/** + * 任务调度常量类 + * + * @author sr on 2020-11-25 + */ +public interface XxlJobHandlerConstants { + + /** + * 统计机构最近登录时间 HCY + **/ + String STATISTIC_ORG_LAST_LOGIN_TIME = "statisticOrgLastLoginTimeHandler"; + + /** + * 授权订阅用户列表 + **/ + String AUTH_SUBSCRIBE_USER_LIST = "authSubscribeUserListHandler"; + /** + * 用户注销通知工作 + */ + String USER_CANCEL_NOTIFY_JOB = "userCancelNotifyHandler"; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/common/controller/SlickParamController.java b/backend/src/main/java/com/senmesh/usercenter/common/controller/SlickParamController.java new file mode 100644 index 0000000..5c7b22d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/common/controller/SlickParamController.java @@ -0,0 +1,55 @@ +package com.senmesh.usercenter.common.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +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; + +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.common.dto.SlickParamCreateDTO; +import com.senmesh.usercenter.common.dto.SlickParamDTO; +import com.senmesh.usercenter.common.dto.SlickParamQueryDTO; +import com.senmesh.usercenter.common.service.SlickParamService; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2022-01-11 + */ +@RestController +@RequestMapping("slick_param") +@Api(tags = "圆滑的参数") +public class SlickParamController { + + @Autowired + private SlickParamService slickParamService; + + @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create( + @Validated @RequestBody SlickParamCreateDTO slickParamCreateDTO){ + return AlitaResult.success(slickParamService.create(slickParamCreateDTO)); + } + + @DeleteMapping("/remove/{id}") + @ApiOperation("删除") + public AlitaResult remove(@PathVariable Long id){ + slickParamService.remove(id); + return AlitaResult.success(true); + } + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(SlickParamQueryDTO slickParamQueryDTO){ + slickParamService.page(slickParamQueryDTO); + return AlitaResult.success(slickParamQueryDTO.getPageResult()); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/common/controller/SmsController.java b/backend/src/main/java/com/senmesh/usercenter/common/controller/SmsController.java new file mode 100644 index 0000000..7ac6d6f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/common/controller/SmsController.java @@ -0,0 +1,48 @@ +package com.senmesh.usercenter.common.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.usercenter.user.phone.dto.PhoneCodeDTO; +import com.senmesh.usercenter.user.phone.dto.PhoneCodeSmsDTO; +import com.senmesh.usercenter.user.phone.dto.SmsSimpleSendDTO; +import com.senmesh.usercenter.user.phone.provider.simple.ISimpleSms; +import com.senmesh.usercenter.user.phone.util.PhoneCodeUtils; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author sr on 2022-09-26 + */ +@RestController +@Api(tags = "短信") +public class SmsController { + + @Autowired + private ISimpleSms simpleSms; + + @PostMapping("sms/send/simple/async") + @ApiOperation("发送短信") + public AlitaResult simpleSms(@Validated @RequestBody SmsSimpleSendDTO sendDTO) { + simpleSms.sendAsync(sendDTO); + return AlitaResult.success(); + } + +// @PostMapping("anon/sms/send") + @ApiOperation("获取验证码-不同类型") + public AlitaResult sms(@Validated @RequestBody PhoneCodeSmsDTO phoneCodeSmsDTO) { + PhoneCodeUtils.send(phoneCodeSmsDTO); + return AlitaResult.success(); + } + + @PostMapping("sms/match") + @ApiOperation("获取验证码-匹配验证") + public AlitaResult match(@Validated @RequestBody PhoneCodeDTO phoneCodeDTO) { + PhoneCodeUtils.matchBiz(phoneCodeDTO); + return AlitaResult.success(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/common/dao/SlickParamMapper.java b/backend/src/main/java/com/senmesh/usercenter/common/dao/SlickParamMapper.java new file mode 100644 index 0000000..b70d815 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/common/dao/SlickParamMapper.java @@ -0,0 +1,28 @@ +package com.senmesh.usercenter.common.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.usercenter.common.dto.SlickParamDTO; +import com.senmesh.usercenter.common.dto.SlickParamQueryDTO; +import com.senmesh.usercenter.common.entity.SlickParam; +import com.senmesh.tkmybatis.mybatis.MyMapper; + +/** + * 圆滑的参数 + * + * @author sr on 2022-01-11 + */ +public interface SlickParamMapper extends MyMapper { + + /** + * 查询 + * + * @param slickParamQueryDTO + * @return + * @author sr on 2022-01-11 + */ + List listSlickParamDTO(@Param("param") SlickParamQueryDTO slickParamQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/common/dto/SlickParamCreateDTO.java b/backend/src/main/java/com/senmesh/usercenter/common/dto/SlickParamCreateDTO.java new file mode 100644 index 0000000..629fbb9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/common/dto/SlickParamCreateDTO.java @@ -0,0 +1,33 @@ +package com.senmesh.usercenter.common.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2022-01-11 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "圆滑的参数创建") +public class SlickParamCreateDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("参数属性") + @NotNull(message = "参数属性不能为空") + private Object paramData; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/common/dto/SlickParamDTO.java b/backend/src/main/java/com/senmesh/usercenter/common/dto/SlickParamDTO.java new file mode 100644 index 0000000..ab91251 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/common/dto/SlickParamDTO.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.common.dto; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2022-01-11 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "圆滑的参数") +public class SlickParamDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("唯一码-uuid") + private String uniqueCode; + @ApiModelProperty("query升序值(格式:**=**&**=**)") + private String queryValue; + @ApiModelProperty("json数据") + private String paramData; + @ApiModelProperty("哈希值") + private Integer hashCode; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/common/dto/SlickParamQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/common/dto/SlickParamQueryDTO.java new file mode 100644 index 0000000..bd07c5d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/common/dto/SlickParamQueryDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.common.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; + +import com.senmesh.common.dto.PageQueryDTO; + +/** + * @author sr on 2022-01-11 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "圆滑的参数查询条件") +public class SlickParamQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + @ApiModelProperty("唯一码-uuid") + private String uniqueCode; + @ApiModelProperty("query升序值(格式:**=**&**=**)") + private String queryValue; + @ApiModelProperty("哈希值") + private Integer hashCode; +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/common/entity/SlickParam.java b/backend/src/main/java/com/senmesh/usercenter/common/entity/SlickParam.java new file mode 100644 index 0000000..f5ac7c2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/common/entity/SlickParam.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.common.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 圆滑的参数 + * + * @author sr on 2022-01-11 + */ +@TableName("uc_slick_param") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class SlickParam extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 唯一码-uuid **/ + private String uniqueCode; + /** query升序值(格式:**=**&**=**) **/ + private String queryValue; + /** json数据 **/ + private String paramData; + /** 哈希值 **/ + private Integer hashCode; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/common/mapper/SlickParamMapper.xml b/backend/src/main/java/com/senmesh/usercenter/common/mapper/SlickParamMapper.xml new file mode 100644 index 0000000..3357ffb --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/common/mapper/SlickParamMapper.xml @@ -0,0 +1,25 @@ + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/common/mapstruct/SlickParamMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/common/mapstruct/SlickParamMapMapper.java new file mode 100644 index 0000000..8b00d65 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/common/mapstruct/SlickParamMapMapper.java @@ -0,0 +1,30 @@ +package com.senmesh.usercenter.common.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.common.dto.SlickParamDTO; +import com.senmesh.usercenter.common.entity.SlickParam; + +/** + * @author sr on 2022-01-11 + */ +@Mapper +public interface SlickParamMapMapper { + + SlickParamMapMapper INSTANCE = + Mappers.getMapper(SlickParamMapMapper.class); + + /** + * dto to entity + * + * @param slickParamDto + * @return + * @author sr on 2022-01-11 + */ + SlickParam toEntity( + SlickParamDTO slickParamDto); + + SlickParamDTO toDto(SlickParam slickParam); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/common/mq/constant/UcMqConstants.java b/backend/src/main/java/com/senmesh/usercenter/common/mq/constant/UcMqConstants.java new file mode 100644 index 0000000..8c510ac --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/common/mq/constant/UcMqConstants.java @@ -0,0 +1,22 @@ +package com.senmesh.usercenter.common.mq.constant; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.util.EnvironmentUtils; + +/** + * mq常量类(routingkey) + * @author sr on 2021-01-05 + */ +public interface UcMqConstants { + + /** 用户中心系统mq前缀 **/ + String MQ_PREFIX = EnvironmentUtils.getApplicationName() + CommonConstants.POINT; + + /** 修改手机号 **/ + String CHANGE_PHONE = UcMqConstants.MQ_PREFIX + "change_phone"; + + /** 修改手机号 关联简历 **/ + String CHANGE_PHONE_RESUME = UcMqConstants.MQ_PREFIX + "change_phone_resume"; + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/common/mybatis/MyBatisConfig.java b/backend/src/main/java/com/senmesh/usercenter/common/mybatis/MyBatisConfig.java new file mode 100644 index 0000000..72341e7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/common/mybatis/MyBatisConfig.java @@ -0,0 +1,24 @@ +package com.senmesh.usercenter.common.mybatis; + +import com.senmesh.mybatis.handle.BaseEnumTypeHandler; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.type.TypeHandlerRegistry; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; + +/** + * @description: + * @author: chenyun.huang + * @create: 2020-04-13 14:53 + **/ +@Configuration +public class MyBatisConfig { + + @Autowired + public void myInterceptor(SqlSessionFactory sqlSessionFactory) { + // 取得类型转换注册器 + TypeHandlerRegistry typeHandlerRegistry = sqlSessionFactory.getConfiguration().getTypeHandlerRegistry(); + // 注册默认枚举转换器 + typeHandlerRegistry.setDefaultEnumTypeHandler(BaseEnumTypeHandler.class); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/common/service/SlickParamService.java b/backend/src/main/java/com/senmesh/usercenter/common/service/SlickParamService.java new file mode 100644 index 0000000..19c3810 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/common/service/SlickParamService.java @@ -0,0 +1,70 @@ +package com.senmesh.usercenter.common.service; + +import java.util.List; + +import com.senmesh.usercenter.common.dto.SlickParamQueryDTO; +import com.senmesh.usercenter.common.dto.SlickParamCreateDTO; +import com.senmesh.usercenter.common.dto.SlickParamDTO; + +/** + * 圆滑的参数 + * + * @author sr on 2022-01-11 + */ +public interface SlickParamService { + + /** + * 新增 + * + * @param slickParamCreateDTO + * @return + * @author sr on 2022-01-11 + */ + SlickParamDTO create(SlickParamCreateDTO slickParamCreateDTO); + + /** + * 删除 + * + * @param id + * @author sr on 2022-01-11 + */ + void remove(Long id); + + /** + * 查询 + * + * @param slickParamQueryDTO + * @return + * @author sr on 2022-01-11 + */ + List list(SlickParamQueryDTO slickParamQueryDTO); + + /** + * 分页查询 + * + * @param slickParamQueryDTO + * @return + * @author sr on 2022-01-11 + */ + void page(SlickParamQueryDTO slickParamQueryDTO); + + /** + * 单个查询 + * + * @param slickParamQueryDTO + * @return + * @author sr on 2022-01-11 + */ + SlickParamDTO find(SlickParamQueryDTO slickParamQueryDTO); + + /** + * 转换参数对象 + * @param + * @param uniqueCode + * @param clazz + * @return + * @author sr on 2022-01-11 + */ + T parseCode(String uniqueCode, Class clazz); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/common/service/impl/SlickParamServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/common/service/impl/SlickParamServiceImpl.java new file mode 100644 index 0000000..9b7789d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/common/service/impl/SlickParamServiceImpl.java @@ -0,0 +1,89 @@ +package com.senmesh.usercenter.common.service.impl; + +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.common.util.ListUtil; +import com.senmesh.common.util.RandomUtils; +import com.senmesh.common.util.StrUtils; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.common.dao.SlickParamMapper; +import com.senmesh.usercenter.common.dto.SlickParamCreateDTO; +import com.senmesh.usercenter.common.dto.SlickParamDTO; +import com.senmesh.usercenter.common.dto.SlickParamQueryDTO; +import com.senmesh.usercenter.common.entity.SlickParam; +import com.senmesh.usercenter.common.mapstruct.SlickParamMapMapper; +import com.senmesh.usercenter.common.service.SlickParamService; + +/** + * @author sr on 2022-01-11 + */ +@Service +public class SlickParamServiceImpl implements SlickParamService { + + @Autowired + private SlickParamMapper slickParamMapper; + + @Override + @Transactional + public SlickParamDTO create(SlickParamCreateDTO slickParamCreateDTO) { + Object paramData = slickParamCreateDTO.getParamData(); + String queryValue = StrUtils.buildAscQueryValue(paramData); + Assert.notNull(queryValue, "无有效参数"); + Integer hashCode = queryValue.hashCode(); + SlickParamQueryDTO slickParamQueryDTO = + SlickParamQueryDTO.builder().queryValue(queryValue).hashCode(hashCode).build(); + SlickParamDTO slickParamDTO = find(slickParamQueryDTO); + if (slickParamDTO != null) { + return slickParamDTO; + } + SlickParam slickParam = SlickParam.builder().queryValue(queryValue) + .paramData(JsonUtils.toJsonString(paramData)).hashCode(hashCode) + .uniqueCode(RandomUtils.generateUUID()).build(); + slickParamMapper.saveEntity(slickParam); + return SlickParamMapMapper.INSTANCE.toDto(slickParam); + } + + + @Override + @Transactional + public void remove(Long id) { + slickParamMapper.deleteEntity(SlickParam.builder().id(id).build(), + UserContextHolder.getLoginUserId()); + } + + @Override + public List list(SlickParamQueryDTO slickParamQueryDTO) { + slickParamQueryDTO.disablePage(); + return slickParamMapper.listSlickParamDTO(slickParamQueryDTO); + } + + @Override + public void page(SlickParamQueryDTO slickParamQueryDTO) { + slickParamMapper.listSlickParamDTO(slickParamQueryDTO); + } + + @Override + public SlickParamDTO find(SlickParamQueryDTO slickParamQueryDTO) { + List slickParamDTOs = this.list(slickParamQueryDTO); + return slickParamDTOs.isEmpty() ? null : ListUtil.first(slickParamDTOs); + } + + + @Override + public T parseCode(String uniqueCode, Class clazz) { + if (StringUtils.isBlank(uniqueCode)) { + return null; + } + SlickParamDTO slickParamDTO = find(SlickParamQueryDTO.builder().uniqueCode(uniqueCode).build()); + Assert.notNull(slickParamDTO, "无效码"); + return JsonUtils.toObject(slickParamDTO.getParamData(), clazz); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/common/threadPools/AsyncExecutorConfig.java b/backend/src/main/java/com/senmesh/usercenter/common/threadPools/AsyncExecutorConfig.java new file mode 100644 index 0000000..ef1200c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/common/threadPools/AsyncExecutorConfig.java @@ -0,0 +1,50 @@ +package com.senmesh.usercenter.common.threadPools; + + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; + + +/** + * 外部方法线程池配置 + * + * @author on 2019-11-05 + */ +@Configuration +@EnableAsync +public class AsyncExecutorConfig { + + @Value("${async-executor.core_pool_size:10}") + private int corePoolSize; + @Value("${async-executor.max_pool_size:50}") + private int maxPoolSize; + @Value("${async-executor.queue-capacity:1000}") + private int queueCapacity; + @Value("${async-executor.name-prefix:async-}") + private String namePrefix; + + + @Bean("asyncExecutor") + public Executor asyncExecutor() { + ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); + taskExecutor.setCorePoolSize(corePoolSize);// 线程池核心线程数 + taskExecutor.setMaxPoolSize(maxPoolSize);// 线程池最大线程数 + taskExecutor.setQueueCapacity(queueCapacity);// 缓冲队列 + taskExecutor.setThreadNamePrefix(namePrefix);// 线程名称前缀 + taskExecutor.setKeepAliveSeconds(60);// 线程空闲后的最大存活时间 + // rejection-policy:当pool已经达到max size的时候,如何处理新任务 + // CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行 + // 对拒绝task的处理策略 + taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + // 执行初始化 + taskExecutor.initialize(); + return taskExecutor; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/common/validate/ValidatorConf.java b/backend/src/main/java/com/senmesh/usercenter/common/validate/ValidatorConf.java new file mode 100644 index 0000000..43dfb51 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/common/validate/ValidatorConf.java @@ -0,0 +1,24 @@ +package com.senmesh.usercenter.common.validate; + +import org.hibernate.validator.HibernateValidator; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.validation.Validation; +import javax.validation.Validator; + +/** + * @description: 参数校验配置 + * @author: chenyun.huang + * @create: 2020-04-11 10:09 + **/ +@Configuration +public class ValidatorConf { + @Bean + public Validator validator() { + return Validation.byProvider(HibernateValidator.class) + .configure() + .failFast(true) + .buildValidatorFactory().getValidator(); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/constants/CacheConstants.java b/backend/src/main/java/com/senmesh/usercenter/constants/CacheConstants.java new file mode 100644 index 0000000..cfc2ff9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/constants/CacheConstants.java @@ -0,0 +1,16 @@ +package com.senmesh.usercenter.constants; + +public interface CacheConstants { + + String DISTRICT_TREE_ALL_KEY = "districtTreeAll"; + + String DISTRICT_TREE_PROVINCE_KEY = "districtTreeProvince"; + //省级 + String DISTRICT_PROVINCE_LIST_KEY = "districtProvinceList"; + //城市 + String DISTRICT_CITY_MAP_KEY = "districtCityMap"; + //区、县 + String DISTRICT_COUNTY_MAP_KEY = "districtCountyMap"; + //街道 + String DISTRICT_STREET_MAP_KEY = "districtStreetMap"; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/constants/CompanyConstants.java b/backend/src/main/java/com/senmesh/usercenter/constants/CompanyConstants.java new file mode 100644 index 0000000..7b021d6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/constants/CompanyConstants.java @@ -0,0 +1,33 @@ +package com.senmesh.usercenter.constants; + +/** + * 企业常量类 + * + * @author sr on 2019-10-19 + */ +public class CompanyConstants { + + /** 关联分类:产品 **/ + public static final String UNION_TYPE_PROD = "1"; + /** 关联分类:机构 **/ + public static final String UNION_TYPE_ORG = "2"; + + /** + * 未认证:1 + */ + public static final String STATUS_NOT_CERTIFIED = "1"; + /** + * 已认证:2 + */ + public static final String STATUS_CERTIFIED = "2"; + /** + * 已注销:3 + */ + public static final String STATUS_CANCELED = "3"; + + + /** -----异常信息----- **/ + public static final String COMPANY_ID_NULL = "企业id为空"; + /** -----异常信息----- **/ + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/constants/DomainSettingTypeEnum.java b/backend/src/main/java/com/senmesh/usercenter/constants/DomainSettingTypeEnum.java new file mode 100644 index 0000000..d5abe7b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/constants/DomainSettingTypeEnum.java @@ -0,0 +1,30 @@ +package com.senmesh.usercenter.constants; + +/** + * 域名配置类型枚举 + * @author sr on 2021-08-18 + */ +public enum DomainSettingTypeEnum { + + /** 轮播图 **/ + CAROUSEL(1), + /** banner图 **/ + BANNER(2), + /** 个人端入口 **/ + MC_ENTRYPOINT(3), + /** 短信配置 **/ + SMS(4), + /** 微信消息模板 **/ + MESSAGE_TEMPLATE(12); + + DomainSettingTypeEnum(Integer type) { + this.type = type; + } + + private Integer type; + + public Integer getType() { + return type; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/constants/OrgConstants.java b/backend/src/main/java/com/senmesh/usercenter/constants/OrgConstants.java new file mode 100644 index 0000000..b0bb749 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/constants/OrgConstants.java @@ -0,0 +1,15 @@ +package com.senmesh.usercenter.constants; + +/** + * 机构相关常量 + */ +public class OrgConstants { + + private OrgConstants() {} + + /** + * 平台机构id + **/ + public static final Long PLATFORM_ORG_ID = 1L; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/constants/RoleConstants.java b/backend/src/main/java/com/senmesh/usercenter/constants/RoleConstants.java new file mode 100644 index 0000000..2c24e40 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/constants/RoleConstants.java @@ -0,0 +1,30 @@ +package com.senmesh.usercenter.constants; + +/** + * 角色常量类 + * @author sr on 2019-10-11 + */ +public interface RoleConstants { + + /** 角色类型:业务角色(机构内) **/ + String ROLE_TYPE_BUSINESS = "1"; + + /** 标准角色类型:其他 **/ + String STANDARD_ROLE_TYPE_ELSE = "1"; + /** 标准角色类型:销售 **/ + String STANDARD_ROLE_TYPE_SALE = "2"; + /** 标准角色类型:财务 **/ + String STANDARD_ROLE_TYPE_FINANCE = "3"; + /** 标准角色类型:法务 **/ + String STANDARD_ROLE_TYPE_LEGAL = "4"; + /** 标准角色类型:运维 **/ + String STANDARD_ROLE_TYPE_OPS = "5"; + /** 标准角色类型:运营 **/ + String STANDARD_ROLE_TYPE_OPERATION = "6"; + /** 标准角色类型:招聘负责人 **/ + String STANDARD_ROLE_TYPE_PERSONCHARGE = "7"; + + /** 角色类型:制单 **/ + String PREPARED_BY = "7"; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/constants/SecurityConstants.java b/backend/src/main/java/com/senmesh/usercenter/constants/SecurityConstants.java new file mode 100644 index 0000000..c78f4e0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/constants/SecurityConstants.java @@ -0,0 +1,93 @@ +package com.senmesh.usercenter.constants; + +/** + * 权限常量类 + * @author sr on 2019-10-07 + */ +public interface SecurityConstants { + + /** 通用权限鉴别属性前缀 **/ + String ROLE_PERMISSION_PREFIX = "ROLE_"; + + /** 角色分配类型:个人 **/ + String ALLOCATION_TYPE_USER = "1"; + + /** 缓存key:方法名 **/ + String CACHE_KEY_METHOD = "#root.methodName"; + /** 缓存key:方法参数-账号 **/ + String CACHE_KEY_PERMISSION_ORG_SYSTEM = "#permissionQueryDTO.systemCode + ':' + #permissionQueryDTO.orgId"; + String CACHE_KEY_SYSTEM = "#systemCode"; + String CACHE_KEY_ORG_USER = "#userDetails.orgId + ':' + #userDetails.id"; + String CACHE_KEY_ORG_SYSTEM_USER = "#systemCode + ':' + #iUserDetail.orgId + ':' + #iUserDetail.id"; + String CACHE_KEY_ORG_SYSTEM_USER_ROLE = CACHE_KEY_ORG_SYSTEM_USER + " + ':' + #roleId"; + + public interface CacheName { + + /** 所有组件权限缓存关键字:id-attributes orgId_systemCode **/ + String COMPONENT_ATTRIBUTE_MAP_CACHE_KEY = "componentAttributeMap"; + + /** 所有菜单权限缓存关键字:id-attributes orgId_systemCode **/ + String URL_ATTRIBUTE_MAP_CACHE_KEY = "urlAttributeMap"; + + /** 所有菜单(访问)权限缓存关键字:link-attributes orgId_systemCode **/ + String URL_FILTER_ATTRIBUTE_MAP_CACHE_KEY = "urlFilterAttributeMap"; + + /** 资源树(包含菜单和组件)orgId_systemCode_userId(_roleId) **/ + String RESOURCE_TREE_CACHE_KEY = "resourceTree"; + + /** 用户已经授权角色 orgId_userId **/ + String USER_GRANTED_AUTHORITY_CACHE_KEY = "userGrantedAuthority"; + + + } + + /** map-key:资源id **/ + String MAP_KEY_RESOURCE_ID = "resourceId"; + /** map-key:资源类型 **/ + String MAP_KEY_RESOURCE_TYPE = "resourceType"; + + /** 属性配置键:是否启用jwt **/ + String PROP_KEY_JWT_ENBALE = "security.jwt.enable"; + /** 属性配置键:jwt过期时间 **/ + String PROP_KEY_JWT_EXPIRATION = "security.jwt.expiration"; + /** 属性配置键:jwt密钥 **/ + String PROP_KEY_JWT_SECRET = "security.jwt.secret"; + + /** 属性配置键:security是否本地调用 **/ + String PROP_KEY_SECURITY_USELOCAL = "security.useLocal"; + /** 属性配置键:security匿名访问路径 **/ + String PROP_KEY_SECURITY_ANONYMOUS = "security.anonymous"; + + String PROP_KEY_SECURITY_OAUTH2_USEDB = "security.oauth2.usedb"; + + /** 指定登陆完成跳转地址 **/ + String REDIRECT_URL_FORMAT = "%s?success_to=%s"; + /** 指定成功跳转地址 **/ + String SUCCESS_TO_URL = "success_to"; + /** token **/ + String TOKEN = "token"; + + /** 登录参数:手机号 **/ + String LOGIN_PHONE_KEY = "phone"; + /** 登录参数:手机号验证码 **/ + String LOGIN_CODE_KEY = "code"; + /** 登录参数:用户类型 **/ + String LOGIN_USER_TYPE_KEY = "userType"; + /** 登录参数:用户id **/ + String LOGIN_USER_ID_KEY = "userId"; + /** 登录参数:用户名 **/ + String LOGIN_USERNAME_KEY = "username"; + /** 登录参数:密码 **/ + String LOGIN_PASSWORD_KEY = "password"; + /** 登录参数:注册邀请码 **/ + String LOGIN_REGISTER_CODE_KEY = "registerCode"; + /** 登录参数:入口来源 **/ + String LOGIN_ENTRYPOINT_KEY = "entrypoint"; + /** 登录参数:临时token **/ + String LOGIN_TEMP_TOKEN_KEY = "tempToken"; + /** 登录参数:机构id **/ + String LOGIN_ORG_ID_KEY = "orgId"; + + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/constants/SecurityExceptionMsg.java b/backend/src/main/java/com/senmesh/usercenter/constants/SecurityExceptionMsg.java new file mode 100644 index 0000000..af10821 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/constants/SecurityExceptionMsg.java @@ -0,0 +1,26 @@ +package com.senmesh.usercenter.constants; + +/** + * 权限相关异常信息 + * @author sr on 2019-10-14 + */ +public class SecurityExceptionMsg { + + public static final String UPDATE_NOT_EXIST = "未找到对应数据"; + public static final String USERNAME_EXIST = "账号已存在"; + public static final String ORG_USER_NOT_EXIST = "机构下不存在对应用户"; + public static final String USER_NOT_EXIST = "用户不存在"; + public static final String USER_OLD_PASSWORD_ERROR = "用户原密码错误"; + public static final String ORG_ROLE_NOT_EXIST = "未找到对应角色"; + public static final String NOT_SUPERIOR_LOGIN = "只有平台管理员能访问"; + public static final String NOT_PLATFORM_LOGIN = "无权限访问(platform only)"; + public static final String URL_NOT_EXIST = "未找到对应菜单"; + public static final String COMPONENT_NOT_EXIST = "未找到对应组件"; + public static final String UNALLOCATE_ROLES_EMPTY = "请选择有效角色取消授权"; + public static final String ALLOCATE_ROLES_EMPTY = "请选择有效角色授权"; + public static final String ORG_NOT_EXIST = "未找到对应有效机构"; + public static final String ORG_TYPE_ERROR = "机构类型错误"; + public static final String ROLE_NAME_EXIST = "角色名称已存在"; + public static final String ORG_NAME_EXIST = "企业名称已存在"; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/constants/SecurityValidateConstants.java b/backend/src/main/java/com/senmesh/usercenter/constants/SecurityValidateConstants.java new file mode 100644 index 0000000..6d27e28 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/constants/SecurityValidateConstants.java @@ -0,0 +1,46 @@ +package com.senmesh.usercenter.constants; + +/** + * 权限模块校验信息常量 + * + * @author sr on 2019-10-11 + */ +public class SecurityValidateConstants { + + public static final String PLATFORM_CODE_EMPTY = "平台编码不能为空"; + public static final String ROLE_ID_EMPTY = "角色不能为空"; + public static final String RESOURCE_TYPE_EMPTY = "资源类型不能为空"; + + public static final String USER_NAME_EMPTY = "账号不能为空"; + public static final String USER_NAME_SIZE = "账号长度不符(3-5)"; + public static final String USER_ID_NULL = "用户id不能为空"; + public static final String USER_OLD_PASSWORD_EMPTY = "原密码不能为空"; + public static final String USER_NEW_PASSWORD_EMPTY = "新密码不能为空"; + + + public static final String ROLE_NAME_EMPTY = "角色名称不能为空"; + public static final String ROLE_ID_NULL = "角色id不能为空"; + public static final String ROLE_ALLOCATE_OPERATE_TYPE = "操作类型不能为空(授权true/取消false)"; + + + public static final String URL_ID_NULL = "菜单id不能为空"; + public static final String URL_NAME_EMPTY = "菜单名称不能为空"; + public static final String URL_LINK_EMPTY = "菜单地址不能为空"; + public static final String URL_PARENT_ID_NULL = "父菜单id不能为空"; + + public static final String COMPONENT_ID_NULL = "组件id不能为空"; + public static final String COMPONENT_URL_ID_NULL = "组件所属菜单id不能为空"; + public static final String COMPONENT_CODE_EMPTY = "组件不能为空"; + + + public static final String RESOURCE_ID_NULL = "资源id不能为空"; + public static final String RESOURCE_TYPE_NULL = "资源类型不能为空"; + + public static final String PERMISSION_PACKAGE_ID_NULL = "权限包ID不能为空"; + public static final String PERMISSION_PACKAGE_NAME_NULL = "权限包名称不能为空"; + public static final String PERMISSION_PACKAGE_TYPE_NULL = "权限包类型不能为空"; + public static final String PERMISSION_ORG_ID_NULL = "分配机构ID不能为空"; + public static final String PERMISSION_COMPANY_ID_NULL = "分配企业ID不能为空"; + public static final String PERMISSION_SELECTED_FLAG_NULL = "是否选中标识不能为空"; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/constants/UrlConstants.java b/backend/src/main/java/com/senmesh/usercenter/constants/UrlConstants.java new file mode 100644 index 0000000..43c1223 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/constants/UrlConstants.java @@ -0,0 +1,12 @@ +package com.senmesh.usercenter.constants; + +/** + * 菜单常量 + * @author sr on 2019-10-15 + */ +public class UrlConstants { + + /** 顶级菜单父id **/ + public static final Long URL_TOP_PARENT_ID = 0L; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/constants/UserCenterValidateConstants.java b/backend/src/main/java/com/senmesh/usercenter/constants/UserCenterValidateConstants.java new file mode 100644 index 0000000..0e43bb5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/constants/UserCenterValidateConstants.java @@ -0,0 +1,19 @@ +package com.senmesh.usercenter.constants; + +/** + * @author Jerry.li + * @description 用户中心验证常量类 + * @date 2020/3/24 + */ +public class UserCenterValidateConstants { + + private UserCenterValidateConstants() { + } + + public static final String ORG_ID_NULL = "机构ID不能为空"; + public static final String COMPANY_RATE_NULL = "服务费率不能为空"; + public static final String ORG_NAME_NULL = "机构名称不能为空"; + public static final String ORG_TYPE_NULL = "机构类型不能为空"; + public static final String COMPANY_RATE_OUT_RANGE = "费率超出范围(0-1)"; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/constants/UserConstants.java b/backend/src/main/java/com/senmesh/usercenter/constants/UserConstants.java new file mode 100644 index 0000000..39fde15 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/constants/UserConstants.java @@ -0,0 +1,33 @@ +package com.senmesh.usercenter.constants; + +/** + * 用户常量类 + * + * @author sr on 2019-10-10 + */ +public class UserConstants { + /** + * 机构管理员后缀 + **/ + public static final String ORG_MANAGER_USERNAME_SUFFIX = "admin"; + + /** + * 超管用户id + **/ + public static final Long SUPERIOR_USER_ID = 1L; + + + /** + * 查询类型 + */ + public static class queryType { + + /** + * 页面查询的用户列表,包含类型 平台管理员、企业管理员、企业用户 + */ + public static final String USER_INFO = "userInfo"; + } + + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/controller/UcDictionaryController.java b/backend/src/main/java/com/senmesh/usercenter/controller/UcDictionaryController.java new file mode 100644 index 0000000..7d06d8f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/controller/UcDictionaryController.java @@ -0,0 +1,67 @@ +package com.senmesh.usercenter.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.TreeHelper; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.component.dict.dto.DictDTO; +import com.senmesh.component.dict.dto.DictDetailDTO; +import com.senmesh.component.dict.dto.DictDetailQueryDTO; +import com.senmesh.component.dict.dto.DictQueryDTO; +import com.senmesh.component.dict.service.DictDetailService; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.service.UcDictionaryService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +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; + +import java.util.List; + +/** + * @author: Jerry.li + * @description: 数据字典 + * @create: 2020-06-18 14:39 + **/ +@Api(tags = "数据字典") +@RestController +@RequestMapping(value = "/dict") +public class UcDictionaryController { + + @Autowired + private UcDictionaryService ucDictionaryService; + + @Autowired + private DictDetailService dictDetailService; + + @ApiOperation("编辑字典数据") + @PostMapping("/edit_dict") + public AlitaResult editDict(@RequestBody DictDTO dictDTO) { + return ucDictionaryService.editDictionary(dictDTO, UserContextHolder.getExistLoginUserId()); + } + + @ApiOperation("编辑字典详情数据") + @PostMapping("/edit_dict_detail") + public AlitaResult editDictDetail(@RequestBody DictDetailDTO detailDTO) { + return ucDictionaryService + .editDictionaryDetail(detailDTO, UserContextHolder.getExistLoginUserId()); + } + + @ApiOperation("分页查询数据字典列表") + @PostMapping("/page_dict_list") + public AlitaResult> pageQueryDictionaryList(@RequestBody DictQueryDTO query) { + ucDictionaryService.pageDictionaryList(query); + return AlitaResult.success(query.getPageResult()); + } + + @ApiOperation("根据ID获取字典详情列表") + @PostMapping("/get_dict_detail_list") + public AlitaResult> getDictDetailList(@RequestBody DictDetailQueryDTO dictDetailQueryDTO) { + dictDetailQueryDTO.disablePage(); + List details = ucDictionaryService.getDictDetailList(dictDetailQueryDTO); + return AlitaResult.success(TreeHelper.buildTree(null, details)); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/controller/UcRoleStandardTypeController.java b/backend/src/main/java/com/senmesh/usercenter/controller/UcRoleStandardTypeController.java new file mode 100644 index 0000000..1b0065d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/controller/UcRoleStandardTypeController.java @@ -0,0 +1,42 @@ +package com.senmesh.usercenter.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.constants.SecurityConstants; +import com.senmesh.usercenter.dto.RoleStandardTypeDTO; +import com.senmesh.usercenter.query.RoleStandardTypeQuery; +import com.senmesh.usercenter.service.UcRoleStandardTypeService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @Author dylanyuan + * @Date 2021/2/19 4:15 下午 + * @Version 1.0 + */ +@Api(tags = "标准角色管理") +@RestController +@RequestMapping(value = "/role_standard_type") +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +@ConditionalOnProperty(name = SecurityConstants.PROP_KEY_SECURITY_USELOCAL, havingValue = "true", + matchIfMissing = true) +public class UcRoleStandardTypeController { + + private final UcRoleStandardTypeService ucRoleStandardTypeService; + + @ApiOperation("分页查询") + @GetMapping("/page") + public AlitaResult> page(RoleStandardTypeQuery query) { + ucRoleStandardTypeService.page(query); + return AlitaResult.success(query.getPageResult()); + } + + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dao/XsRoleStandardTypeMapper.java b/backend/src/main/java/com/senmesh/usercenter/dao/XsRoleStandardTypeMapper.java new file mode 100644 index 0000000..3b55b7e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dao/XsRoleStandardTypeMapper.java @@ -0,0 +1,18 @@ +package com.senmesh.usercenter.dao; + +import java.util.List; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.senmesh.usercenter.dto.RoleStandardTypeDTO; +import com.senmesh.usercenter.entity.RoleStandardType; +import com.senmesh.usercenter.query.RoleStandardTypeQuery; + +/** + * @Author dylanyuan + * @Date 2021/2/19 2:09 下午 + * @Version 1.0 + */ +public interface XsRoleStandardTypeMapper extends BaseMapper { + + List page(RoleStandardTypeQuery query); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/district/constants/DistrictConstants.java b/backend/src/main/java/com/senmesh/usercenter/district/constants/DistrictConstants.java new file mode 100644 index 0000000..a13ca67 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/district/constants/DistrictConstants.java @@ -0,0 +1,29 @@ +package com.senmesh.usercenter.district.constants; + +/** + * @author czy + * @date 2021-07-08 + */ +public interface DistrictConstants { + + Long DEFAULT_DISTRICT_ID = 0l; + + String CACHE_KEY_DISTRICT_ID = "#districtId"; + + interface CacheNames { + + /** 省 **/ + String DISTRICT_PROVINCE = "district:province"; + + /** 市 **/ + String DISTRICT_CITY = "district:city"; + + /** 区 **/ + String DISTRICT_AREA = "district:area"; + + /** 街 **/ + String DISTRICT_STREET = "district:street"; + + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/district/controller/DistrictController.java b/backend/src/main/java/com/senmesh/usercenter/district/controller/DistrictController.java new file mode 100644 index 0000000..d5f4c26 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/district/controller/DistrictController.java @@ -0,0 +1,60 @@ +package com.senmesh.usercenter.district.controller; + + +import com.senmesh.common.AlitaResult; +import com.senmesh.usercenter.district.constants.DistrictConstants; +import com.senmesh.usercenter.district.dto.DistrictDTO; +import com.senmesh.usercenter.district.dto.DistrictTreeQueryDTO; +import com.senmesh.usercenter.district.entity.District; +import com.senmesh.usercenter.district.service.IDistrictService; + +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + *

+ * 省份城市 前端控制器 + *

+ * + * @author Carlye + * @since 2021-01-25 + */ +//@RestController +@RequestMapping("/anon/district") +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class DistrictController { + + private final IDistrictService districtService; + + @GetMapping("/tree") + @ApiOperation("创建用户附件") + public AlitaResult> tree(DistrictTreeQueryDTO queryDTO) { + return AlitaResult.success(districtService.treeList(queryDTO)); + } + + @GetMapping("/list") + @ApiOperation("获取指定Id下的城市列表(不传就默认查省列表)") + public AlitaResult> loadDataById(@RequestParam(value = "districtId", required = false) Long districtId) { + if (districtId == null) { + districtId = DistrictConstants.DEFAULT_DISTRICT_ID; + } + return AlitaResult.success(districtService.queryListById(districtId)); + } + + @GetMapping("/all") + @ApiOperation("获取全部") + public AlitaResult> all(@RequestParam(value = "level") Integer level) { + return AlitaResult.success(districtService.all(level)); + } + + +} + diff --git a/backend/src/main/java/com/senmesh/usercenter/district/dao/DistrictMapper.java b/backend/src/main/java/com/senmesh/usercenter/district/dao/DistrictMapper.java new file mode 100644 index 0000000..c7ca721 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/district/dao/DistrictMapper.java @@ -0,0 +1,23 @@ +package com.senmesh.usercenter.district.dao; + +import com.senmesh.usercenter.district.dto.DistrictDTO; +import com.senmesh.usercenter.district.entity.District; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import java.util.List; +import org.apache.ibatis.annotations.Param; + +/** + *

+ * 省份城市 Mapper 接口 + *

+ * + * @author Carlye + * @since 2021-01-25 + */ +public interface DistrictMapper extends BaseMapper { + + List queryById(Long districtId); + + String queryNameByCode(@Param("codes") List codes); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/district/dto/DistrictDTO.java b/backend/src/main/java/com/senmesh/usercenter/district/dto/DistrictDTO.java new file mode 100644 index 0000000..5108b3b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/district/dto/DistrictDTO.java @@ -0,0 +1,80 @@ +package com.senmesh.usercenter.district.dto; + +import com.google.common.collect.Lists; +import com.senmesh.common.dto.BaseDTO; +import com.senmesh.common.util.TreeNode; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.Accessors; +import lombok.experimental.SuperBuilder; + +import java.util.List; +import java.util.Objects; + +/** + *

+ * 省份城市 + *

+ * + * @author Carlye + * @since 2021-01-25 + */ +@ApiModel("省份城市树形DTO") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +public class DistrictDTO extends BaseDTO implements TreeNode { + + private static final long serialVersionUID = -3042079366109391854L; + + @ApiModelProperty("城市名称") + private String name; + + @ApiModelProperty("上级城市ID") + private Long parentId; + + @ApiModelProperty("首字母") + private String initial; + + @ApiModelProperty("简拼") + private String initials; + + @ApiModelProperty("全拼") + private String pinyin; + + @ApiModelProperty("特别行政区") + private String extra; + + @ApiModelProperty("后缀") + private String suffix; + + @ApiModelProperty("城市编码") + private String code; + + @ApiModelProperty("区域编码") + private String areaCode; + + @ApiModelProperty("排序") + private Integer districtOrder; + + private Integer level; + + @ApiModelProperty("下级") + private List childrenSet; + + public List getChildrenSet() { + if (Objects.isNull(this.childrenSet)) { + this.childrenSet = Lists.newArrayList(); + } + return this.childrenSet; + } + + @Override + public void addChildren(DistrictDTO node) { + getChildrenSet().add(node); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/district/dto/DistrictTreeQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/district/dto/DistrictTreeQueryDTO.java new file mode 100644 index 0000000..a68de89 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/district/dto/DistrictTreeQueryDTO.java @@ -0,0 +1,31 @@ +package com.senmesh.usercenter.district.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + *

+ * 省份城市 + *

+ * + * @author Carlye + * @since 2021-01-25 + */ +@ApiModel("省份城市树形查询DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class DistrictTreeQueryDTO { + + private static final long serialVersionUID = -3042079366109391854L; + + + @ApiModelProperty("省份编码") + private String code; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/district/entity/District.java b/backend/src/main/java/com/senmesh/usercenter/district/entity/District.java new file mode 100644 index 0000000..aff741f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/district/entity/District.java @@ -0,0 +1,56 @@ +package com.senmesh.usercenter.district.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; +import lombok.*; +import lombok.experimental.Accessors; + +/** + * 省份城市 + * + * @author Carlye + * @since 2021-01-25 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableName("xs_district") +public class District extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** 城市名称 */ + private String name; + + /** 上级城市ID */ + private Long parentId; + + /** 首字母 */ + private String initial; + + /** 简拼 */ + private String initials; + + /** 全拼 */ + private String pinyin; + + /** 特别行政区 */ + private String extra; + + /** 后缀 */ + private String suffix; + + /** 城市编码 */ + private String code; + + /** 区域编码 */ + private String areaCode; + + /** 排序 */ + private Integer districtOrder; + + private Integer level; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/district/mapper/DistrictMapper.xml b/backend/src/main/java/com/senmesh/usercenter/district/mapper/DistrictMapper.xml new file mode 100644 index 0000000..9f793db --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/district/mapper/DistrictMapper.xml @@ -0,0 +1,30 @@ + + + + + + + + + diff --git a/backend/src/main/java/com/senmesh/usercenter/district/mapstruct/DistrictMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/district/mapstruct/DistrictMapMapper.java new file mode 100644 index 0000000..3002233 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/district/mapstruct/DistrictMapMapper.java @@ -0,0 +1,24 @@ +package com.senmesh.usercenter.district.mapstruct; + +import com.senmesh.usercenter.district.dto.DistrictDTO; +import com.senmesh.usercenter.district.entity.District; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + + +/** + * 用户映射器附件地图 + * + * @author Carlye + * @date 2021/01/12 + */ +@Mapper +public interface DistrictMapMapper { + + DistrictMapMapper INSTANCE = Mappers.getMapper(DistrictMapMapper.class); + + DistrictDTO exchange(District district); + + DistrictDTO exchange(DistrictDTO districtDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/district/service/IDistrictService.java b/backend/src/main/java/com/senmesh/usercenter/district/service/IDistrictService.java new file mode 100644 index 0000000..19538a0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/district/service/IDistrictService.java @@ -0,0 +1,28 @@ +package com.senmesh.usercenter.district.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.senmesh.usercenter.district.dto.DistrictDTO; +import com.senmesh.usercenter.district.dto.DistrictTreeQueryDTO; +import com.senmesh.usercenter.district.entity.District; + +import java.util.List; + +/** + * 省份城市 服务类 + * + * @author Carlye + * @since 2021-01-25 + */ +public interface IDistrictService extends IService { + + /** + * 树列表 + * + * @return {@link List} + */ + List treeList(DistrictTreeQueryDTO queryDTO); + + List queryListById(Long districtId); + + List all(Integer level); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/district/service/impl/DistrictServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/district/service/impl/DistrictServiceImpl.java new file mode 100644 index 0000000..6bed27f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/district/service/impl/DistrictServiceImpl.java @@ -0,0 +1,137 @@ +package com.senmesh.usercenter.district.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +import com.google.common.collect.Lists; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.TreeHelper; +import com.senmesh.frame.redis.aop.annotation.AutoUnLock; +import com.senmesh.frame.redis.dto.LockDTO; +import com.senmesh.frame.redis.redisson.RedissonUtils; +import com.senmesh.usercenter.constants.CacheConstants; +import com.senmesh.usercenter.district.constants.DistrictConstants; +import com.senmesh.usercenter.district.dao.DistrictMapper; +import com.senmesh.usercenter.district.dto.DistrictDTO; +import com.senmesh.usercenter.district.dto.DistrictTreeQueryDTO; +import com.senmesh.usercenter.district.entity.District; +import com.senmesh.usercenter.district.mapstruct.DistrictMapMapper; +import com.senmesh.usercenter.district.service.IDistrictService; + +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +/** + * 省份城市 服务实现类 + * + * @author Carlye + * @since 2021-01-25 + */ +@Slf4j +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class DistrictServiceImpl extends ServiceImpl + implements IDistrictService { + + private final RedisTemplate redisTemplate; + + private final DistrictMapper districtMapper; + + @Override + @AutoUnLock + public List treeList(DistrictTreeQueryDTO queryDTO) { + List range = redisTemplate.opsForList().range(CacheConstants.DISTRICT_TREE_PROVINCE_KEY, 0, -1); + if (CollectionUtils.isEmpty(range)) { + Assert.isTrue(RedissonUtils.tryLockAutomatically(LockDTO.builder().methodName("treeList").build()), "正在初始化数据,请稍后再试"); + List range2 = redisTemplate.opsForList().range(CacheConstants.DISTRICT_TREE_PROVINCE_KEY, 0, -1); + if (CollectionUtils.isEmpty(range2)) { + @SuppressWarnings("unchecked") + List allDistricts = + list(Wrappers.lambdaQuery() + .eq(District::getDeleted, false) + .orderByAsc(District::getParentId, District::getDistrictOrder, + District::getId)); + if (CollectionUtils.isEmpty(allDistricts)) { + List districtDTOS = Lists.newArrayList(new DistrictDTO()); + redisTemplate.opsForList() + .leftPush(CacheConstants.DISTRICT_TREE_PROVINCE_KEY, districtDTOS); + redisTemplate.expire(CacheConstants.DISTRICT_TREE_PROVINCE_KEY, 5, TimeUnit.MINUTES); + return districtDTOS; + } + //省市区 + List allDistrictDTOS = allDistricts.stream() + .map(DistrictMapMapper.INSTANCE::exchange).collect(Collectors.toList()); + + List districtDTOS = TreeHelper.buildTree(0L, allDistrictDTOS); + //区-街道 + List suffix = Lists.newArrayList(); + districtDTOS.forEach(districtDTO -> recursiveDistrictDTO(districtDTO, suffix)); + for (DistrictDTO districtDTO : suffix) { + String key = String + .join(":", CacheConstants.DISTRICT_TREE_ALL_KEY, districtDTO.getCode()); + redisTemplate.delete(key); + redisTemplate.opsForList().rightPushAll(key, districtDTO.getChildrenSet()); + redisTemplate.expire(key, 1, TimeUnit.DAYS); + } + redisTemplate.delete(CacheConstants.DISTRICT_TREE_PROVINCE_KEY); + redisTemplate.opsForList() + .rightPushAll(CacheConstants.DISTRICT_TREE_PROVINCE_KEY, districtDTOS); + redisTemplate.expire(CacheConstants.DISTRICT_TREE_PROVINCE_KEY, 1, TimeUnit.DAYS); + range = districtDTOS; + } + } + String code = queryDTO.getCode(); + if (StringUtils.isNotEmpty(code)) { + String key = String.join(":", CacheConstants.DISTRICT_TREE_ALL_KEY, code); + return redisTemplate.opsForList().range(key, 0, -1); + } + return range; + } + + + private static final Integer TAG = 4; + + private void recursiveDistrictDTO(DistrictDTO districtDTO, + List suffix) { + int length = districtDTO.getCode().length(); + if (length < TAG) { + for (DistrictDTO child : districtDTO.getChildrenSet()) { + recursiveDistrictDTO(child, suffix); + } + } + if (length == TAG) { + suffix.add(DistrictMapMapper.INSTANCE.exchange(districtDTO)); + districtDTO.setChildrenSet(null); + } + } + + @Override + @Cacheable(cacheNames = DistrictConstants.CacheNames.DISTRICT_PROVINCE, + key = DistrictConstants.CACHE_KEY_DISTRICT_ID) + public List queryListById(Long districtId) { + List districtDTOS = districtMapper.queryById(districtId); + return districtDTOS; + } + + @Override + public List all(Integer level) { + List districts = districtMapper.selectList(new LambdaQueryWrapper() + .eq(District::getLevel, level) + .eq(District::getDeleted, false) + .orderByAsc(District::getCode)); + return districts; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/AllocatedBusinessRoleQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/AllocatedBusinessRoleQueryDTO.java new file mode 100644 index 0000000..79a8e6f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/AllocatedBusinessRoleQueryDTO.java @@ -0,0 +1,66 @@ +package com.senmesh.usercenter.dto; + +import com.senmesh.usercenter.constants.RoleConstants; +import com.senmesh.usercenter.constants.SecurityConstants; + +import java.io.Serializable; +import java.util.List; + +import javax.validation.constraints.NotNull; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: 已分配业务角色DTO + * @author: guixinman + * @create: 2023-10-31 18:20 + **/ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AllocatedBusinessRoleQueryDTO implements Serializable { + + @NotNull(message = "orgId不能为null") + private Long orgId; + + /** + * 所属平台 + **/ + @NotNull(message = "platformCode不能为null") + private Integer platformCode; + + /** + * 角色具体分配类型对应的id + **/ + @NotNull(message = "allocationId不能为null") + private Long allocationId; + + /** + * 角色分配类型:1个人2部门3组 + **/ + @Builder.Default + private String allocationType = SecurityConstants.ALLOCATION_TYPE_USER; + + /** + * 类型 + **/ + @Builder.Default + private String type = RoleConstants.ROLE_TYPE_BUSINESS; + + @ApiModelProperty("标准角色类型:见role_standard_type") + private List standardTypes; + + /** + * 是否启用 + **/ + @Builder.Default + private Boolean enabled = Boolean.TRUE; + +} + + diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/AllocationDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/AllocationDTO.java new file mode 100644 index 0000000..f337e32 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/AllocationDTO.java @@ -0,0 +1,30 @@ +package com.senmesh.usercenter.dto; + +import java.io.Serializable; +import java.util.List; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2019-10-17 + */ +@ApiModel("用户角色分配") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class AllocationDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 8761125972738825343L; + + @ApiModelProperty("已分配") + private List allocated; + + @ApiModelProperty("未分配") + private List unallocated; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/AllocationRoleDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/AllocationRoleDTO.java new file mode 100644 index 0000000..294b1cc --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/AllocationRoleDTO.java @@ -0,0 +1,38 @@ +package com.senmesh.usercenter.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; + +/** + * @author: Jerry.li + * @description: 可分配角色 + * @create: 2020-06-17 17:48 + **/ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class AllocationRoleDTO implements Serializable { + + /** + * 用户ID + */ + private Long userId; + + /** + * 可分配的角色列表 + */ + private List unallocatedRoleList; + + /** + * 已分配的角色ID列表 + */ + private List allocatedRoleIdList; + + @ApiModelProperty("所属平台") + private Integer platformCode; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/AllocationRoleUserDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/AllocationRoleUserDTO.java new file mode 100644 index 0000000..b258977 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/AllocationRoleUserDTO.java @@ -0,0 +1,25 @@ +package com.senmesh.usercenter.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class AllocationRoleUserDTO implements Serializable { + + @ApiModelProperty("用户ID") + private List userIds; + + @ApiModelProperty("所属平台") + private Integer platformCode; + + @ApiModelProperty("角色ID") + private Long roleId; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/CaptchaDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/CaptchaDTO.java new file mode 100644 index 0000000..678d317 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/CaptchaDTO.java @@ -0,0 +1,30 @@ +package com.senmesh.usercenter.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-08-11 + */ +@ApiModel("防水墙验证信息") +@Data +@NoArgsConstructor +public class CaptchaDTO implements Serializable { + + /** **/ + private static final long serialVersionUID = 4760648640763876418L; + + @ApiModelProperty("前端回调函数返回的用户验证票据") + @NotBlank(message = "防水墙验证票据不能为空") + private String ticket; + @ApiModelProperty("前端回调函数返回的随机字符串") + @NotBlank(message = "防水墙随机字符串不能为空") + private String randstr; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/CheckKeyDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/CheckKeyDTO.java new file mode 100644 index 0000000..df1f801 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/CheckKeyDTO.java @@ -0,0 +1,25 @@ +package com.senmesh.usercenter.dto; + +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@ApiModel("角色权限树已选数据") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CheckKeyDTO { + + /** + * 角色Id + */ + private Long roleId; + + /** + * 已勾选的菜单Id + */ + private String checkedKeys; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/DomainSettingOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/DomainSettingOperateDTO.java new file mode 100644 index 0000000..9e27393 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/DomainSettingOperateDTO.java @@ -0,0 +1,44 @@ +package com.senmesh.usercenter.dto; + +import com.senmesh.common.dto.BaseDTO; +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(value = "域名配置-请求DTO", description = "域名配置-请求DTO") +@SuperBuilder +public class DomainSettingOperateDTO extends BaseDTO { + + + private static final long serialVersionUID = 5671785716204667479L; + @ApiModelProperty("域名ID") + @NotNull(message = "域名ID不能为空", groups = {Create.class}) + private Long domainId; + /** + * 类型 + */ + @ApiModelProperty("类型") + @NotNull(message = "类型不能为空", groups = {Create.class, Update.class}) + private Integer type; + + @ApiModelProperty("描述") + private String remark; + + /** + * 配置数据 + */ + @ApiModelProperty("配置数据") + @NotEmpty(message = "配置数据不能为空", groups = {Create.class, Update.class}) + private String data; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/DomainSettingReqDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/DomainSettingReqDTO.java new file mode 100644 index 0000000..8d5f225 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/DomainSettingReqDTO.java @@ -0,0 +1,31 @@ +package com.senmesh.usercenter.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import java.io.Serializable; +import java.util.Objects; +import java.util.Set; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(value = "域名配置-请求DTO", description = "域名配置-请求DTO") +@Builder +public class DomainSettingReqDTO implements Serializable { + private static final long serialVersionUID = -8208703257479920916L; + @ApiModelProperty("域名或IP") +// @NotNull(message = "域名或IP不能为空") + private String domainOrIp; + @ApiModelProperty("域名ID") + private Long domainId; + @ApiModelProperty("类型集合") + @Singular + private Set types; + + @Override + public String toString() { + return String.join("_", "domain_setting", Objects.nonNull(domainId) ? Long.toString(domainId) : ""); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/DomainSettingResDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/DomainSettingResDTO.java new file mode 100644 index 0000000..43eccff --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/DomainSettingResDTO.java @@ -0,0 +1,30 @@ +package com.senmesh.usercenter.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Date; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(value = "域名配置-响应DTO",description = "域名配置-响应DTO") +public class DomainSettingResDTO implements Serializable { + private static final long serialVersionUID = 4501680475900802319L; + @ApiModelProperty("id") + private Long id; + @ApiModelProperty("类型集合") + private Integer type; + @ApiModelProperty("配置备注") + private String remark; + @ApiModelProperty("配置数据") + private String data; + @ApiModelProperty("创建时间") + private Date createTime; + @ApiModelProperty("修改时间") + private Date updateTime; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/IUserDetail.java b/backend/src/main/java/com/senmesh/usercenter/dto/IUserDetail.java new file mode 100644 index 0000000..361431f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/IUserDetail.java @@ -0,0 +1,38 @@ +package com.senmesh.usercenter.dto; + +public interface IUserDetail { + + /** 用户id **/ + Long getId(); + + /** 是否超管 **/ + Boolean getSupeiror(); + + /** 类型 **/ + Integer getType(); + + /** 当前操作机构 **/ + Long getOrgId(); + + /** 当前操作机构名称 **/ + String getOrgName(); + + /** 当前操作机构类型 **/ + String getOrgType(); + + /** 是否机构管理员 **/ + Boolean getAdministrator(); + + /** 用户名 **/ + String getUsername(); + + /** 标签 **/ + String getTag(); + + /** 状态 */ + Integer getStatus(); + + /** 手机号绑定状态 */ + Boolean getPhoneBinding(); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/MenuResourceDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/MenuResourceDTO.java new file mode 100644 index 0000000..49604e2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/MenuResourceDTO.java @@ -0,0 +1,38 @@ +package com.senmesh.usercenter.dto; + +import com.senmesh.usercenter.resource.dto.ComponentDTO; +import com.senmesh.usercenter.resource.dto.UrlDTO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; +import java.util.Set; + +/** + * @author: Jerry.li + * @description: 菜单资源 + * @create: 2020-07-10 15:13 + **/ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class MenuResourceDTO implements Serializable { + + /** + * 用户资源列表 + */ + private List resourceList; + + /** + * 组件列表 + */ + private List componentList; + + private Set urlIds; + private Set componentIds; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/OrgAdminDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/OrgAdminDTO.java new file mode 100644 index 0000000..c2b547e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/OrgAdminDTO.java @@ -0,0 +1,73 @@ +package com.senmesh.usercenter.dto; + +import com.senmesh.common.dto.BaseDTO; +import com.senmesh.common.validation.Update; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + * @author: Jerry.li + * @description: 机构管理员 + * @create: 2020-06-15 17:16 + * @create: 2020-06-17 12:00 + **/ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class OrgAdminDTO extends BaseDTO implements Serializable { + /** + * 用户中文名 + */ + @NotNull(groups = {Update.class}, message = "用户中文名不能为空") + private String chineseName; + /** + * 帐号 + */ + @NotNull(groups = {Update.class}, message = "登录账号不能为空") + private String username; + /** + * 手机号码 + */ + @NotNull(groups = {Update.class}, message = "手机号不能为空") + private String phone; + /** + * 邮箱 + */ + private String email; + /** + * 是否启用 + */ + private Boolean enabled; + /** + * 手机号绑定状态 + */ + private Boolean phoneBinding; + /** + * 机构ID: 更新和修改时必填 + */ + private Long orgId; + /** + * 机构名称 + */ + private String orgName; + + /** + * 类型 + */ + private String type; + + /** + * 用户状态 + */ + private Integer userStatus; + + /** + * 是否管理员 + */ + private Boolean administrator; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/OrgLoginTimeDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/OrgLoginTimeDTO.java new file mode 100644 index 0000000..a39bbfd --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/OrgLoginTimeDTO.java @@ -0,0 +1,32 @@ +package com.senmesh.usercenter.dto; + +import java.io.Serializable; +import java.util.Date; + +import org.springframework.format.annotation.DateTimeFormat; + +import com.senmesh.common.util.JsonUtils; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OrgLoginTimeDTO implements Serializable { + private static final long serialVersionUID = 7457935915892036131L; + + private Long orgId; + + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date requestTime; + + @Override + public String toString() { + return JsonUtils.toJsonString(this); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/OrgTreeDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/OrgTreeDTO.java new file mode 100644 index 0000000..76d98e2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/OrgTreeDTO.java @@ -0,0 +1,45 @@ +package com.senmesh.usercenter.dto; + +import com.google.common.collect.Lists; +import com.senmesh.common.util.TreeNode; +import java.io.Serializable; +import java.util.List; +import java.util.Objects; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + + +/** + * org树dto + * + * @author Carlye + * @date 2021/02/22 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OrgTreeDTO implements Serializable, TreeNode { + + private static final long serialVersionUID = 8410087864668609131L; + + private Long id; + + private Long parentId; + + private List childrenSet; + + public List getChildrenSet() { + if (Objects.isNull(this.childrenSet)) { + this.childrenSet = Lists.newArrayList(); + } + return this.childrenSet; + } + + @Override + public void addChildren(OrgTreeDTO node) { + getChildrenSet().add(node); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/OrgUserEditDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/OrgUserEditDTO.java new file mode 100644 index 0000000..429b24d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/OrgUserEditDTO.java @@ -0,0 +1,59 @@ +package com.senmesh.usercenter.dto; + +import io.swagger.annotations.ApiModelProperty; +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseDTO; +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * yzq + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@SuperBuilder +public class OrgUserEditDTO extends BaseDTO{ + + private static final long serialVersionUID = -9143944005872387841L; + + + @ApiModelProperty("昵称") + private String nickname; + + @ApiModelProperty("姓名") + private String realName; + + /** + * 帐号 + */ + @NotNull(groups = {Create.class}, message = "中文名不能为空") + private String username; + + /** + * 手机号码 + */ +// @NotNull(groups = {Update.class,Create.class}, message = "手机号码不能为空") +// private String phone; + + /** + * 手机号验证码 + */ + private String code; + /** + * 邮箱 + */ + private String email; + + /** + * 是否启用 + */ + private Boolean enabled; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/PaymentCodeDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/PaymentCodeDTO.java new file mode 100644 index 0000000..4311297 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/PaymentCodeDTO.java @@ -0,0 +1,29 @@ +package com.senmesh.usercenter.dto; + +import com.senmesh.common.validation.Create; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + * @description: 创建支付密码DTO + * @author: chenyun.huang + * @create: 2020-04-11 11:18 + **/ +@Data +public class PaymentCodeDTO implements Serializable { + private static final long serialVersionUID = -2177790509082680961L; + + /** + * 用户ID + */ + @NotNull(message = "用户ID不能为空", groups = {Create.class}) + private Long userId; + + /** + * 支付密码 + */ + @NotNull(message = "支付密码不能为空", groups = {Create.class}) + private String paymentCode; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/ResetPasswordByPhoneDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/ResetPasswordByPhoneDTO.java new file mode 100644 index 0000000..7186b67 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/ResetPasswordByPhoneDTO.java @@ -0,0 +1,43 @@ +package com.senmesh.usercenter.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotEmpty; + +import com.senmesh.common.dto.BaseOperateDTO; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author chenyun + * @description 重置密码DTO + * @date 2020/8/26 17:54 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ResetPasswordByPhoneDTO extends BaseOperateDTO implements Serializable { + private static final long serialVersionUID = 8505258030368487025L; + + /** + * 验证码 + */ + @NotEmpty(message = "短信验证码不能为空") + private String phoneCode; + + /** + * 新密码 + */ + @NotEmpty(message = "新密码不能为空") + private String newPassword; + + /** + * 确认密码 + */ + @NotEmpty(message = "确认新密码不能为空") + private String confirmPassword; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/Resource.java b/backend/src/main/java/com/senmesh/usercenter/dto/Resource.java new file mode 100644 index 0000000..be5bce7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/Resource.java @@ -0,0 +1,24 @@ +package com.senmesh.usercenter.dto; + +import org.springframework.security.access.ConfigAttribute; + +import java.io.Serializable; +import java.util.List; + +/** + * 支持授权的资源接口 + * + * @author on 2019-11-05 + */ +public interface Resource extends Serializable { + + Long getId(); + + /** + * 提供资源对于的权限信息 + * + * @return 权限信息 + */ + List getAttributes(); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/ResourceDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/ResourceDTO.java new file mode 100644 index 0000000..cbb53e9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/ResourceDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.dto; + +import com.senmesh.common.validation.Delete; +import com.senmesh.common.validation.Update; +import com.senmesh.usercenter.constants.SecurityValidateConstants; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + * 资源父dto + * @author sr on 2019-10-17 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class ResourceDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = -1196257535328529826L; + + @ApiModelProperty("资源id") + @NotNull(message = SecurityValidateConstants.RESOURCE_ID_NULL, groups = {Update.class, Delete.class}) + private Long id; + + @ApiModelProperty("是否授权") + private Boolean selected; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/RoleDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/RoleDTO.java new file mode 100644 index 0000000..39dd5f0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/RoleDTO.java @@ -0,0 +1,77 @@ +package com.senmesh.usercenter.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; +import com.senmesh.usercenter.constants.SecurityValidateConstants; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.io.Serializable; +import java.util.Date; + +/** + * 角色 + * + * @author sr on 2019-11-05 + */ +@ApiModel("角色") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RoleDTO implements Serializable { + + /** **/ + private static final long serialVersionUID = -1148469623294607563L; + + @ApiModelProperty("角色id") + @NotNull(message = SecurityValidateConstants.ROLE_ID_NULL, groups = {Update.class}) + private Long id; + + @ApiModelProperty("名称") + @NotBlank(message = SecurityValidateConstants.ROLE_NAME_EMPTY, groups = {Create.class}) + @Size(max = 128) + private String name; + + /** 类型 **/ + @JsonIgnore + private String type; + + @ApiModelProperty("是否启用") + private Boolean enabled; + + @ApiModelProperty("描述") + @Size(max = 64, groups = {Create.class, Update.class}) + private String description; + + @ApiModelProperty("标准角色类型:见role_standard_type") + private String standardType; + + @ApiModelProperty("标准角色名称") + private String standardRoleName; + + @ApiModelProperty("所属平台") + private Integer platformCode; + + @ApiModelProperty("创建时间") + @DateTimeFormat( + pattern = "yyyy-MM-dd HH:mm:ss" + ) + @JsonFormat( + shape = JsonFormat.Shape.STRING, + pattern = "yyyy-MM-dd HH:mm:ss", + timezone = "GMT+8" + ) + private Date createTime; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/RoleQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/RoleQueryDTO.java new file mode 100644 index 0000000..b035e8c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/RoleQueryDTO.java @@ -0,0 +1,17 @@ +package com.senmesh.usercenter.dto; + +import com.senmesh.common.dto.PageQueryDTO; + +import lombok.Data; + +@Data +public class RoleQueryDTO extends PageQueryDTO{ + + /** **/ + private static final long serialVersionUID = 2970842314451422682L; + + private String type; + private String name; + private Boolean enabled; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/RoleStandardTypeDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/RoleStandardTypeDTO.java new file mode 100644 index 0000000..1f5cdde --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/RoleStandardTypeDTO.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.dto; + +import java.io.Serializable; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author dylanyuan + */ +@ApiModel("标准角色") +@EqualsAndHashCode(callSuper = true) +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class RoleStandardTypeDTO extends BaseOperateDTO implements Serializable { + + private static final long serialVersionUID = 3433337468933511136L; + + @ApiModelProperty("编码") + private String roleCode; + + @ApiModelProperty("名称") + private String name; + + @ApiModelProperty("平台编码") + private String platformCode; + + @ApiModelProperty("顺序") + private Integer typeOrder; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/SecurityCodeRequestDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/SecurityCodeRequestDTO.java new file mode 100644 index 0000000..24bf039 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/SecurityCodeRequestDTO.java @@ -0,0 +1,41 @@ +package com.senmesh.usercenter.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import java.io.Serializable; + +/** + * @author chenyun + * @description 安全码DTO + * @date 2020/8/27 15:32 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class SecurityCodeRequestDTO implements Serializable { + + private static final long serialVersionUID = 9212030527588925234L; + + /** + * 短信验证码 + */ + @NotEmpty(message = "短信验证码不能为空") + private String phoneCode; + + /** + * 安全码 + */ + @NotEmpty(message = "安全码不能为空") + private String securityCode; + + /** + * 确认安全码 + */ + @NotEmpty(message = "确认安全码不能为空") + private String confirmSecurityCode; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/SuperResetPasswordDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/SuperResetPasswordDTO.java new file mode 100644 index 0000000..300780d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/SuperResetPasswordDTO.java @@ -0,0 +1,49 @@ +package com.senmesh.usercenter.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseOperateDTO; +import com.senmesh.common.validation.annotation.Expression; +import com.senmesh.common.validation.constants.ValidProviderEnum; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author chenyun + * @description 重置密码DTO + * @date 2020/7/27 10:55 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class SuperResetPasswordDTO extends BaseOperateDTO implements Serializable { + private static final long serialVersionUID = 8505258030368487025L; + + /** + * 用户ID + */ + @NotNull(message = "用户id不能为空") + private Long userId; + + /** + * 新密码 + */ + @ApiModelProperty("密码") + @Expression(type = ValidProviderEnum.PASSWORD, message = "密码格式不正确") + private String newPassword; + + /** + * 确认密码 + */ + @ApiModelProperty("二次确认密码") + @NotBlank(message = "二次确认密码不能为空") + private String confirmPassword; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/UserAllocateRoleDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/UserAllocateRoleDTO.java new file mode 100644 index 0000000..152f042 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/UserAllocateRoleDTO.java @@ -0,0 +1,32 @@ +package com.senmesh.usercenter.dto; + +import java.util.List; + +import javax.validation.constraints.NotNull; + +import com.senmesh.usercenter.constants.SecurityValidateConstants; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2019-10-17 + */ +@ApiModel("用户分配角色") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UserAllocateRoleDTO { + + @ApiModelProperty("操作角色id列表") + @NotNull(message = SecurityValidateConstants.ROLE_ID_NULL) + private List roleIds; + + @ApiModelProperty("操作类型:是否分配") + @NotNull(message = SecurityValidateConstants.ROLE_ALLOCATE_OPERATE_TYPE) + private Boolean allocated; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/dto/UserContractStatusDTO.java b/backend/src/main/java/com/senmesh/usercenter/dto/UserContractStatusDTO.java new file mode 100644 index 0000000..0cd123f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/dto/UserContractStatusDTO.java @@ -0,0 +1,23 @@ +package com.senmesh.usercenter.dto; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class UserContractStatusDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1126318170374281724L; + + private Long orgId; + private Long userId; + private Integer contractStatus; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/entity/CompanyBankAccount.java b/backend/src/main/java/com/senmesh/usercenter/entity/CompanyBankAccount.java new file mode 100644 index 0000000..92fe134 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/entity/CompanyBankAccount.java @@ -0,0 +1,38 @@ +package com.senmesh.usercenter.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.OrgBaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@TableName("xs_company_bank_account") +@Data +@AllArgsConstructor +@NoArgsConstructor +@SuperBuilder +public class CompanyBankAccount extends OrgBaseEntity { + + /** + * 支付账号 + */ + private String account; + + /** + * 是否默认银行账户 + */ + private Boolean defaulted; + + /** + * 开户名 + */ + private String accountName; + + /** + * 开户行 + */ + private String accountBankName; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/entity/CompanyContact.java b/backend/src/main/java/com/senmesh/usercenter/entity/CompanyContact.java new file mode 100644 index 0000000..24fb5c4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/entity/CompanyContact.java @@ -0,0 +1,53 @@ +package com.senmesh.usercenter.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.OrgBaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; +import lombok.experimental.SuperBuilder; + +/** + * @author Jerry.li + * @description 企业联系信息 + * @date 2020/3/27 + */ +@TableName("xs_company_contact") +@Data +@ToString +@SuperBuilder +@AllArgsConstructor +@NoArgsConstructor +public class CompanyContact extends OrgBaseEntity { + + private static final long serialVersionUID = -5534436456179658622L; + + /** + * 联系人 + */ + private String name; + /** + * 联系电话 + */ + private String phone; + /** + * 联系邮箱 + */ + private String email; + /** + * 联系地址 + */ + private String address; + + /** 类型:1联系信息2邮寄信息 **/ + private String type; + + /** 是否默认 **/ + private Boolean defaulted; + + /** 备注信息 **/ + private String remark; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/entity/CompanyExtend.java b/backend/src/main/java/com/senmesh/usercenter/entity/CompanyExtend.java new file mode 100644 index 0000000..f4eaeff --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/entity/CompanyExtend.java @@ -0,0 +1,32 @@ +package com.senmesh.usercenter.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.OrgBaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + + +/** + * @description: 企业扩展信息 + * @author: chenyun.huang + * @create: 2020-04-10 11:08 + **/ +@EqualsAndHashCode(callSuper = true) +@Data +@TableName("xs_company_extend") +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class CompanyExtend extends OrgBaseEntity { + private static final long serialVersionUID = 5630132200895607964L; + + /** + * 销售 + */ + private Long sellerId; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/entity/CompanyFile.java b/backend/src/main/java/com/senmesh/usercenter/entity/CompanyFile.java new file mode 100644 index 0000000..fa24683 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/entity/CompanyFile.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.OrgBaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; +import lombok.experimental.SuperBuilder; + +/** + * @author Jerry.li + * @description 企业附件 + * @date 2020/3/27 + */ +@TableName("xs_company_file") +@Data +@ToString +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class CompanyFile extends OrgBaseEntity { + + private static final long serialVersionUID = 3031159277420008898L; + + /** + * 附件编码 + */ + private String fileCode; + /** + * 附件名称 + */ + private String fileName; + /** + * 分类(1-其他;) + */ + private String type; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/entity/CompanyInvoice.java b/backend/src/main/java/com/senmesh/usercenter/entity/CompanyInvoice.java new file mode 100644 index 0000000..67da8e4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/entity/CompanyInvoice.java @@ -0,0 +1,52 @@ +package com.senmesh.usercenter.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.OrgBaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; +import lombok.experimental.SuperBuilder; + +/** + * @author Jerry.li + * @description 企业发票 + * @date 2020/3/28 + */ +@TableName("xs_company_invoice") +@Data +@ToString +@AllArgsConstructor +@NoArgsConstructor +@SuperBuilder +public class CompanyInvoice extends OrgBaseEntity { + + private static final long serialVersionUID = -5026281298873254982L; + + /** + * 发票抬头 + */ + private String title; + /** + * 税号 + */ + private String taxNo; + /** + * 地址 + */ + private String address; + /** + * 电话号码 + */ + private String phone; + /** + * 开户银行 + */ + private String bankName; + /** + * 银行账号 + */ + private String bankAccount; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/entity/MessageLog.java b/backend/src/main/java/com/senmesh/usercenter/entity/MessageLog.java new file mode 100644 index 0000000..35d289c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/entity/MessageLog.java @@ -0,0 +1,87 @@ +package com.senmesh.usercenter.entity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Date; + +/** + * @author: Jerry.li + * @description: 消息日志实体 + * @create: 2020-05-26 09:46 + **/ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class MessageLog implements Serializable { + + /** + * 编号 + */ + private Long id; + /** + * 发送者 + */ + private String msgSender; + /** + * 接收者 + */ + private String msgReceiver; + /** + * 消息主题 + */ + private String msgSubject; + /** + * 消息内容 + */ + private String msgContent; + /** + * 激活码 or 者验证码 + */ + private String verifyCode; + /** + * 验证状态:0-未验证 1-已验证 + */ + private Integer verifyStatus; + /** + * 发送状态:0-待发送 1-已发送 9-发送失败 2-手动补发成功 + */ + private Integer sendStatus; + /** + * 消息通道:1-短信 2-邮件 + */ + private Integer msgChannel; + /** + * 模板编号 + */ + private String templateCode; + /** + * 回执ID + */ + private String bizId; + /** + * 请求ID + */ + private String requestId; + /** + * 响应码 + */ + private String respCode; + /** + * 响应描述 + */ + private String respDesc; + /** + * 创建时间 + */ + private Date createTime; + /** + * 更新时间 + */ + private Date lastUpdateTime; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/entity/RoleStandardType.java b/backend/src/main/java/com/senmesh/usercenter/entity/RoleStandardType.java new file mode 100644 index 0000000..49fc836 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/entity/RoleStandardType.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @Author dylanyuan + * @Date 2021/2/19 1:46 下午 + * @Version 1.0 + */ +@EqualsAndHashCode(callSuper = true) +@TableName("xs_role_standard_type") +@NoArgsConstructor +@AllArgsConstructor +@Data +public class RoleStandardType extends BaseEntity { + + private static final long serialVersionUID = 928812997780345557L; + /** + * 编码 + **/ + private String roleCode; + /** + * 名称 + **/ + private String name; + /** + * 平台编码 + **/ + private String platformCode; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/enums/AllocationType.java b/backend/src/main/java/com/senmesh/usercenter/enums/AllocationType.java new file mode 100644 index 0000000..d8f1ac7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/enums/AllocationType.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.enums; + +/** + * @author Jerry.li + * @description 角色分配类型 + * @date 2020/3/26 + */ +public enum AllocationType { + ALLOCATION_TYPE_PERSON("1", "个人"), + ALLOCATION_TYPE_DEPARTMENT("2", "部门"), + ALLOCATION_TYPE_GROUP("3", "组"); + + /** + * 分配类型 + */ + private String type; + /** + * 类型描述 + */ + private String desc; + + AllocationType(String type, String desc) { + this.type = type; + this.desc = desc; + } + + + public String getAllocationType() { + return type; + } + + public String getAllocationTypeDesc() { + return desc; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/enums/AuthStatu.java b/backend/src/main/java/com/senmesh/usercenter/enums/AuthStatu.java new file mode 100644 index 0000000..d570837 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/enums/AuthStatu.java @@ -0,0 +1,52 @@ +package com.senmesh.usercenter.enums; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.annotation.EnumValue; +import com.senmesh.mybatis.handle.BaseEnum; + +import java.util.Arrays; + +/** + * 二要素认证状态 1:待认证 2:认证成功 3:认证失败 + */ +public enum AuthStatu implements BaseEnum { + AUTH_READY("1", "待认证"), + AUTH_SUCCESS("2", "认证成功"), + AUTH_FAILED("3", "认证失败"); + + AuthStatu(String statu, String desc) { + this.statu = statu; + this.desc = desc; + } + + /** + * 认证状态 + */ + @EnumValue + private final String statu; + /** + * 类型描述 + */ + private final String desc; + + public String getStatu() { + return statu; + } + + public String getType() { + return statu; + } + + public String getDesc() { + return desc; + } + + @Override + public String getValue() { + return this.statu; + } + + public static AuthStatu findByStatu(String statu) { + return Arrays.stream(AuthStatu.values()).filter(authStatu -> StrUtil.equals(authStatu.getType(), statu)).findFirst().orElse(null); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/enums/OrgTypeEnum.java b/backend/src/main/java/com/senmesh/usercenter/enums/OrgTypeEnum.java new file mode 100644 index 0000000..7ba0b91 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/enums/OrgTypeEnum.java @@ -0,0 +1,62 @@ +package com.senmesh.usercenter.enums; + +import java.util.Map; + +import com.baomidou.mybatisplus.annotation.EnumValue; +import com.google.common.collect.Maps; +import com.senmesh.mybatis.handle.BaseEnum; + +/** + * 机构类型 + * @author sr on 2024-04-18 + */ +public enum OrgTypeEnum implements BaseEnum { + + ORG_TYPE_PLATFORM("1", "平台"), + ORG_TYPE_GOV("2", "政府机构"), + ORG_TYPE_SIMPLE("3", "用工机构"), + ORG_TYPE_HR("4", "服务机构"), + ; + + OrgTypeEnum(String type, String desc) { + this.type = type; + this.desc = desc; + } + + /** + * 机构类型 + */ + @EnumValue + private final String type; + /** + * 机构类型描述 + */ + private final String desc; + + public String getType() { + return type; + } + + + static Map orgTypeMap ; + static { + OrgTypeEnum[] orgTypes = OrgTypeEnum.values(); + orgTypeMap = Maps.newHashMapWithExpectedSize(orgTypes.length); + for (OrgTypeEnum orgType :OrgTypeEnum.values()) { + orgTypeMap.put(orgType.getType(), orgType); + } + } + + public static OrgTypeEnum findByType(String orgType) { + return orgTypeMap.get(orgType); + } + + @Override + public String getValue() { + return this.type; + } + + + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/enums/ResourceType.java b/backend/src/main/java/com/senmesh/usercenter/enums/ResourceType.java new file mode 100644 index 0000000..4c6582a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/enums/ResourceType.java @@ -0,0 +1,28 @@ +package com.senmesh.usercenter.enums; + +/** + * @author: Jerry.li + * @description: 资源类型 + * @create: 2020-06-17 09:27 + **/ +public enum ResourceType { + RESOURCE_MENU_TYPE("1", "菜单"), + RESOURCE_COMPONENT_TYPE("2", "组件"), + RESOURCE_INTERFACE_TYPE("3", "接口"); + + ResourceType(String type, String desc) { + this.type = type; + this.desc = desc; + } + + private String type; + private String desc; + + public String getType() { + return type; + } + + public String getDesc() { + return desc; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/enums/SmsScenesEnum.java b/backend/src/main/java/com/senmesh/usercenter/enums/SmsScenesEnum.java new file mode 100644 index 0000000..899749c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/enums/SmsScenesEnum.java @@ -0,0 +1,56 @@ +package com.senmesh.usercenter.enums; + +import java.util.Arrays; + +/** + * SMS 短信使用场景 + */ +public enum SmsScenesEnum { + + CREATE_USER_INFO("1", "创建用户"), + UPDATE_USER_INFO("2", "更新用户"), + UPDATE_PAY_PASSWORD("3", "更新支付密码"), + CREATE_SAVE_CODE("4", "设置安全码"), + UPDATE_PASSWORD("5", "更新密码"), + WECHAT_USER_INFO("7", "微信端用户信息绑定"); + + private String type; + private String desc; + private String signName; + private SmsTemplateCodeEnum templateCode; + + SmsScenesEnum(String type, String desc) { + this.type = type; + this.desc = desc; + this.signName = null; + this.templateCode = SmsTemplateCodeEnum.PHONE_SMS; + } + + SmsScenesEnum(String type, String desc, String signName, SmsTemplateCodeEnum templateCode) { + this.type = type; + this.desc = desc; + this.signName = signName; + this.templateCode = templateCode; + } + + public String getType() { + return type; + } + + public String getDesc() { + return desc; + } + + public String getSignName() { + return signName; + } + + public SmsTemplateCodeEnum getTemplateCode() { + return templateCode; + } + + public static SmsScenesEnum findByType(String type) { + return Arrays.stream(SmsScenesEnum.values()) + .filter(smsScenesEnum -> smsScenesEnum.getType().equals(type)).findFirst().orElse(null); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/enums/SmsTemplateCodeEnum.java b/backend/src/main/java/com/senmesh/usercenter/enums/SmsTemplateCodeEnum.java new file mode 100644 index 0000000..ff50c8a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/enums/SmsTemplateCodeEnum.java @@ -0,0 +1,66 @@ +package com.senmesh.usercenter.enums; + +import com.senmesh.sdk.sms.dto.ITemplateCode; +import com.google.common.collect.Maps; + +import java.util.Map; + +/** + * 短信模版 + * + * @author sr on 2020-07-02 + */ +public enum SmsTemplateCodeEnum implements ITemplateCode { + + /** + * 手机短信模拟 + **/ + PHONE_SMS("phoneSms"), + + /** + * 岗位报名-邀请面试 + **/ + POSITION_INVITE("position_invite"), + + /** + * 岗位报名-面试通过 + **/ + POSITION_INTERVIEW_PASS("position_interview_pass"), + + /** + * 岗位报名-面试不通过 + **/ + POSITION_INTERVIEW_FAIL("position_interview_fail"), + + + ; + + private static final Map templateCodeMap; + + static { + SmsTemplateCodeEnum[] smsTemplateCodeEnums = SmsTemplateCodeEnum.values(); + templateCodeMap = Maps.newHashMapWithExpectedSize(smsTemplateCodeEnums.length); + for (SmsTemplateCodeEnum smsTemplateCodeEnum : smsTemplateCodeEnums) { + templateCodeMap.put(smsTemplateCodeEnum.getTemplateCodeKey(), smsTemplateCodeEnum); + } + } + + /** + * 模版配置键 + **/ + private String templateCodeKey; + + SmsTemplateCodeEnum(String templateCodeKey) { + this.templateCodeKey = templateCodeKey; + } + + @Override + public String getTemplateCodeKey() { + return this.templateCodeKey; + } + + public static SmsTemplateCodeEnum getByTemplateCodeKey(String templateCodeKey) { + return templateCodeMap.get(templateCodeKey); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/enums/UserType.java b/backend/src/main/java/com/senmesh/usercenter/enums/UserType.java new file mode 100644 index 0000000..4b1b50b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/enums/UserType.java @@ -0,0 +1,44 @@ +package com.senmesh.usercenter.enums; + +import com.baomidou.mybatisplus.annotation.EnumValue; +import com.senmesh.mybatis.handle.BaseEnum; + +/** + * @author Jerry.li + * @description 用户类型 + * @date 2020/3/24 + */ +public enum UserType implements BaseEnum { + USER_TYPE_PLATFORM("1", "平台管理员"), + USER_TYPE_ORG("2", "机构管理员"), + USER_TYPE_COMPANY("3", "企业用户"), + USER_TYPE_PERSON("4", "个人用户"); + + UserType(String type, String desc) { + this.type = type; + this.desc = desc; + } + + /** + * 用户类型 + */ + @EnumValue + private final String type; + /** + * 类型描述 + */ + private final String desc; + + public String getType() { + return type; + } + + public String getDesc() { + return desc; + } + + @Override + public String getValue() { + return this.type; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/face/controller/FaceController.java b/backend/src/main/java/com/senmesh/usercenter/face/controller/FaceController.java new file mode 100644 index 0000000..5946475 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/face/controller/FaceController.java @@ -0,0 +1,48 @@ +package com.senmesh.usercenter.face.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.face.dto.FaceCreateDTO; +import com.senmesh.usercenter.face.dto.FaceInfoDTO; +import com.senmesh.usercenter.face.dto.FacePageQueryDTO; +import com.senmesh.usercenter.face.service.FaceService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + + +/** + * org控制器 + * + * @author Carlye + * @date 2021/06/16 + */ +@RestController +@RequestMapping("/uc/face") +@Api(tags = "用户活体信息") +public class FaceController { + + @Autowired + private FaceService faceService; + + @ApiOperation("创建") + @PostMapping("/create") + public AlitaResult create(@RequestBody FaceCreateDTO createDTO) { + return AlitaResult.success(faceService.create(createDTO)); + } + + @ApiOperation("删除") + @PostMapping("/delete") + public AlitaResult delete(@RequestBody FaceInfoDTO infoDTO) { + faceService.delete(infoDTO); + return AlitaResult.success(); + } + + @ApiOperation("分页查询") + @GetMapping("/page") + public AlitaResult> page(FacePageQueryDTO queryDTO) { + faceService.page(queryDTO); + return AlitaResult.success(queryDTO.getPageResult()); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/face/dao/FaceMapper.java b/backend/src/main/java/com/senmesh/usercenter/face/dao/FaceMapper.java new file mode 100644 index 0000000..81e44de --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/face/dao/FaceMapper.java @@ -0,0 +1,21 @@ +package com.senmesh.usercenter.face.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.senmesh.usercenter.face.dto.FaceInfoDTO; +import com.senmesh.usercenter.face.dto.FacePageQueryDTO; +import com.senmesh.usercenter.face.entity.Face; + +import java.util.List; + +/** + *

+ * 活体 Mapper 接口 + *

+ * + * @author Carlye + * @since 2021-06-16 + */ +public interface FaceMapper extends BaseMapper { + + List page(FacePageQueryDTO queryDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/face/dto/FaceCreateDTO.java b/backend/src/main/java/com/senmesh/usercenter/face/dto/FaceCreateDTO.java new file mode 100644 index 0000000..5b334af --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/face/dto/FaceCreateDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.face.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FaceCreateDTO implements Serializable { + private static final long serialVersionUID = -871298279722550146L; + + /** + * 用户ID + */ + private Long userId; + + /** + * 类型 1:照片 2:视频 + */ + @NotNull(message = "活体类型不能为空") + private Integer type; + + /** + * 文件编码 + */ + @NotEmpty(message = "文件编码不能为空") + private String fileCode; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/face/dto/FaceInfoDTO.java b/backend/src/main/java/com/senmesh/usercenter/face/dto/FaceInfoDTO.java new file mode 100644 index 0000000..419816a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/face/dto/FaceInfoDTO.java @@ -0,0 +1,28 @@ +package com.senmesh.usercenter.face.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FaceInfoDTO implements Serializable { + private static final long serialVersionUID = 4838665122721131760L; + + private Long id; + + /** + * 类型 1:照片 2:视频 + */ + private Integer type; + + /** + * 文件编码 + */ + private String fileCode; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/face/dto/FacePageQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/face/dto/FacePageQueryDTO.java new file mode 100644 index 0000000..a4b917c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/face/dto/FacePageQueryDTO.java @@ -0,0 +1,32 @@ +package com.senmesh.usercenter.face.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import com.senmesh.common.util.UserContextHolder; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Objects; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FacePageQueryDTO extends PageQueryDTO { + + private static final long serialVersionUID = -5013896780324404266L; + /** + * 类型 1:照片 2:视频 + */ + private Integer type; + + private Long userId; + + public Long getUserId() { + if (Objects.isNull(userId)) { + userId = UserContextHolder.getExistLoginUserId(); + } + return userId; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/face/entity/Face.java b/backend/src/main/java/com/senmesh/usercenter/face/entity/Face.java new file mode 100644 index 0000000..0dbf343 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/face/entity/Face.java @@ -0,0 +1,41 @@ +package com.senmesh.usercenter.face.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; +import com.senmesh.usercenter.face.enums.FaceTypeEnum; +import lombok.*; +import lombok.experimental.Accessors; + +/** + *

+ * 机构 + *

+ * + * @author Carlye + * @since 2021-06-16 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableName("uc_user_face") +public class Face extends BaseEntity { + + private static final long serialVersionUID = -2769462084799607560L; + /** + * 用户ID + */ + private Long userId; + + /** + * 类型 1:照片 2:视频 + */ + private FaceTypeEnum type; + + /** + * 文件编码 + */ + private String fileCode; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/face/enums/FaceTypeEnum.java b/backend/src/main/java/com/senmesh/usercenter/face/enums/FaceTypeEnum.java new file mode 100644 index 0000000..094f7ef --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/face/enums/FaceTypeEnum.java @@ -0,0 +1,38 @@ +package com.senmesh.usercenter.face.enums; + +import com.baomidou.mybatisplus.annotation.EnumValue; + +/** + * 活体表类型 枚举类型 + * + * @author Carlye + * @date 2021/10/28 + */ +public enum FaceTypeEnum { + + IMG(1, "照片"), + VIDEO(2, "视频"); + + /** + * 关联类型 + */ + @EnumValue + private final Integer type; + /** + * 类型描述 + */ + private final String desc; + + FaceTypeEnum(Integer type, String desc) { + this.type = type; + this.desc = desc; + } + + public Integer getType() { + return type; + } + + public String getDesc() { + return desc; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/face/mapper/FaceMapper.xml b/backend/src/main/java/com/senmesh/usercenter/face/mapper/FaceMapper.xml new file mode 100644 index 0000000..2f26a3a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/face/mapper/FaceMapper.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/backend/src/main/java/com/senmesh/usercenter/face/service/FaceService.java b/backend/src/main/java/com/senmesh/usercenter/face/service/FaceService.java new file mode 100644 index 0000000..7ccd384 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/face/service/FaceService.java @@ -0,0 +1,38 @@ +package com.senmesh.usercenter.face.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.senmesh.usercenter.face.dto.FaceCreateDTO; +import com.senmesh.usercenter.face.dto.FaceInfoDTO; +import com.senmesh.usercenter.face.dto.FacePageQueryDTO; +import com.senmesh.usercenter.face.entity.Face; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.groups.Default; +import java.util.List; + +@Validated(Default.class) +public interface FaceService extends IService { + + /** + * 创建 + * + * @param createDTO 创建dto + */ + FaceInfoDTO create(@Valid FaceCreateDTO createDTO); + + /** + * 删除 + * @param faceInfoDTO + */ + void delete(FaceInfoDTO faceInfoDTO); + + /** + * 页面 + * + * @param queryDTO 查询dto + * @return {@link List}<{@link FaceInfoDTO}> + */ + List page(FacePageQueryDTO queryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/face/service/impl/FaceServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/face/service/impl/FaceServiceImpl.java new file mode 100644 index 0000000..15e0ce1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/face/service/impl/FaceServiceImpl.java @@ -0,0 +1,63 @@ +package com.senmesh.usercenter.face.service.impl; + +import cn.hutool.core.date.DateUtil; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.EnumUtil; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.face.dao.FaceMapper; +import com.senmesh.usercenter.face.dto.FaceCreateDTO; +import com.senmesh.usercenter.face.dto.FaceInfoDTO; +import com.senmesh.usercenter.face.dto.FacePageQueryDTO; +import com.senmesh.usercenter.face.entity.Face; +import com.senmesh.usercenter.face.enums.FaceTypeEnum; +import com.senmesh.usercenter.face.service.FaceService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Objects; + +/** + * 用户活体 服务impl + * + * @author Carlye + * @date 2021/06/16 + */ +@Slf4j +@Service +public class FaceServiceImpl extends ServiceImpl implements FaceService { + + @Override + public FaceInfoDTO create(FaceCreateDTO createDTO) { + Long userId = Objects.isNull(createDTO.getUserId()) ? UserContextHolder.getExistLoginUserId() : createDTO.getUserId(); + FaceTypeEnum resolve = EnumUtil.resolve(FaceTypeEnum::getType, createDTO.getType()); + Assert.notNull(resolve, "活体类型错误"); + List list = list(Wrappers.lambdaQuery().eq(Face::getUserId, userId).eq(Face::getType, resolve).eq(Face::getDeleted, false)); + if (list.size() > 0) { + Face face = list.get(0); + return FaceInfoDTO.builder().id(face.getId()).type(face.getType().getType()).fileCode(face.getFileCode()).build(); + } else { + Face face = Face.builder().userId(userId).type(resolve).fileCode(createDTO.getFileCode()).build(); + save(face); + return FaceInfoDTO.builder().id(face.getId()).type(face.getType().getType()).fileCode(face.getFileCode()).build(); + } + } + + @Override + public void delete(FaceInfoDTO faceInfoDTO) { + update(Wrappers.lambdaUpdate() + .set(Face::getDeleted, true) + .set(Face::getUpdateBy, UserContextHolder.getExistLoginUserId()) + .set(Face::getUpdateTime, DateUtil.date()) + .eq(Face::getId, faceInfoDTO.getId()) + .eq(Face::getUserId, UserContextHolder.getExistLoginUserId()) + ); + } + + @Override + public List page(FacePageQueryDTO queryDTO) { + return getBaseMapper().page(queryDTO); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/mapper/UcMessageMapper.xml b/backend/src/main/java/com/senmesh/usercenter/mapper/UcMessageMapper.xml new file mode 100644 index 0000000..e610117 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/mapper/UcMessageMapper.xml @@ -0,0 +1,97 @@ + + + + + + insert into xs_message_log + ( + msg_sender, + msg_receiver, + msg_subject, + msg_content, + msg_channel, + template_code, + verify_code, + verify_status + ) + values( + #{msgSender}, + #{msgReceiver}, + #{msgSubject}, + #{msgContent}, + #{msgChannel}, + #{templateCode}, + #{verifyCode}, + #{verifyStatus} + ) + + + + + + + + update xs_message_log + set + + verify_status = #{verifyStatus}, + + + send_status = #{sendStatus}, + + + biz_id = #{bizId}, + + + request_id = #{requestId}, + + + resp_code = #{respCode}, + + + resp_desc = #{respDesc}, + + last_update_time = now() + where id = #{id} + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/mapper/XsRoleStandardTypeMapper.xml b/backend/src/main/java/com/senmesh/usercenter/mapper/XsRoleStandardTypeMapper.xml new file mode 100644 index 0000000..01a45db --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/mapper/XsRoleStandardTypeMapper.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/config/NoticeProperties.java b/backend/src/main/java/com/senmesh/usercenter/notice/config/NoticeProperties.java new file mode 100644 index 0000000..2930f2c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/config/NoticeProperties.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.notice.config; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@ConfigurationProperties(prefix = "notice") +@Data +@Component +public class NoticeProperties { + + private Map wechatOffiaccountMsgs = new HashMap<>(); + + @Data + @NoArgsConstructor + public static class WechatOffiaccountMsgProvider { + + /** 通知模版标识 **/ + private String noticeTemplateCode; + + /** 微信公众号消息模版id **/ + private String templateId; + + /** 微信公众号消息链接 **/ + private String link; + + } + + + public WechatOffiaccountMsgProvider getWechatOffiaccountProvider(String providerCode) { + return this.wechatOffiaccountMsgs.get(providerCode); + } + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeChannelTypeEnum.java b/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeChannelTypeEnum.java new file mode 100644 index 0000000..36348ea --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeChannelTypeEnum.java @@ -0,0 +1,32 @@ +package com.senmesh.usercenter.notice.constant; + +/** + * 消息通道类型: + * @author sr on 2020-12-21 + */ +public enum NoticeChannelTypeEnum { + + /** 1站内信 **/ + SITE(1), + /** 2短信 **/ + SMS(2), + /** 3钉钉 **/ + DING_TALK(3), + /** 4企业微信 **/ + WORK_WECHAT(4), + /** 5邮件 **/ + MAIL(5), + /** 6微信公众号 **/ + WECHAT_OFFIACCOUNT(6); + + NoticeChannelTypeEnum(Integer type) { + this.type = type; + } + + private Integer type; + + public Integer getType() { + return type; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeContentTemplateConstants.java b/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeContentTemplateConstants.java new file mode 100644 index 0000000..bff628e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeContentTemplateConstants.java @@ -0,0 +1,8 @@ +package com.senmesh.usercenter.notice.constant; + +/** + * @author sr on 2020-12-20 + */ +public interface NoticeContentTemplateConstants { + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeLevelEnum.java b/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeLevelEnum.java new file mode 100644 index 0000000..e747395 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeLevelEnum.java @@ -0,0 +1,24 @@ +package com.senmesh.usercenter.notice.constant; + +/** + * 级别: + * @author sr on 2020-12-21 + */ +public enum NoticeLevelEnum { + + /** 1平台 **/ + PLATFORM(1), + /** 2机构 **/ + ORG(2); + + NoticeLevelEnum(Integer type) { + this.type = type; + } + + private Integer type; + + public Integer getType() { + return type; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeModuleTypeEnum.java b/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeModuleTypeEnum.java new file mode 100644 index 0000000..4235ef4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeModuleTypeEnum.java @@ -0,0 +1,24 @@ +package com.senmesh.usercenter.notice.constant; + +/** + * 模块分类 + * @author sr on 2020-12-21 + */ +public enum NoticeModuleTypeEnum { + + /** 1业务 **/ + BIZ(1), + /** 2监控/预警 **/ + ACTUATOR(2); + + NoticeModuleTypeEnum(Integer type) { + this.type = type; + } + + private Integer type; + + public Integer getType() { + return type; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeReceiverSettingConstants.java b/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeReceiverSettingConstants.java new file mode 100644 index 0000000..c9d5445 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeReceiverSettingConstants.java @@ -0,0 +1,8 @@ +package com.senmesh.usercenter.notice.constant; + +/** + * @author sr on 2020-12-20 + */ +public interface NoticeReceiverSettingConstants { + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeReceiverStatusEnum.java b/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeReceiverStatusEnum.java new file mode 100644 index 0000000..e8a3cfd --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeReceiverStatusEnum.java @@ -0,0 +1,28 @@ +package com.senmesh.usercenter.notice.constant; + +/** + * 接收状态: + * @author sr on 2020-12-21 + */ +public enum NoticeReceiverStatusEnum { + + /** 1待发送 **/ + INIT(1), + /** 2已发送 **/ + SENT(2), + /** 3发送失败 **/ + SEND_FAIL(3), + /** 4接收已读 **/ + READ(4); + + NoticeReceiverStatusEnum(Integer type) { + this.type = type; + } + + private Integer type; + + public Integer getType() { + return type; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeReceiverTypeEnum.java b/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeReceiverTypeEnum.java new file mode 100644 index 0000000..178b6bb --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeReceiverTypeEnum.java @@ -0,0 +1,26 @@ +package com.senmesh.usercenter.notice.constant; + +/** + * 接收人关联类型: + * @author sr on 2020-12-21 + */ +public enum NoticeReceiverTypeEnum { + + /** 1用户id **/ + USER(1), + /** 2角色 **/ + ROLE(2), + /** 3标准角色 **/ + STANDARD_ROLE(3); + + NoticeReceiverTypeEnum(Integer type) { + this.type = type; + } + + private Integer type; + + public Integer getType() { + return type; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeSendStatusEnum.java b/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeSendStatusEnum.java new file mode 100644 index 0000000..3281532 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeSendStatusEnum.java @@ -0,0 +1,25 @@ +package com.senmesh.usercenter.notice.constant; + +/** + * 接收状态: + * @author sr on 2020-12-21 + */ +public enum NoticeSendStatusEnum { + + /** 1待处理 **/ + INIT(1), + /** 2已处理 **/ + SENT(2); + + + NoticeSendStatusEnum(Integer type) { + this.type = type; + } + + private Integer type; + + public Integer getType() { + return type; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeTemplateCodeEnum.java b/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeTemplateCodeEnum.java new file mode 100644 index 0000000..86f042b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/constant/NoticeTemplateCodeEnum.java @@ -0,0 +1,23 @@ +package com.senmesh.usercenter.notice.constant; + +public enum NoticeTemplateCodeEnum { + + /** 岗位报名-邀请面试 */ + POSITION_INVITE("position_invite"), + /** 岗位报名-面试通过 */ + POSITION_INTERVIEW_PASS("position_interview_pass"), + /** 岗位报名-面试不通过 */ + POSITION_INTERVIEW_FAIL("position_interview_fail"), + ; + + private String type; + + NoticeTemplateCodeEnum(String type) { + this.type = type; + } + + public String getType() { + return type; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/controller/NoticeContentTemplateController.java b/backend/src/main/java/com/senmesh/usercenter/notice/controller/NoticeContentTemplateController.java new file mode 100644 index 0000000..4e727f6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/controller/NoticeContentTemplateController.java @@ -0,0 +1,69 @@ +package com.senmesh.usercenter.notice.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.common.validation.Update; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.notice.dto.NoticeContentTemplateDTO; +import com.senmesh.usercenter.notice.dto.NoticeContentTemplateOperateDTO; +import com.senmesh.usercenter.notice.dto.NoticeContentTemplateQueryDTO; +import com.senmesh.usercenter.notice.service.NoticeContentTemplateService; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2020-12-20 + */ +@RestController +@RequestMapping("notice_content_template") +@Api(tags = "通知消息体模版") +public class NoticeContentTemplateController{ + + @Autowired + private NoticeContentTemplateService noticeContentTemplateService; + + @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create( + @Validated @RequestBody NoticeContentTemplateOperateDTO noticeContentTemplateOperateDTO){ + UserContextHolder.checkPlatformOrg(); + return AlitaResult.success(noticeContentTemplateService.create(noticeContentTemplateOperateDTO)); + } + + @PutMapping("/modify") + @ApiOperation("修改") + public AlitaResult modify( + @Validated(Update.class) @RequestBody NoticeContentTemplateOperateDTO noticeContentTemplateOperateDTO){ + UserContextHolder.checkPlatformOrg(); + noticeContentTemplateService.modify(noticeContentTemplateOperateDTO); + return AlitaResult.success(true); + } + + @DeleteMapping("/remove/{id}") + @ApiOperation("删除") + public AlitaResult remove(@PathVariable Long id){ + UserContextHolder.checkPlatformOrg(); + noticeContentTemplateService.remove(id); + return AlitaResult.success(true); + } + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(NoticeContentTemplateQueryDTO noticeContentTemplateQueryDTO){ + noticeContentTemplateService.page(noticeContentTemplateQueryDTO); + return AlitaResult.success(noticeContentTemplateQueryDTO.getPageResult()); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/controller/NoticeReceiverSettingController.java b/backend/src/main/java/com/senmesh/usercenter/notice/controller/NoticeReceiverSettingController.java new file mode 100644 index 0000000..3a901ab --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/controller/NoticeReceiverSettingController.java @@ -0,0 +1,84 @@ +package com.senmesh.usercenter.notice.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +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; + +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingDTO; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingOperateDTO; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingQueryDTO; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingRemoveDTO; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingRoleDTO; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingUserDTO; +import com.senmesh.usercenter.notice.service.NoticeReceiverSettingService; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2020-12-20 + */ +@RestController +@RequestMapping("notice_receiver_setting") +@Api(tags = "通知接收人设置") +public class NoticeReceiverSettingController{ + + @Autowired + private NoticeReceiverSettingService noticeReceiverSettingService; + + @PostMapping("/create") + @ApiOperation("创建(新增)") + public AlitaResult create( + @Validated @RequestBody NoticeReceiverSettingOperateDTO noticeReceiverSettingOperateDTO) { + noticeReceiverSettingService.create(noticeReceiverSettingOperateDTO); + return AlitaResult.success(true); + } + + @PostMapping("/save") + @ApiOperation("保存设置(内部判断新增/删除)") + public AlitaResult save( + @Validated @RequestBody NoticeReceiverSettingOperateDTO noticeReceiverSettingOperateDTO) { + noticeReceiverSettingService.save(noticeReceiverSettingOperateDTO); + return AlitaResult.success(true); + } + + @DeleteMapping("/remove") + @ApiOperation("删除") + public AlitaResult remove( + @Validated @RequestBody NoticeReceiverSettingRemoveDTO noticeReceiverSettingRemoveDTO) { + noticeReceiverSettingService.remove(noticeReceiverSettingRemoveDTO); + return AlitaResult.success(true); + } + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page( + NoticeReceiverSettingQueryDTO noticeReceiverSettingQueryDTO) { + noticeReceiverSettingService.list(noticeReceiverSettingQueryDTO); + return AlitaResult.success(noticeReceiverSettingQueryDTO.getPageResult()); + } + + @GetMapping("/page_user") + @ApiOperation("分页查询") + public AlitaResult> pageUser( + @Validated NoticeReceiverSettingQueryDTO noticeReceiverSettingQueryDTO){ + noticeReceiverSettingService.listUser(noticeReceiverSettingQueryDTO); + return AlitaResult.success(noticeReceiverSettingQueryDTO.getPageResult()); + } + + @GetMapping("/page_role") + @ApiOperation("分页查询") + public AlitaResult> pageRole( + @Validated NoticeReceiverSettingQueryDTO noticeReceiverSettingQueryDTO){ + noticeReceiverSettingService.listRole(noticeReceiverSettingQueryDTO); + return AlitaResult.success(noticeReceiverSettingQueryDTO.getPageResult()); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/controller/NoticeSendRecordController.java b/backend/src/main/java/com/senmesh/usercenter/notice/controller/NoticeSendRecordController.java new file mode 100644 index 0000000..f750c5d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/controller/NoticeSendRecordController.java @@ -0,0 +1,47 @@ +package com.senmesh.usercenter.notice.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +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; + +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordOperateDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordQueryDTO; +import com.senmesh.usercenter.notice.service.NoticeSendRecordService; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2020-12-20 + */ +@RestController +@RequestMapping("notice_send_record") +@Api(tags = "通知发送记录(内容模版级)") +public class NoticeSendRecordController { + + @Autowired + private NoticeSendRecordService noticeSendRecordService; + + @PostMapping("/create") + @ApiOperation("创建(发送通知)") + public AlitaResult create( + @Validated @RequestBody NoticeSendRecordOperateDTO noticeSendRecordOperateDTO){ + noticeSendRecordService.create(noticeSendRecordOperateDTO); + return AlitaResult.success(true); + } + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(NoticeSendRecordQueryDTO noticeSendRecordQueryDTO){ + noticeSendRecordService.page(noticeSendRecordQueryDTO); + return AlitaResult.success(noticeSendRecordQueryDTO.getPageResult()); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/controller/NoticeSendRecordDetailController.java b/backend/src/main/java/com/senmesh/usercenter/notice/controller/NoticeSendRecordDetailController.java new file mode 100644 index 0000000..8bc4221 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/controller/NoticeSendRecordDetailController.java @@ -0,0 +1,64 @@ +package com.senmesh.usercenter.notice.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDetailDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDetailQueryDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDetailReqDTO; +import com.senmesh.usercenter.notice.service.NoticeSendRecordDetailService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +/** + * @author sr on 2020-12-20 + */ +@RestController +@RequestMapping("notice_send_record_detail") +@Api(tags = "通知发送记录明细") +public class NoticeSendRecordDetailController { + + @Autowired + private NoticeSendRecordDetailService noticeSendRecordDetailService; + + @PostMapping("/page") + @ApiOperation("分页查询(当前登录人通知)") + public AlitaResult> page(@RequestBody + NoticeSendRecordDetailQueryDTO noticeSendRecordDetailQueryDTO) { + noticeSendRecordDetailQueryDTO.setUserId(noticeSendRecordDetailQueryDTO.getOperateUserId()); + noticeSendRecordDetailService.list(noticeSendRecordDetailQueryDTO); + return AlitaResult.success(noticeSendRecordDetailQueryDTO.getPageResult()); + } + + @GetMapping("/detail") + @ApiOperation("单个明细查询") + public AlitaResult detail(@Validated NoticeSendRecordDetailReqDTO reqDTO) { + return AlitaResult.success(noticeSendRecordDetailService.detail(reqDTO)); + } + + + @PostMapping("/count") + @ApiOperation("消息数量查询(当前登录人通知)") + public AlitaResult count(@RequestBody NoticeSendRecordDetailQueryDTO noticeSendRecordDetailQueryDTO) { + noticeSendRecordDetailQueryDTO.setUserId(noticeSendRecordDetailQueryDTO.getOperateUserId()); + return AlitaResult.success(noticeSendRecordDetailService.count(noticeSendRecordDetailQueryDTO)); + } + + // 已读 + @PostMapping("/read/{recordDetailId}") + @ApiOperation("已读通知") + public AlitaResult read(@PathVariable Long recordDetailId){ + noticeSendRecordDetailService.read(recordDetailId); + return AlitaResult.success(true); + } + + @PostMapping("/read_all") + @ApiOperation("已读通知") + public AlitaResult readAll(){ + noticeSendRecordDetailService.readAll(); + return AlitaResult.success(true); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/controller/NoticeTemplateController.java b/backend/src/main/java/com/senmesh/usercenter/notice/controller/NoticeTemplateController.java new file mode 100644 index 0000000..a26cff4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/controller/NoticeTemplateController.java @@ -0,0 +1,75 @@ +package com.senmesh.usercenter.notice.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.common.validation.Update; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.notice.dto.NoticeTemplateDTO; +import com.senmesh.usercenter.notice.dto.NoticeTemplateOperateDTO; +import com.senmesh.usercenter.notice.dto.NoticeTemplateQueryDTO; +import com.senmesh.usercenter.notice.service.NoticeTemplateService; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2020-12-17 + */ +@RestController +@RequestMapping("notice_template") +@Api(tags = "通知模版") +public class NoticeTemplateController{ + + @Autowired + private NoticeTemplateService noticeTemplateService; + + @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create( + @Validated @RequestBody NoticeTemplateOperateDTO noticeTemplateOperateDTO) { + UserContextHolder.checkPlatformOrg(); + return AlitaResult.success(noticeTemplateService.create(noticeTemplateOperateDTO)); + } + + @PutMapping("/modify") + @ApiOperation("修改") + public AlitaResult modify( + @Validated(Update.class) @RequestBody NoticeTemplateOperateDTO noticeTemplateOperateDTO) { + UserContextHolder.checkPlatformOrg(); + noticeTemplateService.modify(noticeTemplateOperateDTO); + return AlitaResult.success(true); + } + + @DeleteMapping("/remove/{id}") + @ApiOperation("删除") + public AlitaResult remove(@PathVariable Long id) { + UserContextHolder.checkPlatformOrg(); + noticeTemplateService.remove(id); + return AlitaResult.success(true); + } + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(NoticeTemplateQueryDTO noticeTemplateQueryDTO) { + noticeTemplateService.page(noticeTemplateQueryDTO); + return AlitaResult.success(noticeTemplateQueryDTO.getPageResult()); + } + + @GetMapping("/find/{id}") + @ApiOperation("单个查询") + public AlitaResult find(@PathVariable Long id) { + return AlitaResult.success(noticeTemplateService.find(id)); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dao/NoticeContentTemplateMapper.java b/backend/src/main/java/com/senmesh/usercenter/notice/dao/NoticeContentTemplateMapper.java new file mode 100644 index 0000000..38f5b8d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dao/NoticeContentTemplateMapper.java @@ -0,0 +1,29 @@ +package com.senmesh.usercenter.notice.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.notice.dto.NoticeContentTemplateDTO; +import com.senmesh.usercenter.notice.dto.NoticeContentTemplateQueryDTO; +import com.senmesh.usercenter.notice.entity.NoticeContentTemplate; + +/** + * 通知消息体模版 + * + * @author sr on 2020-12-20 + */ +public interface NoticeContentTemplateMapper extends MyMapper { + + /** + * 查询 + * + * @param noticeContentTemplateQueryDTO + * @return + * @author sr on 2020-12-20 + */ + List listNoticeContentTemplateDTO( + @Param("param") NoticeContentTemplateQueryDTO noticeContentTemplateQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dao/NoticeReceiverSettingMapper.java b/backend/src/main/java/com/senmesh/usercenter/notice/dao/NoticeReceiverSettingMapper.java new file mode 100644 index 0000000..651c1e3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dao/NoticeReceiverSettingMapper.java @@ -0,0 +1,110 @@ +package com.senmesh.usercenter.notice.dao; + +import java.util.List; +import java.util.Set; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingDTO; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingOperateDTO; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingQueryDTO; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingRemoveDTO; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingRoleDTO; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingUserDTO; +import com.senmesh.usercenter.notice.entity.NoticeReceiverSetting; + +/** + * 通知接收人设置 + * + * @author sr on 2020-12-20 + */ +public interface NoticeReceiverSettingMapper extends MyMapper { + + /** + * 查询 + * + * @param noticeReceiverSettingQueryDTO + * @return + * @author sr on 2020-12-20 + */ + List listNoticeReceiverSettingDTO( + @Param("param") NoticeReceiverSettingQueryDTO noticeReceiverSettingQueryDTO); + + /** + * 根据模版id删除接收人配置 + * + * @param noticeReceiverSettingRemoveDTO + * @return + * @author sr on 2020-12-20 + */ + int remove(@Param("param") NoticeReceiverSettingRemoveDTO noticeReceiverSettingRemoveDTO); + + /** + * 查询操作机构接收人现有配置 + * + * @param noticeReceiverSettingOperateDTO + * @return + * @author sr on 2020-12-20 + */ + Set findReceiverUnionIds( + @Param("param") NoticeReceiverSettingOperateDTO noticeReceiverSettingOperateDTO); + + /** + * 新增接收人配置 + * @param noticeReceiverSettingOperateDTO + * @param receiverUnionIds + * @return + * @author sr on 2020-12-21 + */ + int create(@Param("param") NoticeReceiverSettingOperateDTO noticeReceiverSettingOperateDTO, + @Param("receiverUnionIds") Set receiverUnionIds); + + /** + * 根据关联id获取用户id + * + * @param orgId + * @param unionType + * @param unionIds + * @return + * @author sr on 2020-12-21 + */ + Set findUserIdByUnionType(Long orgId, Integer unionType, Set unionIds); + + /** + * 获取有效用户 + * + * @return + * @author sr on 2020-12-21 + */ + Set validUser(Long orgId, Set userIds); + + /** + * 获取有效角色 + * @param orgId + * @param roleIds + * @return + * @author sr on 2020-12-21 + */ + Set validRole(Long orgId, Set roleIds); + + /** + * 查询接收人-用户 + * + * @param noticeReceiverSettingQueryDTO + * @return + * @author sr on 2021-01-07 + */ + List listNoticeReceiverSettingUserDTO( + @Param("param") NoticeReceiverSettingQueryDTO noticeReceiverSettingQueryDTO); + + /** + * 查询接收人-角色 + * + * @param noticeReceiverSettingQueryDTO + * @return + * @author sr on 2021-01-07 + */ + List listNoticeReceiverSettingRoleDTO( + @Param("param") NoticeReceiverSettingQueryDTO noticeReceiverSettingQueryDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dao/NoticeSendRecordDetailMapper.java b/backend/src/main/java/com/senmesh/usercenter/notice/dao/NoticeSendRecordDetailMapper.java new file mode 100644 index 0000000..c1c702e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dao/NoticeSendRecordDetailMapper.java @@ -0,0 +1,55 @@ +package com.senmesh.usercenter.notice.dao; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDetailDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDetailQueryDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDetailReqDTO; +import com.senmesh.usercenter.notice.dto.RecordDetailUpdateStatusDTO; +import com.senmesh.usercenter.notice.entity.NoticeSendRecordDetail; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 通知发送记录明细(接收人) + * + * @author sr on 2020-12-20 + */ +public interface NoticeSendRecordDetailMapper extends MyMapper { + + /** + * 查询 + * + * @param noticeSendRecordDetailQueryDTO + * @return + * @author sr on 2020-12-20 + */ + List listNoticeSendRecordDetailDTO( + @Param("param") NoticeSendRecordDetailQueryDTO noticeSendRecordDetailQueryDTO); + + /** + * @param noticeSendRecordDetails + * @param operateUserId + * @author sr on 2020-12-21 + */ + void createDetails(@Param("entities") List noticeSendRecordDetails, + @Param("operateUserId") Long operateUserId); + + int modifyStatus(@Param("param") RecordDetailUpdateStatusDTO recordDetailUpdateStatusDTO); + + /** + * 详细通知发送记录数 + * + * @param noticeSendRecordDetailQueryDTO 通知发送记录详细查询dto + * @return {@link Integer} + */ + Integer countNoticeSendRecordDetail(@Param("param") NoticeSendRecordDetailQueryDTO noticeSendRecordDetailQueryDTO); + + /** + * 查询消息详情 + * + * @param reqDTO 通知发送记录详细查询dto + * @return {@link NoticeSendRecordDetailDTO} + */ + NoticeSendRecordDetailDTO findNoticeSendRecordDetailDTO(@Param("param") NoticeSendRecordDetailReqDTO reqDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dao/NoticeSendRecordMapper.java b/backend/src/main/java/com/senmesh/usercenter/notice/dao/NoticeSendRecordMapper.java new file mode 100644 index 0000000..4e9a6d9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dao/NoticeSendRecordMapper.java @@ -0,0 +1,38 @@ +package com.senmesh.usercenter.notice.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordModifyDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordQueryDTO; +import com.senmesh.usercenter.notice.entity.NoticeSendRecord; + +/** + * 通知发送记录(内容模版级) + * + * @author sr on 2020-12-20 + */ +public interface NoticeSendRecordMapper extends MyMapper { + + /** + * 查询 + * + * @param noticeSendRecordQueryDTO + * @return + * @author sr on 2020-12-20 + */ + List listNoticeSendRecordDTO(@Param("param") NoticeSendRecordQueryDTO noticeSendRecordQueryDTO); + + /** + * 修改 + * + * @param noticeSendRecordModifyDTO + * @return + * @author sr on 2021-02-08 + */ + int modify(@Param("param")NoticeSendRecordModifyDTO noticeSendRecordModifyDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dao/NoticeTemplateMapper.java b/backend/src/main/java/com/senmesh/usercenter/notice/dao/NoticeTemplateMapper.java new file mode 100644 index 0000000..c6a35a0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dao/NoticeTemplateMapper.java @@ -0,0 +1,29 @@ +package com.senmesh.usercenter.notice.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.notice.dto.NoticeTemplateDTO; +import com.senmesh.usercenter.notice.dto.NoticeTemplateQueryDTO; +import com.senmesh.usercenter.notice.entity.NoticeTemplate; + +/** + * 通知模版 + * + * @author sr on 2020-12-17 + */ +public interface NoticeTemplateMapper extends MyMapper { + + /** + * 查询 + * + * @param noticeTemplateQueryDto + * @return + * @author sr on 2020-12-17 + */ + List listNoticeTemplateDTO( + @Param("param") NoticeTemplateQueryDTO noticeTemplateQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeContentTemplateDTO.java b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeContentTemplateDTO.java new file mode 100644 index 0000000..34b8378 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeContentTemplateDTO.java @@ -0,0 +1,42 @@ +package com.senmesh.usercenter.notice.dto; + +import java.io.Serializable; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2020-12-17 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "通知消息体模版") +public class NoticeContentTemplateDTO extends BaseDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("通知模版id") + private Long templateId ; + @ApiModelProperty("消息通道类型:1站内信,2短信,3钉钉,4企业微信,5邮件(见notice_channel_type)") + private Integer channelType ; + @ApiModelProperty("标题") + private String title; + @ApiModelProperty("内容模版") + private String contentTemplate ; + @ApiModelProperty("是否启用") + private Boolean enabled; + @ApiModelProperty("链接") + private String link; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeContentTemplateOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeContentTemplateOperateDTO.java new file mode 100644 index 0000000..b3b828f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeContentTemplateOperateDTO.java @@ -0,0 +1,53 @@ +package com.senmesh.usercenter.notice.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseOperateDTO; +import com.senmesh.common.validation.Update; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-12-20 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "通知消息体模版") +public class NoticeContentTemplateOperateDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + @NotNull(message = "id不能为空", groups = {Update.class}) + private Long id; + @ApiModelProperty("通知模版id") + @NotNull(message = "通知模版id不能为空") + private Long templateId ; + @ApiModelProperty("消息通道类型:1站内信,2短信,3钉钉,4企业微信,5邮件(见notice_channel_type)") + @NotNull(message = "消息通道类型不能为空") + private Integer channelType ; + @ApiModelProperty("标题") + @NotBlank(message = "标题不能为空") + private String title; + @ApiModelProperty("内容模版") + @NotBlank(message = "内容模版不能为空") + private String contentTemplate ; + @ApiModelProperty("是否启用") + private Boolean enabled; + @ApiModelProperty("链接") + private String link; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeContentTemplateQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeContentTemplateQueryDTO.java new file mode 100644 index 0000000..43ca23e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeContentTemplateQueryDTO.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.notice.dto; + +import java.io.Serializable; + +import com.senmesh.common.dto.PageQueryDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-12-17 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "通知消息体模版查询条件") +public class NoticeContentTemplateQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + @ApiModelProperty("通知模版id") + private Long templateId ; + @ApiModelProperty("消息通道类型:1站内信,2短信,3钉钉,4企业微信,5邮件 等(见notice_channel_type)") + private Integer channelType ; + @ApiModelProperty("标题(模糊匹配)") + private String titleLike; + @ApiModelProperty("是否启用") + private Boolean enabled; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeReceiverSettingDTO.java b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeReceiverSettingDTO.java new file mode 100644 index 0000000..71851b8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeReceiverSettingDTO.java @@ -0,0 +1,42 @@ +package com.senmesh.usercenter.notice.dto; + +import java.io.Serializable; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2020-12-17 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "通知接收人设置") +public class NoticeReceiverSettingDTO extends BaseDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("通知模版id") + private Long templateId ; + @ApiModelProperty("机构id") + private Long orgId ; + @ApiModelProperty("接收人关联类型:1用户id,2角色,3标准角色(见notice_receiver_type)") + private Integer receiverUnionType ; + @ApiModelProperty("接收人关联id:用户id,角色id,标准角色id") + private Long receiverUnionId ; + @ApiModelProperty("接受人名称") + private String receiverName; + @ApiModelProperty("是否启用") + private Boolean enabled; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeReceiverSettingOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeReceiverSettingOperateDTO.java new file mode 100644 index 0000000..5b4e733 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeReceiverSettingOperateDTO.java @@ -0,0 +1,42 @@ +package com.senmesh.usercenter.notice.dto; + +import java.io.Serializable; +import java.util.Set; + +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-12-20 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "通知接收人设置") +public class NoticeReceiverSettingOperateDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("通知模版id") + @NotNull(message = "通知模版id不能为空") + private Long templateId ; + @ApiModelProperty("接收人关联类型:1用户id,2角色,3标准角色(见notice_receiver_type)") + @NotNull(message = "接收人关联类型不能为空") + private Integer receiverUnionType ; + @ApiModelProperty("接收人关联id:用户id,角色id,标准角色id") + @NotNull(message = "接收人关联id不能为空") + private Set receiverUnionIds ; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeReceiverSettingQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeReceiverSettingQueryDTO.java new file mode 100644 index 0000000..5818b32 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeReceiverSettingQueryDTO.java @@ -0,0 +1,47 @@ +package com.senmesh.usercenter.notice.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotNull; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; + +import com.senmesh.common.dto.PageQueryDTO; + +/** + * PageQueryDTO 范型 NoticeReceiverSettingDTO或其子类 + * + * @author sr on 2020-12-17 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "通知接收人设置查询条件") +public class NoticeReceiverSettingQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + @ApiModelProperty("通知模版id") + @NotNull(message = "通知模版id不能为空") + private Long templateId ; + @ApiModelProperty("机构id") + private Long orgId ; + @ApiModelProperty("接收人关联类型:1用户id,2角色,3标准角色(见notice_receiver_type)") + private Integer receiverUnionType ; + + public Long getOrgId() { + return orgId == null ? getOperateOrgId() : orgId; + } + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeReceiverSettingRemoveDTO.java b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeReceiverSettingRemoveDTO.java new file mode 100644 index 0000000..c839105 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeReceiverSettingRemoveDTO.java @@ -0,0 +1,50 @@ +package com.senmesh.usercenter.notice.dto; + +import java.io.Serializable; +import java.util.Set; + +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-12-20 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(description = "删除通知接收人") +public class NoticeReceiverSettingRemoveDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = -9143022441853162885L; + + @ApiModelProperty("通知模版id") + @NotNull(message = "通知模版id不能为空") + private Long templateId ; + @ApiModelProperty("接收人关联类型:1用户id,2角色,3标准角色(见notice_receiver_type)") + @NotNull(message = "接收人关联类型不能为空") + private Integer receiverUnionType ; + @ApiModelProperty("接收人关联id:用户id,角色id,标准角色id") + private Set receiverUnionIds ; + + @Builder + public NoticeReceiverSettingRemoveDTO(Long operateOrgId, Long operateUserId, + @NotNull(message = "通知模版id不能为空") Long templateId, + @NotNull(message = "接收人关联类型不能为空") Integer receiverUnionType, Set receiverUnionIds) { + super(operateOrgId, operateUserId); + this.templateId = templateId; + this.receiverUnionType = receiverUnionType; + this.receiverUnionIds = receiverUnionIds; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeReceiverSettingRoleDTO.java b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeReceiverSettingRoleDTO.java new file mode 100644 index 0000000..bbca841 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeReceiverSettingRoleDTO.java @@ -0,0 +1,30 @@ +package com.senmesh.usercenter.notice.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2021-01-07 + */ +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Data +@ApiModel(description = "通知接收人设置--用户") +public class NoticeReceiverSettingRoleDTO extends NoticeReceiverSettingDTO{ + + /** **/ + private static final long serialVersionUID = 8752617190208418705L; + + @ApiModelProperty("角色名称") + private String roleName; + @ApiModelProperty("是否启用") + private Boolean enabled; + @ApiModelProperty("标准角色") + private Integer standardType; + @ApiModelProperty("所属平台") + private Integer platformCode; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeReceiverSettingUserDTO.java b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeReceiverSettingUserDTO.java new file mode 100644 index 0000000..31b0beb --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeReceiverSettingUserDTO.java @@ -0,0 +1,28 @@ +package com.senmesh.usercenter.notice.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2021-01-07 + */ +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Data +@ApiModel(description = "通知接收人设置--用户") +public class NoticeReceiverSettingUserDTO extends NoticeReceiverSettingDTO{ + + /** **/ + private static final long serialVersionUID = 8752617190208418705L; + + @ApiModelProperty("账户名") + private String username; + @ApiModelProperty("中文名") + private String chineseName; + @ApiModelProperty("是否启用") + private Boolean enabled; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordDTO.java b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordDTO.java new file mode 100644 index 0000000..2dd83b0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordDTO.java @@ -0,0 +1,75 @@ +package com.senmesh.usercenter.notice.dto; + +import java.io.Serializable; +import java.util.Collections; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.senmesh.common.dto.BaseDTO; +import com.senmesh.common.util.JsonUtils; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2020-12-17 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "通知发送记录(内容模版级)") +public class NoticeSendRecordDTO extends BaseDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("通知模版id") + private Long templateId ; + @ApiModelProperty("发送方机构id") + private Long senderOrgId ; + @ApiModelProperty("接收方机构id") + private Long receiverOrgId ; + @ApiModelProperty("消息体模版id") + private Long contentTemplateId ; + @ApiModelProperty("消息体参数") + private String contentParamData ; + @ApiModelProperty("消息体") + private String content ; + @ApiModelProperty("是否指定接收方(非预先设定)") + private Boolean appointed ; + + @ApiModelProperty("状态:1待处理,2已处理(见notice_send_status)") + private Integer status ; + @ApiModelProperty("消息通道类型:1站内信,2短信,3钉钉,4企业微信,5邮件 等(见notice_channel_type)") + private Integer channelType ; + @ApiModelProperty("标题") + private String title; + @ApiModelProperty("内容模版") + private String contentTemplate ; + @ApiModelProperty("链接") + private String link; + + @JsonIgnore + private Map contentParamDataMap; + + public Map getContentParamDataMap(){ + if (contentParamDataMap == null) { + if (StringUtils.isNotBlank(contentParamData)) { + contentParamDataMap = JsonUtils.toObject(this.getContentParamData(), Map.class); + } else { + contentParamDataMap = Collections.emptyMap(); + } + } + return contentParamDataMap; + } + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordDetailDTO.java b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordDetailDTO.java new file mode 100644 index 0000000..9548d98 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordDetailDTO.java @@ -0,0 +1,47 @@ +package com.senmesh.usercenter.notice.dto; + +import java.io.Serializable; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2020-12-17 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "通知发送记录明细(接收人)") +public class NoticeSendRecordDetailDTO extends BaseDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("发送记录id") + private Long recordId ; + @ApiModelProperty("接收人id") + private Long userId ; + @ApiModelProperty("接收方帐号") + private String receiverAccountNo ; + @ApiModelProperty("接收状态:1待发送,2已发送,3发送失败,4接收已读(见notice_receiver_status)") + private Integer receiverStatus ; + + @ApiModelProperty("通知模版code") + private String templateCode; + @ApiModelProperty("标题") + private String title; + @ApiModelProperty("链接") + private String link; + @ApiModelProperty("消息体") + private String content ; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordDetailOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordDetailOperateDTO.java new file mode 100644 index 0000000..96cf653 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordDetailOperateDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.notice.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-12-20 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "通知发送记录明细(接收人)") +public class NoticeSendRecordDetailOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("发送记录id") + private Long recordId ; + @ApiModelProperty("接收人id") + private Long userId ; + @ApiModelProperty("接收方帐号") + private String receiverAccountNo ; + @ApiModelProperty("接收状态:1待发送,2已发送,3发送失败,4接收已读(见notice_receiver_status)") + private Integer receiverStatus ; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordDetailQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordDetailQueryDTO.java new file mode 100644 index 0000000..2813a72 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordDetailQueryDTO.java @@ -0,0 +1,63 @@ +package com.senmesh.usercenter.notice.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.io.Serializable; +import java.util.Date; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +/** + * @author sr on 2020-12-17 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "通知发送记录明细(接收人)查询条件") +public class NoticeSendRecordDetailQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + @ApiModelProperty("发送记录id") + private Long recordId ; + @ApiModelProperty("通知模版id") + private Long templateId ; + // 或模版code + @ApiModelProperty("通知模版code") + private String templateCode; + @ApiModelProperty("消息通道类型:1站内信,2短信,3钉钉,4企业微信,5邮件(见notice_channel_type)") + private Integer channelType ; + @JsonIgnore + @ApiModelProperty("接收人id") + private Long userId ; + @ApiModelProperty("接收状态:1待发送,2已发送,3发送失败,4接收已读(见notice_receiver_status)") + private Integer receiverStatus ; + @ApiModelProperty("消息通知时间起") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat( + shape = JsonFormat.Shape.STRING, + pattern = "yyyy-MM-dd HH:mm:ss", + timezone = "GMT+8" + ) + private Date createTimeStart ; + @ApiModelProperty("消息通知时间止") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat( + shape = JsonFormat.Shape.STRING, + pattern = "yyyy-MM-dd HH:mm:ss", + timezone = "GMT+8" + ) + private Date createTimeEnd ; +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordDetailReqDTO.java b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordDetailReqDTO.java new file mode 100644 index 0000000..53244cd --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordDetailReqDTO.java @@ -0,0 +1,43 @@ +package com.senmesh.usercenter.notice.dto; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.senmesh.common.util.UserContextHolder; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Objects; + +/** + * @author sr on 2020-12-17 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "通知发送记录明细(接收人)查询条件") +public class NoticeSendRecordDetailReqDTO implements Serializable{ + + private static final long serialVersionUID = -3715540940245404664L; + /** **/ + + @ApiModelProperty("id") + @NotNull(message = "消息ID不能为空") + private Long id; + + @JsonIgnore + @ApiModelProperty("接收人id") + private Long userId ; + + public Long getUserId() { + if (Objects.isNull(userId)){ + userId = UserContextHolder.getExistLoginUserId(); + } + return userId; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordModifyDTO.java b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordModifyDTO.java new file mode 100644 index 0000000..8809f49 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordModifyDTO.java @@ -0,0 +1,34 @@ +package com.senmesh.usercenter.notice.dto; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2021-02-08 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "通知发送记录-修改") +public class NoticeSendRecordModifyDTO extends BaseOperateDTO{ + + /** **/ + private static final long serialVersionUID = 1035598395983126645L; + + @ApiModelProperty("id") + private Long id; + @ApiModelProperty("旧状态") + public Integer oldStatus; + @ApiModelProperty("新状态") + public Integer newStatus; + @ApiModelProperty("消息体") + private String content ; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordOperateDTO.java new file mode 100644 index 0000000..5f6c3d0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordOperateDTO.java @@ -0,0 +1,66 @@ +package com.senmesh.usercenter.notice.dto; + +import com.senmesh.usercenter.notice.constant.NoticeChannelTypeEnum; +import java.io.Serializable; +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.Maps; +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Builder.Default; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-12-20 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "通知发送记录(内容模版级)") +public class NoticeSendRecordOperateDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("通知模版id") + private Long templateId ; + // 或模版code + @ApiModelProperty("通知模版code") + private String templateCode; + + @ApiModelProperty("消息体模版id") + private Long contentTemplateId ; + // 或消息体通道类型 + @ApiModelProperty("消息通道类型:1站内信,2短信,3钉钉,4企业微信,5邮件(见notice_channel_type)") + @Default + private Integer channelType = NoticeChannelTypeEnum.SITE.getType(); + + @ApiModelProperty("接收方机构id,不传平台模版取1,非平台模版取当前上下文机构id") + private Long receiverOrgId ; + @ApiModelProperty("消息体参数") + @Default + private Map contentParamDataMap = Maps.newHashMap(); + @ApiModelProperty("指定接收人") + private Set receiverUserIds; + + /** 定制,通道类型不能为空 **/ + @ApiModelProperty("定制模版内容") + private Boolean customContent; + @ApiModelProperty("标题") + private String title; + @ApiModelProperty("内容模版") + private String contentTemplate ; + @ApiModelProperty("链接") + private String link; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordQueryDTO.java new file mode 100644 index 0000000..a2f5623 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeSendRecordQueryDTO.java @@ -0,0 +1,44 @@ +package com.senmesh.usercenter.notice.dto; + +import java.io.Serializable; + +import com.senmesh.common.dto.PageQueryDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-12-17 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "通知发送记录(内容模版级)查询条件") +public class NoticeSendRecordQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + @ApiModelProperty("通知模版id") + private Long templateId ; + @ApiModelProperty("通知模版code") + private String templateCode; + @ApiModelProperty("发送方机构id") + private Long senderOrgId ; + @ApiModelProperty("消息通道类型:1站内信,2短信,3钉钉,4企业微信,5邮件(见notice_channel_type)") + private Integer channelType ; + @ApiModelProperty("接收人id") + private Long userId ; + @ApiModelProperty("状态:1待处理,2已处理(见notice_send_status)") + private Integer status ; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeTemplateDTO.java b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeTemplateDTO.java new file mode 100644 index 0000000..6ed6498 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeTemplateDTO.java @@ -0,0 +1,41 @@ +package com.senmesh.usercenter.notice.dto; + +import java.io.Serializable; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2020-12-17 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "通知") +public class NoticeTemplateDTO extends BaseDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("通知模版code") + private String templateCode; + @ApiModelProperty("通知名称") + private String templateName ; + @ApiModelProperty("模块分类:1业务,2监控/预警(见notice_module_type)") + private Integer moduleType; + @ApiModelProperty("业务分类:") + private Integer bizType; + @ApiModelProperty("级别:1平台,2机构(见notice_level)") + private Integer level; + @ApiModelProperty("是否启用") + private Boolean enabled; +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeTemplateOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeTemplateOperateDTO.java new file mode 100644 index 0000000..b028a06 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeTemplateOperateDTO.java @@ -0,0 +1,53 @@ +package com.senmesh.usercenter.notice.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseOperateDTO; +import com.senmesh.common.validation.Update; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-12-17 + */ +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Data +@EqualsAndHashCode(callSuper = true) +@ApiModel(description = "通知") +public class NoticeTemplateOperateDTO extends BaseOperateDTO implements Serializable { + + /** **/ + private static final long serialVersionUID = 6246259217863925980L; + + @ApiModelProperty("id") + @NotNull(message = "id不能为空", groups = {Update.class}) + private Long id; + @ApiModelProperty("通知模版code") + @NotBlank(message = "模版标识不能为空") + private String templateCode; + @ApiModelProperty("通知名称") + @NotBlank(message = "模版名称不能为空") + private String templateName ; + @ApiModelProperty("模块分类:1业务,2监控/预警(见notice_module_type)") + @NotNull(message = "模块分类不能为空") + private Integer moduleType; + @ApiModelProperty("业务分类:") + private Integer bizType; + @ApiModelProperty("级别:1平台,2机构(见notice_level)") + @NotNull(message = "级别不能为空") + private Integer level; + @ApiModelProperty("是否启用") + private Boolean enabled; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeTemplateQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeTemplateQueryDTO.java new file mode 100644 index 0000000..4d61bb2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dto/NoticeTemplateQueryDTO.java @@ -0,0 +1,41 @@ +package com.senmesh.usercenter.notice.dto; + +import com.senmesh.common.annotation.trimAndUpper.TrimAndUpper; +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import java.io.Serializable; + +/** + * @author sr on 2020-12-17 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class NoticeTemplateQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + @ApiModelProperty("通知模版code") + private String templateCode; + @ApiModelProperty("通知模版code(模糊匹配)") + @TrimAndUpper(TrimAndUpper.ExecuteType.TRIM) + private String templateCodeLike; + @ApiModelProperty("通知名称(模糊匹配)") + @TrimAndUpper(TrimAndUpper.ExecuteType.TRIM) + private String templateNameLike ; + @ApiModelProperty("模块分类:1业务,2监控/预警(见notice_module_type)") + private Integer moduleType; + @ApiModelProperty("级别:1平台,2机构(见notice_level)") + private Integer level; + @ApiModelProperty("是否启用") + private Boolean enabled; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/dto/RecordDetailUpdateStatusDTO.java b/backend/src/main/java/com/senmesh/usercenter/notice/dto/RecordDetailUpdateStatusDTO.java new file mode 100644 index 0000000..1009c59 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/dto/RecordDetailUpdateStatusDTO.java @@ -0,0 +1,48 @@ +package com.senmesh.usercenter.notice.dto; + +import java.io.Serializable; +import java.util.Set; + +import javax.validation.constraints.NotEmpty; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-12-28 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel("通知发送记录更新状态") +public class RecordDetailUpdateStatusDTO extends BaseOperateDTO implements Serializable { + + /** **/ + private static final long serialVersionUID = 2700111335512586751L; + + @ApiModelProperty("旧状态") + @NotEmpty(message = "旧状态不能为空") + private Integer oldStatus; + @ApiModelProperty("新状态") + @NotEmpty(message = "新状态不能为空") + private Integer newStatus; + @ApiModelProperty("通知发送记录明细id") + private Long recordDetailId; + @ApiModelProperty("通知发送记录明细id集合") + private Set recordDetailIds; + @ApiModelProperty("通知发送记录id") + private Long recordId; + @ApiModelProperty("消息通道类型") + @NotEmpty(message = "消息通道类型不能为空") + private Integer channelType; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/entity/NoticeContentTemplate.java b/backend/src/main/java/com/senmesh/usercenter/notice/entity/NoticeContentTemplate.java new file mode 100644 index 0000000..d017d05 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/entity/NoticeContentTemplate.java @@ -0,0 +1,56 @@ +package com.senmesh.usercenter.notice.entity; + +import java.io.Serializable; +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; +import com.senmesh.usercenter.notice.constant.NoticeChannelTypeEnum; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 通知消息体模版 + * + * @author sr on 2020-12-17 + */ +@TableName("notice_content_template") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Data +public class NoticeContentTemplate extends BaseEntity implements Serializable { + + /** **/ + private static final long serialVersionUID = 1L; + /** 通知模版id */ + private Long templateId ; + /** {@link NoticeChannelTypeEnum} 消息通道类型:1站内信,2短信,3钉钉,4企业微信,5邮件 等(见notice_channel_type) */ + private Integer channelType ; + /** 标题 **/ + private String title; + /** 内容模版 */ + private String contentTemplate ; + /** 是否启用 **/ + private Boolean enabled; + /** 链接 **/ + private String link; + + @Builder + public NoticeContentTemplate(Long id, Boolean deleted, Long createBy, Date createTime, + Long updateBy, Date updateTime, Long proxyBy, Long templateId, Integer channelType, + String title, String contentTemplate, Boolean enabled, String link) { + super(id, deleted, createBy, createTime, updateBy, updateTime, proxyBy); + this.templateId = templateId; + this.channelType = channelType; + this.title = title; + this.contentTemplate = contentTemplate; + this.enabled = enabled; + this.link = link; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/entity/NoticeReceiverSetting.java b/backend/src/main/java/com/senmesh/usercenter/notice/entity/NoticeReceiverSetting.java new file mode 100644 index 0000000..fdd031c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/entity/NoticeReceiverSetting.java @@ -0,0 +1,50 @@ +package com.senmesh.usercenter.notice.entity; + +import java.io.Serializable; +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 通知接收人设置 + * + * @author sr on 2020-12-17 + */ +@TableName("notice_receiver_setting") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Data +public class NoticeReceiverSetting extends BaseEntity implements Serializable { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 通知模版id */ + private Long templateId ; + /** 机构id */ + private Long orgId ; + /** 接收人关联类型:1用户id,2角色,3标准角色(见notice_receiver_type) */ + private Integer receiverUnionType ; + /** 接收人关联id:用户id,角色id,标准角色id */ + private Long receiverUnionId ; + + @Builder + public NoticeReceiverSetting(Long id, Boolean deleted, Long createBy, Date createTime, + Long updateBy, Date updateTime, Long proxyBy, Long templateId, Long orgId, + Integer receiverUnionType, Long receiverUnionId) { + super(id, deleted, createBy, createTime, updateBy, updateTime, proxyBy); + this.templateId = templateId; + this.orgId = orgId; + this.receiverUnionType = receiverUnionType; + this.receiverUnionId = receiverUnionId; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/entity/NoticeSendRecord.java b/backend/src/main/java/com/senmesh/usercenter/notice/entity/NoticeSendRecord.java new file mode 100644 index 0000000..bee8df6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/entity/NoticeSendRecord.java @@ -0,0 +1,56 @@ +package com.senmesh.usercenter.notice.entity; + +import java.io.Serializable; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; +import com.senmesh.usercenter.notice.constant.NoticeChannelTypeEnum; +import com.senmesh.usercenter.notice.constant.NoticeSendStatusEnum; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 通知发送记录(内容模版级) + * + * @author sr on 2020-12-17 + */ +@TableName("notice_send_record") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Data +public class NoticeSendRecord extends BaseEntity implements Serializable { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 通知模版id */ + private Long templateId ; + /** 发送方机构id */ + private Long senderOrgId ; + /** 接收方机构id */ + private Long receiverOrgId ; + /** 消息体模版id */ + private Long contentTemplateId ; + /** 消息体参数 */ + private String contentParamData ; + /** 消息体 */ + private String content ; + /** 是否指定接收方(非预先设定) **/ + private Boolean appointed ; + + /** {@link NoticeSendStatusEnum}状态:1待处理,2已处理(见notice_send_status) */ + private Integer status ; + /** {@link NoticeChannelTypeEnum} 消息通道类型:1站内信,2短信,3钉钉,4企业微信,5邮件 等(见notice_channel_type) */ + private Integer channelType ; + /** 标题 **/ + private String title; + /** 内容模版 */ + private String contentTemplate ; + /** 链接 **/ + private String link; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/entity/NoticeSendRecordDetail.java b/backend/src/main/java/com/senmesh/usercenter/notice/entity/NoticeSendRecordDetail.java new file mode 100644 index 0000000..38be7af --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/entity/NoticeSendRecordDetail.java @@ -0,0 +1,51 @@ +package com.senmesh.usercenter.notice.entity; + +import java.io.Serializable; +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 通知发送记录明细(接收人) + * + * @author sr on 2020-12-17 + */ +@TableName("notice_send_record_detail") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Builder +@Data +public class NoticeSendRecordDetail extends BaseEntity implements Serializable { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 发送记录id */ + private Long recordId ; + /** 接收人id */ + private Long userId ; + /** 接收方帐号 */ + private String receiverAccountNo ; + /** 接收状态:1待发送,2已发送,3发送失败,4接收已读(见notice_receiver_status) */ + private Integer receiverStatus ; + + @Builder + public NoticeSendRecordDetail(Long id, Boolean deleted, Long createBy, Date createTime, + Long updateBy, Date updateTime, Long proxyBy, Long recordId, Long userId, + String receiverAccountNo, Integer receiverStatus) { + super(id, deleted, createBy, createTime, updateBy, updateTime, proxyBy); + this.recordId = recordId; + this.userId = userId; + this.receiverAccountNo = receiverAccountNo; + this.receiverStatus = receiverStatus; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/entity/NoticeTemplate.java b/backend/src/main/java/com/senmesh/usercenter/notice/entity/NoticeTemplate.java new file mode 100644 index 0000000..f8fe75c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/entity/NoticeTemplate.java @@ -0,0 +1,57 @@ +package com.senmesh.usercenter.notice.entity; + +import java.io.Serializable; +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 通知模版 + * + * @author sr on 2020-12-17 + */ +@TableName("notice_template") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Data +public class NoticeTemplate extends BaseEntity implements Serializable { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 通知模版code */ + private String templateCode ; + /** 通知名称 **/ + private String templateName ; + /** 模块分类:1业务,2监控/预警(见notice_module_type) */ + private Integer moduleType ; + /** 业务分类: */ + private Integer bizType ; + /** 级别:1平台,2机构(见notice_level) */ + private Integer level ; + /** 是否启用 **/ + private Boolean enabled; + + @Builder + public NoticeTemplate(Long id, Boolean deleted, Long createBy, Date createTime, Long updateBy, + Date updateTime, Long proxyBy, String templateCode, String templateName, Integer moduleType, Integer bizType, + Integer level, Boolean enabled) { + super(id, deleted, createBy, createTime, updateBy, updateTime, proxyBy); + this.templateCode = templateCode; + this.templateName = templateName; + this.moduleType = moduleType; + this.bizType = bizType; + this.level = level; + this.enabled = enabled; + } + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/mapper/NoticeContentTemplateMapper.xml b/backend/src/main/java/com/senmesh/usercenter/notice/mapper/NoticeContentTemplateMapper.xml new file mode 100644 index 0000000..24fa1af --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/mapper/NoticeContentTemplateMapper.xml @@ -0,0 +1,29 @@ + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/mapper/NoticeReceiverSettingMapper.xml b/backend/src/main/java/com/senmesh/usercenter/notice/mapper/NoticeReceiverSettingMapper.xml new file mode 100644 index 0000000..30ec2f0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/mapper/NoticeReceiverSettingMapper.xml @@ -0,0 +1,207 @@ + + + + + + + update + notice_receiver_setting + set + deleted = TRUE, + update_time = now(), + update_by = #{param.operateUserId} + where + template_id = #{param.templateId} + and receiver_union_type = #{param.receiverUnionType} + and org_id = #{param.operateOrgId} + and deleted = FALSE + + and receiver_union_id in + + #{receiverUnionId} + + + + + + + + insert into notice_receiver_setting + ( + template_id, + org_id, + receiver_union_type, + receiver_union_id, + deleted, + create_by, + create_time + ) values + + (#{param.templateId}, + #{param.operateOrgId}, + #{param.receiverUnionType}, + #{receiverUnionId}, + 0, + #{param.operateUserId}, + now()) + + + + + + + + + + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/mapper/NoticeSendRecordDetailMapper.xml b/backend/src/main/java/com/senmesh/usercenter/notice/mapper/NoticeSendRecordDetailMapper.xml new file mode 100644 index 0000000..184489a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/mapper/NoticeSendRecordDetailMapper.xml @@ -0,0 +1,171 @@ + + + + + + + + + insert into notice_send_record_detail + ( + record_id, + user_id, + receiver_account_no, + receiver_status, + deleted, + create_by, + create_time + ) + values + + (#{item.recordId}, + #{item.userId}, + #{item.receiverAccountNo}, + #{item.receiverStatus}, + 0, + #{operateUserId}, + now()) + + + + + update notice_send_record_detail rd + set + rd.receiver_status = #{param.newStatus}, + rd.update_by = #{param.operateUserId}, + rd.update_time = now() + where + rd.receiver_status = #{param.oldStatus} + and rd.deleted = FALSE + + and exists ( + select * + from notice_send_record r + where r.id = rd.record_id + and r.deleted = FALSE + and r.channel_type = #{param.channelType} + ) + + + and rd.user_id = #{param.operateUserId} + + + and rd.id = #{param.recordDetailId} + + + and rd.record_id = #{param.param.recordId} + + + and rd.id in + + #{detailId} + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/mapper/NoticeSendRecordMapper.xml b/backend/src/main/java/com/senmesh/usercenter/notice/mapper/NoticeSendRecordMapper.xml new file mode 100644 index 0000000..5e02088 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/mapper/NoticeSendRecordMapper.xml @@ -0,0 +1,58 @@ + + + + + + + update + notice_send_record + + status = #{param.newStatus}, + update_by = #{param.operateUserId}, + update_time = now(), + + content = #{param.content}, + + + where + id = #{param.id} + and status = #{param.oldStatus} + and deleted = FALSE + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/mapper/NoticeTemplateMapper.xml b/backend/src/main/java/com/senmesh/usercenter/notice/mapper/NoticeTemplateMapper.xml new file mode 100644 index 0000000..ee87d17 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/mapper/NoticeTemplateMapper.xml @@ -0,0 +1,37 @@ + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/mapstruct/NoticeContentTemplateMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/notice/mapstruct/NoticeContentTemplateMapMapper.java new file mode 100644 index 0000000..70b2d90 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/mapstruct/NoticeContentTemplateMapMapper.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.notice.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.notice.dto.NoticeContentTemplateDTO; +import com.senmesh.usercenter.notice.entity.NoticeContentTemplate; +import com.senmesh.usercenter.notice.dto.NoticeContentTemplateOperateDTO; + +/** + * @author sr on 2020-12-20 + */ +@Mapper +public interface NoticeContentTemplateMapMapper { + + NoticeContentTemplateMapMapper INSTANCE = + Mappers.getMapper(NoticeContentTemplateMapMapper.class); + + /** + * dto to entity + * + * @param noticeContentTemplateDto + * @return + * @author sr on 2020-12-20 + */ + NoticeContentTemplate toEntity( + NoticeContentTemplateDTO noticeContentTemplateDto); + + + /** + * @param noticeContentTemplateOperateDTO + * @return + * @author sr on 2020-12-20 + */ + NoticeContentTemplate toEntity(NoticeContentTemplateOperateDTO noticeContentTemplateOperateDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/mapstruct/NoticeReceiverSettingMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/notice/mapstruct/NoticeReceiverSettingMapMapper.java new file mode 100644 index 0000000..faa4388 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/mapstruct/NoticeReceiverSettingMapMapper.java @@ -0,0 +1,45 @@ +package com.senmesh.usercenter.notice.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingDTO; +import com.senmesh.usercenter.notice.entity.NoticeReceiverSetting; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingOperateDTO; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingRemoveDTO; + +/** + * @author sr on 2020-12-20 + */ +@Mapper +public interface NoticeReceiverSettingMapMapper { + + NoticeReceiverSettingMapMapper INSTANCE = + Mappers.getMapper(NoticeReceiverSettingMapMapper.class); + + /** + * dto to entity + * + * @param noticeReceiverSettingDto + * @return + * @author sr on 2020-12-20 + */ + NoticeReceiverSetting toEntity( + NoticeReceiverSettingDTO noticeReceiverSettingDto); + + + /** + * @param noticeReceiverSettingOperateDTO + * @return + * @author sr on 2020-12-20 + */ + NoticeReceiverSetting toEntity(NoticeReceiverSettingOperateDTO noticeReceiverSettingOperateDTO); + + /** + * @param noticeReceiverSettingOperateDTO + * @return + * @author sr on 2020-12-21 + */ + NoticeReceiverSettingRemoveDTO toRemoveDTO(NoticeReceiverSettingOperateDTO noticeReceiverSettingOperateDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/mapstruct/NoticeSendRecordDetailMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/notice/mapstruct/NoticeSendRecordDetailMapMapper.java new file mode 100644 index 0000000..0ec65f4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/mapstruct/NoticeSendRecordDetailMapMapper.java @@ -0,0 +1,29 @@ +package com.senmesh.usercenter.notice.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDetailDTO; +import com.senmesh.usercenter.notice.entity.NoticeSendRecordDetail; + +/** + * @author sr on 2020-12-20 + */ +@Mapper +public interface NoticeSendRecordDetailMapMapper { + + NoticeSendRecordDetailMapMapper INSTANCE = + Mappers.getMapper(NoticeSendRecordDetailMapMapper.class); + + /** + * dto to entity + * + * @param noticeSendRecordDetailDto + * @return + * @author sr on 2020-12-20 + */ + NoticeSendRecordDetail toEntity( + NoticeSendRecordDetailDTO noticeSendRecordDetailDto); + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/mapstruct/NoticeSendRecordMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/notice/mapstruct/NoticeSendRecordMapMapper.java new file mode 100644 index 0000000..6bdccaf --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/mapstruct/NoticeSendRecordMapMapper.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.notice.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.notice.dto.NoticeContentTemplateDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordOperateDTO; +import com.senmesh.usercenter.notice.entity.NoticeSendRecord; + +/** + * @author sr on 2020-12-20 + */ +@Mapper +public interface NoticeSendRecordMapMapper { + + NoticeSendRecordMapMapper INSTANCE = + Mappers.getMapper(NoticeSendRecordMapMapper.class); + + /** + * dto to entity + * + * @param noticeSendRecordDto + * @return + * @author sr on 2020-12-20 + */ + NoticeSendRecord toEntity( + NoticeSendRecordDTO noticeSendRecordDto); + + + NoticeSendRecordOperateDTO clone(NoticeSendRecordOperateDTO dto); + + NoticeContentTemplateDTO toContentTemplate(NoticeSendRecordOperateDTO dto); + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/mapstruct/NoticeTemplateMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/notice/mapstruct/NoticeTemplateMapMapper.java new file mode 100644 index 0000000..442cf8e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/mapstruct/NoticeTemplateMapMapper.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.notice.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.notice.dto.NoticeTemplateDTO; +import com.senmesh.usercenter.notice.dto.NoticeTemplateOperateDTO; +import com.senmesh.usercenter.notice.entity.NoticeTemplate; + +/** + * @author sr on 2020-12-17 + */ +@Mapper +public interface NoticeTemplateMapMapper { + + NoticeTemplateMapMapper INSTANCE = + Mappers.getMapper(NoticeTemplateMapMapper.class); + + /** + * dto to entity + * + * @param noticeTemplateDto + * @return + * @author sr on 2020-12-17 + */ + NoticeTemplate toEntity(NoticeTemplateDTO noticeTemplateDto); + + /** + * @param noticeTemplateOperateDTO + * @return + * @author sr on 2020-12-17 + */ + NoticeTemplate toEntity(NoticeTemplateOperateDTO noticeTemplateOperateDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/service/INoticeChannelProvider.java b/backend/src/main/java/com/senmesh/usercenter/notice/service/INoticeChannelProvider.java new file mode 100644 index 0000000..aa472f0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/service/INoticeChannelProvider.java @@ -0,0 +1,75 @@ +package com.senmesh.usercenter.notice.service; + +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.freemarker.util.FreeMarkerTemplateUtils; +import com.senmesh.mq.consumer.handler.ITopicMqHandler; +import com.senmesh.mq.dto.TopicMqMessage; +import com.senmesh.mq.util.MqSendUtils; +import com.senmesh.security.util.MockUtils; +import com.senmesh.usercenter.notice.constant.NoticeChannelTypeEnum; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDTO; +import com.senmesh.usercenter.notice.util.NoticeSendRecordUtils; +import com.senmesh.usercenter.userprod.constant.UcMqSelfConstants; + +public interface INoticeChannelProvider extends ITopicMqHandler{ + + Logger LOGGER = LoggerFactory.getLogger(INoticeChannelProvider.class); + + /** + * + * @return {@link NoticeChannelTypeEnum} + * @author sr on 2021-01-04 + */ + Integer getChannelType(); + + default String format(String contentTemplate, Map contentParamDataMap) { + return FreeMarkerTemplateUtils.formatString(contentTemplate, contentParamDataMap); + } + + /** + * 发送(保存发送记录+明细+处理真实通道消息发送) + * + * @param noticeSendRecordDTO + * @author sr on 2021-02-19 + */ + void send(NoticeSendRecordDTO noticeSendRecordDTO); + + /** + * 异步,发送mq + * + * @param noticeSendRecordDTO + * @return + * @author sr on 2021-02-19 + */ + default AlitaResult asyncDeal(NoticeSendRecordDTO noticeSendRecordDTO) { + return MqSendUtils.send( + getRoutingKey(), + noticeSendRecordDTO); + } + + /** + * mq routingKey: {@link UcMqSelfConstants}.ROUTING_KEY_NOTICE_CHANNEL_DEAL_PREFIX_channelType + */ + default String getRoutingKey() { + return NoticeSendRecordUtils.getNoticeChannelDealKey(getChannelType()); + } + + /** + * 接收异步mq消息,处理send + */ + default void onMessage(TopicMqMessage message) { + try { + // mock用户 + MockUtils.mockPlatUser(); + send(message.getData()); + } catch (Exception e) { + LOGGER.info("notice channel deal error:{}", e); + } + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/service/NoticeContentTemplateService.java b/backend/src/main/java/com/senmesh/usercenter/notice/service/NoticeContentTemplateService.java new file mode 100644 index 0000000..414ab3e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/service/NoticeContentTemplateService.java @@ -0,0 +1,50 @@ +package com.senmesh.usercenter.notice.service; + +import java.util.List; + +import com.senmesh.usercenter.notice.dto.NoticeContentTemplateQueryDTO; +import com.senmesh.usercenter.notice.dto.NoticeContentTemplateOperateDTO; +import com.senmesh.usercenter.notice.dto.NoticeContentTemplateDTO; + +/** + * 通知消息体模版 + * + * @author sr on 2020-12-20 + */ +public interface NoticeContentTemplateService { + + /** + * 新增 + * + * @param noticeContentTemplateOperateDTO + * @return + * @author sr on 2020-12-20 + */ + Long create(NoticeContentTemplateOperateDTO noticeContentTemplateOperateDTO); + + /** + * 修改 + * + * @param noticeContentTemplateOperateDTO + * @author sr on 2020-12-20 + */ + void modify(NoticeContentTemplateOperateDTO noticeContentTemplateOperateDTO); + + /** + * 删除 + * + * @param id + * @author sr on 2020-12-20 + */ + void remove(Long id); + + /** + * 查询 + * + * @param noticeContentTemplateQueryDTO + * @return + * @author sr on 2020-12-20 + */ + List page(NoticeContentTemplateQueryDTO noticeContentTemplateQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/service/NoticeReceiverSettingService.java b/backend/src/main/java/com/senmesh/usercenter/notice/service/NoticeReceiverSettingService.java new file mode 100644 index 0000000..e622ae3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/service/NoticeReceiverSettingService.java @@ -0,0 +1,93 @@ +package com.senmesh.usercenter.notice.service; + +import java.util.List; +import java.util.Set; + +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingDTO; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingOperateDTO; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingQueryDTO; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingRemoveDTO; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingRoleDTO; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingUserDTO; + +/** + * 通知接收人设置 + * + * @author sr on 2020-12-20 + */ +public interface NoticeReceiverSettingService { + + /** + * 创建(新增) + * + * @param noticeReceiverSettingOperateDTO + * @author sr on 2021-01-07 + */ + void create(NoticeReceiverSettingOperateDTO noticeReceiverSettingOperateDTO); + + /** + * 保存设置(内部判断新增/删除) + * + * @param noticeReceiverSettingOperateDTO + * @return + * @author sr on 2020-12-20 + */ + void save(NoticeReceiverSettingOperateDTO noticeReceiverSettingOperateDTO); + + + /** + * 删除 + * + * @param id + * @author sr on 2020-12-20 + */ + void remove(Long id); + + /** + * 删除 + * + * @param noticeReceiverSettingRemoveDTO + * @author sr on 2020-12-20 + */ + void remove(NoticeReceiverSettingRemoveDTO noticeReceiverSettingRemoveDTO); + + /** + * 查询 + * + * @param noticeReceiverSettingQueryDTO + * @return + * @author sr on 2020-12-20 + */ + List list(NoticeReceiverSettingQueryDTO noticeReceiverSettingQueryDTO); + + /** + * 获取指定模版的所有接收人id + * + * @param templateId + * @param receiverOrgId + * @return + * @author sr on 2021-01-07 + */ + Set getReceiverIds(Long templateId, Long receiverOrgId); + + /** + * 查询接收人配置-人列表 + * + * @param noticeReceiverSettingQueryDTO + * @return + * @author sr on 2021-01-07 + */ + List listUser( + NoticeReceiverSettingQueryDTO noticeReceiverSettingQueryDTO); + + /** + * 查询接收人配置-角色列表 + * + * @param noticeReceiverSettingQueryDTO + * @return + * @author sr on 2021-01-07 + */ + List listRole( + NoticeReceiverSettingQueryDTO noticeReceiverSettingQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/service/NoticeSendRecordDetailService.java b/backend/src/main/java/com/senmesh/usercenter/notice/service/NoticeSendRecordDetailService.java new file mode 100644 index 0000000..28662f5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/service/NoticeSendRecordDetailService.java @@ -0,0 +1,45 @@ +package com.senmesh.usercenter.notice.service; + +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDetailDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDetailQueryDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDetailReqDTO; + +import java.util.List; + +/** + * 通知发送记录明细(接收人) + * + * @author sr on 2020-12-20 + */ +public interface NoticeSendRecordDetailService { + + /** + * 查询 + * + * @param noticeSendRecordDetailQueryDTO + * @return + * @author sr on 2020-12-20 + */ + List list(NoticeSendRecordDetailQueryDTO noticeSendRecordDetailQueryDTO); + + /** + * 消息明细 + * + * @param reqDTO 通知发送记录详细查询dto + * @return {@link NoticeSendRecordDetailDTO} + */ + NoticeSendRecordDetailDTO detail(NoticeSendRecordDetailReqDTO reqDTO); + + /** + * 消息数量 + * + * @param noticeSendRecordDetailQueryDTO 通知发送记录详细查询dto + * @return {@link Integer} + */ + Integer count(NoticeSendRecordDetailQueryDTO noticeSendRecordDetailQueryDTO); + + void read(Long recordDetailId); + + void readAll(); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/service/NoticeSendRecordService.java b/backend/src/main/java/com/senmesh/usercenter/notice/service/NoticeSendRecordService.java new file mode 100644 index 0000000..5283d06 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/service/NoticeSendRecordService.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.notice.service; + +import java.util.List; + +import com.senmesh.usercenter.notice.dto.NoticeSendRecordQueryDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordOperateDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDTO; + +/** + * 通知发送记录(内容模版级) + * + * @author sr on 2020-12-20 + */ +public interface NoticeSendRecordService { + + /** + * 新增 + * + * @param noticeSendRecordOperateDTO + * @return + * @author sr on 2020-12-20 + */ + void create(NoticeSendRecordOperateDTO noticeSendRecordOperateDTO); + + + /** + * 查询 + * + * @param noticeSendRecordQueryDTO + * @return + * @author sr on 2020-12-20 + */ + List page(NoticeSendRecordQueryDTO noticeSendRecordQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/service/NoticeTemplateService.java b/backend/src/main/java/com/senmesh/usercenter/notice/service/NoticeTemplateService.java new file mode 100644 index 0000000..b4cc790 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/service/NoticeTemplateService.java @@ -0,0 +1,65 @@ +package com.senmesh.usercenter.notice.service; + +import java.util.List; + +import com.senmesh.usercenter.notice.dto.NoticeTemplateDTO; +import com.senmesh.usercenter.notice.dto.NoticeTemplateOperateDTO; +import com.senmesh.usercenter.notice.dto.NoticeTemplateQueryDTO; + +/** + * 通知模版 + * + * @author sr on 2020-12-17 + */ +public interface NoticeTemplateService { + + /** + * 新增 + * + * @param noticeTemplateOperateDTO + * @return + * @author sr on 2020-12-17 + */ + Long create(NoticeTemplateOperateDTO noticeTemplateOperateDTO); + + /** + * 修改 + * + * @param noticeTemplateOperateDTO + * @author sr on 2020-12-17 + */ + void modify(NoticeTemplateOperateDTO noticeTemplateOperateDTO); + + /** + * 删除 + * + * @param id + * @author sr on 2020-12-17 + */ + void remove(Long id); + + /** + * 查询 + * + * @param noticeTemplateQueryDTO + * @return + * @author sr on 2020-12-17 + */ + List page(NoticeTemplateQueryDTO noticeTemplateQueryDTO); + + /** + * 校验模版 + * + * @param templateId + * @author sr on 2020-12-28 + */ + void checkTemplate(Long templateId); + + /** + * @param id + * @return + * @author sr on 2021-02-01 + */ + NoticeTemplateDTO find(Long id); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/service/impl/NoticeContentTemplateServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/notice/service/impl/NoticeContentTemplateServiceImpl.java new file mode 100644 index 0000000..317d699 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/service/impl/NoticeContentTemplateServiceImpl.java @@ -0,0 +1,89 @@ +package com.senmesh.usercenter.notice.service.impl; + +import java.util.List; + +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.notice.constant.NoticeChannelTypeEnum; +import com.senmesh.usercenter.notice.dao.NoticeContentTemplateMapper; +import com.senmesh.usercenter.notice.dto.NoticeContentTemplateDTO; +import com.senmesh.usercenter.notice.dto.NoticeContentTemplateOperateDTO; +import com.senmesh.usercenter.notice.dto.NoticeContentTemplateQueryDTO; +import com.senmesh.usercenter.notice.entity.NoticeContentTemplate; +import com.senmesh.usercenter.notice.mapstruct.NoticeContentTemplateMapMapper; +import com.senmesh.usercenter.notice.service.NoticeContentTemplateService; +import com.senmesh.usercenter.notice.service.NoticeTemplateService; + +/** + * @author sr on 2020-12-20 + */ +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class NoticeContentTemplateServiceImpl implements NoticeContentTemplateService { + + private final NoticeContentTemplateMapper noticeContentTemplateMapper; + + private final NoticeTemplateService noticeTemplateService; + + private void checkExist(Long templateId, Integer channelType) { + boolean exists = noticeContentTemplateMapper.existsEntity( + NoticeContentTemplate.builder().templateId(templateId).channelType(channelType).deleted(false).build()); + Assert.isTrue(!exists, "该模版消息通道类型已存在"); + } + + @Override + @Transactional + public Long create(NoticeContentTemplateOperateDTO noticeContentTemplateOperateDTO) { + Assert.isTrue( + NoticeChannelTypeEnum.SITE.getType() + .equals(noticeContentTemplateOperateDTO.getChannelType()), + "暂只支持站内信配置"); + Long templateId = noticeContentTemplateOperateDTO.getTemplateId(); + // 校验模版是否有效 + noticeTemplateService.checkTemplate(templateId); + this.checkExist(templateId, + noticeContentTemplateOperateDTO.getChannelType()); + // 设置初始值 + if (noticeContentTemplateOperateDTO.getEnabled() == null) { + noticeContentTemplateOperateDTO.setEnabled(true); + } + NoticeContentTemplate noticeContentTemplate = + NoticeContentTemplateMapMapper.INSTANCE.toEntity(noticeContentTemplateOperateDTO); + noticeContentTemplateMapper.saveEntity(noticeContentTemplate, + UserContextHolder.getLoginUserId()); + return noticeContentTemplate.getId(); + } + + @Override + @Transactional + public void modify(NoticeContentTemplateOperateDTO noticeContentTemplateOperateDTO) { + noticeContentTemplateMapper.updateEntitySelective( + NoticeContentTemplate.builder().id(noticeContentTemplateOperateDTO.getId()) + .channelType(noticeContentTemplateOperateDTO.getChannelType()) + .title(noticeContentTemplateOperateDTO.getTitle()) + .contentTemplate(noticeContentTemplateOperateDTO.getContentTemplate()) + .enabled(noticeContentTemplateOperateDTO.getEnabled()) + .link(noticeContentTemplateOperateDTO.getLink()) + .build(), + UserContextHolder.getLoginUserId()); + } + + @Override + @Transactional + public void remove(Long id) { + noticeContentTemplateMapper.deleteEntity(NoticeContentTemplate.builder().id(id).build(), + UserContextHolder.getLoginUserId()); + } + + @Override + public List page( + NoticeContentTemplateQueryDTO noticeContentTemplateQueryDTO) { + return noticeContentTemplateMapper.listNoticeContentTemplateDTO(noticeContentTemplateQueryDTO); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/service/impl/NoticeReceiverSettingServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/notice/service/impl/NoticeReceiverSettingServiceImpl.java new file mode 100644 index 0000000..9b0a83d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/service/impl/NoticeReceiverSettingServiceImpl.java @@ -0,0 +1,162 @@ +package com.senmesh.usercenter.notice.service.impl; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.google.common.collect.Sets; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.notice.constant.NoticeLevelEnum; +import com.senmesh.usercenter.notice.constant.NoticeReceiverTypeEnum; +import com.senmesh.usercenter.notice.dao.NoticeReceiverSettingMapper; +import com.senmesh.usercenter.notice.dao.NoticeTemplateMapper; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingDTO; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingOperateDTO; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingQueryDTO; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingRemoveDTO; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingRoleDTO; +import com.senmesh.usercenter.notice.dto.NoticeReceiverSettingUserDTO; +import com.senmesh.usercenter.notice.entity.NoticeReceiverSetting; +import com.senmesh.usercenter.notice.entity.NoticeTemplate; +import com.senmesh.usercenter.notice.mapstruct.NoticeReceiverSettingMapMapper; +import com.senmesh.usercenter.notice.service.NoticeReceiverSettingService; + +/** + * @author sr on 2020-12-20 + */ +@Service +public class NoticeReceiverSettingServiceImpl implements NoticeReceiverSettingService { + + @Autowired + private NoticeReceiverSettingMapper noticeReceiverSettingMapper; + + @Autowired + private NoticeTemplateMapper noticeTemplateMapper; + + @Override + @Transactional + public void create(NoticeReceiverSettingOperateDTO noticeReceiverSettingOperateDTO) { + this.save(noticeReceiverSettingOperateDTO, true); + } + + @Override + @Transactional + public void save(NoticeReceiverSettingOperateDTO noticeReceiverSettingOperateDTO) { + this.save(noticeReceiverSettingOperateDTO, false); + } + + private void save(NoticeReceiverSettingOperateDTO noticeReceiverSettingOperateDTO, boolean created) { + NoticeTemplate noticeTemplate = + noticeTemplateMapper.getById(noticeReceiverSettingOperateDTO.getTemplateId()); + if (NoticeLevelEnum.PLATFORM.getType().equals(noticeTemplate.getLevel()) + && !CommonConstants.PLATFORM_ORG_ID + .equals(noticeReceiverSettingOperateDTO.getOperateOrgId())) { + throw new BusinessException("该模版不支持机构设置"); + } + // 校验传入接收人信息是否有效 + Long orgId = noticeReceiverSettingOperateDTO.getOperateOrgId(); + Integer receiverUnionType = noticeReceiverSettingOperateDTO.getReceiverUnionType(); + Set newReceiverUnionIds = noticeReceiverSettingOperateDTO.getReceiverUnionIds(); + if (NoticeReceiverTypeEnum.USER.getType().equals(receiverUnionType)) { + Assert.isTrue(noticeReceiverSettingMapper.validUser(orgId, newReceiverUnionIds) + .size() == newReceiverUnionIds.size(), "接收人关联无效"); + } else if (NoticeReceiverTypeEnum.ROLE.getType().equals(receiverUnionType)) { + Assert.isTrue(noticeReceiverSettingMapper.validRole(orgId, newReceiverUnionIds) + .size() == newReceiverUnionIds.size(), "接收人关联无效"); + } + + // 查询当前机构现有templateId/receiverUnionType 配置 + Set currentReceiverUnionIds = + noticeReceiverSettingMapper.findReceiverUnionIds(noticeReceiverSettingOperateDTO); + + // 新增 + Set createReceiverUnionIds = Sets.newHashSet(newReceiverUnionIds); + createReceiverUnionIds.removeAll(currentReceiverUnionIds); + if (!createReceiverUnionIds.isEmpty()) { + noticeReceiverSettingMapper.create(noticeReceiverSettingOperateDTO, createReceiverUnionIds); + } + // 新增不处理删除 + if (!created) { + // 删除 + Set removeReceiverUnionIds = Sets.newHashSet(currentReceiverUnionIds); + removeReceiverUnionIds.removeAll(newReceiverUnionIds); + if (!removeReceiverUnionIds.isEmpty()) { + NoticeReceiverSettingRemoveDTO removeDto = + NoticeReceiverSettingMapMapper.INSTANCE.toRemoveDTO(noticeReceiverSettingOperateDTO); + removeDto.setReceiverUnionIds(removeReceiverUnionIds); + this.remove(removeDto); + } + } + + } + + @Override + @Transactional + public void remove(Long id) { + noticeReceiverSettingMapper.deleteEntity(NoticeReceiverSetting.builder().id(id).build(), + UserContextHolder.getLoginUserId()); + } + + @Override + @Transactional + public void remove(NoticeReceiverSettingRemoveDTO noticeReceiverSettingRemoveDTO) { + // 只能删除当前登录人机构的配置;如需代机构删除配置请另外实现 + noticeReceiverSettingMapper.remove(noticeReceiverSettingRemoveDTO); + } + + @Override + public List list( + NoticeReceiverSettingQueryDTO noticeReceiverSettingQueryDTO) { + // 暂只支持查询当前机构 + noticeReceiverSettingQueryDTO.setOrgId(noticeReceiverSettingQueryDTO.getOperateOrgId()); + return noticeReceiverSettingMapper.listNoticeReceiverSettingDTO(noticeReceiverSettingQueryDTO); + } + + @Override + public Set getReceiverIds(Long templateId, Long receiverOrgId) { + // 获取接收人配置 + List noticeReceiverSettingDTOs = + noticeReceiverSettingMapper.listNoticeReceiverSettingDTO(NoticeReceiverSettingQueryDTO + .builder().templateId(templateId).orgId(receiverOrgId).build()); + Map> noticeReceiverSettingMap = + noticeReceiverSettingDTOs.stream() + .collect(Collectors.toMap(NoticeReceiverSettingDTO::getReceiverUnionType, + dto -> Sets.newHashSet(dto.getReceiverUnionId()), (o, n) -> { + o.addAll(n); + return o; + }, HashMap::new)); + // 根据接收人配置获取人id; orgId+unionType+unionIds + Set userIds = Sets.newHashSet(); + noticeReceiverSettingMap.forEach((k, v) -> { + if (NoticeReceiverTypeEnum.USER.getType().equals(k)) { + userIds.addAll(v); + } else { + userIds + .addAll(noticeReceiverSettingMapper.findUserIdByUnionType(receiverOrgId, k, v)); + } + }); + return userIds; + } + + @Override + public List listUser( + NoticeReceiverSettingQueryDTO noticeReceiverSettingQueryDTO) { + return noticeReceiverSettingMapper.listNoticeReceiverSettingUserDTO(noticeReceiverSettingQueryDTO); + } + + @Override + public List listRole( + NoticeReceiverSettingQueryDTO noticeReceiverSettingQueryDTO) { + return noticeReceiverSettingMapper.listNoticeReceiverSettingRoleDTO(noticeReceiverSettingQueryDTO); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/service/impl/NoticeSendRecordDetailServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/notice/service/impl/NoticeSendRecordDetailServiceImpl.java new file mode 100644 index 0000000..5036004 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/service/impl/NoticeSendRecordDetailServiceImpl.java @@ -0,0 +1,62 @@ +package com.senmesh.usercenter.notice.service.impl; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.usercenter.notice.constant.NoticeChannelTypeEnum; +import com.senmesh.usercenter.notice.dao.NoticeSendRecordDetailMapper; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDetailDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDetailQueryDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDetailReqDTO; +import com.senmesh.usercenter.notice.service.NoticeSendRecordDetailService; +import com.senmesh.usercenter.notice.util.NoticeSendRecordDetailUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * @author sr on 2020-12-20 + */ +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class NoticeSendRecordDetailServiceImpl implements NoticeSendRecordDetailService { + + private final NoticeSendRecordDetailMapper noticeSendRecordDetailMapper; + + @Override + public NoticeSendRecordDetailDTO detail(NoticeSendRecordDetailReqDTO reqDTO) { + return noticeSendRecordDetailMapper.findNoticeSendRecordDetailDTO(reqDTO); + } + + @Override + public List list( + NoticeSendRecordDetailQueryDTO noticeSendRecordDetailQueryDTO) { + return noticeSendRecordDetailMapper + .listNoticeSendRecordDetailDTO(noticeSendRecordDetailQueryDTO); + } + + @Override + public Integer count(NoticeSendRecordDetailQueryDTO noticeSendRecordDetailQueryDTO) { + noticeSendRecordDetailQueryDTO.setNeedPage(Boolean.FALSE); + noticeSendRecordDetailQueryDTO.setPageSize(0); + return noticeSendRecordDetailMapper + .countNoticeSendRecordDetail(noticeSendRecordDetailQueryDTO); + } + + @Override + @Transactional + public void read(Long recordDetailId) { + Assert.notNull(recordDetailId, "通知明细id不能为空"); + int modifyNum = noticeSendRecordDetailMapper + .modifyStatus(NoticeSendRecordDetailUtils.buildRead(recordDetailId, NoticeChannelTypeEnum.SITE.getType())); + Assert.isTrue(modifyNum > 0, "请勿重复读取,请检查数据或刷新数据"); + } + + @Override + @Transactional + public void readAll() { + noticeSendRecordDetailMapper.modifyStatus(NoticeSendRecordDetailUtils.buildReadAll(NoticeChannelTypeEnum.SITE.getType())); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/service/impl/NoticeSendRecordServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/notice/service/impl/NoticeSendRecordServiceImpl.java new file mode 100644 index 0000000..5e96724 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/service/impl/NoticeSendRecordServiceImpl.java @@ -0,0 +1,182 @@ +package com.senmesh.usercenter.notice.service.impl; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.BaseDtoUtils; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.notice.constant.NoticeLevelEnum; +import com.senmesh.usercenter.notice.constant.NoticeReceiverStatusEnum; +import com.senmesh.usercenter.notice.constant.NoticeSendStatusEnum; +import com.senmesh.usercenter.notice.dao.NoticeContentTemplateMapper; +import com.senmesh.usercenter.notice.dao.NoticeSendRecordDetailMapper; +import com.senmesh.usercenter.notice.dao.NoticeSendRecordMapper; +import com.senmesh.usercenter.notice.dao.NoticeTemplateMapper; +import com.senmesh.usercenter.notice.dto.NoticeContentTemplateDTO; +import com.senmesh.usercenter.notice.dto.NoticeContentTemplateQueryDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordOperateDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordQueryDTO; +import com.senmesh.usercenter.notice.dto.NoticeTemplateDTO; +import com.senmesh.usercenter.notice.dto.NoticeTemplateQueryDTO; +import com.senmesh.usercenter.notice.entity.NoticeSendRecord; +import com.senmesh.usercenter.notice.entity.NoticeSendRecordDetail; +import com.senmesh.usercenter.notice.mapstruct.NoticeSendRecordMapMapper; +import com.senmesh.usercenter.notice.service.INoticeChannelProvider; +import com.senmesh.usercenter.notice.service.NoticeReceiverSettingService; +import com.senmesh.usercenter.notice.service.NoticeSendRecordService; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author sr on 2020-12-20 + */ +@Service +@Slf4j +public class NoticeSendRecordServiceImpl implements NoticeSendRecordService { + + @Autowired + private NoticeSendRecordMapper noticeSendRecordMapper; + + @Autowired + private NoticeTemplateMapper noticeTemplateMapper; + + @Autowired + private NoticeContentTemplateMapper noticeContentTemplateMapper; + + @Autowired + private NoticeReceiverSettingService noticeReceiverSettingService; + + @Autowired + private NoticeSendRecordDetailMapper noticeSendRecordDetailMapper; + + private Map channelProviderMap; + + @Autowired + public void setChannelProviderMap(List channelProviders) { + channelProviderMap = + channelProviders.stream() + .collect(Collectors.toMap(k -> k.getChannelType(), v -> v)); + } + + @Override + @Transactional + public void create(NoticeSendRecordOperateDTO noticeSendRecordOperateDTO) { + // 克隆操作对象,清洗参数,替换流程中需要的正确的id等属性 + NoticeSendRecordOperateDTO tempOperateDto = + NoticeSendRecordMapMapper.INSTANCE.clone(noticeSendRecordOperateDTO); + Long templateId = noticeSendRecordOperateDTO.getTemplateId(); + String templateCode = noticeSendRecordOperateDTO.getTemplateCode(); + // 判断参数必填 + Assert.isTrue(templateId != null || StringUtils.isNotBlank(templateCode), "通知模版参数缺失"); + // 获取模版,级别-》机构id + NoticeTemplateQueryDTO noticeTemplateQueryDTO = + NoticeTemplateQueryDTO.builder().id(templateId).templateCode(templateCode).enabled(true) + .build(); + noticeTemplateQueryDTO.setNeedPage(false); + List noticeTemplateDTOs = + noticeTemplateMapper.listNoticeTemplateDTO(noticeTemplateQueryDTO); + Assert.isTrue(!noticeTemplateDTOs.isEmpty(), "未找到对应通知模版"); + NoticeTemplateDTO noticeTemplateDTO = noticeTemplateDTOs.get(0); + Assert.isTrue(noticeTemplateDTO.getEnabled(), "通知模版未开启"); + tempOperateDto.setTemplateId(noticeTemplateDTO.getId()); + // 平台模版指定接收人机构为平台 + Long receiverOrgId = + NoticeLevelEnum.PLATFORM.getType().equals(noticeTemplateDTOs.get(0).getLevel()) + ? CommonConstants.PLATFORM_ORG_ID + : noticeSendRecordOperateDTO.getReceiverOrgId(); + if (receiverOrgId == null) { + receiverOrgId = noticeSendRecordOperateDTO.getOperateOrgId(); + } + tempOperateDto.setReceiverOrgId(receiverOrgId); + + // 是否定制内容模版 + if (BooleanUtils.isTrue(noticeSendRecordOperateDTO.getCustomContent())) { + Assert.isTrue(noticeSendRecordOperateDTO.getChannelType() != null, "定制内容模版,消息通道类型不能为空"); + dealByChannel(tempOperateDto, + NoticeSendRecordMapMapper.INSTANCE.toContentTemplate(tempOperateDto)); + } else { + // 获取内容模版, 未指定模版->获取所有内容模版 + List noticeContentTemplateDTOs = noticeContentTemplateMapper + .listNoticeContentTemplateDTO(NoticeContentTemplateQueryDTO.builder() + .id(noticeSendRecordOperateDTO.getContentTemplateId()) + .templateId(tempOperateDto.getTemplateId()) + .channelType(noticeSendRecordOperateDTO.getChannelType()).enabled(true).build()); + Assert.isTrue(!noticeContentTemplateDTOs.isEmpty(), "未找到对应通知内容模版"); + noticeContentTemplateDTOs.forEach( + noticeContentTemplateDTO -> dealByChannel(tempOperateDto, + noticeContentTemplateDTO)); + } + } + + private void dealByChannel(NoticeSendRecordOperateDTO noticeSendRecordOperateDTO, + NoticeContentTemplateDTO noticeContentTemplateDTO) { + INoticeChannelProvider channelProvicer = + channelProviderMap.get(noticeContentTemplateDTO.getChannelType()); + if (channelProvicer == null) { + log.error("无对应消息通道处理..."); + } + Set receiverUserIds = noticeSendRecordOperateDTO.getReceiverUserIds(); + NoticeSendRecordDTO noticeSendRecordDTO = + NoticeSendRecordDTO.builder().templateId(noticeSendRecordOperateDTO.getTemplateId()) + .senderOrgId(noticeSendRecordOperateDTO.getOperateOrgId()) + .receiverOrgId(noticeSendRecordOperateDTO.getReceiverOrgId()) + .contentTemplateId(noticeContentTemplateDTO.getId()) + .contentParamData( + JsonUtils.toJsonString(noticeSendRecordOperateDTO.getContentParamDataMap())) + .appointed(CollectionUtils.isNotEmpty(receiverUserIds)) + .status(NoticeSendStatusEnum.INIT.getType()) + .channelType(noticeContentTemplateDTO.getChannelType()) + .title(noticeContentTemplateDTO.getTitle()) + .contentTemplate(noticeContentTemplateDTO.getContentTemplate()) + .link(noticeContentTemplateDTO.getLink()).build(); + + this.createDetail(noticeSendRecordDTO, receiverUserIds, NoticeReceiverStatusEnum.INIT.getType()); + // mq 触发消息通道真实处理流程 + channelProvicer.asyncDeal(noticeSendRecordDTO); + + } + + private void createDetail(NoticeSendRecordDTO noticeSendRecordDTO, Set receiverUserIds, + Integer receiverStatus) { + NoticeSendRecord noticeSendRecord = + NoticeSendRecordMapMapper.INSTANCE.toEntity(noticeSendRecordDTO); + noticeSendRecordMapper.saveEntity(noticeSendRecord, + UserContextHolder.getLoginUserId()); + BaseDtoUtils.createCopy(noticeSendRecord, noticeSendRecordDTO); + // TODO 根据channel获取接收人相关帐号List noticeSendRecordDetailOperateDTOs + if (CollectionUtils.isEmpty(receiverUserIds)) { + receiverUserIds = + noticeReceiverSettingService.getReceiverIds(noticeSendRecordDTO.getTemplateId(), + noticeSendRecordDTO.getReceiverOrgId()); + } + // 插入发送记录明细;占位符替换内容模版内容 + Long recordId = noticeSendRecord.getId(); + List noticeSendRecordDetails = receiverUserIds.stream() + .map(userId -> NoticeSendRecordDetail.builder().recordId(recordId).userId(userId) + .receiverStatus(receiverStatus).build()) + .collect(Collectors.toList()); + noticeSendRecordDetailMapper.saveEntites(noticeSendRecordDetails, + UserContextHolder.getLoginUserId()); + } + + @Override + public List page(NoticeSendRecordQueryDTO noticeSendRecordQueryDTO) { + // 暂只支持查询当前机构 + noticeSendRecordQueryDTO.setSenderOrgId(noticeSendRecordQueryDTO.getOperateOrgId()); + return noticeSendRecordMapper.listNoticeSendRecordDTO(noticeSendRecordQueryDTO); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/service/impl/NoticeTemplateServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/notice/service/impl/NoticeTemplateServiceImpl.java new file mode 100644 index 0000000..2bb1aaa --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/service/impl/NoticeTemplateServiceImpl.java @@ -0,0 +1,94 @@ +package com.senmesh.usercenter.notice.service.impl; + + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.notice.constant.NoticeLevelEnum; +import com.senmesh.usercenter.notice.dao.NoticeTemplateMapper; +import com.senmesh.usercenter.notice.dto.NoticeTemplateDTO; +import com.senmesh.usercenter.notice.dto.NoticeTemplateOperateDTO; +import com.senmesh.usercenter.notice.dto.NoticeTemplateQueryDTO; +import com.senmesh.usercenter.notice.entity.NoticeTemplate; +import com.senmesh.usercenter.notice.mapstruct.NoticeTemplateMapMapper; +import com.senmesh.usercenter.notice.service.NoticeTemplateService; + +/** + * @author sr on 2020-12-17 + */ +@Service +public class NoticeTemplateServiceImpl implements NoticeTemplateService { + + @Autowired + private NoticeTemplateMapper noticeTemplateMapper; + + private void exist(NoticeTemplateOperateDTO noticeTemplateOperateDTO) { + // templateCode 验重 + boolean exists = noticeTemplateMapper.existsEntity( + NoticeTemplate.builder().id(noticeTemplateOperateDTO.getId()) + .templateCode(noticeTemplateOperateDTO.getTemplateCode()).build()); + Assert.isTrue(!exists, "模版标识已存在"); + Assert.isTrue( + NoticeLevelEnum.ORG.getType().equals(noticeTemplateOperateDTO.getLevel()) + || CommonConstants.PLATFORM_ORG_ID.equals(noticeTemplateOperateDTO.getOperateOrgId()), + "不支持机构设置该级别模版"); + } + + @Override + @Transactional + public Long create(NoticeTemplateOperateDTO noticeTemplateOperateDTO) { + this.exist(noticeTemplateOperateDTO); + // 设置初始值 + if (noticeTemplateOperateDTO.getEnabled() == null) { + noticeTemplateOperateDTO.setEnabled(true); + } + NoticeTemplate noticeTemplate = + NoticeTemplateMapMapper.INSTANCE.toEntity(noticeTemplateOperateDTO); + noticeTemplateMapper.saveEntity(noticeTemplate, UserContextHolder.getLoginUserId()); + return noticeTemplate.getId(); + } + + @Override + @Transactional + public void modify(NoticeTemplateOperateDTO noticeTemplateOperateDTO) { + this.exist(noticeTemplateOperateDTO); + NoticeTemplate noticeTemplate = + NoticeTemplateMapMapper.INSTANCE.toEntity(noticeTemplateOperateDTO); + noticeTemplateMapper.updateEntitySelective(noticeTemplate, UserContextHolder.getLoginUserId()); + } + + @Override + @Transactional + public void remove(Long id) { + noticeTemplateMapper.deleteEntity(NoticeTemplate.builder().id(id).build(), + UserContextHolder.getLoginUserId()); + } + + @Override + public List page(NoticeTemplateQueryDTO noticeTemplateQueryDTO) { + return noticeTemplateMapper.listNoticeTemplateDTO(noticeTemplateQueryDTO); + } + + @Override + public void checkTemplate(Long templateId) { + NoticeTemplate noticeTemplate = noticeTemplateMapper.getById(templateId); + Assert.isTrue(noticeTemplate != null, "未找到对应通知模版"); + Assert.isTrue(noticeTemplate.getEnabled(), "该通知模版无法操作"); + } + + @Override + public NoticeTemplateDTO find(Long id) { + Assert.notNull(id, "id为空"); + List templateDtos = + noticeTemplateMapper.listNoticeTemplateDTO(NoticeTemplateQueryDTO.builder().id(id).build()); + Assert.isTrue(!templateDtos.isEmpty(), "未找到对应模版"); + return templateDtos.get(0); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/service/provider/AbstractNoticeChannelProvider.java b/backend/src/main/java/com/senmesh/usercenter/notice/service/provider/AbstractNoticeChannelProvider.java new file mode 100644 index 0000000..dbb5d59 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/service/provider/AbstractNoticeChannelProvider.java @@ -0,0 +1,124 @@ +package com.senmesh.usercenter.notice.service.provider; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.transaction.annotation.Transactional; + +import com.google.common.collect.Sets; +import com.senmesh.common.AlitaResult; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.usercenter.notice.constant.NoticeReceiverStatusEnum; +import com.senmesh.usercenter.notice.constant.NoticeSendStatusEnum; +import com.senmesh.usercenter.notice.dao.NoticeSendRecordDetailMapper; +import com.senmesh.usercenter.notice.dao.NoticeSendRecordMapper; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDetailDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDetailQueryDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordModifyDTO; +import com.senmesh.usercenter.notice.service.INoticeChannelProvider; +import com.senmesh.usercenter.notice.util.NoticeSendRecordDetailUtils; + +import lombok.extern.slf4j.Slf4j; + +/** + * 通知处理抽象类 + * + * @author sr on 2021-02-19 + */ +@Slf4j +public abstract class AbstractNoticeChannelProvider implements INoticeChannelProvider { + + private NoticeSendRecordMapper noticeSendRecordMapper; + + private NoticeSendRecordDetailMapper noticeSendRecordDetailMapper; + + public AbstractNoticeChannelProvider(NoticeSendRecordMapper noticeSendRecordMapper, + NoticeSendRecordDetailMapper noticeSendRecordDetailMapper) { + this.noticeSendRecordMapper = noticeSendRecordMapper; + this.noticeSendRecordDetailMapper = noticeSendRecordDetailMapper; + } + + public void beforeSendDetails(NoticeSendRecordDTO noticeSendRecordDTO) {} + + /** + * 处理发送记录下所有明细 + * @param noticeSendRecordDTO + * @author sr on 2021-02-19 + */ + public void sendDetails(NoticeSendRecordDTO noticeSendRecordDTO) { + NoticeSendRecordDetailQueryDTO noticeSendRecordDetailQueryDTO = + NoticeSendRecordDetailQueryDTO.builder().recordId(noticeSendRecordDTO.getId()) + .receiverStatus(NoticeReceiverStatusEnum.INIT.getType()).build(); + List recordDetails = + noticeSendRecordDetailMapper + .listNoticeSendRecordDetailDTO(noticeSendRecordDetailQueryDTO); + if (recordDetails.isEmpty()) { + return; + } + Set sucRecordDetailIds = Sets.newHashSetWithExpectedSize(recordDetails.size()); + Set errRecordDetailIds = Sets.newHashSetWithExpectedSize(recordDetails.size()); + recordDetails.forEach(detail -> { + AlitaResult invokeResult = null; + try { + invokeResult = this.invoke(noticeSendRecordDTO, detail); + } catch (Exception e) { + invokeResult = AlitaResult.bizError(ExceptionUtils.getStackTrace(e)); + } + if (invokeResult.getSuccess()) { + sucRecordDetailIds.add(detail.getId()); + } else { + errRecordDetailIds.add(detail.getId()); + log.error("notice sendDetail, id-{} error:{}", detail.getId(), invokeResult.getMsg()); + } + }); + // 更新状态 + if (!sucRecordDetailIds.isEmpty()) { + noticeSendRecordDetailMapper.modifyStatus(NoticeSendRecordDetailUtils.buildSend( + sucRecordDetailIds, getChannelType(), NoticeReceiverStatusEnum.SENT.getType())); + } + if (!errRecordDetailIds.isEmpty()) { + noticeSendRecordDetailMapper.modifyStatus(NoticeSendRecordDetailUtils.buildSend( + errRecordDetailIds, getChannelType(), NoticeReceiverStatusEnum.SEND_FAIL.getType())); + } + } + + public void afterSendDetails(NoticeSendRecordDTO noticeSendRecordDTO) {} + + + /** + * 单个明细真实发送处理 + * @param noticeSendRecordDTO + * @param noticeSendRecordDetailDTO + * @return + * @author sr on 2021-02-19 + */ + public AlitaResult invoke(NoticeSendRecordDTO noticeSendRecordDTO, + NoticeSendRecordDetailDTO noticeSendRecordDetailDTO) { + return AlitaResult.bizError("未实现单个明细实际调用"); + } + + + @SuppressWarnings("unchecked") + @Transactional + public void send(NoticeSendRecordDTO noticeSendRecordDTO) { + // 组装消息体 + String contentTemplate = noticeSendRecordDTO.getContentTemplate(); + String content = this.format(contentTemplate, + JsonUtils.toObject(noticeSendRecordDTO.getContentParamData(), Map.class)); + noticeSendRecordDTO.setContent(content); + int updateNum = noticeSendRecordMapper + .modify(NoticeSendRecordModifyDTO.builder().id(noticeSendRecordDTO.getId()) + .oldStatus(NoticeSendStatusEnum.INIT.getType()) + .newStatus(NoticeSendStatusEnum.SENT.getType()) + .content(content).build()); + Assert.isTrue(updateNum > 0, "当前通知发送记录无法操作"); + beforeSendDetails(noticeSendRecordDTO); + this.sendDetails(noticeSendRecordDTO); + afterSendDetails(noticeSendRecordDTO); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/service/provider/SiteNoticeChannelProvider.java b/backend/src/main/java/com/senmesh/usercenter/notice/service/provider/SiteNoticeChannelProvider.java new file mode 100644 index 0000000..54b343d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/service/provider/SiteNoticeChannelProvider.java @@ -0,0 +1,41 @@ +package com.senmesh.usercenter.notice.service.provider; + +import com.senmesh.component.notice.constant.NoticeFirstTypeEnum; +import com.senmesh.component.notice.dto.NoticeMsgDTO; +import com.senmesh.component.notice.util.NoticeUtils; +import org.springframework.stereotype.Service; + +import com.senmesh.common.AlitaResult; +import com.senmesh.usercenter.notice.constant.NoticeChannelTypeEnum; +import com.senmesh.usercenter.notice.dao.NoticeSendRecordDetailMapper; +import com.senmesh.usercenter.notice.dao.NoticeSendRecordMapper; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDetailDTO; + +/** + * 站内信 + * + * @author sr on 2021-01-04 + */ +@Service +public class SiteNoticeChannelProvider extends AbstractNoticeChannelProvider { + + public SiteNoticeChannelProvider(NoticeSendRecordMapper noticeSendRecordMapper, + NoticeSendRecordDetailMapper noticeSendRecordDetailMapper) { + super(noticeSendRecordMapper, noticeSendRecordDetailMapper); + } + + @Override + public Integer getChannelType() { + return NoticeChannelTypeEnum.SITE.getType(); + } + + public AlitaResult invoke(NoticeSendRecordDTO noticeSendRecordDTO, + NoticeSendRecordDetailDTO noticeSendRecordDetailDTO) { + NoticeUtils.sendAsyncNotice( + NoticeMsgDTO.create(noticeSendRecordDetailDTO.getUserId(), NoticeFirstTypeEnum.SITE.getType(), noticeSendRecordDTO)); + return noticeSendRecordDTO.getContent() != null ? AlitaResult.success() + : AlitaResult.bizError("消息内容为空,模版替换失败"); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/service/provider/WechatOffiaccountNoticeChannelProvider.java b/backend/src/main/java/com/senmesh/usercenter/notice/service/provider/WechatOffiaccountNoticeChannelProvider.java new file mode 100644 index 0000000..369a17b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/service/provider/WechatOffiaccountNoticeChannelProvider.java @@ -0,0 +1,98 @@ +package com.senmesh.usercenter.notice.service.provider; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.sdk.wechat.WechatClient; +import com.senmesh.sdk.wechat.model.KeyData; +import com.senmesh.sdk.wechat.model.TemplateMessageReq; +import com.senmesh.sdk.wechat.util.MessageParamUtils; +import com.senmesh.usercenter.auth.constant.AuthTypeEnum; +import com.senmesh.usercenter.auth.dto.AuthClientQueryDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailQueryDTO; +import com.senmesh.usercenter.auth.service.AuthDetailService; +import com.senmesh.usercenter.auth.util.AuthClientUtils; +import com.senmesh.usercenter.notice.constant.NoticeChannelTypeEnum; +import com.senmesh.usercenter.notice.dao.NoticeSendRecordDetailMapper; +import com.senmesh.usercenter.notice.dao.NoticeSendRecordMapper; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDTO; +import com.senmesh.usercenter.notice.dto.NoticeSendRecordDetailDTO; + +/** + * 微信公众号模版消息发送 + * @author sr on 2021-02-19 + */ +@Service +public class WechatOffiaccountNoticeChannelProvider extends AbstractNoticeChannelProvider { + + @Autowired + private AuthDetailService authDetailService; + + /** 缓存微信公众号模版参数 recordId:templateData **/ + private Map> recordTemplateData = + new ConcurrentHashMap>(200); + + public WechatOffiaccountNoticeChannelProvider(NoticeSendRecordMapper noticeSendRecordMapper, + NoticeSendRecordDetailMapper noticeSendRecordDetailMapper) { + super(noticeSendRecordMapper, noticeSendRecordDetailMapper); + } + + @Override + public Integer getChannelType() { + return NoticeChannelTypeEnum.WECHAT_OFFIACCOUNT.getType(); + } + + @Override + public String format(String contentTemplate, Map contentParamDataMap) { + return null; + } + + @Override + public void beforeSendDetails(NoticeSendRecordDTO noticeSendRecordDTO) { + Long recordId = noticeSendRecordDTO.getId(); + Map templateData = recordTemplateData.get(recordId); + if (templateData == null) { + templateData = + MessageParamUtils.dealData(noticeSendRecordDTO.getContentParamDataMap()); + recordTemplateData.put(recordId, templateData); + } + } + + @Override + public AlitaResult invoke(NoticeSendRecordDTO noticeSendRecordDTO, + NoticeSendRecordDetailDTO noticeSendRecordDetailDTO) { + + Long userId = noticeSendRecordDetailDTO.getUserId(); + Assert.isTrue(userId != null, "用户id为空"); + // 查询微信授权信息 + List authDetailDTOs = authDetailService.list(AuthDetailQueryDTO.builder() + .authTypeCode(AuthTypeEnum.WECHAT.getCode()).userId(userId).build()); + Assert.isTrue(!authDetailDTOs.isEmpty(), "未找到用户微信授权信息"); + AuthDetailDTO authDetailDTO = authDetailDTOs.get(0); + String openId = authDetailDTO.getOpenId(); + // 发送公众号 + String token = AuthClientUtils + .getService().getAccessToken(AuthClientQueryDTO.builder().id(authDetailDTO.getAuthClientId()).build()); + TemplateMessageReq templateMessageRequestParam = + TemplateMessageReq.builder().accessToken( + token) + .toUser(openId) + .templateId(noticeSendRecordDTO.getContentTemplate()) + .data(recordTemplateData.get(noticeSendRecordDTO.getId())) + .url(noticeSendRecordDTO.getLink()).build(); + return WechatClient.sendTemplateMessage(templateMessageRequestParam); + } + + @Override + public void afterSendDetails(NoticeSendRecordDTO noticeSendRecordDTO) { + recordTemplateData.remove(noticeSendRecordDTO.getId()); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/util/NoticeSendRecordDetailUtils.java b/backend/src/main/java/com/senmesh/usercenter/notice/util/NoticeSendRecordDetailUtils.java new file mode 100644 index 0000000..3a16b53 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/util/NoticeSendRecordDetailUtils.java @@ -0,0 +1,34 @@ +package com.senmesh.usercenter.notice.util; + +import java.util.Set; + +import com.senmesh.usercenter.notice.constant.NoticeReceiverStatusEnum; +import com.senmesh.usercenter.notice.dto.RecordDetailUpdateStatusDTO; + +/** + * @author sr on 2020-12-20 + */ +public class NoticeSendRecordDetailUtils { + + public static RecordDetailUpdateStatusDTO buildRead(Long recordDetailId, Integer channelType) { + RecordDetailUpdateStatusDTO recordDetailUpdateStatusDTO = buildReadAll(channelType); + recordDetailUpdateStatusDTO.setRecordDetailId(recordDetailId); + return recordDetailUpdateStatusDTO; + } + + public static RecordDetailUpdateStatusDTO buildReadAll(Integer channelType) { + return RecordDetailUpdateStatusDTO.builder().channelType(channelType) + .oldStatus(NoticeReceiverStatusEnum.SENT.getType()) + .newStatus(NoticeReceiverStatusEnum.READ.getType()).build(); + } + + public static RecordDetailUpdateStatusDTO buildSend(Set recordDetailIds, Integer channelType, + Integer sendStatus) { + return RecordDetailUpdateStatusDTO.builder() + .channelType(channelType) + .oldStatus(NoticeReceiverStatusEnum.INIT.getType()) + .newStatus(sendStatus) + .recordDetailIds(recordDetailIds).build(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/notice/util/NoticeSendRecordUtils.java b/backend/src/main/java/com/senmesh/usercenter/notice/util/NoticeSendRecordUtils.java new file mode 100644 index 0000000..40e13b8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/notice/util/NoticeSendRecordUtils.java @@ -0,0 +1,23 @@ +package com.senmesh.usercenter.notice.util; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.usercenter.userprod.constant.UcMqSelfConstants; + +/** + * @author sr on 2020-12-20 + */ +public class NoticeSendRecordUtils { + + /** + * 根据消息通道获取通道处理mq的routingKey + * + * @param channelType + * @return + * @author sr on 2021-02-04 + */ + public static String getNoticeChannelDealKey(Integer channelType) { + return String.join(CommonConstants.UNDERLINE, + UcMqSelfConstants.ROUTING_KEY_NOTICE_CHANNEL_DEAL_PREFIX, channelType.toString()); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/controller/OrgController.java b/backend/src/main/java/com/senmesh/usercenter/org/controller/OrgController.java new file mode 100644 index 0000000..648a173 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/controller/OrgController.java @@ -0,0 +1,101 @@ +package com.senmesh.usercenter.org.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.enums.OrgTypeEnum; +import com.senmesh.usercenter.org.dto.OrgCreateDTO; +import com.senmesh.usercenter.org.dto.OrgDTO; +import com.senmesh.usercenter.org.dto.OrgModifyDTO; +import com.senmesh.usercenter.org.dto.OrgQueryDTO; +import com.senmesh.usercenter.org.dto.UcOpenOrgPartQueryDTO; +import com.senmesh.usercenter.org.dto.UcOrgInfoReqDTO; +import com.senmesh.usercenter.org.dto.UcOrgInfoResDTO; +import com.senmesh.usercenter.org.dto.UcOrgPartInfoDTO; +import com.senmesh.usercenter.org.dto.UcOrgPartQueryDTO; +import com.senmesh.usercenter.org.service.OrgService; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + + +/** + * org控制器 + * + * @author Carlye + * @date 2021/06/16 + */ +@RestController +@Api(tags = "机构信息") +public class OrgController { + + @Autowired + private OrgService orgService; + + @GetMapping("/uc/org/page") + @ApiOperation("分页查询机构") + public AlitaResult> page(OrgQueryDTO orgQueryDTO) { + orgService.page(orgQueryDTO); + return AlitaResult.success(orgQueryDTO.getPageResult()); + } + + + @PostMapping("/uc/org/create") + @ApiOperation("分页查询机构") + public AlitaResult create(@Validated @RequestBody OrgCreateDTO orgCreateDTO) { + orgService.create(orgCreateDTO); + return AlitaResult.success(); + } + + @PutMapping("/uc/org/modify") + @ApiOperation("修改机构") + public AlitaResult modify(@RequestBody @Validated OrgModifyDTO orgModifyDTO) { + orgService.modify(orgModifyDTO); + return AlitaResult.success(); + } + + @GetMapping("/uc/org/find") + @ApiOperation("查看机构信息") + public AlitaResult find() { + return AlitaResult.success(orgService.find(OrgQueryDTO.builder().id(UserContextHolder.getExistLoginOrgId()).build())); + } + +//***********************************分隔符*********************************************** + + + @GetMapping("/info") + @ApiOperation("查询机构信息") + public AlitaResult info(UcOrgInfoReqDTO reqDTO) { + return AlitaResult.success(orgService.info(reqDTO)); + } + + @GetMapping("/part_info_list") + @ApiOperation("查询机构部分的信息") + public AlitaResult> orgPartInfoList(UcOrgPartQueryDTO queryDTO) { + orgService.orgPartInfoList(queryDTO); + return AlitaResult.success(queryDTO.getPageResult()); + } + + @GetMapping("/find_all_org") + @ApiOperation("查询所有机构信息") + public AlitaResult> findAllOrg() { + return AlitaResult.success(orgService.findAllOrg()); + } + + @GetMapping("/open_part_info_list") + @ApiOperation("开放接口--查询机构部分的信息") + public AlitaResult> openOrgPartInfoList(@Validated UcOpenOrgPartQueryDTO queryDTO) { + return AlitaResult.success(orgService.openOrgPartInfoList(queryDTO)); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/controller/OrgRelationController.java b/backend/src/main/java/com/senmesh/usercenter/org/controller/OrgRelationController.java new file mode 100644 index 0000000..c44ee52 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/controller/OrgRelationController.java @@ -0,0 +1,62 @@ +package com.senmesh.usercenter.org.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.org.dto.OrgRelationCreateDTO; +import com.senmesh.usercenter.org.dto.OrgRelationDTO; +import com.senmesh.usercenter.org.dto.OrgRelationModifyDTO; +import com.senmesh.usercenter.org.dto.OrgRelationQueryDTO; +import com.senmesh.usercenter.org.dto.OrgRelationQueryOrgDTO; +import com.senmesh.usercenter.org.dto.SelectOrgDTO; +import com.senmesh.usercenter.org.service.OrgRelationService; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2022-05-25 + */ +@RestController +@RequestMapping("org_relation") +@Api(tags = "机构关系表") +public class OrgRelationController { + + @Autowired + private OrgRelationService orgRelationService; + + @PostMapping + @ApiOperation("新增机构关系") + public AlitaResult create(@Validated @RequestBody OrgRelationCreateDTO orgRelationCreateDTO) { + return AlitaResult.success(orgRelationService.create(orgRelationCreateDTO)); + } + + @PutMapping + @ApiOperation("修改机构关系") + public AlitaResult modify(@Validated @RequestBody OrgRelationModifyDTO orgRelationModifyDTO) { + orgRelationService.modify(orgRelationModifyDTO); + return AlitaResult.success(); + } + + @GetMapping("/find") + @ApiOperation("查询单个机构关系") + public AlitaResult find(OrgRelationQueryDTO orgRelationQueryDTO) { + return AlitaResult.success(orgRelationService.find(orgRelationQueryDTO)); + } + + @GetMapping("/page_org") + @ApiOperation("分页查询机构") + public AlitaResult> pageOrg(@Validated OrgRelationQueryOrgDTO orgRelationQueryOrgDTO){ + orgRelationService.pageOrg(orgRelationQueryOrgDTO); + return AlitaResult.success(orgRelationQueryOrgDTO.getPageResult()); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dao/ImportDetailOrgMapper.java b/backend/src/main/java/com/senmesh/usercenter/org/dao/ImportDetailOrgMapper.java new file mode 100644 index 0000000..d820947 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dao/ImportDetailOrgMapper.java @@ -0,0 +1,26 @@ +package com.senmesh.usercenter.org.dao; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.org.entity.ImportDetailOrg; +import com.senmesh.usercenter.org.dto.ImportDetailOrgDTO; +import com.senmesh.usercenter.org.dto.ImportDetailOrgQueryDTO; +import com.senmesh.usercenter.org.dto.ImportDetailOrgPageQueryDTO; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 机构导入表 + * + * @author guixinman + * @since 1.0.0 2024-06-12 + */ +@Mapper +public interface ImportDetailOrgMapper extends MyMapper { + + List page(@Param("param") ImportDetailOrgPageQueryDTO queryDTO); + + List list(@Param("param") ImportDetailOrgQueryDTO queryDTO); +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dao/OrgMapper.java b/backend/src/main/java/com/senmesh/usercenter/org/dao/OrgMapper.java new file mode 100644 index 0000000..d28da15 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dao/OrgMapper.java @@ -0,0 +1,51 @@ +package com.senmesh.usercenter.org.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.org.dto.OrgDTO; +import com.senmesh.usercenter.org.dto.OrgModifyDTO; +import com.senmesh.usercenter.org.dto.OrgQueryDTO; +import com.senmesh.usercenter.org.dto.UcOpenOrgPartQueryDTO; +import com.senmesh.usercenter.org.dto.UcOrgInfoReqDTO; +import com.senmesh.usercenter.org.dto.UcOrgInfoResDTO; +import com.senmesh.usercenter.org.dto.UcOrgPartInfoDTO; +import com.senmesh.usercenter.org.dto.UcOrgPartQueryDTO; +import com.senmesh.usercenter.org.entity.Org; + +/** + * 机构 + * @author sr on 2024-04-18 + */ +public interface OrgMapper extends MyMapper { + + List listOrgDTO(@Param("param") OrgQueryDTO orgQueryDTO); + + void modifyByOrgId(@Param("param") OrgModifyDTO orgModifyDTO); + + +//***********************************分隔符*********************************************** + + UcOrgInfoResDTO info(@Param("param") UcOrgInfoReqDTO reqDTO); + + /** + * 组织部分信息列表 + * + * @param queryDTO 查询dto + * @return {@link UcOrgPartInfoDTO} + */ + List orgPartInfoList(@Param("param") UcOrgPartQueryDTO queryDTO); + + + List findAllOrg(); + + /** + * @description: 开放接口--查询机构部分的信息 + * @return: 根据产品编号 查询 所有机构名称+orgId + * @author: guixinman + * @param: 产品编号 + */ + List openOrgPartInfoList(@Param("param") UcOpenOrgPartQueryDTO queryDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dao/OrgRelationMapper.java b/backend/src/main/java/com/senmesh/usercenter/org/dao/OrgRelationMapper.java new file mode 100644 index 0000000..5ea4492 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dao/OrgRelationMapper.java @@ -0,0 +1,32 @@ +package com.senmesh.usercenter.org.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.usercenter.org.dto.OrgRelationDTO; +import com.senmesh.usercenter.org.dto.OrgRelationQueryDTO; +import com.senmesh.usercenter.org.dto.OrgRelationQueryOrgDTO; +import com.senmesh.usercenter.org.dto.SelectOrgDTO; +import com.senmesh.usercenter.org.entity.OrgRelation; +import com.senmesh.tkmybatis.mybatis.MyMapper; + +/** + * 机构关系表 + * + * @author sr on 2022-05-25 + */ +public interface OrgRelationMapper extends MyMapper { + + /** + * 查询 + * + * @param orgRelationQueryDTO + * @return + * @author sr on 2022-05-25 + */ + List listOrgRelationDTO(@Param("param") OrgRelationQueryDTO orgRelationQueryDTO); + + List listOrg(@Param("param") OrgRelationQueryOrgDTO orgRelationQueryOrgDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dto/ImportDetailOrgDTO.java b/backend/src/main/java/com/senmesh/usercenter/org/dto/ImportDetailOrgDTO.java new file mode 100644 index 0000000..5966734 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dto/ImportDetailOrgDTO.java @@ -0,0 +1,98 @@ +package com.senmesh.usercenter.org.dto; + +import com.senmesh.component.commonimport.dto.ImportDetailSuperDTO; + +import cn.hutool.core.util.StrUtil; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.SuperBuilder; + +/** + * 机构导入表 + * + * @author guixinman + * @since 1.0.0 2024-06-12 + */ +@ApiModel("机构导入表") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class ImportDetailOrgDTO extends ImportDetailSuperDTO { + private static final long serialVersionUID = 1L; + + @ApiModelProperty("导入任务ID") + private Long mainId; + + @ApiModelProperty("机构ID") + private Long orgId; + + @ApiModelProperty("模板全量数据") + private String dataJson; + + @ApiModelProperty("机构名称") + private String orgName; + + @ApiModelProperty("机构类型(1.平台 2.渠道代理商 3.普通机构 4.定制机构 5.散户机构 6.产品机构)") + private String type; + + @ApiModelProperty("招聘岗位类型") + private String recruitPositionType; + + @ApiModelProperty("管理员姓名") + private String realName; + + @ApiModelProperty("手机号") + private String phone; + + @ApiModelProperty("统一社会信用代码") + private String creditCode; + + @ApiModelProperty("注册地址") + private String registeredAddress; + + @ApiModelProperty("规模 数据字典") + private String companySize; + + @ApiModelProperty("所属行业") + private String trade; + + @ApiModelProperty("机构描述") + private String description; + + @ApiModelProperty("任务地点全称") + private String addressName; + + @ApiModelProperty("任务地点编码") + private String addressCode; + + /** + * 上级机构名称 + */ + private String parentOrgName; + + @ApiModelProperty("明细状态") + private Integer detailStatus; + + @ApiModelProperty("失败原因") + private String failReason; + + @ApiModelProperty("外部生成明细id") + private Long extraDetailId; + + @ApiModelProperty("备注") + private String remark; + + public void appendFailMsg(String msg) { + if (StrUtil.isEmpty(msg)) { + return; + } + if (StrUtil.isEmpty(getFailReason())) { + setFailReason(msg); + } else { + setFailReason(String.join(",", getFailReason(), msg)); + } + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dto/ImportDetailOrgExecuteDTO.java b/backend/src/main/java/com/senmesh/usercenter/org/dto/ImportDetailOrgExecuteDTO.java new file mode 100644 index 0000000..7875b83 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dto/ImportDetailOrgExecuteDTO.java @@ -0,0 +1,14 @@ +package com.senmesh.usercenter.org.dto; + +import com.senmesh.component.commonimport.dto.ImportExecuteSuperDTO; + +import lombok.Data; + +/** + * @description: 确定导入DTO + * @author: guixinman + * @create: 2024-06-12 13:41 + **/ +@Data +public class ImportDetailOrgExecuteDTO extends ImportExecuteSuperDTO { +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dto/ImportDetailOrgExportDTO.java b/backend/src/main/java/com/senmesh/usercenter/org/dto/ImportDetailOrgExportDTO.java new file mode 100644 index 0000000..15a4875 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dto/ImportDetailOrgExportDTO.java @@ -0,0 +1,65 @@ +package com.senmesh.usercenter.org.dto; + +import com.alibaba.excel.annotation.ExcelProperty; + +import java.io.Serializable; + + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: + * @author: guixinman + * @create: 2024-06-13 10:41 + **/ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ImportDetailOrgExportDTO implements Serializable { + + @ExcelProperty("机构名称") + private String orgName; + + @ExcelProperty("机构类型") + private String type; + + @ExcelProperty("招聘岗位类型") + private String recruitPositionType; + + @ExcelProperty("管理员姓名") + private String realName; + + @ExcelProperty("手机号") + private String phone; + + @ExcelProperty("统一社会信用代码") + private String creditCode; + + @ExcelProperty("注册地址") + private String registeredAddress; + + @ExcelProperty("规模") + private String companySize; + + @ExcelProperty("所属行业") + private String trade; + + @ExcelProperty("机构描述") + private String description; + + @ExcelProperty("任务地点全称") + private String addressName; + + @ExcelProperty("上级机构名称") + private String parentOrgName; + + @ExcelProperty("失败原因") + private String failReason; + + @ExcelProperty("备注") + private String remark; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dto/ImportDetailOrgListenerDTO.java b/backend/src/main/java/com/senmesh/usercenter/org/dto/ImportDetailOrgListenerDTO.java new file mode 100644 index 0000000..5f934e0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dto/ImportDetailOrgListenerDTO.java @@ -0,0 +1,53 @@ +package com.senmesh.usercenter.org.dto; + +import com.senmesh.component.commonimport.service.IImportDetailForm; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @description: 机构导入 + * @author: guixinman + * @create: 2024-06-12 13:42 + **/ +@Data +public class ImportDetailOrgListenerDTO implements IImportDetailForm { + + @ApiModelProperty("机构名称") + private String orgName; + + @ApiModelProperty("机构类型(1.平台 2.渠道代理商 3.普通机构 4.定制机构 5.散户机构 6.产品机构)") + private String type; + + @ApiModelProperty("招聘岗位类型") + private String recruitPositionType; + + @ApiModelProperty("管理员姓名") + private String realName; + + @ApiModelProperty("手机号") + private String phone; + + @ApiModelProperty("统一社会信用代码") + private String creditCode; + + @ApiModelProperty("注册地址") + private String registeredAddress; + + @ApiModelProperty("规模 数据字典") + private String companySize; + + @ApiModelProperty("所属行业") + private String trade; + + @ApiModelProperty("任务地点全称") + private String addressName; + + @ApiModelProperty("机构描述") + private String description; + + /** + * 上级机构名称 + */ + private String parentOrgName; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dto/ImportDetailOrgOperatorDTO.java b/backend/src/main/java/com/senmesh/usercenter/org/dto/ImportDetailOrgOperatorDTO.java new file mode 100644 index 0000000..6ab63c6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dto/ImportDetailOrgOperatorDTO.java @@ -0,0 +1,92 @@ +package com.senmesh.usercenter.org.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 机构导入表 + * + * @author guixinman + * @since 1.0.0 2024-06-12 + */ +@ApiModel("机构导入表") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ImportDetailOrgOperatorDTO implements Serializable { + private static final long serialVersionUID = 1L; + + private Long id; + + @ApiModelProperty("导入任务ID") + private Long mainId; + + @ApiModelProperty("机构ID") + private Long orgId; + + @ApiModelProperty("模板全量数据") + private String dataJson; + + @ApiModelProperty("机构名称") + private String orgName; + + @ApiModelProperty("机构类型(1.平台 2.渠道代理商 3.普通机构 4.定制机构 5.散户机构 6.产品机构)") + private String type; + + @ApiModelProperty("招聘岗位类型") + private String recruitPositionType; + + @ApiModelProperty("管理员姓名") + private String realName; + + @ApiModelProperty("手机号") + private String phone; + + @ApiModelProperty("统一社会信用代码") + private String creditCode; + + @ApiModelProperty("注册地址") + private String registeredAddress; + + @ApiModelProperty("规模 数据字典") + private String companySize; + + @ApiModelProperty("所属行业") + private String trade; + + @ApiModelProperty("机构描述") + private String description; + + @ApiModelProperty("任务地点全称") + private String addressName; + + @ApiModelProperty("任务地点编码") + private String addressCode; + + /** + * 上级机构名称 + */ + private String parentOrgName; + + @ApiModelProperty("明细状态") + private Integer detailStatus; + + @ApiModelProperty("失败原因") + private String failReason; + + @ApiModelProperty("外部生成明细id") + private Long extraDetailId; + + @ApiModelProperty("备注") + private String remark; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dto/ImportDetailOrgPageQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/org/dto/ImportDetailOrgPageQueryDTO.java new file mode 100644 index 0000000..d687d0d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dto/ImportDetailOrgPageQueryDTO.java @@ -0,0 +1,112 @@ +package com.senmesh.usercenter.org.dto; + +import com.senmesh.common.dto.PageQueryDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import com.fasterxml.jackson.annotation.JsonFormat; + +import org.springframework.format.annotation.DateTimeFormat; + + +import java.util.Date; + +/** + * 机构导入表 + * + * @author guixinman + * @since 1.0.0 2024-06-12 + */ + +@ApiModel("机构导入表") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class ImportDetailOrgPageQueryDTO extends PageQueryDTO { + private static final long serialVersionUID = 1L; + + private Long id; + + @ApiModelProperty("导入任务ID") + private Long mainId; + + @ApiModelProperty("机构ID") + private Long orgId; + + @ApiModelProperty("模板全量数据") + private String dataJson; + + @ApiModelProperty("机构名称 (模糊匹配)") + private String orgNameLike; + + @ApiModelProperty("机构类型(1.平台 2.渠道代理商 3.普通机构 4.定制机构 5.散户机构 6.产品机构)") + private String type; + + @ApiModelProperty("招聘岗位类型") + private String recruitPositionType; + + @ApiModelProperty("管理员姓名") + private String realName; + + @ApiModelProperty("手机号") + private String phone; + + @ApiModelProperty("统一社会信用代码") + private String creditCode; + + @ApiModelProperty("注册地址") + private String registeredAddress; + + @ApiModelProperty("规模 数据字典") + private String companySize; + + @ApiModelProperty("所属行业") + private String trade; + + @ApiModelProperty("机构描述") + private String description; + + @ApiModelProperty("任务地点全称 (模糊匹配)") + private String addressNameLike; + + @ApiModelProperty("任务地点编码") + private String addressCode; + + @ApiModelProperty("明细状态") + private Integer detailStatus; + + @ApiModelProperty("失败原因") + private String failReason; + + @ApiModelProperty("外部生成明细id") + private Long extraDetailId; + + @ApiModelProperty("备注") + private String remark; + + @ApiModelProperty("创建时间起,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTimeStart; + + @ApiModelProperty("创建时间止,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTimeEnd; + + @ApiModelProperty("更新时间起,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTimeStart; + + @ApiModelProperty("更新时间止,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTimeEnd; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dto/ImportDetailOrgQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/org/dto/ImportDetailOrgQueryDTO.java new file mode 100644 index 0000000..28e6fb3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dto/ImportDetailOrgQueryDTO.java @@ -0,0 +1,112 @@ +package com.senmesh.usercenter.org.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonFormat; + +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +/** + * 机构导入表 + * + * @author guixinman + * @since 1.0.0 2024-06-12 + */ +@ApiModel("机构导入表") +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ImportDetailOrgQueryDTO implements Serializable { + private static final long serialVersionUID = 1L; + + private Long id; + + @ApiModelProperty("导入任务ID") + private Long mainId; + + @ApiModelProperty("机构ID") + private Long orgId; + + @ApiModelProperty("模板全量数据") + private String dataJson; + + @ApiModelProperty("机构名称 (模糊匹配)") + private String orgNameLike; + + @ApiModelProperty("机构类型(1.平台 2.渠道代理商 3.普通机构 4.定制机构 5.散户机构 6.产品机构)") + private String type; + + @ApiModelProperty("招聘岗位类型") + private String recruitPositionType; + + @ApiModelProperty("管理员姓名") + private String realName; + + @ApiModelProperty("手机号") + private String phone; + + @ApiModelProperty("统一社会信用代码") + private String creditCode; + + @ApiModelProperty("注册地址") + private String registeredAddress; + + @ApiModelProperty("规模 数据字典") + private String companySize; + + @ApiModelProperty("所属行业") + private String trade; + + @ApiModelProperty("机构描述") + private String description; + + @ApiModelProperty("任务地点全称 (模糊匹配)") + private String addressNameLike; + + @ApiModelProperty("任务地点编码") + private String addressCode; + + @ApiModelProperty("明细状态") + private Integer detailStatus; + + @ApiModelProperty("失败原因") + private String failReason; + + @ApiModelProperty("外部生成明细id") + private Long extraDetailId; + + @ApiModelProperty("备注") + private String remark; + + @ApiModelProperty("创建时间起,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTimeStart; + + @ApiModelProperty("创建时间止,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTimeEnd; + + @ApiModelProperty("更新时间起,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTimeStart; + + @ApiModelProperty("更新时间止,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTimeEnd; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgCreateDTO.java b/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgCreateDTO.java new file mode 100644 index 0000000..48c644b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgCreateDTO.java @@ -0,0 +1,97 @@ +package com.senmesh.usercenter.org.dto; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseOperateDTO; +import com.senmesh.common.validation.annotation.Expression; +import com.senmesh.common.validation.constants.ValidProviderEnum; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Builder.Default; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Builder +@Data +@ApiModel(description = "机构") +public class OrgCreateDTO extends BaseOperateDTO{ + + /** **/ + private static final long serialVersionUID = 7745034806528023290L; + + @ApiModelProperty("机构类型") +// @NotEmpty(message = "机构类型不能为空") + @Default + private String type = "2"; + @ApiModelProperty("机构名称") + @NotBlank(message = "机构名称不能为空") + private String orgName; + @ApiModelProperty("手机号") + @Expression(type = ValidProviderEnum.PHONE, message = "管理员手机号格式不正确") + private String phone; + +// @NotBlank(message = "管理员姓名不能为空") + @ApiModelProperty("管理员姓名") + private String realName; + + @ApiModelProperty("唯一社会信用代码") +// @Expression(type = ValidProviderEnum.CREDIT_CODE, message = "统一社会信用代码格式错误") + private String creditCode; + @ApiModelProperty("企业所在地") +// @NotBlank(message = "企业所在地不能为空") + private String addressCode; + @ApiModelProperty("上级机构") + @NotNull(message = "上级机构不能为空") + private Long parentId; + + /** + * 招聘岗位类型 + */ + private String recruitPositionType; + + /** + * 营业执照 + */ + private String businessLicense; + + /** + * 注册地址 + */ +// @NotBlank(message = "企业注册地址不能为空") + private String registeredAddress; + + /** + * 规模 + */ + private String companySize; + + /** + * 所属行业 + */ + private String trade; + + /** + * 机构描述 + */ + private String description; + + /** + * 企业所在地 地点全称 + */ +// @NotBlank(message = "企业经营地址不能为空") + private String addressName; + + /** + * logo + */ + private String orgLogo; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgDTO.java b/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgDTO.java new file mode 100644 index 0000000..d0601ab --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgDTO.java @@ -0,0 +1,151 @@ +package com.senmesh.usercenter.org.dto; + +import com.google.common.collect.Lists; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.senmesh.common.dto.BaseDTO; +import com.senmesh.common.util.TreeNode; + +import java.util.List; +import java.util.Optional; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 机构 + * @author sr on 2024-04-18 + */ +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class OrgDTO extends BaseDTO implements TreeNode { + + /** **/ + private static final long serialVersionUID = 5038840445751414497L; + + /** + * 机构名称 + */ + private String orgName; + + /** + * 机构编号 + */ + private String orgCode; + + /** + * 机构类型 + */ + private String type; + + /** + * 企业所在地 地点编码 + */ + private String addressCode; + + /** + * 企业所在地 地点全称 + */ + private String addressName; + + /** + * 机构描述 + */ + private String description; + + /** + * 是否启用 + */ + private Boolean enable; + + /** + * 是否激活 + */ + private Boolean activated; + + /** + * 上级机构ID + */ + private Long parentId; + + /** 上级机构名称 **/ + private String parentName; + + /** + * 机构账号激活码 + */ + private String activationCode; + + /** + * 手机号码 + */ + private String phone; + + /** + * 唯一社会信用代码 + */ + private String creditCode; + + /** + * 所属行业 + */ + private String trade; + + /** + * logo + */ + private String orgLogo; + + /** + * 注册地址 + */ + private String registeredAddress; + + /** + * 规模 + */ + private String companySize; + + /** + * 营业执照 + */ + private String businessLicense; + + private String realName; + + /** + * 招聘岗位类型 + */ + private String recruitPositionType; + + @JsonIgnore + private List children = Lists.newArrayList(); + public List getChildren() { + if (this.children == null) { + this.children = Lists.newArrayList(); + } + return this.children; + } + + public void setChildren(List children) { + this.children = children; + } + + @Override + public void addChildren(OrgDTO node) { + List orgDTOS = Optional.ofNullable(getChildren()) + .orElse(Lists.newArrayList()); + orgDTOS.add(node); + setChildren(orgDTOS); + } + + public Long getParentId() { + return Optional.ofNullable(parentId).orElse(0L); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgModifyDTO.java b/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgModifyDTO.java new file mode 100644 index 0000000..ce112fa --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgModifyDTO.java @@ -0,0 +1,77 @@ +package com.senmesh.usercenter.org.dto; + +import com.senmesh.common.dto.BaseOperateDTO; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import com.senmesh.common.validation.annotation.Expression; +import com.senmesh.common.validation.constants.ValidProviderEnum; +import lombok.Data; + +/** + * @description: + * @author: guixinman + * @create: 2024-04-26 10:53 + **/ +@Data +public class OrgModifyDTO extends BaseOperateDTO { + + @NotNull(message = "id不能为空") + private Long id; + + /** + * logo + */ + private String orgLogo; + + /** + * 规模 + */ + private String companySize; + + /** + * 企业所在地 地点编码 + */ + private String addressCode; + + /** + * 营业执照 + */ + private String businessLicense; + + /** + * 唯一社会信用代码 + */ + @Expression(type = ValidProviderEnum.CREDIT_CODE, message = "统一社会信用代码格式错误") + private String creditCode; + + /** + * 企业所在地 地点全称 + */ + @NotBlank(message = "企业经营地址不能为空") + private String addressName; + + /** + * 注册地址 + */ + @NotBlank(message = "企业注册地址不能为空") + private String registeredAddress; + + + /** + * 所属行业 + */ + private String trade; + + /** + * 机构描述 + */ + private String description; + + /** + * 是否启用 + */ + private Boolean enable; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgQueryDTO.java new file mode 100644 index 0000000..067379e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgQueryDTO.java @@ -0,0 +1,60 @@ +package com.senmesh.usercenter.org.dto; + + +import java.util.Date; +import java.util.Set; + +import javax.validation.constraints.NotEmpty; + +import org.springframework.format.annotation.DateTimeFormat; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.senmesh.common.dto.PageQueryDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2024-04-09 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "动态表格查询条件") +public class OrgQueryDTO extends PageQueryDTO{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + @ApiModelProperty("机构类型") + @NotEmpty(message = "机构类型不能为空") + private String type; + private Set types; + @ApiModelProperty("机构名称") + private String orgName; + @ApiModelProperty("机构名称(模糊匹配)") + private String orgNameLike; + @ApiModelProperty("机构编号") + private String orgCode; + @ApiModelProperty("上级机构") + private Long parentId; + @ApiModelProperty("是否启用") + private Boolean enable; + @ApiModelProperty("创建时间起,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTimeStart; + @ApiModelProperty("创建时间止,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTimeEnd; + + private Set orgIds; +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgRelationCreateDTO.java b/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgRelationCreateDTO.java new file mode 100644 index 0000000..3fbd959 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgRelationCreateDTO.java @@ -0,0 +1,47 @@ +package com.senmesh.usercenter.org.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2022-05-25 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "机构关系表创建") +public class OrgRelationCreateDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + + @ApiModelProperty("机构id") + @NotNull(message = "机构id不能为空") + private Long orgId; + @ApiModelProperty("类型") + @NotNull(message = "机构类型不能为空") + private Integer orgType ; + @ApiModelProperty("上级id") + private Long parentId; + @ApiModelProperty("平台编码") + @NotNull(message = "平台编码不能为空") + private Integer platformCode; + @ApiModelProperty("平台名称") + private String platformName; + + + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgRelationDTO.java b/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgRelationDTO.java new file mode 100644 index 0000000..47859e4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgRelationDTO.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.org.dto; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2022-05-25 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "机构关系表") +public class OrgRelationDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("机构id") + private Long orgId; + @ApiModelProperty("类型") + private Integer orgType; + @ApiModelProperty("上级id") + private Long parentId; + @ApiModelProperty("路径") + private String path; + @ApiModelProperty("平台编码") + private Integer platformCode; + @ApiModelProperty("平台名称") + private String platformName; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgRelationModifyDTO.java b/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgRelationModifyDTO.java new file mode 100644 index 0000000..9de1478 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgRelationModifyDTO.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.org.dto; + +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2022-05-25 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "机构关系表操作") +public class OrgRelationModifyDTO extends BaseOperateDTO{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + @NotNull(message = "id不能为空") + private Long id; + @ApiModelProperty("类型") + private Integer orgType; + @ApiModelProperty("上级id") + private Long parentId; + @ApiModelProperty("平台名称") + private String platformName; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgRelationQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgRelationQueryDTO.java new file mode 100644 index 0000000..bb3233a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgRelationQueryDTO.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.org.dto; + +import java.io.Serializable; + +import com.senmesh.common.dto.PageQueryDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2022-05-25 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "机构关系表查询条件") +public class OrgRelationQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + @ApiModelProperty("机构id") + private Long orgId; + @ApiModelProperty("平台编码") + private Integer platformCode; + @ApiModelProperty("上级机构id") + private Long upOrgId; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgRelationQueryOrgDTO.java b/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgRelationQueryOrgDTO.java new file mode 100644 index 0000000..20278c5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dto/OrgRelationQueryOrgDTO.java @@ -0,0 +1,45 @@ +package com.senmesh.usercenter.org.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.PageQueryDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2022-05-25 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "机构关系表查询条件") +public class OrgRelationQueryOrgDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + + @ApiModelProperty("类型") + private Integer orgType; + + @ApiModelProperty("机构名称-模糊") + private Integer orgNameLike; + + @ApiModelProperty("平台编码") + @NotNull(message = "平台编码不能为空") + private Integer platformCode; + + @ApiModelProperty("上层机构id") + private Long upOrgId; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dto/SelectOrgDTO.java b/backend/src/main/java/com/senmesh/usercenter/org/dto/SelectOrgDTO.java new file mode 100644 index 0000000..f25239a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dto/SelectOrgDTO.java @@ -0,0 +1,31 @@ +package com.senmesh.usercenter.org.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(description = "机构信息(供选择)") +@Builder +public class SelectOrgDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 59302802862397459L; + + @ApiModelProperty("机构id") + private Long orgId; + + @ApiModelProperty("机构名称") + private String orgName; + + @ApiModelProperty("上级id") + private Long parentId; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dto/UcOpenOrgPartQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/org/dto/UcOpenOrgPartQueryDTO.java new file mode 100644 index 0000000..659ceac --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dto/UcOpenOrgPartQueryDTO.java @@ -0,0 +1,24 @@ +package com.senmesh.usercenter.org.dto; + +import com.senmesh.common.dto.BaseOperateDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +/** + * @description: 提供给第三方使用(灵宸) + * @author: guixinman + * @create: 2023-04-25 14:39 + **/ +@Data +public class UcOpenOrgPartQueryDTO extends BaseOperateDTO implements Serializable{ + + private static final long serialVersionUID = -2069753408108532710L; + + @NotBlank(message = "产品编号不能为空") + @ApiModelProperty("产品编号") + private String productCode; +} + diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dto/UcOrgInfoReqDTO.java b/backend/src/main/java/com/senmesh/usercenter/org/dto/UcOrgInfoReqDTO.java new file mode 100644 index 0000000..862f7a5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dto/UcOrgInfoReqDTO.java @@ -0,0 +1,27 @@ +package com.senmesh.usercenter.org.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +@Data +@Builder +@ApiModel("个人端-企业信息-请求DTO") +@NoArgsConstructor +@AllArgsConstructor +public class UcOrgInfoReqDTO implements Serializable { + + private static final long serialVersionUID = 8213441568149895962L; + @ApiModelProperty("机构ID") + @NotNull(message = "机构ID不能为空") + private Long orgId; + + @ApiModelProperty("机构名称") + private String orgName; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dto/UcOrgInfoResDTO.java b/backend/src/main/java/com/senmesh/usercenter/org/dto/UcOrgInfoResDTO.java new file mode 100644 index 0000000..5515265 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dto/UcOrgInfoResDTO.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.org.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@Data +@Builder +@ApiModel("个人端-企业信息-响应DTO") +@NoArgsConstructor +@AllArgsConstructor +public class UcOrgInfoResDTO implements Serializable { + private static final long serialVersionUID = 8612024599522361343L; + + @ApiModelProperty("机构ID") + private Long orgId; + + @ApiModelProperty("机构Code") + private String orgCode; + + @ApiModelProperty("机构描述") + private String description; + + @ApiModelProperty("机构名称") + private String orgName; + + @ApiModelProperty("机构管理员联系电话") + private String phone; + + @ApiModelProperty("机构管理员名称") + private String realName; + + @ApiModelProperty("优质企业") + private Boolean quality; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dto/UcOrgPartInfoDTO.java b/backend/src/main/java/com/senmesh/usercenter/org/dto/UcOrgPartInfoDTO.java new file mode 100644 index 0000000..da729ad --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dto/UcOrgPartInfoDTO.java @@ -0,0 +1,44 @@ +package com.senmesh.usercenter.org.dto; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; + +@Data +@Builder +@ApiModel("个人端-企业部分信息-响应DTO") +@NoArgsConstructor +@AllArgsConstructor +public class UcOrgPartInfoDTO implements Serializable { + private static final long serialVersionUID = 8612024599522361343L; + + @ApiModelProperty("机构ID") + private Long orgId; + + @ApiModelProperty("机构名称") + private String orgName; + + @ApiModelProperty("企业电话") + private String phone; + + @ApiModelProperty("开户银行") + private String bankName; + + @ApiModelProperty("银行账号") + private String bankAccount; + + @JsonIgnore + @ApiModelProperty("科目") + private String categoryName; + + private List categoryNames; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/dto/UcOrgPartQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/org/dto/UcOrgPartQueryDTO.java new file mode 100644 index 0000000..a237dc4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/dto/UcOrgPartQueryDTO.java @@ -0,0 +1,20 @@ +package com.senmesh.usercenter.org.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +@EqualsAndHashCode(callSuper = true) +@Data +@Builder +@ApiModel("个人端-企业部分信息-分页查询DTO") +@NoArgsConstructor +@AllArgsConstructor +public class UcOrgPartQueryDTO extends PageQueryDTO { + + private static final long serialVersionUID = -3571112498546235421L; + + @ApiModelProperty("机构名称") + private String orgName; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/entity/ImportDetailOrg.java b/backend/src/main/java/com/senmesh/usercenter/org/entity/ImportDetailOrg.java new file mode 100644 index 0000000..efc2736 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/entity/ImportDetailOrg.java @@ -0,0 +1,107 @@ +package com.senmesh.usercenter.org.entity; + +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import com.baomidou.mybatisplus.annotation.*; +import com.senmesh.common.entity.BaseEntity; + +/** + * 机构导入表 + * + * @author guixinman + * @since 1.0.0 2024-06-12 + */ +@TableName(value = "hr_import_detail_org") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class ImportDetailOrg extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** + * 导入任务ID + */ + private Long mainId; + /** + * 机构ID + */ + private Long orgId; + /** + * 模板全量数据 + */ + private String dataJson; + /** + * 机构名称 + */ + private String orgName; + /** + * 机构类型(1.平台 2.渠道代理商 3.普通机构 4.定制机构 5.散户机构 6.产品机构) + */ + private String type; + /** + * 招聘岗位类型 + */ + private String recruitPositionType; + + @ApiModelProperty("管理员姓名") + private String realName; + + /** + * 手机号 + */ + private String phone; + /** + * 统一社会信用代码 + */ + private String creditCode; + /** + * 注册地址 + */ + private String registeredAddress; + /** + * 规模 数据字典 + */ + private String companySize; + /** + * 所属行业 + */ + private String trade; + /** + * 机构描述 + */ + private String description; + /** + * 任务地点全称 + */ + private String addressName; + + /** + * 任务地点编码 + */ + private String addressCode; + + /** + * 上级机构名称 + */ + private String parentOrgName; + /** + * 明细状态 + */ + private Integer detailStatus; + /** + * 失败原因 + */ + private String failReason; + /** + * 外部生成明细id + */ + private Long extraDetailId; + /** + * 备注 + */ + private String remark; +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/org/entity/Org.java b/backend/src/main/java/com/senmesh/usercenter/org/entity/Org.java new file mode 100644 index 0000000..21c362b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/entity/Org.java @@ -0,0 +1,110 @@ +package com.senmesh.usercenter.org.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; +import lombok.*; +import lombok.experimental.Accessors; + +/** + * @author sr on 2024-04-18 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableName("xs_org") +public class Org extends BaseEntity { + + + /** + * 机构名称 + */ + private String orgName; + + /** + * 机构编号 + */ + private String orgCode; + + /** + * 机构类型 + */ + private String type; + + /** + * 企业所在地 地点编码 + */ + private String addressCode; + + /** + * 企业所在地 地点全称 + */ + private String addressName; + + /** + * 机构描述 + */ + private String description; + + /** + * 是否启用 + */ + private Boolean enable; + + /** + * 是否激活 + */ + private Boolean activated; + + /** + * 父机构ID + */ + private Long parentId; + + /** + * 机构账号激活码 + */ + private String activationCode; + + /** + * 手机号码 + */ + private String phone; + + /** + * 唯一社会信用代码 + */ + private String creditCode; + + /** + * 所属行业 + */ + private String trade; + + /** + * logo + */ + private String orgLogo; + + /** + * 注册地址 + */ + private String registeredAddress; + + /** + * 规模 + */ + private String companySize; + + /** + * 营业执照 + */ + private String businessLicense; + + /** + * 招聘岗位类型 + */ + private String recruitPositionType; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/entity/OrgRelation.java b/backend/src/main/java/com/senmesh/usercenter/org/entity/OrgRelation.java new file mode 100644 index 0000000..fd98440 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/entity/OrgRelation.java @@ -0,0 +1,41 @@ +package com.senmesh.usercenter.org.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 机构关系表 + * + * @author sr on 2022-05-25 + */ +@TableName("uc_org_relation") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class OrgRelation extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 机构id **/ + private Long orgId; + /** 类型 **/ + private Integer orgType; + /** 上级id **/ + private Long parentId; + /** 路径 **/ + private String path; + /** 平台编码 **/ + private Integer platformCode; + /** 平台名称 **/ + private String platformName; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/enums/RecruitPositionTypeEnum.java b/backend/src/main/java/com/senmesh/usercenter/org/enums/RecruitPositionTypeEnum.java new file mode 100644 index 0000000..45b604e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/enums/RecruitPositionTypeEnum.java @@ -0,0 +1,27 @@ +package com.senmesh.usercenter.org.enums; + +public enum RecruitPositionTypeEnum { + ODD_JOB("1", "零工"), + GENERAL_WORKER("2", "普工"), + ODD_JOB_OR_GENERAL_WORKER("3", "零工+普工"); + + private String type; + /** + * 类型描述 + */ + private String desc; + + + RecruitPositionTypeEnum(String type, String desc) { + this.type = type; + this.desc = desc; + } + + public String getType() { + return type; + } + + public String getDesc() { + return desc; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/mapper/ImportDetailOrgMapper.xml b/backend/src/main/java/com/senmesh/usercenter/org/mapper/ImportDetailOrgMapper.xml new file mode 100644 index 0000000..c6ac04e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/mapper/ImportDetailOrgMapper.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + FROM + hr_import_detail_org t + WHERE t.deleted = FALSE + + AND t.id = #{param.id} + + + AND t.main_id = #{param.mainId} + + + AND t.org_id = #{param.orgId} + + + AND t.data_json = #{param.dataJson} + + + + AND t.org_name like #{orgNameLike} + + + AND t.type = #{param.type} + + + AND t.recruit_position_type = #{param.recruitPositionType} + + + AND t.phone = #{param.phone} + + + AND t.credit_code = #{param.creditCode} + + + AND t.registered_address = #{param.registeredAddress} + + + AND t.company_size = #{param.companySize} + + + AND t.trade = #{param.trade} + + + AND t.description = #{param.description} + + + + AND t.address_name like #{addressNameLike} + + + AND t.address_code = #{param.addressCode} + + + AND t.detail_status = #{param.detailStatus} + + + AND t.fail_reason = #{param.failReason} + + + AND t.extra_detail_id = #{param.extraDetailId} + + + AND t.remark = #{param.remark} + + + AND t.create_time >= #{param.createTimeStart} + + + AND t.create_time <= #{param.createTimeEnd} + + + AND t.update_time >= #{param.updateTimeStart} + + + AND t.update_time <= #{param.updateTimeEnd} + + ORDER BY t.id DESC + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/org/mapper/OrgMapper.xml b/backend/src/main/java/com/senmesh/usercenter/org/mapper/OrgMapper.xml new file mode 100644 index 0000000..a71ed95 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/mapper/OrgMapper.xml @@ -0,0 +1,163 @@ + + + + + + update xs_org + set + update_by = #{param.operateUserId}, + update_time = now(), + org_logo = #{param.orgLogo}, + company_size = #{param.companySize}, + address_code = #{param.addressCode}, + business_license = #{param.businessLicense}, + credit_code = #{param.creditCode}, + address_name = #{param.addressName}, + registered_address = #{param.registeredAddress}, + trade = #{param.trade}, + description = #{param.description}, + enable = #{param.enable} + where id = #{param.id} and deleted = FALSE + + + + + + + + + + + + + + + + + + + + + diff --git a/backend/src/main/java/com/senmesh/usercenter/org/mapper/OrgRelationMapper.xml b/backend/src/main/java/com/senmesh/usercenter/org/mapper/OrgRelationMapper.xml new file mode 100644 index 0000000..0e9ebbf --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/mapper/OrgRelationMapper.xml @@ -0,0 +1,50 @@ + + + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/org/mapstruct/ImportDetailOrgConvert.java b/backend/src/main/java/com/senmesh/usercenter/org/mapstruct/ImportDetailOrgConvert.java new file mode 100644 index 0000000..d0ea1f9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/mapstruct/ImportDetailOrgConvert.java @@ -0,0 +1,26 @@ +package com.senmesh.usercenter.org.mapstruct; + +import com.senmesh.usercenter.org.entity.ImportDetailOrg; +import com.senmesh.usercenter.org.dto.ImportDetailOrgDTO; +import com.senmesh.usercenter.org.dto.ImportDetailOrgOperatorDTO; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * 机构导入表 + * + * @author guixinman + * @since 1.0.0 2024-06-12 + */ +@Mapper +public interface ImportDetailOrgConvert { + ImportDetailOrgConvert INSTANCE = Mappers.getMapper(ImportDetailOrgConvert.class); + + ImportDetailOrg convert(ImportDetailOrgDTO dto); + + ImportDetailOrgDTO convert(ImportDetailOrg entity); + + ImportDetailOrg convert(ImportDetailOrgOperatorDTO dto); + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/org/mapstruct/OrgMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/org/mapstruct/OrgMapMapper.java new file mode 100644 index 0000000..e2d3ebf --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/mapstruct/OrgMapMapper.java @@ -0,0 +1,44 @@ +package com.senmesh.usercenter.org.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.org.dto.OrgCreateDTO; +import com.senmesh.usercenter.org.dto.OrgDTO; +import com.senmesh.usercenter.org.entity.Org; + +/** + * @author sr on 2024-04-18 + */ +@Mapper +public interface OrgMapMapper { + + OrgMapMapper INSTANCE = + Mappers.getMapper(OrgMapMapper.class); + + /** + * @param orgDto + * @return + * @author sr on 2024-04-18 + */ + Org toEntity( + OrgDTO orgDto); + + /** + * entity to dto + * + * @param org + * @return + * @author sr on 2024-04-18 + */ + OrgDTO toDto(Org org); + + /** + * @param orgCreateDTO + * @return + * @author sr on 2024-04-18 + */ + Org toEntity(OrgCreateDTO orgCreateDTO); + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/mapstruct/OrgRelationMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/org/mapstruct/OrgRelationMapMapper.java new file mode 100644 index 0000000..3b44f26 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/mapstruct/OrgRelationMapMapper.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.org.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.org.dto.OrgRelationCreateDTO; +import com.senmesh.usercenter.org.dto.OrgRelationDTO; +import com.senmesh.usercenter.org.entity.OrgRelation; +import com.senmesh.usercenter.org.dto.OrgRelationModifyDTO; + +/** + * @author sr on 2022-05-25 + */ +@Mapper +public interface OrgRelationMapMapper { + + OrgRelationMapMapper INSTANCE = + Mappers.getMapper(OrgRelationMapMapper.class); + + /** + * dto to entity + * + * @param orgRelationDto + * @return + * @author sr on 2022-05-25 + */ + OrgRelation toEntity( + OrgRelationDTO orgRelationDto); + + + /** + * @param orgRelationCreateDTO + * @return + * @author sr on 2022-05-25 + */ + OrgRelation toEntity(OrgRelationCreateDTO orgRelationCreateDTO); + + OrgRelation to(OrgRelationModifyDTO orgRelationModifyDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/service/ImportDetailOrgService.java b/backend/src/main/java/com/senmesh/usercenter/org/service/ImportDetailOrgService.java new file mode 100644 index 0000000..df14272 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/service/ImportDetailOrgService.java @@ -0,0 +1,70 @@ +package com.senmesh.usercenter.org.service; + +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.groups.Default; + +import java.util.List; + +import com.senmesh.usercenter.org.dto.*; + +/** + * 机构导入表 + * + * @author guixinman + * @since 1.0.0 2024-06-12 + */ +@Validated(Default.class) +public interface ImportDetailOrgService { + + /** + * 机构导入表 - 创建 + * + * @param operatorDto 操作dto + * @return {@link ImportDetailOrgDTO} + */ + ImportDetailOrgDTO create(@Valid ImportDetailOrgOperatorDTO operatorDto); + + /** + * 机构导入表 - 修改 + * + * @param operatorDto 操作dto + * @return {@link ImportDetailOrgDTO} + */ + ImportDetailOrgDTO modify(@Valid ImportDetailOrgOperatorDTO operatorDto); + + /** + * 机构导入表 - 删除 + * + * @param id id + * @return {@link ImportDetailOrgDTO} + */ + ImportDetailOrgDTO delete(Long id); + + /** + * 机构导入表 - 根据ID查询单个 + * + * @param id id + * @return {@link ImportDetailOrgDTO} + */ + ImportDetailOrgDTO findById(Long id); + + /** + * 机构导入表 - 列表查询 + * + * @param queryDTO 列表查询dto + * @return {@link List}<{@link ImportDetailOrgDTO}> + */ + List list(ImportDetailOrgQueryDTO queryDTO); + + /** + * 机构导入表 - 分页查询 + * + * @param queryDTO 分页查询dto + * @return {@link ImportDetailOrgDTO} + */ + List page(ImportDetailOrgPageQueryDTO queryDTO); + + void batchCreate(List importDetailOrgDTOS); +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/org/service/OrgRelationService.java b/backend/src/main/java/com/senmesh/usercenter/org/service/OrgRelationService.java new file mode 100644 index 0000000..936df0e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/service/OrgRelationService.java @@ -0,0 +1,67 @@ +package com.senmesh.usercenter.org.service; + +import java.util.List; + +import javax.validation.Valid; + +import com.senmesh.usercenter.org.dto.OrgRelationQueryDTO; +import com.senmesh.usercenter.org.dto.OrgRelationQueryOrgDTO; +import com.senmesh.usercenter.org.dto.OrgRelationModifyDTO; +import com.senmesh.usercenter.org.dto.OrgRelationCreateDTO; +import com.senmesh.usercenter.org.dto.OrgRelationDTO; + +/** + * 机构关系表 + * + * @author sr on 2022-05-25 + */ +public interface OrgRelationService { + + /** + * 新增 + * + * @param orgRelationOperateDTO + * @return + * @author sr on 2022-05-25 + */ + Long create(@Valid OrgRelationCreateDTO orgRelationCreateDTO); + + /** + * 修改 + * + * @param orgRelationModifyDTO + * @author sr on 2022-05-25 + */ + void modify(OrgRelationModifyDTO orgRelationModifyDTO); + + /** + * 查询 + * + * @param orgRelationQueryDTO + * @return + * @author sr on 2022-05-25 + */ + List list(OrgRelationQueryDTO orgRelationQueryDTO); + + /** + * 分页查询 + * + * @param orgRelationQueryDTO + * @return + * @author sr on 2022-05-25 + */ + void page(OrgRelationQueryDTO orgRelationQueryDTO); + + /** + * 单个查询 + * + * @param orgRelationQueryDTO + * @return + * @author sr on 2022-05-25 + */ + OrgRelationDTO find(OrgRelationQueryDTO orgRelationQueryDTO); + + void pageOrg(OrgRelationQueryOrgDTO orgRelationQueryOrgDTO); + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/service/OrgService.java b/backend/src/main/java/com/senmesh/usercenter/org/service/OrgService.java new file mode 100644 index 0000000..e921f9c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/service/OrgService.java @@ -0,0 +1,70 @@ +package com.senmesh.usercenter.org.service; + +import java.util.List; +import java.util.Set; + +import javax.validation.Valid; +import javax.validation.groups.Default; + +import org.springframework.validation.annotation.Validated; + +import com.senmesh.usercenter.org.dto.OrgCreateDTO; +import com.senmesh.usercenter.org.dto.OrgDTO; +import com.senmesh.usercenter.org.dto.OrgModifyDTO; +import com.senmesh.usercenter.org.dto.OrgQueryDTO; +import com.senmesh.usercenter.org.dto.UcOpenOrgPartQueryDTO; +import com.senmesh.usercenter.org.dto.UcOrgInfoReqDTO; +import com.senmesh.usercenter.org.dto.UcOrgInfoResDTO; +import com.senmesh.usercenter.org.dto.UcOrgPartInfoDTO; +import com.senmesh.usercenter.org.dto.UcOrgPartQueryDTO; + +@Validated(Default.class) +public interface OrgService { + + Long create(@Valid OrgCreateDTO orgCreateDTO); + + List list(OrgQueryDTO orgQueryDTO); + void page(OrgQueryDTO orgQueryDTO); + OrgDTO find(OrgQueryDTO orgQueryDTO); + + void modify(OrgModifyDTO orgModifyDTO); + + /** + * 获取所有子级机构id+自己 + */ + Set childrenOrgIdList(Long parentId); + + + + /** + * 企业信息 + * + * @param reqDTO 点播dto + * @return {@link UcOrgInfoResDTO} + */ + UcOrgInfoResDTO info(@Valid UcOrgInfoReqDTO reqDTO); + + /** + * 页面 + * + * @param queryDTO 查询dto + * @return {@link UcOrgPartInfoDTO} + */ + List orgPartInfoList(UcOrgPartQueryDTO queryDTO); + + /** + * 找到所有组织 + * + * @return {@link List}<{@link UcOrgProductInfoDTO}> + */ + List findAllOrg(); + + /** + * @description: 开放接口--查询机构部分的信息 + * @return: + * @author: guixinman + * @param: 产品编号 + */ + List openOrgPartInfoList(UcOpenOrgPartQueryDTO queryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/service/impl/ImportDetailOrgExcelListener.java b/backend/src/main/java/com/senmesh/usercenter/org/service/impl/ImportDetailOrgExcelListener.java new file mode 100644 index 0000000..54d7834 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/service/impl/ImportDetailOrgExcelListener.java @@ -0,0 +1,66 @@ +package com.senmesh.usercenter.org.service.impl; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.usercenter.org.dto.ImportDetailOrgListenerDTO; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @description: + * @author: guixinman + * @create: 2024-06-12 15:35 + **/ +public class ImportDetailOrgExcelListener extends AnalysisEventListener { + + private List dtos; + private Map headMap = new HashMap<>(); + + public ImportDetailOrgExcelListener() { + this.dtos = new ArrayList<>(); + } + + + @Override + public void invoke(ImportDetailOrgListenerDTO data, AnalysisContext analysisContext) { + dtos.add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + + } + + @Override + public void invokeHeadMap(Map headMap, AnalysisContext context) { + this.headMap = headMap; + if (headMap.isEmpty()) { + throw new BusinessException("导入模板表头有误"); + } + + if (headMap.size() != 12) { + throw new BusinessException("导入模板表头有误"); + } + Assert.isTrue(headMap.get(0).toString().contains("机构名称"), "导入模板表头有误"); + Assert.isTrue(headMap.get(1).toString().contains("机构类型"), "导入模板表头有误"); + Assert.isTrue(headMap.get(2).toString().contains("招聘岗位类型"), "导入模板表头有误"); + Assert.isTrue(headMap.get(3).toString().contains("管理员姓名"), "导入模板表头有误"); + Assert.isTrue(headMap.get(4).toString().contains("管理员手机号"), "导入模板表头有误"); + Assert.isTrue(headMap.get(5).toString().contains("统一社会信用代码"), "导入模板表头有误"); + Assert.isTrue(headMap.get(6).toString().contains("注册地址"), "导入模板表头有误"); + Assert.isTrue(headMap.get(7).toString().contains("企业规模"), "导入模板表头有误"); + Assert.isTrue(headMap.get(8).toString().contains("所属行业"), "导入模板表头有误"); + Assert.isTrue(headMap.get(9).toString().contains("企业经营地址"), "导入模板表头有误"); + Assert.isTrue(headMap.get(10).toString().contains("机构简介"), "导入模板表头有误"); + Assert.isTrue(headMap.get(11).toString().contains("上级机构"), "导入模板表头有误"); + } + + public List getDtos() { + return dtos; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/service/impl/ImportDetailOrgProvider.java b/backend/src/main/java/com/senmesh/usercenter/org/service/impl/ImportDetailOrgProvider.java new file mode 100644 index 0000000..028547b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/service/impl/ImportDetailOrgProvider.java @@ -0,0 +1,394 @@ +package com.senmesh.usercenter.org.service.impl; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.read.builder.ExcelReaderBuilder; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.senmesh.common.dto.ExportHeadDetailInfoDTO; +import com.senmesh.common.dto.ExportHeadInfoDTO; +import com.senmesh.common.easyexcel.ExcelUtil; +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.component.commonimport.constant.ImportDetailStatusEnum; +import com.senmesh.component.commonimport.constant.ImportStatusEnum; +import com.senmesh.component.commonimport.constant.ImportTypeEnum; +import com.senmesh.component.commonimport.dto.ImportDetailPageDTO; +import com.senmesh.component.commonimport.dto.ImportMainDTO; +import com.senmesh.component.commonimport.dto.ImportMainQueryDTO; +import com.senmesh.component.commonimport.dto.ImportMainUpdateDTO; +import com.senmesh.component.commonimport.service.ImportMainService; +import com.senmesh.component.commonimport.service.impl.AbstractCommonImportProvider; +import com.senmesh.component.dict.util.DictUtils; +import com.senmesh.component.file.entity.FileRecord; +import com.senmesh.component.file.service.FileRecordService; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.org.dao.OrgMapper; +import com.senmesh.usercenter.org.dto.ImportDetailOrgDTO; +import com.senmesh.usercenter.org.dto.ImportDetailOrgExecuteDTO; +import com.senmesh.usercenter.org.dto.ImportDetailOrgExportDTO; +import com.senmesh.usercenter.org.dto.ImportDetailOrgListenerDTO; +import com.senmesh.usercenter.org.dto.ImportDetailOrgOperatorDTO; +import com.senmesh.usercenter.org.dto.ImportDetailOrgPageQueryDTO; +import com.senmesh.usercenter.org.dto.OrgCreateDTO; +import com.senmesh.usercenter.org.entity.Org; +import com.senmesh.usercenter.org.service.ImportDetailOrgService; +import com.senmesh.usercenter.org.service.OrgService; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.InputStream; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + + +import javax.annotation.Resource; + +import lombok.extern.slf4j.Slf4j; + +/** + * @description: + * @author: guixinman + * @create: 2024-06-12 13:45 + **/ +@Service +@Slf4j +public class ImportDetailOrgProvider extends AbstractCommonImportProvider { + + @Autowired + private ImportMainService importMainService; + + @Autowired + private FileRecordService fileRecordService; + + @Autowired + private ImportDetailOrgService importDetailOrgService; + + @Autowired + private OrgService orgService; + + @Resource + private OrgMapper orgMapper; + + + public ImportDetailOrgProvider(ImportMainService imprImportMainService) { + super(imprImportMainService); + } + + @Override + public String getType() { + return ImportTypeEnum.ORG.getType(); + } + + @Override + public Page pageDetail(ImportDetailPageDTO importDetailPageDTO) { + ImportDetailOrgPageQueryDTO queryDTO = new ImportDetailOrgPageQueryDTO(); + BeanUtils.copyProperties(importDetailPageDTO, queryDTO); + queryDTO.setType(null); + importDetailOrgService.page(queryDTO); + return queryDTO.getPageResult(); + } + + @Override + public void importDetailExport(ImportDetailPageDTO importDetailPageDTO) { + ImportDetailOrgPageQueryDTO queryDTO = new ImportDetailOrgPageQueryDTO(); + BeanUtils.copyProperties(importDetailPageDTO, queryDTO); + queryDTO.setType(null); + queryDTO.disablePage(); + List list = importDetailOrgService.page(queryDTO); + + List exportDTOList = list.stream().map(dto -> { + ImportDetailOrgExportDTO exportDTO = JsonUtils.toObject(dto.getDataJson(), ImportDetailOrgExportDTO.class); + exportDTO.setRemark(dto.getRemark()); + exportDTO.setFailReason(dto.getFailReason()); + return exportDTO; + }).collect(Collectors.toList()); + + if (org.springframework.util.CollectionUtils.isEmpty(exportDTOList)) { + return; + } + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); + String commonImportDetailStatus = DictUtils.getCodeNameMap("common_import_detail_status").get(String.valueOf(importDetailPageDTO.getDetailStatus())); + String fileName = "机构导入" + ( StringUtils.isNotBlank(commonImportDetailStatus) ? commonImportDetailStatus : "") + "明细导出" + "(" + formatter.format(LocalDateTime.now()) + ")"; + + ExportHeadInfoDTO infoDTO = ExportHeadInfoDTO.builder() + .fileName(fileName) + .build(); + List heads = infoDTO.getHeads(); + heads.add(ExportHeadDetailInfoDTO.builder().head("机构名称").build()); + heads.add(ExportHeadDetailInfoDTO.builder().head("机构类型").build()); + heads.add(ExportHeadDetailInfoDTO.builder().head("招聘岗位类型").build()); + heads.add(ExportHeadDetailInfoDTO.builder().head("管理员姓名").build()); + heads.add(ExportHeadDetailInfoDTO.builder().head("手机号").build()); + heads.add(ExportHeadDetailInfoDTO.builder().head("统一社会信用代码").build()); + heads.add(ExportHeadDetailInfoDTO.builder().head("注册地址").build()); + heads.add(ExportHeadDetailInfoDTO.builder().head("规模").build()); + heads.add(ExportHeadDetailInfoDTO.builder().head("所属行业").build()); + heads.add(ExportHeadDetailInfoDTO.builder().head("机构描述").build()); + heads.add(ExportHeadDetailInfoDTO.builder().head("任务地点全称").build()); + heads.add(ExportHeadDetailInfoDTO.builder().head("上级机构名称").build()); + heads.add(ExportHeadDetailInfoDTO.builder().head("失败原因").build()); + heads.add(ExportHeadDetailInfoDTO.builder().head("备注").build()); + + List datas = Lists.newArrayList(); + for (ImportDetailOrgExportDTO dto : exportDTOList) { + List objects = Lists.newArrayList(); + datas.add(objects); + objects.add(dto.getOrgName()); + objects.add(dto.getType()); + objects.add(dto.getRecruitPositionType()); + objects.add(dto.getRealName()); + objects.add(dto.getPhone()); + objects.add(dto.getCreditCode()); + objects.add(dto.getRegisteredAddress()); + objects.add(dto.getCompanySize()); + objects.add(dto.getTrade()); + objects.add(dto.getDescription()); + objects.add(dto.getAddressName()); + objects.add(dto.getParentOrgName()); + objects.add(dto.getFailReason()); + objects.add(dto.getRemark()); + + } + infoDTO.setDatas(datas); + + ExcelUtil.dynamicExportTemplate(infoDTO); + + } + + @Override + public List analy(Long mainId) { + // 解析文件+明细 + ImportMainDTO importMainDTO = importMainService.find(ImportMainQueryDTO.builder().id(mainId).build()); + Assert.notNull(importMainDTO, "未查询到导入的数据"); + FileRecord fileRecord; + try { + fileRecord = fileRecordService.find(FileRecord.builder().fileCode(importMainDTO.getFileCode()).build()); + } catch (Exception e) { + log.info("导入文件异常,", e); + fileRecord = null; + } + Assert.notNull(fileRecord, "上传文件不存在"); + + try (InputStream is = fileRecordService.getFile(importMainDTO.getFileCode())) { + ImportDetailOrgExcelListener listener = new ImportDetailOrgExcelListener(); + ExcelReaderBuilder reader = EasyExcel.read(is, ImportDetailOrgListenerDTO.class, listener); + reader.sheet().doRead(); + List dtos = listener.getDtos(); + Assert.isTrue(!dtos.isEmpty(), "导入文件无有效数据"); + return dtos; + } catch (Exception e) { + throw new BusinessException(e.getMessage()); + } + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void checkAndSave(Long mainId, List detailCreateDtos) { + //更改状态为校验中 + ImportMainUpdateDTO updateDto = ImportMainUpdateDTO.builder().id(mainId) + .oldStatusSet(Sets.newHashSet(ImportStatusEnum.INIT.getStatus())) + .newStatus(ImportStatusEnum.CHECKING.getStatus()) + .build(); + importMainService.modify(updateDto); + + List importDetailOrgDTOS = new ArrayList<>(); + for (ImportDetailOrgListenerDTO detailCreateDto : detailCreateDtos) { + ImportDetailOrgDTO importDetailOrgDTO = new ImportDetailOrgDTO(); + + this.checkAndFill(importDetailOrgDTO, detailCreateDto); + + if (StringUtils.isNotBlank(importDetailOrgDTO.getFailReason())) { + importDetailOrgDTO.setDetailStatus(ImportDetailStatusEnum.CHECK_FAIL.getStatus()); + } else { + importDetailOrgDTO.setDetailStatus(ImportDetailStatusEnum.CHECK_SUCCESS.getStatus()); + } + importDetailOrgDTO.setMainId(mainId); + importDetailOrgDTO.setOrgId(UserContextHolder.getExistLoginOrgId()); + importDetailOrgDTOS.add(importDetailOrgDTO); + } + + importDetailOrgService.batchCreate(importDetailOrgDTOS); + super.finishCheck(mainId, importDetailOrgDTOS); + } + + private void checkAndFill(ImportDetailOrgDTO importDetailOrgDTO, ImportDetailOrgListenerDTO importDetailOrgListenerDTO) { + BeanUtils.copyProperties(importDetailOrgListenerDTO, importDetailOrgDTO); + importDetailOrgDTO.setDataJson(JsonUtils.toJsonString(importDetailOrgListenerDTO)); + + if (StringUtils.isBlank(importDetailOrgDTO.getOrgName())) { + importDetailOrgDTO.appendFailMsg("机构名称不能为空"); + } else { + if (importDetailOrgDTO.getOrgName().length() > 32) { + importDetailOrgDTO.appendFailMsg("机构名称超过最大限制长度"); + importDetailOrgDTO.setOrgName(null); + } else { + Org org = orgMapper.selectOne(new LambdaQueryWrapper().eq(Org::getDeleted, false).eq(Org::getOrgName, importDetailOrgDTO.getOrgName())); + if (Objects.nonNull(org)) { + importDetailOrgDTO.appendFailMsg("机构已存在"); + } + } + + } + + if (StringUtils.isBlank(importDetailOrgDTO.getType())) { + importDetailOrgDTO.appendFailMsg("机构类型不能为空"); + } else { + String orgType = DictUtils.getNameCodeMap("org_type").get(importDetailOrgDTO.getType()); + if (StringUtils.isBlank(orgType)) { + importDetailOrgDTO.appendFailMsg("机构类型未匹配到"); + importDetailOrgDTO.setType(null); + }else { + importDetailOrgDTO.setType(orgType); + } + } + + if (StringUtils.isBlank(importDetailOrgDTO.getRecruitPositionType())) { + importDetailOrgDTO.appendFailMsg("招聘岗位类型不能为空"); + } else { + String recruitPositionType = DictUtils.getNameCodeMap("recruit_position_type").get(importDetailOrgDTO.getRecruitPositionType()); + if (StringUtils.isBlank(recruitPositionType)) { + importDetailOrgDTO.appendFailMsg("招聘岗位类型未匹配到"); + importDetailOrgDTO.setRecruitPositionType(null); + }else { + importDetailOrgDTO.setRecruitPositionType(recruitPositionType); + } + + } + + if (StringUtils.isBlank(importDetailOrgDTO.getRealName())) { + importDetailOrgDTO.appendFailMsg("管理员姓名不能为空"); + } else if (importDetailOrgDTO.getRealName().length() > 32) { + importDetailOrgDTO.appendFailMsg("管理员姓名超过最大限制长度"); + importDetailOrgDTO.setRealName(null); + } + + if (StringUtils.isBlank(importDetailOrgDTO.getPhone())) { + importDetailOrgDTO.appendFailMsg("管理员手机号不能为空"); + } else if (importDetailOrgDTO.getPhone().length() > 32) { + importDetailOrgDTO.appendFailMsg("管理员手机号超过最大限制长度"); + importDetailOrgDTO.setPhone(null); + } + + if (StringUtils.isBlank(importDetailOrgDTO.getCreditCode())) { + importDetailOrgDTO.appendFailMsg("统一社会信用代码不能为空"); + } else if (importDetailOrgDTO.getCreditCode().length() > 64) { + importDetailOrgDTO.appendFailMsg("统一社会信用代码超过最大限制长度"); + importDetailOrgDTO.setCreditCode(null); + } + + if (StringUtils.isBlank(importDetailOrgDTO.getRegisteredAddress())) { + importDetailOrgDTO.appendFailMsg("注册地址不能为空"); + } else if (importDetailOrgDTO.getRegisteredAddress().length() > 128) { + importDetailOrgDTO.appendFailMsg("注册地址超过最大限制长度"); + importDetailOrgDTO.setRegisteredAddress(null); + } + + if (StringUtils.isBlank(importDetailOrgDTO.getCompanySize())) { + importDetailOrgDTO.appendFailMsg("企业规模不能为空"); + } else { + String companySize = DictUtils.getNameCodeMap("company_size").get(importDetailOrgDTO.getCompanySize()); + if (StringUtils.isBlank(companySize)) { + importDetailOrgDTO.appendFailMsg("企业规模未匹配到"); + importDetailOrgDTO.setCompanySize(null); + }else { + importDetailOrgDTO.setCompanySize(companySize); + } + } + + if (StringUtils.isNotBlank(importDetailOrgDTO.getTrade())) { + String industryType = DictUtils.getNameCodeMap("industry_type").get(importDetailOrgDTO.getTrade()); + if (StringUtils.isBlank(industryType)) { + importDetailOrgDTO.appendFailMsg("所属行业未匹配到"); + importDetailOrgDTO.setTrade(null); + }else { + importDetailOrgDTO.setTrade(industryType); + } + } + + if (StringUtils.isBlank(importDetailOrgDTO.getAddressName())) { + importDetailOrgDTO.appendFailMsg("企业所在地不能为空"); + } else if (importDetailOrgDTO.getAddressName().length() > 128) { + importDetailOrgDTO.appendFailMsg("企业所在地超过最大限制长度"); + importDetailOrgDTO.setAddressName(null); + } + + if (StringUtils.isNotBlank(importDetailOrgDTO.getDescription())) { + if (importDetailOrgDTO.getDescription().length() > 1024) { + importDetailOrgDTO.appendFailMsg("机构简介超过最大限制长度"); + importDetailOrgDTO.setDescription(null); + } + } + + if (StringUtils.isNotBlank(importDetailOrgDTO.getParentOrgName())) { + if (importDetailOrgDTO.getParentOrgName().length() > 32) { + importDetailOrgDTO.appendFailMsg("上级机构超过最大限制长度"); + importDetailOrgDTO.setParentOrgName(null); + }else { + Org org = orgMapper.selectOne(new LambdaQueryWrapper().eq(Org::getDeleted, false).eq(Org::getOrgName, importDetailOrgDTO.getParentOrgName())); + if (Objects.isNull(org)) { + importDetailOrgDTO.appendFailMsg("上级机构未匹配到"); + importDetailOrgDTO.setParentOrgName(null); + } + } + } + } + + @Transactional(rollbackFor = Exception.class) + @Override + public Long execute(ImportDetailOrgExecuteDTO executeDto) { + Long mainId = executeDto.getMainId(); + Assert.notNull(mainId, "参数异常"); + + ImportMainDTO importMainDTO = importMainService.find(ImportMainQueryDTO.builder().id(mainId).build()); + Assert.notNull(importMainDTO, "未查询到导入数据"); + ImportDetailOrgPageQueryDTO queryDTO = new ImportDetailOrgPageQueryDTO(); + queryDTO.disablePage(); + queryDTO.setMainId(mainId); + queryDTO.setDetailStatus(ImportDetailStatusEnum.CHECK_SUCCESS.getStatus()); + List importDetailOrgDTOS = importDetailOrgService.page(queryDTO); + + if (CollectionUtils.isEmpty(importDetailOrgDTOS)) { + throw new BusinessException("未查询到成功的明细数据"); + } + + for (ImportDetailOrgDTO importDetailOrgDTO : importDetailOrgDTOS) { + + OrgCreateDTO orgCreateDTO = new OrgCreateDTO(); + BeanUtils.copyProperties(importDetailOrgDTO, orgCreateDTO); + + orgCreateDTO.setAddressCode("31"); + + //文本填写上级机构名称,不填则上级机构为当前导入机构,填则根据填写的名称匹配系统机构,匹配不上做失败记录处理。 + if (StringUtils.isBlank(importDetailOrgDTO.getParentOrgName())) { + orgCreateDTO.setParentId(UserContextHolder.getExistLoginOrgId()); + }else { + Org org = orgMapper.selectOne(new LambdaQueryWrapper().eq(Org::getDeleted, false).eq(Org::getOrgName, importDetailOrgDTO.getParentOrgName())); + if (Objects.nonNull(org)) { + orgCreateDTO.setParentId(org.getId()); + } + } + + Long orgId = orgService.create(orgCreateDTO); + + ImportDetailOrgOperatorDTO importDetailOrgOperatorDTO = new ImportDetailOrgOperatorDTO(); + BeanUtils.copyProperties(importDetailOrgDTO, importDetailOrgOperatorDTO); + importDetailOrgOperatorDTO.setExtraDetailId(orgId); + importDetailOrgService.modify(importDetailOrgOperatorDTO); + } + + return null; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/service/impl/ImportDetailOrgServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/org/service/impl/ImportDetailOrgServiceImpl.java new file mode 100644 index 0000000..bbf6eff --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/service/impl/ImportDetailOrgServiceImpl.java @@ -0,0 +1,100 @@ +package com.senmesh.usercenter.org.service.impl; + +import lombok.extern.slf4j.Slf4j; + +import com.senmesh.usercenter.org.entity.ImportDetailOrg; +import com.senmesh.usercenter.org.dto.*; +import com.senmesh.usercenter.org.dao.ImportDetailOrgMapper; +import com.senmesh.usercenter.org.mapstruct.ImportDetailOrgConvert; +import com.senmesh.usercenter.org.service.ImportDetailOrgService; + +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.common.util.UserContextHolder; + +import javax.annotation.Resource; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 机构导入表 + * + * @author guixinman + * @since 1.0.0 2024-06-12 + */ +@Slf4j +@Service +public class ImportDetailOrgServiceImpl implements ImportDetailOrgService { + + @Resource + private ImportDetailOrgMapper importDetailOrgMapper; + + @Override + public ImportDetailOrgDTO create(ImportDetailOrgOperatorDTO operatorDto) { + ImportDetailOrg importDetailOrg = ImportDetailOrgConvert.INSTANCE.convert(operatorDto); + importDetailOrgMapper.saveEntity(importDetailOrg); + return ImportDetailOrgConvert.INSTANCE.convert(importDetailOrg); + } + + @Override + public ImportDetailOrgDTO modify(ImportDetailOrgOperatorDTO operatorDto) { + ImportDetailOrgDTO importDetailOrgDto = this.findById(operatorDto.getId()); + if (Objects.isNull(importDetailOrgDto)) { + return null; + } + ImportDetailOrg importDetailOrg = ImportDetailOrgConvert.INSTANCE.convert(operatorDto); + importDetailOrgMapper.updateEntitySelective(importDetailOrg); + return this.findById(operatorDto.getId()); + } + + @Override + public ImportDetailOrgDTO delete(Long id) { + ImportDetailOrgDTO importDetailOrgDto = this.findById(id); + if (Objects.isNull(importDetailOrgDto)) { + return null; + } + ImportDetailOrg importDetailOrg = ImportDetailOrg.builder().build(); + importDetailOrg.setId(id); + importDetailOrgMapper.deleteEntity(importDetailOrg, UserContextHolder.getLoginUserId()); + return importDetailOrgDto; + } + + @Override + public ImportDetailOrgDTO findById(Long id) { + ImportDetailOrg importDetailOrg = importDetailOrgMapper.getById(id); + if (Objects.isNull(importDetailOrg)) { + return null; + } + return ImportDetailOrgConvert.INSTANCE.convert(importDetailOrg); + } + + @Override + public List list(ImportDetailOrgQueryDTO queryDTO) { + return importDetailOrgMapper.list(queryDTO); + } + + @Override + public List page(ImportDetailOrgPageQueryDTO queryDTO) { + return importDetailOrgMapper.page(queryDTO); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void batchCreate(List importDetailOrgDTOS) { + if (CollectionUtils.isEmpty(importDetailOrgDTOS)) { + return; + } + + List importDetailOrgs= importDetailOrgDTOS.stream().map(dto -> { + ImportDetailOrg importDetailOrg = new ImportDetailOrg(); + BeanUtils.copyProperties(dto, importDetailOrg); + return importDetailOrg; + }).collect(Collectors.toList()); + + importDetailOrgMapper.saveEntites(importDetailOrgs); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/org/service/impl/OrgRelationServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/org/service/impl/OrgRelationServiceImpl.java new file mode 100644 index 0000000..ca11151 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/service/impl/OrgRelationServiceImpl.java @@ -0,0 +1,100 @@ +package com.senmesh.usercenter.org.service.impl; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.usercenter.constants.OrgConstants; +import com.senmesh.usercenter.org.dao.OrgRelationMapper; +import com.senmesh.usercenter.org.service.OrgRelationService; +import com.senmesh.usercenter.org.dto.OrgRelationQueryDTO; +import com.senmesh.usercenter.org.dto.OrgRelationQueryOrgDTO; +import com.senmesh.usercenter.org.dto.OrgRelationCreateDTO; +import com.senmesh.usercenter.org.dto.OrgRelationDTO; +import com.senmesh.usercenter.org.dto.OrgRelationModifyDTO; +import com.senmesh.usercenter.org.entity.OrgRelation; +import com.senmesh.usercenter.org.mapstruct.OrgRelationMapMapper; +import com.senmesh.frame.redis.dto.LockDTO; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.ListUtil; + +/** + * @author sr on 2022-05-25 + */ +@Service +public class OrgRelationServiceImpl implements OrgRelationService { + + @Autowired + private OrgRelationMapper orgRelationMapper; + + + public static LockDTO getLockDTO(Long orgId) { + Assert.notNull(orgId, "机构id不能为空"); + return LockDTO.builder().methodName("orgrelation").tryLockWaitTime(0L) + .arg(orgId.toString()) + .failMsg("该机构关系正在被操作") + .build(); + } + + @Override + @Transactional + public Long create(OrgRelationCreateDTO orgRelationCreateDTO) { + Long orgId = orgRelationCreateDTO.getOrgId(); + Integer platformCode = orgRelationCreateDTO.getPlatformCode(); + OrgRelationDTO existDto = this.find(OrgRelationQueryDTO.builder().orgId(orgId).platformCode(platformCode).build()); + if (existDto != null) { + return existDto.getId(); + } + Long parentId = orgRelationCreateDTO.getParentId(); + if (parentId == null) { + parentId = OrgConstants.PLATFORM_ORG_ID; + orgRelationCreateDTO.setParentId(parentId); + } + OrgRelation orgRelation = OrgRelationMapMapper.INSTANCE.toEntity(orgRelationCreateDTO); + OrgRelationDTO parentOrgRelation = this.find(OrgRelationQueryDTO.builder().orgId(parentId) + .platformCode(platformCode).build()); + Assert.notNull(parentOrgRelation, "上级机构信息有误"); + String path = String.join(CommonConstants.COMMA, parentOrgRelation.getPath(), + orgRelationCreateDTO.getOrgId().toString()); + orgRelation.setPath(path); + orgRelationMapper.saveEntity(orgRelation); + return orgRelation.getId(); + } + + @Override + @Transactional + public void modify(OrgRelationModifyDTO orgRelationModifyDTO) { + Long id = orgRelationModifyDTO.getId(); + OrgRelation existOrgRelation = orgRelationMapper.getById(id); + Assert.notNull(existOrgRelation, "机构关系不存在"); + List children = this + .list(OrgRelationQueryDTO.builder().id(id).upOrgId(existOrgRelation.getOrgId()).build()); + Assert.isTrue(children.isEmpty(), "存在下级机构,不支持修改"); + orgRelationMapper.updateEntitySelective(OrgRelationMapMapper.INSTANCE.to(orgRelationModifyDTO)); + } + + @Override + public List list(OrgRelationQueryDTO orgRelationQueryDTO) { + orgRelationQueryDTO.disablePage(); + return orgRelationMapper.listOrgRelationDTO(orgRelationQueryDTO); + } + + @Override + public void page(OrgRelationQueryDTO orgRelationQueryDTO) { + orgRelationMapper.listOrgRelationDTO(orgRelationQueryDTO); + } + + @Override + public OrgRelationDTO find(OrgRelationQueryDTO orgRelationQueryDTO) { + List orgRelationDTOs = this.list(orgRelationQueryDTO); + return ListUtil.first(orgRelationDTOs); + } + + @Override + public void pageOrg(OrgRelationQueryOrgDTO orgRelationQueryOrgDTO) { + orgRelationMapper.listOrg(orgRelationQueryOrgDTO); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/org/service/impl/OrgServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/org/service/impl/OrgServiceImpl.java new file mode 100644 index 0000000..2b314aa --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/org/service/impl/OrgServiceImpl.java @@ -0,0 +1,200 @@ +package com.senmesh.usercenter.org.service.impl; + +import java.util.*; +import java.util.stream.Collectors; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.codegenerator.util.CodeUtils; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.common.util.ListUtil; +import com.senmesh.common.util.TreeHelper; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.frame.redis.dto.LockDTO; +import com.senmesh.frame.redis.redisson.RedissonUtils; +import com.senmesh.usercenter.common.constant.CodeTypeEnum; +import com.senmesh.usercenter.enums.OrgTypeEnum; +import com.senmesh.usercenter.org.dao.OrgMapper; +import com.senmesh.usercenter.org.dto.OrgCreateDTO; +import com.senmesh.usercenter.org.dto.OrgDTO; +import com.senmesh.usercenter.org.dto.OrgModifyDTO; +import com.senmesh.usercenter.org.dto.OrgQueryDTO; +import com.senmesh.usercenter.org.dto.OrgRelationCreateDTO; +import com.senmesh.usercenter.org.dto.UcOpenOrgPartQueryDTO; +import com.senmesh.usercenter.org.dto.UcOrgInfoReqDTO; +import com.senmesh.usercenter.org.dto.UcOrgInfoResDTO; +import com.senmesh.usercenter.org.dto.UcOrgPartInfoDTO; +import com.senmesh.usercenter.org.dto.UcOrgPartQueryDTO; +import com.senmesh.usercenter.org.entity.Org; +import com.senmesh.usercenter.org.mapstruct.OrgMapMapper; +import com.senmesh.usercenter.org.service.OrgRelationService; +import com.senmesh.usercenter.org.service.OrgService; +import com.senmesh.usercenter.permissionpackage.service.UcPermissionOrganizationService; +import com.senmesh.usercenter.user.dto.OrgUserCreateDTO; +import com.senmesh.usercenter.user.service.UserService; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class OrgServiceImpl implements OrgService { + + @Autowired + private OrgMapper orgMapper; + + @Autowired + private UcPermissionOrganizationService permissionOrganizationService; + + @Autowired + private UserService userService; + + @Autowired + private OrgRelationService orgRelationService; + + + public static LockDTO getLockDTO(String orgName) { + Assert.notNull(orgName, "机构名称不能为空"); + return LockDTO.builder().methodName("org").tryLockWaitTime(0L) + .arg(orgName) + .failMsg("该机构正在被操作") + .build(); + } + + private void initCreateOrg(Org org) { + org.setOrgCode(CodeUtils.getCode(CodeTypeEnum.ORG.getCodeParam())); + org.setEnable(Boolean.TRUE); + org.setActivated(Boolean.FALSE); + + } + + @Override + @Transactional + public Long create(OrgCreateDTO orgCreateDTO) { + OrgTypeEnum orgTypeEnum = OrgTypeEnum.findByType(orgCreateDTO.getType()); + Assert.notNull(orgTypeEnum, "机构类型有误"); + Assert.isTrue(orgTypeEnum != OrgTypeEnum.ORG_TYPE_PLATFORM, "该机构类型不支持创建"); + String orgName = orgCreateDTO.getOrgName(); + OrgDTO orgDTO = RedissonUtils.lockAndSave(getLockDTO(orgName), + () -> this.find(OrgQueryDTO.builder().orgName(orgName).build()), () -> { + Org org = + OrgMapMapper.INSTANCE.toEntity(orgCreateDTO); + initCreateOrg(org); + orgMapper.saveEntity(org); + return OrgMapMapper.INSTANCE.toDto(org); + }, "该机构名称已存在"); + Long orgId = orgDTO.getId(); + // 创建管理员用户 + userService.createOrgUser(OrgUserCreateDTO.builder().orgId(orgId).phone(orgCreateDTO.getPhone()).realName(orgCreateDTO.getRealName()) + .administrator(Boolean.TRUE).build()); + + Integer orgType = Integer.valueOf(orgCreateDTO.getType()); + // 分配权限包 +// permissionOrganizationService.saveOrgByType(orgId, orgType); + // orgrelation上下级 + orgRelationService.create(OrgRelationCreateDTO.builder().orgId(orgId).orgType(orgType) + .platformCode(EnvironmentUtils.getSystemCode()).parentId(orgCreateDTO.getParentId()).build()); + + return orgId; + } + + @Override + public List list(OrgQueryDTO orgQueryDTO) { + orgQueryDTO.disablePage(); + return orgMapper.listOrgDTO(orgQueryDTO); + } + + @Override + public void page(OrgQueryDTO orgQueryDTO) { + //小程序有匿名的需要调用。不做权限 + if (Objects.nonNull(UserContextHolder.getLoginOrgId())) { + if (!CommonConstants.PLATFORM_ORG_ID.equals(UserContextHolder.getLoginOrgId())) { + //指定了id就查指定的id + if (Objects.isNull(orgQueryDTO.getId())) { + orgQueryDTO.setOrgIds(this.childrenOrgIdList(UserContextHolder.getLoginOrgId())); + } + } + } + orgMapper.listOrgDTO(orgQueryDTO); + } + + @Override + public OrgDTO find(OrgQueryDTO orgQueryDTO) { + return ListUtil.first(this.list(orgQueryDTO)); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void modify(OrgModifyDTO orgModifyDTO) { + orgMapper.modifyByOrgId(orgModifyDTO); + + + } + + @Override + public Set childrenOrgIdList(Long parentId) { + OrgQueryDTO orgQueryDTO = new OrgQueryDTO(); + List list = this.list(orgQueryDTO); + Set orgIds = TreeHelper.childrenNodeIds(parentId, list); + orgIds.add(parentId); + return orgIds; + } + + // ***********************************分隔符*********************************************** + + @Override + public UcOrgInfoResDTO info(UcOrgInfoReqDTO reqDTO) { + return orgMapper.info(reqDTO); + } + + + @Override + public List orgPartInfoList(UcOrgPartQueryDTO queryDTO) { + return orgMapper.orgPartInfoList(queryDTO); + } + + @Override + public List findAllOrg() { + return orgMapper.findAllOrg(); + } + + @Override + public List openOrgPartInfoList(UcOpenOrgPartQueryDTO queryDTO) { + //sql不分组,代码分组 + List ucOrgPartInfoDTOS = orgMapper.openOrgPartInfoList(queryDTO); + + if (CollectionUtils.isNotEmpty(ucOrgPartInfoDTOS)) { + LinkedHashMap> ucOrgPartInfoDTOMap = + ucOrgPartInfoDTOS.stream().collect(Collectors.groupingBy(UcOrgPartInfoDTO::getOrgId, + LinkedHashMap::new, Collectors.toList())); + List ucOrgPartInfoList = new ArrayList<>(); + + for (Long orgId : ucOrgPartInfoDTOMap.keySet()) { + List dtos = ucOrgPartInfoDTOMap.get(orgId); + + UcOrgPartInfoDTO ucOrgPartInfoDTO = new UcOrgPartInfoDTO(); + ucOrgPartInfoDTO.setOrgId(orgId); + ucOrgPartInfoDTO.setOrgName(dtos.get(0).getOrgName()); + ucOrgPartInfoDTO.setBankAccount(dtos.get(0).getBankAccount()); + ucOrgPartInfoDTO.setBankName(dtos.get(0).getBankName()); + ucOrgPartInfoDTO.setPhone(dtos.get(0).getPhone()); + List categoryNames = + dtos.stream().filter(map -> StringUtils.isNotBlank(map.getCategoryName())) + .map(dto -> dto.getCategoryName()).collect(Collectors.toList()); + ucOrgPartInfoDTO.setCategoryNames(categoryNames); + ucOrgPartInfoList.add(ucOrgPartInfoDTO); + } + return ucOrgPartInfoList; + } + + return ucOrgPartInfoDTOS; + } + + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/constants/PermissionPackageConstants.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/constants/PermissionPackageConstants.java new file mode 100644 index 0000000..82a9a87 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/constants/PermissionPackageConstants.java @@ -0,0 +1,22 @@ +package com.senmesh.usercenter.permissionpackage.constants; + +/** + * @author : yzq + * create at: 2020/9/14 17:47 + * @description: 权限包常量类 + */ +public class PermissionPackageConstants { + + /** + * 权限包状态:1.有效 2.无效 + **/ + + public static final Integer PERMISSION_PACKAGE_STATUS_NOT_INVALID = 1; + + /** + * 权限包状态:1.有效 2.无效 + **/ + + public static final Integer PERMISSION_PACKAGE_STATUS_INVALID = 2; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/controller/UcPermissionPackageController.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/controller/UcPermissionPackageController.java new file mode 100644 index 0000000..732e4da --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/controller/UcPermissionPackageController.java @@ -0,0 +1,179 @@ +package com.senmesh.usercenter.permissionpackage.controller; + +import java.util.List; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +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.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.validation.Check; +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.cache.SecurityCacheUtils; +import com.senmesh.usercenter.permissionpackage.dto.PackageResourcesDTO; +import com.senmesh.usercenter.permissionpackage.dto.PackageResourcesOperateDTO; +import com.senmesh.usercenter.permissionpackage.dto.PackageResourcesPageQueryDTO; +import com.senmesh.usercenter.permissionpackage.dto.PermissionOrganizeDTO; +import com.senmesh.usercenter.permissionpackage.dto.PermissionOrganizePageQueryDTO; +import com.senmesh.usercenter.permissionpackage.dto.PermissionPackageDTO; +import com.senmesh.usercenter.permissionpackage.dto.PermissionPackageOperateDTO; +import com.senmesh.usercenter.permissionpackage.dto.PermissionPackagePageQueryDTO; +import com.senmesh.usercenter.permissionpackage.service.UcPermissionOrganizationService; +import com.senmesh.usercenter.permissionpackage.service.UcPermissionPackageService; +import com.senmesh.usercenter.permissionpackage.service.UcPermissionResourceService; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; + +/** + * 权限包操作 + * + * @author yzq + */ +@Api(tags = "权限包操作") +@RestController +@RequestMapping("/permission_package") +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class UcPermissionPackageController { + + private final UcPermissionPackageService ucPermissionPackageService; + + private final UcPermissionResourceService ucPermissionResourceService; + + private final UcPermissionOrganizationService ucPermissionOrganizationService; + + @ApiOperation("创建权限包") + @PostMapping("/create") + public AlitaResult createPermissionPackage(@Validated(Create.class) + @RequestBody PermissionPackageDTO permissionPackageDTO) { + ucPermissionPackageService.createPermissionPackage(permissionPackageDTO); + SecurityCacheUtils.flushAll(); + return AlitaResult.success(permissionPackageDTO); + } + + @ApiOperation("修改权限包") + @PostMapping("/update") + public AlitaResult updatePermissionPackage( + @Validated(Update.class) @RequestBody PermissionPackageDTO permissionPackageDTO) { + ucPermissionPackageService.updatePermissionPackage(permissionPackageDTO); + SecurityCacheUtils.flushAll(); + return AlitaResult.success(permissionPackageDTO); + } + + @ApiOperation("删除权限包") + @DeleteMapping("/delete/{id}") + public AlitaResult deletePermissionPackageDTO(@PathVariable("id") Long id) { + ucPermissionPackageService.removePermissionPackage(id); + SecurityCacheUtils.flushAll(); + return AlitaResult.success(Boolean.TRUE); + } + + @ApiOperation("查询权限包列表") + @GetMapping("/list") + public AlitaResult> PermissionPackageList( + @Validated PermissionPackagePageQueryDTO permissionPackagePageQueryDTO) { + return AlitaResult + .success(ucPermissionPackageService.list(permissionPackagePageQueryDTO)); + } + + @ApiOperation("查询权限包分页列表") + @GetMapping("/page") + public AlitaResult> pagePermissionPackageList( + @Validated PermissionPackagePageQueryDTO permissionPackagePageQueryDTO) { + ucPermissionPackageService.page(permissionPackagePageQueryDTO); + return AlitaResult.success(permissionPackagePageQueryDTO.getPageResult()); + } + + @ApiOperation("查询权限包下的菜单资源") + @GetMapping("/url_list") + public AlitaResult urlList( + @RequestParam(name = "permissionPackageId", required = + true) Long permissionPackageId, @RequestParam(name = "platformCode", required = + true) Integer platformCode) { + return AlitaResult + .success(ucPermissionResourceService.urlList(permissionPackageId, platformCode)); + } + + @ApiOperation("保存权限包下的菜单资源分配") + @PostMapping("/update_url_list") + public AlitaResult updateUrlList( + @Validated(Update.class) @RequestBody + PermissionPackageOperateDTO permissionPackageOperateDTO) { + ucPermissionResourceService.updateUrlList(permissionPackageOperateDTO); + ucPermissionResourceService.cleanUrlCompentAndInterface(permissionPackageOperateDTO.getPermissionPackageId()); + SecurityCacheUtils.flushAll(); + return AlitaResult.success(permissionPackageOperateDTO); + } + + @ApiOperation("查询对应菜单下组件/接口列表") + @GetMapping("/url_component_list") + public AlitaResult> urlComponentList( + @Validated(Check.class) + PackageResourcesPageQueryDTO packageResourcesPageQueryDTO) { + ucPermissionResourceService.urlComponentList(packageResourcesPageQueryDTO); + return AlitaResult.success(packageResourcesPageQueryDTO.getPageResult()); + } + + @ApiOperation("保存对应菜单下组件/接口列表") + @PostMapping("/save_url_component_list") + public AlitaResult> saveUrlResourcesOperateDTO( + @Validated(Create.class) @RequestBody PackageResourcesDTO packageResourcesDTO) { + ucPermissionResourceService.saveUrlComponentList(packageResourcesDTO); + SecurityCacheUtils.flushAll(); + return AlitaResult.success(packageResourcesDTO.getPackageResourcesOperateDTOList()); + } + + @ApiOperation("查询对应权限包下可分配的机构信息") + @GetMapping("/can_be_allocated_org_list") + public AlitaResult> canBeAllocatedOrgList( + @Validated PermissionOrganizePageQueryDTO permissionOrganizePageQueryDTO) { + ucPermissionOrganizationService.canBeAllocatedOrgList(permissionOrganizePageQueryDTO); + return AlitaResult.success(permissionOrganizePageQueryDTO.getPageResult()); + } + + @ApiOperation("查询对应权限包下已分配的机构信息") + @GetMapping("/allocated_org_list") + public AlitaResult> allocatedOrgList( + @Validated PermissionOrganizePageQueryDTO permissionOrganizePageQueryDTO) { + ucPermissionOrganizationService.allocatedOrgList(permissionOrganizePageQueryDTO); + return AlitaResult.success(permissionOrganizePageQueryDTO.getPageResult()); + } + + @ApiOperation("新增机构分配信息") + @PostMapping("/save_org_list") + public AlitaResult saveOrgList( + @Validated(Create.class) @RequestBody List permissionOrganizeDTOList) { + ucPermissionOrganizationService.saveOrgList(permissionOrganizeDTOList); + return AlitaResult.success(); + } + + @ApiOperation("删除机构分配信息") + @DeleteMapping("/remove_allocated_org/{id}") + public AlitaResult removeAllocatedOrg(@PathVariable("id") Long id) { + ucPermissionOrganizationService.removeAllocatedOrg(id); + SecurityCacheUtils.flushAll(); + return AlitaResult.success(Boolean.TRUE); + } + + @ApiOperation("删除机构分配信息列表") + @PostMapping("/remove_allocated_org_list") + public AlitaResult removeAllocatedOrgList(@RequestBody + Set permissionOrganizeId) { + ucPermissionOrganizationService.removeAllocatedOrgList(permissionOrganizeId); + SecurityCacheUtils.flushAll(); + return AlitaResult.success(Boolean.TRUE); + } + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dao/PermissionPackageMapper.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dao/PermissionPackageMapper.java new file mode 100644 index 0000000..29c882c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dao/PermissionPackageMapper.java @@ -0,0 +1,18 @@ +package com.senmesh.usercenter.permissionpackage.dao; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.permissionpackage.dto.PermissionPackageDTO; +import com.senmesh.usercenter.permissionpackage.dto.PermissionPackagePageQueryDTO; +import com.senmesh.usercenter.permissionpackage.entity.PermissionPackage; +import java.util.List; +import org.apache.ibatis.annotations.Param; + +/** + * @author : yzq create at: 2020/9/7 17:35 + * @description: 权限包 + */ +public interface PermissionPackageMapper extends MyMapper { + + List listPermissionPackage( + @Param("param") PermissionPackagePageQueryDTO permissionPackagePageQueryDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dao/PermissionPackageOrgMapper.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dao/PermissionPackageOrgMapper.java new file mode 100644 index 0000000..bc45358 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dao/PermissionPackageOrgMapper.java @@ -0,0 +1,21 @@ +package com.senmesh.usercenter.permissionpackage.dao; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.permissionpackage.dto.PermissionOrganizeDTO; +import com.senmesh.usercenter.permissionpackage.dto.PermissionOrganizePageQueryDTO; +import com.senmesh.usercenter.permissionpackage.entity.PermissionOrganization; +import java.util.List; +import org.apache.ibatis.annotations.Param; + +/** + * @author : yzq create at: 2020/9/7 17:35 + * @description: 权限包机构关系 + */ +public interface PermissionPackageOrgMapper extends MyMapper { + + List canBeAllocatedOrgList( + @Param("param") PermissionOrganizePageQueryDTO permissionOrganizePageQueryDTO); + + List allocatedOrgList( + @Param("param") PermissionOrganizePageQueryDTO permissionOrganizePageQueryDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dao/PermissionResourceMapper.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dao/PermissionResourceMapper.java new file mode 100644 index 0000000..f141428 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dao/PermissionResourceMapper.java @@ -0,0 +1,41 @@ +package com.senmesh.usercenter.permissionpackage.dao; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.permissionpackage.dto.PackageResourcesOperateDTO; +import com.senmesh.usercenter.permissionpackage.dto.PackageResourcesPageQueryDTO; +import com.senmesh.usercenter.permissionpackage.entity.PermissionResources; +import com.senmesh.usercenter.resource.dto.UrlDTO; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Set; + +/** + * @author : yzq create at: 2020/9/7 17:35 + * @description: 权限包 + */ +public interface PermissionResourceMapper extends MyMapper { + + /** + * 查询已经选择的菜单 + * + * @return + */ + List findSelectdUrl(@Param("permissionPackageId") Long permissionPackageId); + + + List urlComponentList( + @Param("param") PackageResourcesPageQueryDTO packageResourcesPageQueryDTO); + + List urlInterfaceList( + @Param("param") PackageResourcesPageQueryDTO packageResourcesPageQueryDTO); + + void removeAllUrlResourcesById(@Param("permissionPackageId") Long permissionPackageId); + + void refreshComponentResourcesInfo(@Param("permissionPackageId") Long permissionPackageId); + + void refreshUrlResourcesInfo(@Param("permissionPackageId") Long permissionPackageId); + + void removeUrlResources(Set removeResourceIds, Long permissionPackageId,Long usrId, + Integer resourceType); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PackageResourcesDTO.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PackageResourcesDTO.java new file mode 100644 index 0000000..6ee665b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PackageResourcesDTO.java @@ -0,0 +1,25 @@ +package com.senmesh.usercenter.permissionpackage.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.io.Serializable; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + + +/** + * @author leijiaping + */ +@ApiModel("权限包资源保存DTO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PackageResourcesDTO extends PackageResourcesPageQueryDTO implements Serializable { + + @ApiModelProperty("权限包ID不能为空") + private List packageResourcesOperateDTOList; + +} + diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PackageResourcesOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PackageResourcesOperateDTO.java new file mode 100644 index 0000000..786c554 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PackageResourcesOperateDTO.java @@ -0,0 +1,61 @@ +package com.senmesh.usercenter.permissionpackage.dto; + +import com.senmesh.common.dto.BaseDTO; +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; +import com.senmesh.usercenter.constants.SecurityValidateConstants; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; + + +/** + * @author yzq + */ +@ApiModel("权限包资源操作DTO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PackageResourcesOperateDTO extends BaseDTO implements Serializable { + + private static final long serialVersionUID = -4203821389531547990L; + + @ApiModelProperty("权限包ID") + @NotNull(message = SecurityValidateConstants.PERMISSION_PACKAGE_ID_NULL, groups = {Create.class}) + private Long permissionPackageId; + + @ApiModelProperty("资源ID") + @NotNull(message = SecurityValidateConstants.COMPONENT_URL_ID_NULL, groups = {Create.class}) + private Long resourceId; + + @ApiModelProperty("资源类型 1.菜单 2.组件 3.接口") + @NotNull(message = SecurityValidateConstants.RESOURCE_TYPE_NULL, groups = {Create.class}) + private Integer resourceType; + + @ApiModelProperty("组件/接口名称") + private String name; + + @ApiModelProperty("接口地址") + private String link; + + @ApiModelProperty("组件编码") + private String code; + + @ApiModelProperty("描述") + private String description; + + @ApiModelProperty("平台编码") + private Integer platformCode; + + @ApiModelProperty("是否授权") + @NotNull(message = SecurityValidateConstants.PERMISSION_SELECTED_FLAG_NULL, groups = { + Create.class, Update.class}) + private Boolean selected; + +} + diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PackageResourcesPageQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PackageResourcesPageQueryDTO.java new file mode 100644 index 0000000..ddbdaa3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PackageResourcesPageQueryDTO.java @@ -0,0 +1,45 @@ +package com.senmesh.usercenter.permissionpackage.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import com.senmesh.common.validation.Check; +import com.senmesh.usercenter.constants.SecurityValidateConstants; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; + + +/** + * @author yzq + */ +@ApiModel("权限包资源查询DTO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PackageResourcesPageQueryDTO extends PageQueryDTO + implements + Serializable { + + private static final long serialVersionUID = -4203821389531547990L; + + @ApiModelProperty("权限包ID不能为空") + @NotNull(message = SecurityValidateConstants.PERMISSION_PACKAGE_ID_NULL, groups = {Check.class}) + private Long permissionPackageId; + + @ApiModelProperty("父菜单Id") + @NotNull(message = SecurityValidateConstants.URL_PARENT_ID_NULL, groups = {Check.class}) + private Long urlId; + + @ApiModelProperty("资源类型 1.菜单 2.组件 3.接口") + @NotNull(message = SecurityValidateConstants.RESOURCE_TYPE_NULL, groups = {Check.class}) + private Integer resourceType; + + @ApiModelProperty("是否选中") + private Boolean selected; + +} + diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PermissionOrgCreateDTO.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PermissionOrgCreateDTO.java new file mode 100644 index 0000000..2d82e0d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PermissionOrgCreateDTO.java @@ -0,0 +1,31 @@ +package com.senmesh.usercenter.permissionpackage.dto; + +import java.util.Set; + +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@EqualsAndHashCode(callSuper = true) +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PermissionOrgCreateDTO extends BaseOperateDTO{ + + @ApiModelProperty("权限包ID") + @NotNull(message = "权限包ID不能为空") + private Long permissionPackageId; + + @ApiModelProperty("分配机构ID") + @NotNull(message = "分配机构ID不能为空") + private Set allocationOrgIds; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PermissionOrganizeDTO.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PermissionOrganizeDTO.java new file mode 100644 index 0000000..ee6b6e6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PermissionOrganizeDTO.java @@ -0,0 +1,48 @@ +package com.senmesh.usercenter.permissionpackage.dto; + +import com.senmesh.common.dto.BaseDTO; +import com.senmesh.common.validation.Create; +import com.senmesh.usercenter.constants.SecurityValidateConstants; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; + + +/** + * @author yzq + */ +@EqualsAndHashCode(callSuper = true) +@Data +@AllArgsConstructor +@NoArgsConstructor +@SuperBuilder +public class PermissionOrganizeDTO extends BaseDTO implements Serializable { + + private static final long serialVersionUID = 7381062994217834327L; + + @ApiModelProperty("权限包ID") + @NotNull(message = SecurityValidateConstants.PERMISSION_PACKAGE_ID_NULL, groups = + {Create.class}) + private Long permissionPackageId; + + @ApiModelProperty("分配机构ID") + @NotNull(message = SecurityValidateConstants.PERMISSION_ORG_ID_NULL, groups = + {Create.class}) + private Long allocationOrgId; + + @ApiModelProperty("机构编号") + private String orgCode; + + @ApiModelProperty("机构名称") + private String orgName; + + @ApiModelProperty("机构类型") + private Integer orgType; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PermissionOrganizePageQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PermissionOrganizePageQueryDTO.java new file mode 100644 index 0000000..9912f97 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PermissionOrganizePageQueryDTO.java @@ -0,0 +1,42 @@ +package com.senmesh.usercenter.permissionpackage.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import com.senmesh.usercenter.constants.SecurityValidateConstants; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Set; + + +/** + * @author yzq + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PermissionOrganizePageQueryDTO extends PageQueryDTO implements + Serializable { + + private static final long serialVersionUID = -1920827611245718163L; + @ApiModelProperty("权限包ID") + @NotNull(message = SecurityValidateConstants.PERMISSION_PACKAGE_ID_NULL) + private Long permissionPackageId; + + @ApiModelProperty("机构编号") + private String orgCode; + + @ApiModelProperty("机构名称") + private String orgName; + + @ApiModelProperty("机构类型") + private Integer orgType; + + @ApiModelProperty("分配机构ID集合") + private Set allocationOrgIds; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PermissionPackageDTO.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PermissionPackageDTO.java new file mode 100644 index 0000000..5121c32 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PermissionPackageDTO.java @@ -0,0 +1,56 @@ +package com.senmesh.usercenter.permissionpackage.dto; + +import com.senmesh.common.dto.BaseDTO; +import com.senmesh.common.validation.Create; +import com.senmesh.usercenter.constants.SecurityValidateConstants; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * @author yzq + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@ApiModel("权限包DTO") +@SuperBuilder +public class PermissionPackageDTO extends BaseDTO { + + private static final long serialVersionUID = -3829431820106387725L; + + + @ApiModelProperty("权限包名称") + @NotEmpty(message = SecurityValidateConstants.PERMISSION_PACKAGE_NAME_NULL, groups = + {Create.class}) + private String permissionPackageName; + + @ApiModelProperty("权限包类型:参考{@link OrgTypeEnum}") + @NotNull(message = SecurityValidateConstants.PERMISSION_PACKAGE_TYPE_NULL, groups = + {Create.class}) + private Integer permissionPackageType; + + @ApiModelProperty("状态 1.有效 2.失效") + private Integer status; + + @ApiModelProperty("备注") + private String remark; + + @ApiModelProperty("应用编码 1.业务系统 2.运营中台 3.用户中心 4.支付系统 5.在线培训 6.转发器 7.风控 8.网关 9.发号器 10.基础框架") + @NotNull(message = SecurityValidateConstants.PLATFORM_CODE_EMPTY, groups = + {Create.class}) + private Integer platformCode; + + @ApiModelProperty("是否授权") + private Boolean selected; + + @ApiModelProperty("分配机构关系表Id") + private Long permissionOrganizeId; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PermissionPackageOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PermissionPackageOperateDTO.java new file mode 100644 index 0000000..dfe4354 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PermissionPackageOperateDTO.java @@ -0,0 +1,42 @@ +package com.senmesh.usercenter.permissionpackage.dto; + +import com.senmesh.common.validation.Update; +import com.senmesh.usercenter.constants.SecurityValidateConstants; +import com.senmesh.usercenter.resource.dto.UrlDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.List; + + +/** + * @author yzq + * 权限包 + */ +@ApiModel("权限包树DTO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PermissionPackageOperateDTO implements Serializable { + + private static final long serialVersionUID = -3116840853887604199L; + + @ApiModelProperty("权限包ID") + @NotNull(message = SecurityValidateConstants.PERMISSION_PACKAGE_ID_NULL, groups = {Update.class}) + private Long permissionPackageId; + + @ApiModelProperty("平台编码") + private Integer platformCode; + + @ApiModelProperty("菜单资源树") + List urlDTOs; + + @ApiModelProperty("已分配的菜单资源Id列表") + List selectedResourceIdList; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PermissionPackagePageQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PermissionPackagePageQueryDTO.java new file mode 100644 index 0000000..08fd3d8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/dto/PermissionPackagePageQueryDTO.java @@ -0,0 +1,42 @@ +package com.senmesh.usercenter.permissionpackage.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import com.senmesh.usercenter.constants.SecurityValidateConstants; +import com.senmesh.usercenter.enums.OrgTypeEnum; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * @author yzq + */ +@ApiModel("权限包查询DTO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class PermissionPackagePageQueryDTO extends PageQueryDTO { + + private static final long serialVersionUID = 3308348258162338939L; + + @ApiModelProperty("权限包名称") + private String permissionPackageName; + + /** 权限包类型:参考{@link OrgTypeEnum} **/ + @ApiModelProperty("权限包类型") + private Integer permissionPackageType; + + @ApiModelProperty("应用编码 1.业务系统 2.运营中台 3.用户中心 4.支付系统 5.在线培训 6.转发器 7.风控 8.网关 9.发号器 10.基础框架") + @NotNull(message = SecurityValidateConstants.PLATFORM_CODE_EMPTY) + private Integer platformCode; + + @ApiModelProperty("机构Id") + private Long orgId; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/entity/PermissionOrganization.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/entity/PermissionOrganization.java new file mode 100644 index 0000000..a47ed46 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/entity/PermissionOrganization.java @@ -0,0 +1,50 @@ +package com.senmesh.usercenter.permissionpackage.entity; + +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author : yzq create at: 2020/9/3 15:52 + * @description: 权限包-机构关系表 + */ +@TableName("xs_permission_organization") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Data +public class PermissionOrganization extends BaseEntity { + + + private static final long serialVersionUID = -1017315735785518362L; + /** + * 权限包ID + **/ + private Long permissionPackageId; + + /** + * 分配机构orgId + **/ + private Long allocationOrgId; + + /** + * 备注 + **/ + private String remark; + + @Builder + public PermissionOrganization(Long id, Boolean deleted, Long createBy, Date createTime, + Long updateBy, Date updateTime, Long proxyBy, Long permissionsPackageId, Long allocationOrgId, String remark) { + super(id, deleted, createBy, createTime, updateBy, updateTime, proxyBy); + this.permissionPackageId = permissionsPackageId; + this.allocationOrgId = allocationOrgId; + this.remark = remark; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/entity/PermissionPackage.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/entity/PermissionPackage.java new file mode 100644 index 0000000..70bf718 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/entity/PermissionPackage.java @@ -0,0 +1,66 @@ +package com.senmesh.usercenter.permissionpackage.entity; + +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; +import com.senmesh.usercenter.enums.OrgTypeEnum; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author : yzq create at: 2020/9/3 15:52 + * @description: 标准权限包 + */ +@TableName("xs_permission_package") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Data +public class PermissionPackage extends BaseEntity { + + + private static final long serialVersionUID = 3822862490863266305L; + + + /** + * 权限包名称 + **/ + private String permissionPackageName; + + /** + * 应用编码 + */ + private Integer platformCode; + + /** + * 权限包类型:参考{@link OrgTypeEnum} + **/ + private Integer permissionPackageType; + + /** + * 状态 1.有效 2.失效 + **/ + private Integer status; + + /** + * 备注 + **/ + private String remark; + + @Builder + public PermissionPackage(Long id, Boolean deleted, Long createBy, Date createTime, + Long updateBy, Date updateTime, Long proxyBy, String permissionPackageName, + Integer platformCode, Integer permissionPackageType, Integer status, String remark) { + super(id, deleted, createBy, createTime, updateBy, updateTime, proxyBy); + this.permissionPackageName = permissionPackageName; + this.platformCode = platformCode; + this.permissionPackageType = permissionPackageType; + this.status = status; + this.remark = remark; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/entity/PermissionResources.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/entity/PermissionResources.java new file mode 100644 index 0000000..c836322 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/entity/PermissionResources.java @@ -0,0 +1,57 @@ +package com.senmesh.usercenter.permissionpackage.entity; + +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author : yzq create at: 2020/9/3 15:52 + * @description: 权限包-资源关系表 + */ +@TableName("xs_permission_resources") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Data +public class PermissionResources extends BaseEntity { + + + private static final long serialVersionUID = 617520887852396742L; + /** + * 权限包Id + **/ + private Long permissionPackageId; + + /** + * 资源ID + **/ + private Long resourceId; + + /** + * 类型 1.菜单 2.组件 3.接口 + **/ + private Integer resourceType; + + /** + * 备注 + **/ + private String remark; + + @Builder + public PermissionResources(Long id, Boolean deleted, Long createBy, Date createTime, + Long updateBy, Date updateTime, Long proxyBy, Long permissionPackageId, + Long resourceId, Integer resourceType, String remark) { + super(id, deleted, createBy, createTime, updateBy, updateTime, proxyBy); + this.permissionPackageId = permissionPackageId; + this.resourceId = resourceId; + this.resourceType = resourceType; + this.remark = remark; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/mapper/PermissionPackageMapper.xml b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/mapper/PermissionPackageMapper.xml new file mode 100644 index 0000000..b282ae1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/mapper/PermissionPackageMapper.xml @@ -0,0 +1,44 @@ + + + + + diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/mapper/PermissionPackageOrgMapper.xml b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/mapper/PermissionPackageOrgMapper.xml new file mode 100644 index 0000000..fc49c8e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/mapper/PermissionPackageOrgMapper.xml @@ -0,0 +1,81 @@ + + + + + + + diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/mapper/PermissionResourceMapper.xml b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/mapper/PermissionResourceMapper.xml new file mode 100644 index 0000000..7882700 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/mapper/PermissionResourceMapper.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + UPDATE + xs_permission_resources + SET + deleted = TRUE + WHERE + deleted = FALSE + AND resource_type = 1 + AND permission_package_id= #{permissionPackageId} + + + + UPDATE + xs_permission_package t1 + INNER JOIN xs_permission_resources t2 ON + t2.permission_package_id = t1.id + AND t2.deleted = FALSE + AND t2.resource_type = 2 + LEFT JOIN xs_component t3 ON + t3.id = t2.resource_id + AND t3.deleted = FALSE + LEFT JOIN xs_permission_resources t4 ON + t4.permission_package_id=t1.id + AND t4.resource_id=t3.url_id + AND t4.resource_type=1 + AND t4.deleted = FALSE + SET t2.deleted = TRUE + WHERE t1.deleted = FALSE AND t4.id IS NULL AND t1.id=#{permissionPackageId} + + + + UPDATE + xs_permission_package t1 + INNER JOIN xs_permission_resources t2 ON + t2.permission_package_id = t1.id + AND t2.deleted = FALSE + AND t2.resource_type = 3 + LEFT JOIN xs_url t3 ON + t3.id = t2.resource_id + AND t3.deleted = FALSE + LEFT JOIN xs_permission_resources t4 ON + t4.permission_package_id=t1.id + AND t4.resource_id=t3.parent_id + AND t4.resource_type=1 + AND t4.deleted = FALSE + SET t2.deleted = TRUE + WHERE t1.deleted = FALSE AND t4.id IS NULL AND t1.id=#{permissionPackageId} + + + + + UPDATE + xs_permission_resources t + SET + t.deleted = TRUE, + t.update_by = #{usrId}, + t.update_time = now() + WHERE + t.deleted = FALSE + AND t.permission_package_id = #{permissionPackageId} + + AND t.resource_id IN + + #{resourceId} + + + AND t.resource_type = #{resourceType} + + diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/mapstruct/PermissionPackageMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/mapstruct/PermissionPackageMapMapper.java new file mode 100644 index 0000000..1c0772c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/mapstruct/PermissionPackageMapMapper.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.permissionpackage.mapstruct; + +import com.senmesh.usercenter.permissionpackage.dto.PackageResourcesOperateDTO; +import com.senmesh.usercenter.permissionpackage.dto.PermissionOrganizeDTO; +import com.senmesh.usercenter.permissionpackage.entity.PermissionOrganization; +import com.senmesh.usercenter.permissionpackage.entity.PermissionResources; +import java.util.List; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + + +/** + * @author yzq + */ +@Mapper +public interface PermissionPackageMapMapper { + + PermissionPackageMapMapper INSTANCE = + Mappers.getMapper(PermissionPackageMapMapper.class); + + /** + * 批量转换PermissionResources + * + * @param packageResourcesOperateDTOList + * @return + */ + List toResourcesEntityList( + List packageResourcesOperateDTOList); + + /** + * 批量转换PermissionOrganization + * + * @param permissionOrganizeDTOList + * @return + */ + List toOrganizationEntityList( + List permissionOrganizeDTOList); + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/service/UcPermissionOrganizationService.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/service/UcPermissionOrganizationService.java new file mode 100644 index 0000000..941fe62 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/service/UcPermissionOrganizationService.java @@ -0,0 +1,80 @@ +package com.senmesh.usercenter.permissionpackage.service; + +import java.util.List; +import java.util.Set; + +import javax.validation.Valid; + +import com.senmesh.usercenter.permissionpackage.dto.PermissionOrgCreateDTO; +import com.senmesh.usercenter.permissionpackage.dto.PermissionOrganizeDTO; +import com.senmesh.usercenter.permissionpackage.dto.PermissionOrganizePageQueryDTO; + +/** + * @author : yzq create at: 2020/9/3 16:54 + * @description: 权限包接口 + */ +public interface UcPermissionOrganizationService { + + /** + * 根据机构类型保存机构权限包 + * @param orgId + * @param orgType + * @author sr on 2024-04-19 + */ + void saveOrgByType(Long orgId, Integer orgType); + + void create(@Valid PermissionOrgCreateDTO permissionOrgCreateDTO); + + + + + + + /** + * 查询对应权限包下所有可以被选择的机构信息 + * + * @param permissionOrganizePageQueryDTO + * @return + */ + List canBeAllocatedOrgList( + PermissionOrganizePageQueryDTO permissionOrganizePageQueryDTO); + + /** + * 查询对应权限包下的分配的机构信息 + * + * @param permissionOrganizePageQueryDTO + * @return + */ + List allocatedOrgList( + PermissionOrganizePageQueryDTO permissionOrganizePageQueryDTO); + + /** + * 保存机构分配信息 + * + * @param permissionOrganizeDTOList + * @return + */ + void saveOrgList(List permissionOrganizeDTOList); + + /** + * 删除机构分配信息 + * + * @param id + * @return + */ + void removeAllocatedOrg(Long id); + + void removeAllocatedOrgList(Set ids); + + + + + + + + + + +} + + diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/service/UcPermissionPackageService.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/service/UcPermissionPackageService.java new file mode 100644 index 0000000..2617ad3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/service/UcPermissionPackageService.java @@ -0,0 +1,60 @@ +package com.senmesh.usercenter.permissionpackage.service; + + +import com.senmesh.usercenter.permissionpackage.dto.PermissionPackageDTO; +import com.senmesh.usercenter.permissionpackage.dto.PermissionPackageOperateDTO; +import com.senmesh.usercenter.permissionpackage.dto.PermissionPackagePageQueryDTO; +import java.util.List; + +/** + * @author : yzq create at: 2020/9/3 16:54 + * @description: 权限包接口 + */ +public interface UcPermissionPackageService { + + /** + * 分页查询权限包列表 + */ + void page( + PermissionPackagePageQueryDTO permissionPackagePageQueryDTO); + + /** + * 查询权限包列表 + */ + List list( + PermissionPackagePageQueryDTO permissionPackagePageQueryDTO); + + PermissionPackageDTO findOne(PermissionPackagePageQueryDTO permissionPackagePageQueryDTO); + + + + + + + + + /** + * 新增权限包 + */ + void createPermissionPackage(PermissionPackageDTO permissionPackageDTO); + + /** + * 修改权限包 + */ + void updatePermissionPackage(PermissionPackageDTO permissionPackageDTO); + + /** + * 删除权限包 + */ + void removePermissionPackage(Long id); + + + + + + PermissionPackageOperateDTO urlList(PermissionPackageDTO permissionPackageDTO); + + +} + + diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/service/UcPermissionResourceService.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/service/UcPermissionResourceService.java new file mode 100644 index 0000000..7f9aa5b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/service/UcPermissionResourceService.java @@ -0,0 +1,51 @@ +package com.senmesh.usercenter.permissionpackage.service; + +import com.senmesh.usercenter.permissionpackage.dto.PackageResourcesDTO; +import com.senmesh.usercenter.permissionpackage.dto.PackageResourcesOperateDTO; +import com.senmesh.usercenter.permissionpackage.dto.PackageResourcesPageQueryDTO; +import com.senmesh.usercenter.permissionpackage.dto.PermissionPackageOperateDTO; +import java.util.List; + +/** + * @author : yzq create at: 2020/9/3 16:54 + * @description: 权限包资源明细接口 + */ +public interface UcPermissionResourceService { + + /** + * 查询权限包下的菜单资源 + * + * @param permissionPackageId + * @param platformCode + * @return + */ + PermissionPackageOperateDTO urlList( + Long permissionPackageId, Integer platformCode); + + /** + * 变更权限包下的菜单资源 + * + * @param permissionPackageOperateDTO + */ + void updateUrlList(PermissionPackageOperateDTO permissionPackageOperateDTO); + + /** + * 查询对应菜单下组件接口列表 + * + * @param packageResourcesPageQueryDTO + * @return + */ + List urlComponentList( + PackageResourcesPageQueryDTO packageResourcesPageQueryDTO); + + /** + * 更新菜单下的相关资源 + * + * @param packageResourcesDTO + */ + void saveUrlComponentList(PackageResourcesDTO packageResourcesDTO); + + + void cleanUrlCompentAndInterface(Long permissionPackageId); +} + diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/service/impl/UcPermissionOrganizationServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/service/impl/UcPermissionOrganizationServiceImpl.java new file mode 100644 index 0000000..61cc028 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/service/impl/UcPermissionOrganizationServiceImpl.java @@ -0,0 +1,140 @@ +package com.senmesh.usercenter.permissionpackage.service.impl; + +import com.google.common.collect.Lists; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.cache.SecurityCacheUtils; +import com.senmesh.usercenter.constants.SecurityConstants; +import com.senmesh.usercenter.permissionpackage.dao.PermissionPackageOrgMapper; +import com.senmesh.usercenter.permissionpackage.dto.PermissionOrgCreateDTO; +import com.senmesh.usercenter.permissionpackage.dto.PermissionOrganizeDTO; +import com.senmesh.usercenter.permissionpackage.dto.PermissionOrganizePageQueryDTO; +import com.senmesh.usercenter.permissionpackage.dto.PermissionPackageDTO; +import com.senmesh.usercenter.permissionpackage.dto.PermissionPackagePageQueryDTO; +import com.senmesh.usercenter.permissionpackage.entity.PermissionOrganization; +import com.senmesh.usercenter.permissionpackage.service.UcPermissionOrganizationService; +import com.senmesh.usercenter.permissionpackage.service.UcPermissionPackageService; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +/** + * @author : yzq create at: 2020/9/9 19:55 + * @description: 权限包机构实现类 + */ +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +@ConditionalOnProperty(name = SecurityConstants.PROP_KEY_SECURITY_USELOCAL, havingValue = "true", matchIfMissing = true) +public class UcPermissionOrganizationServiceImpl implements UcPermissionOrganizationService { + + private final PermissionPackageOrgMapper permissionPackageOrgMapper; + + private final UcPermissionPackageService permissionPackageService; + + @Override + @Transactional + public void saveOrgByType(Long orgId, Integer orgType) { + PermissionPackageDTO permissionPackageDTO = + permissionPackageService.findOne(PermissionPackagePageQueryDTO.builder() + .platformCode(EnvironmentUtils.getSystemCode()) + .permissionPackageType(orgType).build()); + Long permissionPackageId = permissionPackageDTO.getId(); + List permissions = Lists.newArrayList(PermissionOrganizeDTO.builder() + .permissionPackageId(permissionPackageId).allocationOrgId(orgId).build()); + this.saveOrgList(permissions); + } + + @Override + @Transactional + public void create(PermissionOrgCreateDTO permissionOrgCreateDTO) { + Set orgIds = permissionOrgCreateDTO.getAllocationOrgIds(); + Long permissionsPackageId = permissionOrgCreateDTO.getPermissionPackageId(); + Assert.notEmpty(orgIds, "请传入有效的机构信息"); + List existOrgs = this.allocatedOrgList(PermissionOrganizePageQueryDTO.builder() + .permissionPackageId(permissionsPackageId) + .allocationOrgIds(orgIds).build()); + Set checkOrgIds = orgIds; + if (!existOrgs.isEmpty()) { + Set allocatedOrgSet = + existOrgs.stream().map(PermissionOrganizeDTO::getAllocationOrgId) + .collect(Collectors.toSet()); + checkOrgIds = orgIds.stream().filter(orgId -> !allocatedOrgSet + .contains(orgId)).collect(Collectors.toSet()); + } + if (checkOrgIds.isEmpty()) { + return ; + } + List permissionOrganizationList = orgIds + .stream().map(orgId -> PermissionOrganization.builder() + .permissionsPackageId(permissionsPackageId).allocationOrgId(orgId).build()) + .collect(Collectors.toList()); + permissionPackageOrgMapper.saveEntites(permissionOrganizationList); + SecurityCacheUtils.flushSystemOrgs(null, checkOrgIds); + } + + +//***********************************分隔符*********************************************** + + + + + + @Override + @Transactional(rollbackFor = Exception.class) + public List canBeAllocatedOrgList( + PermissionOrganizePageQueryDTO permissionOrganizePageQueryDTO) { + return permissionPackageOrgMapper.canBeAllocatedOrgList(permissionOrganizePageQueryDTO); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public List allocatedOrgList( + PermissionOrganizePageQueryDTO permissionOrganizePageQueryDTO) { + return permissionPackageOrgMapper.allocatedOrgList(permissionOrganizePageQueryDTO); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveOrgList( + List permissionOrganizeDTOList) { + Assert.notEmpty(permissionOrganizeDTOList, "请传入有效的机构信息"); + Set orgIds = permissionOrganizeDTOList.stream().map(d -> d.getAllocationOrgId()) + .collect(Collectors.toSet()); + this.create(PermissionOrgCreateDTO.builder() + .permissionPackageId(permissionOrganizeDTOList.get(0).getPermissionPackageId()) + .allocationOrgIds(orgIds).build()); + } + + + + @Override + @Transactional(rollbackFor = Exception.class) + public void removeAllocatedOrg(Long id) { + Assert.isTrue( + permissionPackageOrgMapper.deleteEntity(PermissionOrganization.builder().id(id).build(), + UserContextHolder.getLoginUserId()) == 1, + "取消分配机构失败"); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void removeAllocatedOrgList(Set ids) { + Assert.isTrue(!CollectionUtils.isEmpty(ids), + "请传入有效的机构"); + List permissionOrganizationList = + ids.stream().map(id -> PermissionOrganization.builder().id(id).build()) + .collect(Collectors.toList()); + permissionPackageOrgMapper + .deleteEntites(permissionOrganizationList, UserContextHolder.getExistLoginUserId()); + } + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/service/impl/UcPermissionPackageServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/service/impl/UcPermissionPackageServiceImpl.java new file mode 100644 index 0000000..7b64ee6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/service/impl/UcPermissionPackageServiceImpl.java @@ -0,0 +1,109 @@ +package com.senmesh.usercenter.permissionpackage.service.impl; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.ListUtil; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.constants.SecurityConstants; +import com.senmesh.usercenter.permissionpackage.dao.PermissionPackageMapper; +import com.senmesh.usercenter.permissionpackage.dao.PermissionPackageOrgMapper; +import com.senmesh.usercenter.permissionpackage.dto.PermissionPackageDTO; +import com.senmesh.usercenter.permissionpackage.dto.PermissionPackageOperateDTO; +import com.senmesh.usercenter.permissionpackage.dto.PermissionPackagePageQueryDTO; +import com.senmesh.usercenter.permissionpackage.entity.PermissionOrganization; +import com.senmesh.usercenter.permissionpackage.entity.PermissionPackage; +import com.senmesh.usercenter.permissionpackage.service.UcPermissionPackageService; +import com.senmesh.usercenter.utils.PermissionPackageUtils; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * @author : yzq create at: 2020/9/7 17:20 + * @description: 权限包实现类 + */ +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +@ConditionalOnProperty(name = SecurityConstants.PROP_KEY_SECURITY_USELOCAL, havingValue = "true", matchIfMissing = true) +public class UcPermissionPackageServiceImpl implements UcPermissionPackageService { + + private final PermissionPackageMapper permissionPackageMapper; + + private final PermissionPackageOrgMapper permissionPackageOrgMapper; + + @Override + public void page( + PermissionPackagePageQueryDTO permissionPackagePageQueryDTO) { + permissionPackageMapper.listPermissionPackage(permissionPackagePageQueryDTO); + } + + @Override + public List list( + PermissionPackagePageQueryDTO permissionPackagePageQueryDTO) { + permissionPackagePageQueryDTO.disablePage(); + return permissionPackageMapper.listPermissionPackage(permissionPackagePageQueryDTO); + } + + @Override + public PermissionPackageDTO findOne(PermissionPackagePageQueryDTO permissionPackagePageQueryDTO) { + List permissionPackageDTOs = list(permissionPackagePageQueryDTO); + Assert.isTrue(permissionPackageDTOs.size() == 1, "未找到唯一匹配的权限包"); + return ListUtil.first(permissionPackageDTOs); + } + + +//***********************************分隔符*********************************************** + + + + @Override + @Transactional(rollbackFor = Exception.class) + public void createPermissionPackage(PermissionPackageDTO permissionPackageDTO) { + //校验唯一性 + List packageList = + permissionPackageMapper.listPermissionPackage(PermissionPackagePageQueryDTO.builder() + .permissionPackageName(permissionPackageDTO.getPermissionPackageName()) + .platformCode(permissionPackageDTO.getPlatformCode()) + .permissionPackageType(permissionPackageDTO.getPermissionPackageType()) + .build()); + Assert.isTrue(CollectionUtils.isEmpty(packageList), "该应用下已存在同名权限包"); + PermissionPackage permissionPackage = + PermissionPackageUtils.toCreatePermissionPackage(permissionPackageDTO); + permissionPackageMapper.saveEntity(permissionPackage, UserContextHolder.getLoginUserId()); + permissionPackageDTO.setId(permissionPackage.getId()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updatePermissionPackage(PermissionPackageDTO permissionPackageDTO) { + PermissionPackage permissionPackage = + PermissionPackageUtils.toCreatePermissionPackage(permissionPackageDTO); + permissionPackage.setId(permissionPackageDTO.getId()); + Assert.isTrue(permissionPackageMapper.updateEntitySelective(permissionPackage, + UserContextHolder.getLoginUserId()) == 1 + , "更新权限包失败"); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void removePermissionPackage(Long id) { + //已分配的权限包不能删除 + boolean exists = permissionPackageOrgMapper + .existsEntity(PermissionOrganization.builder().permissionsPackageId(id).build()); + Assert.isTrue(!exists, + "该权限包已分配机构,不能删除"); + Assert.isTrue(permissionPackageMapper.deleteEntity(PermissionPackage.builder().id(id).build(), + UserContextHolder.getLoginUserId()) == 1, + "删除权限包失败"); + } + + + @Override + @Transactional(rollbackFor = Exception.class) + public PermissionPackageOperateDTO urlList(PermissionPackageDTO permissionPackageDTO) { + return null; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/permissionpackage/service/impl/UcPermissionResourceServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/service/impl/UcPermissionResourceServiceImpl.java new file mode 100644 index 0000000..18d284e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/permissionpackage/service/impl/UcPermissionResourceServiceImpl.java @@ -0,0 +1,179 @@ +package com.senmesh.usercenter.permissionpackage.service.impl; + +import com.google.common.collect.Lists; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.authority.constants.PermissionConstants; +import com.senmesh.usercenter.constants.SecurityConstants; +import com.senmesh.usercenter.enums.ResourceType; +import com.senmesh.usercenter.permissionpackage.dao.PermissionPackageMapper; +import com.senmesh.usercenter.permissionpackage.dao.PermissionResourceMapper; +import com.senmesh.usercenter.permissionpackage.dto.PackageResourcesDTO; +import com.senmesh.usercenter.permissionpackage.dto.PackageResourcesOperateDTO; +import com.senmesh.usercenter.permissionpackage.dto.PackageResourcesPageQueryDTO; +import com.senmesh.usercenter.permissionpackage.dto.PermissionPackageOperateDTO; +import com.senmesh.usercenter.permissionpackage.entity.PermissionPackage; +import com.senmesh.usercenter.permissionpackage.entity.PermissionResources; +import com.senmesh.usercenter.permissionpackage.mapstruct.PermissionPackageMapMapper; +import com.senmesh.usercenter.permissionpackage.service.UcPermissionResourceService; +import com.senmesh.usercenter.resource.dto.UrlDTO; +import com.senmesh.usercenter.resource.dto.UrlPageQueryDTO; +import com.senmesh.usercenter.resource.service.UcUrlService; +import lombok.RequiredArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author : yzq create at: 2020/9/7 17:20 + * @description: 权限包实现类 + */ +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +@ConditionalOnProperty(name = SecurityConstants.PROP_KEY_SECURITY_USELOCAL, havingValue = "true", matchIfMissing = true) +public class UcPermissionResourceServiceImpl implements UcPermissionResourceService { + + private final PermissionResourceMapper permissionResourceMapper; + + private final UcUrlService ucUrlService; + + private final PermissionPackageMapper permissionPackageMapper; + + + @Override + @Transactional(rollbackFor = Exception.class) + public PermissionPackageOperateDTO urlList( + Long permissionPackageId, Integer platformCode) { + //查询权限包 + PermissionPackage permissionPackage = + permissionPackageMapper.getById(permissionPackageId); + if (permissionPackage == null) { + return null; + } + //查询该应用下的所有菜单资源 + PermissionPackageOperateDTO permissionOperateDTO = new PermissionPackageOperateDTO(); + UrlPageQueryDTO urlPageQueryDTO = new UrlPageQueryDTO(); + urlPageQueryDTO.setPlatformCode(platformCode); + urlPageQueryDTO.setTree(Boolean.TRUE); + urlPageQueryDTO.setNeedPage(Boolean.FALSE); + permissionOperateDTO.setUrlDTOs(ucUrlService.list(urlPageQueryDTO)); + //查询已选择的菜单资源 + permissionOperateDTO.setPermissionPackageId(permissionPackageId); + permissionOperateDTO.setPlatformCode(platformCode); + List selectedUrlList = + permissionResourceMapper.findSelectdUrl(permissionPackageId); + if (CollectionUtils.isNotEmpty(selectedUrlList)) { + permissionOperateDTO.setSelectedResourceIdList( + selectedUrlList.stream().map(UrlDTO::getId).collect(Collectors.toList())); + } + return permissionOperateDTO; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateUrlList(PermissionPackageOperateDTO permissionPackageOperateDTO) { + Long permissionPackageId = permissionPackageOperateDTO.getPermissionPackageId(); + //本次所选菜单 + List selectedResourceIdList =permissionPackageOperateDTO.getSelectedResourceIdList(); + if(CollectionUtils.isEmpty(selectedResourceIdList)){ + //删除原本权限包-菜单资源信息 + permissionResourceMapper + .removeAllUrlResourcesById(permissionPackageId); + return; + } + //原本已分配的菜单 + List originalUrlList = + permissionResourceMapper.findSelectdUrl(permissionPackageId); + Set originalUrlSet= + originalUrlList.stream().map(UrlDTO::getId).collect(Collectors.toSet()); + //过滤出需要删除的(原本已存在,不在本次所选菜单中) + Set removeList=originalUrlSet.stream().filter(resourceId ->!selectedResourceIdList.contains(resourceId)).collect(Collectors.toSet()); + if(CollectionUtils.isNotEmpty(removeList)){ + permissionResourceMapper.removeUrlResources(removeList, + permissionPackageId,UserContextHolder.getLoginUserId(),Integer.valueOf(ResourceType.RESOURCE_MENU_TYPE.getType())); + } + //过滤出本次新增的(本次所选菜单存在,原本不存在) + selectedResourceIdList.removeAll(originalUrlSet); + //重新插入已选择的菜单信息 + List permissionResources = Lists.newArrayList(); + selectedResourceIdList.forEach(urlId -> { + permissionResources.add( + PermissionResources.builder().permissionPackageId(permissionPackageId).resourceType( + Integer.valueOf(ResourceType.RESOURCE_MENU_TYPE.getType())) + .resourceId(urlId).build()); + }); + permissionResourceMapper + .saveEntites(permissionResources, UserContextHolder.getExistLoginUserId()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public List urlComponentList( + PackageResourcesPageQueryDTO packageResourcesPageQueryDTO) { + Integer resourceType = packageResourcesPageQueryDTO.getResourceType(); + if (PermissionConstants.RESOURCE_TYPE_COMPONENT.equals(resourceType.toString())) { + return permissionResourceMapper.urlComponentList(packageResourcesPageQueryDTO); + } + return permissionResourceMapper.urlInterfaceList(packageResourcesPageQueryDTO); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveUrlComponentList(PackageResourcesDTO packageResourcesDTO) { + List packageResourcesOperateDTOList = packageResourcesDTO + .getPackageResourcesOperateDTOList(); + /* Assert.isTrue(CollectionUtils.isNotEmpty(packageResourcesOperateDTOList), + "请传入需要保存或者需要取消的组件/接口数据");*/ + // 获取原来已有的 + packageResourcesDTO.setNeedPage(false); + List permissionResourcesList = this + .urlComponentList(packageResourcesDTO); + Set oldResourceIdSet = permissionResourcesList.stream() + .map(PackageResourcesOperateDTO::getResourceId) + .collect(Collectors.toSet()); + + // 获取新增的资源,顺便将旧的列表中移出已存在的资源 + List selectedList = packageResourcesOperateDTOList.stream() + .filter(packageResourcesOperateDTO -> { + Long newResourceId = packageResourcesOperateDTO.getResourceId(); + boolean exist = oldResourceIdSet.contains(newResourceId); + // 移出已存在的资源 + if (exist) { + oldResourceIdSet.remove(newResourceId); + } + return !exist; + }) + .collect(Collectors.toList()); + + // 新增(在新的中排除老的就是新增的) + if (CollectionUtils.isNotEmpty(selectedList)) { + permissionResourceMapper + .saveEntites(PermissionPackageMapMapper.INSTANCE.toResourcesEntityList(selectedList), + UserContextHolder.getLoginUserId()); + } + + // 删除(将老的中排除新增的就是要删除的) + List removeList = permissionResourcesList.stream() + .filter(permissionResource -> oldResourceIdSet.contains(permissionResource.getResourceId())) + .collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(removeList)) { + permissionResourceMapper + .deleteEntites(PermissionPackageMapMapper.INSTANCE.toResourcesEntityList(removeList), + UserContextHolder.getLoginUserId()); + } + } + + @Override + public void cleanUrlCompentAndInterface(Long permissionPackageId) { + //将未勾选的菜单下的组件记录删除 + permissionResourceMapper.refreshComponentResourcesInfo(permissionPackageId); + //将未勾选的菜单下的接口记录删除 + permissionResourceMapper.refreshUrlResourcesInfo(permissionPackageId); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/query/RoleQuery.java b/backend/src/main/java/com/senmesh/usercenter/query/RoleQuery.java new file mode 100644 index 0000000..aaea903 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/query/RoleQuery.java @@ -0,0 +1,46 @@ +package com.senmesh.usercenter.query; + +import com.senmesh.common.dto.PageQueryDTO; +import com.senmesh.usercenter.constants.RoleConstants; +import com.senmesh.usercenter.dto.RoleDTO; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Builder.Default; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author: Jerry.li + * @description: 角色查询 + * @create: 2020-06-16 16:36 + **/ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class RoleQuery extends PageQueryDTO { + + /** **/ + private static final long serialVersionUID = 7563793746636237744L; + + private String roleName; + + /** + * 平台编码 + */ + private Integer platformCode; + + private Long userId; + /** + * 角色类型:1-业务角色 + */ + @Default + private String roleType = RoleConstants.ROLE_TYPE_BUSINESS; + + private String standardType; + private Long orgId; + + private Boolean enabled; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/query/RoleStandardTypeQuery.java b/backend/src/main/java/com/senmesh/usercenter/query/RoleStandardTypeQuery.java new file mode 100644 index 0000000..7d3e41b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/query/RoleStandardTypeQuery.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.query; + +import com.senmesh.common.dto.PageQueryDTO; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author Jerry.li + * @description 企业联系信息查询实体 + * @date 2020/3/27 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@AllArgsConstructor +@NoArgsConstructor +public class RoleStandardTypeQuery extends PageQueryDTO { + + private static final long serialVersionUID = 910664153838006438L; + + /** + * 编码 + **/ + private String roleCode; + /** + * 名称 + **/ + private String name; + /** + * 平台编码 + **/ + private String platformCode; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/query/UserRelationCreateDTO.java b/backend/src/main/java/com/senmesh/usercenter/query/UserRelationCreateDTO.java new file mode 100644 index 0000000..b648feb --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/query/UserRelationCreateDTO.java @@ -0,0 +1,45 @@ +package com.senmesh.usercenter.query; + +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; +import io.swagger.annotations.ApiModelProperty; +import java.io.Serializable; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @Author dylanyuan + * @Date 2021/2/23 6:13 下午 + * @Version 1.0 + */ +@Data +@NoArgsConstructor +public class UserRelationCreateDTO implements Serializable { + + @ApiModelProperty("用户ID") + @NotNull(message = "用户ID不能为空", groups = {Create.class, Update.class}) + private Long userId; + + @ApiModelProperty("上级用户ID") + @NotNull(message = "上级ID不能为空", groups = {Create.class, Update.class}) + private Long upperUserId; + + @ApiModelProperty("平台编码") + @NotEmpty(message = "平台编码不能为空") + private String platformCode; + + @Builder + public UserRelationCreateDTO( + @NotNull(message = "用户ID不能为空", groups = {Create.class, + Update.class}) Long userId, + @NotNull(message = "上级ID不能为空", groups = {Create.class, + Update.class}) Long upperUserId, + @NotEmpty(message = "平台编码不能为空") String platformCode) { + this.userId = userId; + this.upperUserId = upperUserId; + this.platformCode = platformCode; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/query/UserRelationQuery.java b/backend/src/main/java/com/senmesh/usercenter/query/UserRelationQuery.java new file mode 100644 index 0000000..2586dc8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/query/UserRelationQuery.java @@ -0,0 +1,39 @@ +package com.senmesh.usercenter.query; + +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author Jerry.li + * @description 企业联系信息查询实体 + * @date 2020/3/27 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UserRelationQuery extends PageQueryDTO { + + private static final long serialVersionUID = 910664153838006438L; + + @ApiModelProperty("用户ID") + private Long userId; + + @ApiModelProperty("上级用户ID") + private Long upperUserId; + + @ApiModelProperty("平台编码") + private String platformCode; + + @ApiModelProperty("中文名称") + private String chineseName; + + @ApiModelProperty("手机号") + private String phone; + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/resource/controller/UcComponentController.java b/backend/src/main/java/com/senmesh/usercenter/resource/controller/UcComponentController.java new file mode 100644 index 0000000..463a145 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/resource/controller/UcComponentController.java @@ -0,0 +1,70 @@ +package com.senmesh.usercenter.resource.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.constants.SecurityConstants; +import com.senmesh.usercenter.resource.dto.ComponentDTO; +import com.senmesh.usercenter.resource.dto.ComponentPageQueryDTO; +import com.senmesh.usercenter.resource.service.UcComponentService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 组件操作 + * + * @author sr on 2019-11-05 + */ +@Api(tags = "组件操作") +@RestController +@RequestMapping("/component") +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +//TODO 目前只有本地引用,需提供cloud调用,然后放开注释 +@ConditionalOnProperty(name = SecurityConstants.PROP_KEY_SECURITY_USELOCAL, havingValue = "true", matchIfMissing = true) +public class UcComponentController { + + private final UcComponentService componentService; + + @ApiOperation("创建组件") + @PostMapping("/create") + public AlitaResult createComponent( + @Validated(Create.class) @RequestBody ComponentDTO componentDTO) { + return AlitaResult.success(componentService.creatComponent(componentDTO)); + } + + @ApiOperation("修改组件") + @PostMapping("/update") + public AlitaResult updateComponent( + @Validated(Update.class) @RequestBody ComponentDTO componentDTO) { + return AlitaResult.success(componentService.updateComponent(componentDTO)); + } + + @ApiOperation("删除组件") + @DeleteMapping("/delete/{id}") + public AlitaResult deleteComponent(@PathVariable("id") Long componentId) { + componentService.deleteComponent(componentId); + return AlitaResult.success(true); + } + + @ApiOperation("组件列表") + @GetMapping("/list") + public AlitaResult> list(@Validated ComponentPageQueryDTO queryDTO) { + queryDTO.setNeedPage(false); + return AlitaResult.success(componentService.list(queryDTO)); + } + + @ApiOperation("组件分页列表") + @GetMapping("/page") + public AlitaResult> page(@Validated ComponentPageQueryDTO queryDTO) { + componentService.list(queryDTO); + return AlitaResult.success(queryDTO.getPageResult()); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/resource/controller/UcResourceController.java b/backend/src/main/java/com/senmesh/usercenter/resource/controller/UcResourceController.java new file mode 100644 index 0000000..706ee0e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/resource/controller/UcResourceController.java @@ -0,0 +1,73 @@ +package com.senmesh.usercenter.resource.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +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.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.common.validation.Update; +import com.senmesh.security.service.IResourceSecurityService; +import com.senmesh.usercenter.authority.dto.PermissionOperateDTO; +import com.senmesh.usercenter.cache.SecurityCacheUtils; +import com.senmesh.usercenter.resource.dto.UrlDTO; +import com.senmesh.usercenter.resource.service.UcResourceService; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2020-09-08 + */ +@RestController +@RequestMapping("/resource") +@Api(tags = "资源操作(菜单+组件)") +public class UcResourceController { + + @Autowired + private IResourceSecurityService iResourceSecurityService; + + @Autowired + private UcResourceService ucResourceService; + + @ApiOperation("获取当前用户资源列表") + @GetMapping("/list") + public AlitaResult> list(@RequestParam("systemCode") Integer systemCode, + @RequestParam(name = "roleId", required = false) Long roleId) { + if (null != roleId) { + return AlitaResult.success(iResourceSecurityService.listResource(systemCode, UserContextHolder.getLoginUser(), roleId)); + } + return AlitaResult.success(iResourceSecurityService.listResource(systemCode, UserContextHolder.getLoginUser())); + } + + @ApiOperation("设置角色权限(业务角色)") + @PostMapping("/permission/business") + public AlitaResult saveBusinessPermission( + @Validated(Update.class) @RequestBody PermissionOperateDTO permissionDTO) { + ucResourceService.saveBusinessPermission(UserContextHolder.getLoginOrgId(), permissionDTO, + UserContextHolder.getExistLoginUserId()); + return AlitaResult.success(true); + } + + @ApiOperation("获取当前用户资源列表") + @GetMapping("/flush_current_org") + public AlitaResult flushCurrentOrg(@RequestParam("systemCode") Integer systemCode) { + SecurityCacheUtils.flushSystemOrg(systemCode, UserContextHolder.getLoginOrgId()); + return AlitaResult.success(true); + } + + @ApiOperation("获取当前用户资源列表") + @GetMapping("/flush_all") + public AlitaResult flushAll() { + SecurityCacheUtils.flushAll(); + return AlitaResult.success(true); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/resource/controller/UcUrlController.java b/backend/src/main/java/com/senmesh/usercenter/resource/controller/UcUrlController.java new file mode 100644 index 0000000..fdfbf28 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/resource/controller/UcUrlController.java @@ -0,0 +1,89 @@ +package com.senmesh.usercenter.resource.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.EnumUtil; +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.authority.dto.PermissionOperateDTO; +import com.senmesh.usercenter.constants.SecurityConstants; +import com.senmesh.usercenter.resource.dto.UrlDTO; +import com.senmesh.usercenter.resource.dto.UrlPageQueryDTO; +import com.senmesh.usercenter.resource.enums.UrlTypeEnum; +import com.senmesh.usercenter.resource.service.UcUrlService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 菜单操作 + * + * @author sr on 2019-11-05 + */ +@Api(tags = "菜单操作") +@RestController +@RequestMapping("/url") +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +//TODO 目前只有本地引用,需提供cloud调用,然后放开注释 +@ConditionalOnProperty(name = SecurityConstants.PROP_KEY_SECURITY_USELOCAL, havingValue = "true", matchIfMissing = true) +public class UcUrlController { + + private final UcUrlService urlService; + + @ApiOperation("创建菜单") + @PostMapping("/create") + public AlitaResult createUrl(@Validated(Create.class) @RequestBody UrlDTO urlDTO) { + UrlTypeEnum urlTypeEnum = EnumUtil.resolve(UrlTypeEnum::getType, urlDTO.getType()); + if (urlTypeEnum == null) { + return AlitaResult.error("资源类型错误"); + } + if (UrlTypeEnum.INTERFACE == urlTypeEnum && StringUtils.isEmpty(urlDTO.getLink())) { + return AlitaResult.error("接口地址不能为空"); + } + return AlitaResult.success(urlService.creatUrl(urlDTO)); + } + + + @ApiOperation("修改菜单") + @PostMapping("/update") + public AlitaResult updateUrl(@Validated(Update.class) @RequestBody UrlDTO urlDTO) { + return AlitaResult.success(urlService.updateUrl(urlDTO)); + } + + @ApiOperation("删除菜单") + @DeleteMapping("/delete/{id}") + public AlitaResult deleteUrl(@PathVariable Long id) { + urlService.deleteUrl(id); + return AlitaResult.success(true); + } + + @ApiOperation("菜单列表") + @GetMapping("/list") + public AlitaResult> list(@Validated UrlPageQueryDTO query) { + query.setNeedPage(false); + return AlitaResult.success(urlService.list(query)); + } + + @ApiOperation("菜单分页列表") + @GetMapping("/page") + public AlitaResult> page(@Validated UrlPageQueryDTO query) { + urlService.list(query); + return AlitaResult.success(query.getPageResult()); + } + + @ApiOperation("获取全部可分配菜单列表") + @GetMapping("/get_all_menu_list/{roleId}/{platformCode}") + public AlitaResult getAllMenuList(@PathVariable Long roleId, + @PathVariable Integer platformCode) { + return urlService.queryAllMenuList(roleId, platformCode); + } + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/resource/dao/UcComponentMapper.java b/backend/src/main/java/com/senmesh/usercenter/resource/dao/UcComponentMapper.java new file mode 100644 index 0000000..322cbe6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/resource/dao/UcComponentMapper.java @@ -0,0 +1,38 @@ +package com.senmesh.usercenter.resource.dao; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.resource.dto.ComponentDTO; +import com.senmesh.usercenter.resource.dto.ComponentPageQueryDTO; +import com.senmesh.usercenter.resource.entity.Component; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + * 组件mapper + * + * @author sr on 2019-10-15 + */ +public interface UcComponentMapper extends MyMapper { + + /** + * 获取所有组件 + * + * @return + * @author sr on 2019-11-05 + */ + @Select("select * from xs_component where deleted = 0") + List findAll(); + + /** + * 查询组件列表 + * + * @param queryDTO + * @return + */ + List list(@Param("param") ComponentPageQueryDTO queryDTO); + + + List listComponentDTO(@Param("systemCode") Integer systemCode, @Param("orgId") Long orgId); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/resource/dao/UcUrlMapper.java b/backend/src/main/java/com/senmesh/usercenter/resource/dao/UcUrlMapper.java new file mode 100644 index 0000000..faac4df --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/resource/dao/UcUrlMapper.java @@ -0,0 +1,68 @@ +package com.senmesh.usercenter.resource.dao; + +import java.util.List; +import java.util.Set; + +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.resource.dto.UrlDTO; +import com.senmesh.usercenter.resource.dto.UrlPageQueryDTO; +import com.senmesh.usercenter.resource.entity.Url; + +/** + * 菜单 + * @author sr on 2019-10-15 + */ +public interface UcUrlMapper extends MyMapper{ + + String BEAN_ID = "security.urlMapper"; + + /** + * 查询所有菜单列表 + * + * @return + * @author sr on 2019-11-05 + */ + @Select("select * from xs_url where deleted = 0 and platform_code = #{platformCode} order by resource_order") + List findAll(Integer platformCode); + + /** + * 查询所有菜单 + * + * @return + */ + List findAllUrl(Integer platformCode, Long orgId); + + + /** + * 查询所有一级菜单列表 + * + * @param menuQuery 查询条件 + */ +// List selectAllParentMenuList(@Param("param") MenuQuery menuQuery, Page page); + + /** + * 查询所有二级菜单列表 + * @param parentIdList 一级菜单ID + */ + List selectAllChildMenuList(@Param("parentIdList") List parentIdList); + + /** + * 根据Id查询父级ID + * + * @param resourceIds + * @return + */ + Set selectParentIdByResourceIds(@Param("resourceIds") List resourceIds); + + /**************************** 下面的是最新方法 , 上面的逐步删除 *******************************/ + + List list(@Param("param") UrlPageQueryDTO urlQueryDTO); + + int batchDeleted(@Param("urlIds") Set urlIds); + + List listUrlDTO(@Param("systemCode") Integer systemCode, @Param("orgId") Long orgId); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/resource/dto/ComponentDTO.java b/backend/src/main/java/com/senmesh/usercenter/resource/dto/ComponentDTO.java new file mode 100644 index 0000000..e761bad --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/resource/dto/ComponentDTO.java @@ -0,0 +1,69 @@ +package com.senmesh.usercenter.resource.dto; + +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Optional; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +import org.springframework.security.access.ConfigAttribute; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.senmesh.common.validation.Create; +import com.senmesh.usercenter.dto.Resource; +import com.senmesh.usercenter.dto.ResourceDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2019-10-15 + */ +@ApiModel("组件") +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class ComponentDTO extends ResourceDTO implements Resource{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("菜单id") + @NotNull(message = "组件所属菜单id不能为空", groups = {Create.class}) + private Long urlId; + + @ApiModelProperty("组件编码") + @NotEmpty(message = "组件不能为空", groups = {Create.class}) + private String code; + + @ApiModelProperty("组件名称") + private String name; + + @ApiModelProperty("平台编码") + @NotNull(message = "平台编码不能为空", groups = {Create.class}) + private Integer platformCode; + + private List attributes; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + + + @Override + public List getAttributes() { + return Optional.ofNullable(attributes).orElse(Collections.emptyList()); + } + + + +} + diff --git a/backend/src/main/java/com/senmesh/usercenter/resource/dto/ComponentPageQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/resource/dto/ComponentPageQueryDTO.java new file mode 100644 index 0000000..74be149 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/resource/dto/ComponentPageQueryDTO.java @@ -0,0 +1,30 @@ +package com.senmesh.usercenter.resource.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * @author chenyun + * @description + * @date 2020/9/3 10:29 + */ +@ApiModel("菜单查询") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ComponentPageQueryDTO extends PageQueryDTO { + private static final long serialVersionUID = 573525736440675929L; + + /** + * 菜单Id + */ + @NotNull(message = "菜单ID不能为空") + @ApiModelProperty("菜单ID") + private Long urlId; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/resource/dto/UrlDTO.java b/backend/src/main/java/com/senmesh/usercenter/resource/dto/UrlDTO.java new file mode 100644 index 0000000..76f03f8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/resource/dto/UrlDTO.java @@ -0,0 +1,120 @@ +package com.senmesh.usercenter.resource.dto; + +import java.util.Date; +import java.util.List; +import java.util.Optional; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import org.springframework.data.annotation.Transient; +import org.springframework.security.access.ConfigAttribute; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.google.common.collect.Lists; +import com.senmesh.common.util.TreeNode; +import com.senmesh.common.validation.Create; +import com.senmesh.usercenter.dto.Resource; +import com.senmesh.usercenter.dto.ResourceDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2019-10-15 + */ +@ApiModel("菜单") +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class UrlDTO extends ResourceDTO implements Resource, TreeNode { + private static final long serialVersionUID = 3185997122725142996L; + + @ApiModelProperty("资源名称(如果是按钮,从数据字典表取名称)") + @NotBlank(message = "菜单名称不能为空", groups = {Create.class}) + private String name; + + @ApiModelProperty("链接") + private String link; + + @ApiModelProperty("资源图标") + private String icon; + + @ApiModelProperty("对应的父资源ID,一级资源=0") + private Long parentId; + + @ApiModelProperty("排序") + private Integer resourceOrder; + + @ApiModelProperty("是否可见") + private Boolean visible; + + @ApiModelProperty("描述") + private String description; + + @ApiModelProperty("资源类型 1:菜单 2:接口") + @NotNull(message = "资源类型不能为空", groups = {Create.class}) + private Integer type; + + @ApiModelProperty("所属平台") + @NotNull(message = "平台编码不能为空", groups = {Create.class}) + private Integer platformCode; + + @ApiModelProperty("是否删除: 0-否 1-是") + private Integer deleted; + + @ApiModelProperty("创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + + private List children = Lists.newArrayList(); + + private List components = Lists.newArrayList(); + + public List getChildren() { + if (this.children == null) { + this.children = Lists.newArrayList(); + } + return this.children; + } + + public void setChildren(List children) { + this.children = children; + } + + public List getComponents() { + return components; + } + + + @Transient + private List attributes; + + @Override + public List getAttributes() { + return Optional.ofNullable(attributes).orElse(Lists.newArrayList()); + } + + @Override + public void addChildren(UrlDTO node) { + List urlDTOS = Optional.ofNullable(getChildren()) + .orElse(Lists.newArrayList()); + urlDTOS.add(node); + setChildren(urlDTOS); + } + + public Long getParentId() { + return Optional.ofNullable(parentId).orElse(0L); + } + + public Boolean getVisible() { + return Optional.ofNullable(visible).orElse(Boolean.TRUE); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/resource/dto/UrlPageQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/resource/dto/UrlPageQueryDTO.java new file mode 100644 index 0000000..f802fa7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/resource/dto/UrlPageQueryDTO.java @@ -0,0 +1,39 @@ +package com.senmesh.usercenter.resource.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Optional; + +/** + * @author chenyun + * @description + * @date 2020/9/3 10:29 + */ +@ApiModel("菜单查询") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UrlPageQueryDTO extends PageQueryDTO { + private static final long serialVersionUID = 573525736440675929L; + + @ApiModelProperty("平台编码") + private Integer platformCode; + + @ApiModelProperty("是否需要树形结构,默认不是树形") + private Boolean tree; + + @ApiModelProperty("资源类型 1:菜单 2:接口") + private Integer type; + + @ApiModelProperty("对应的父资源ID,一级资源=0") + private Long parentId; + + public Boolean getTree() { + return Optional.ofNullable(tree).orElse(Boolean.FALSE); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/resource/entity/Component.java b/backend/src/main/java/com/senmesh/usercenter/resource/entity/Component.java new file mode 100644 index 0000000..0b09d89 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/resource/entity/Component.java @@ -0,0 +1,62 @@ +package com.senmesh.usercenter.resource.entity; + +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 组件 + * + * @author sr on 2019-10-10 + */ +@TableName("xs_component") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Data +public class Component extends BaseEntity { + + /** + * + **/ + private static final long serialVersionUID = 6157400267849631575L; + + /** + * 菜单id + **/ + private Long urlId; + + /** + * 组件编码 + **/ + private String code; + + /** + * 组件名称 + **/ + private String name; + + /** + * 平台编码 + */ + private Integer platformCode; + + + @Builder + public Component(Long id, Boolean deleted, Long createBy, Date createTime, Long updateBy, + Date updateTime, Long proxyBy, Long urlId, String code, String name, Integer platformCode) { + super(id, deleted, createBy, createTime, updateBy, updateTime, proxyBy); + this.urlId = urlId; + this.code = code; + this.name = name; + this.platformCode = platformCode; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/resource/entity/Url.java b/backend/src/main/java/com/senmesh/usercenter/resource/entity/Url.java new file mode 100644 index 0000000..c4d05b8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/resource/entity/Url.java @@ -0,0 +1,86 @@ +package com.senmesh.usercenter.resource.entity; + +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author chenyun + * @description 菜单资源表 + * @date 2020/9/2 16:20 + */ +@Data +@TableName("xs_url") +@NoArgsConstructor +@AllArgsConstructor +public class Url extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** + * 资源名称(如果是按钮,从数据字典表取名称) + **/ + private String name; + + /** + * 链接 + **/ + private String link; + + /** + * 资源图标 + **/ + private String icon; + + /** + * 对应的父资源ID,一级资源=0 + **/ + private Long parentId; + + /** + * 排序 + **/ + private Integer resourceOrder; + + /** + * 是否可见 + **/ + private Boolean visible; + + /** + * 描述 + **/ + private String description; + + /** + * 所属平台 + */ + private Integer platformCode; + + /** + * 资源类型 1:菜单 2:接口 + */ + private Integer type; + + @Builder + public Url(Long id, Boolean deleted, Long createBy, Date createTime, Long updateBy, + Date updateTime, Long proxyBy, String name, String link, String icon, Long parentId, + Integer resourceOrder, Boolean visible, String description, Integer platformCode, + Integer type) { + super(id, deleted, createBy, createTime, updateBy, updateTime, proxyBy); + this.name = name; + this.link = link; + this.icon = icon; + this.parentId = parentId; + this.resourceOrder = resourceOrder; + this.visible = visible; + this.description = description; + this.platformCode = platformCode; + this.type = type; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/resource/enums/UrlTypeEnum.java b/backend/src/main/java/com/senmesh/usercenter/resource/enums/UrlTypeEnum.java new file mode 100644 index 0000000..60cb001 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/resource/enums/UrlTypeEnum.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.resource.enums; + +import com.baomidou.mybatisplus.annotation.EnumValue; +import com.senmesh.mybatis.handle.BaseEnum; + +/** + * xs_url type 枚举类 + */ +public enum UrlTypeEnum implements BaseEnum { + + MENU(1, "菜单"), + INTERFACE(2, "接口"); + + @EnumValue + private Integer type; + + private String desc; + + UrlTypeEnum(Integer type, String desc) { + this.type = type; + this.desc = desc; + } + + public Integer getType() { + return type; + } + + public String getDesc() { + return desc; + } + + @Override + public Integer getValue() { + return this.type; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/resource/mapper/UcComponentMapper.xml b/backend/src/main/java/com/senmesh/usercenter/resource/mapper/UcComponentMapper.xml new file mode 100644 index 0000000..c702603 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/resource/mapper/UcComponentMapper.xml @@ -0,0 +1,40 @@ + + + + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/resource/mapper/UcUrlMapper.xml b/backend/src/main/java/com/senmesh/usercenter/resource/mapper/UcUrlMapper.xml new file mode 100644 index 0000000..6eb32bc --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/resource/mapper/UcUrlMapper.xml @@ -0,0 +1,123 @@ + + + + + SELECT + id, + name, + link, + icon, + parent_id, + resource_order, + type, + visible, + description, + deleted, + create_time, + platform_code + FROM + xs_url + + + + + + + + + + + + update xs_url set deleted = TRUE + where id in + + #{urlId} + + AND deleted = FALSE + + + + + diff --git a/backend/src/main/java/com/senmesh/usercenter/resource/mapstruct/ResourceMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/resource/mapstruct/ResourceMapMapper.java new file mode 100644 index 0000000..57ee546 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/resource/mapstruct/ResourceMapMapper.java @@ -0,0 +1,31 @@ +package com.senmesh.usercenter.resource.mapstruct; + +import com.senmesh.usercenter.authority.dto.PermissionDTO; +import com.senmesh.usercenter.authority.entity.Permission; +import com.senmesh.usercenter.resource.dto.ComponentDTO; +import com.senmesh.usercenter.resource.dto.UrlDTO; +import com.senmesh.usercenter.resource.entity.Component; +import com.senmesh.usercenter.resource.entity.Url; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * @author sr on 2020-08-27 + */ +@Mapper +public interface ResourceMapMapper { + + ResourceMapMapper instance = Mappers.getMapper(ResourceMapMapper.class); + + @Mapping(target = "deleted", expression = "java(Boolean.TRUE.equals(url.getDeleted())?1:0)") + UrlDTO exchange(Url url); + + ComponentDTO exchange(Component component); + + Component exchange(ComponentDTO componentDTO); + + List exchange(List permissionDTOList); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/resource/service/UcComponentService.java b/backend/src/main/java/com/senmesh/usercenter/resource/service/UcComponentService.java new file mode 100644 index 0000000..a90a3ce --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/resource/service/UcComponentService.java @@ -0,0 +1,42 @@ +package com.senmesh.usercenter.resource.service; + +import com.senmesh.usercenter.resource.dto.ComponentDTO; +import com.senmesh.usercenter.resource.dto.ComponentPageQueryDTO; + +import java.util.List; + + +/** + * 组件权限服务接口 + * + * @author on 2019-11-05 + */ +public interface UcComponentService { + + /** + * 新增组件 + * + * @param componentDTO + * @author sr on 2019-10-15 + */ + ComponentDTO creatComponent(ComponentDTO componentDTO); + + /** + * 修改组件 + * + * @param componentDTO + * @author sr on 2019-10-15 + */ + ComponentDTO updateComponent(ComponentDTO componentDTO); + + /** + * 删除组件 + * + * @param componentId + * @author sr on 2019-10-15 + */ + ComponentDTO deleteComponent(Long componentId); + + + List list(ComponentPageQueryDTO queryDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/resource/service/UcResourceService.java b/backend/src/main/java/com/senmesh/usercenter/resource/service/UcResourceService.java new file mode 100644 index 0000000..d198bba --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/resource/service/UcResourceService.java @@ -0,0 +1,20 @@ +package com.senmesh.usercenter.resource.service; + +import com.senmesh.usercenter.authority.dto.PermissionOperateDTO; + +/** + * 所有资源service + * @author sr on 2019-10-16 + */ +public interface UcResourceService { + + /** + * 保存业务角色权限 + * @param orgId + * @param permissionDTO + * @param operateUserId + * @author sr on 2019-10-17 + */ + void saveBusinessPermission(Long orgId, PermissionOperateDTO permissionDTO, Long operateUserId); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/resource/service/UcUrlService.java b/backend/src/main/java/com/senmesh/usercenter/resource/service/UcUrlService.java new file mode 100644 index 0000000..bdd4cb4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/resource/service/UcUrlService.java @@ -0,0 +1,72 @@ +package com.senmesh.usercenter.resource.service; + +import com.senmesh.common.AlitaResult; +import com.senmesh.usercenter.authority.dto.PermissionDTO; +import com.senmesh.usercenter.authority.dto.PermissionOperateDTO; +import com.senmesh.usercenter.authority.dto.PermissionPageQueryDTO; +import com.senmesh.usercenter.authority.dto.PermissionResourcesDTO; +import com.senmesh.usercenter.resource.dto.UrlDTO; +import com.senmesh.usercenter.resource.dto.UrlPageQueryDTO; + +import java.util.List; + + +/** + * 菜单服务接口 + * + * @author on 2019-11-05 + */ +public interface UcUrlService { + + /** + * 新增菜单 + * + * @param urlDTO + * @author sr on 2019-10-15 + */ + UrlDTO creatUrl(UrlDTO urlDTO); + + /** + * 修改菜单 + * + * @param urlDTO + * @author sr on 2019-10-15 + */ + UrlDTO updateUrl(UrlDTO urlDTO); + + /** + * 删除菜单 + * + * @param urlId + * @author sr on 2019-10-15 + */ + UrlDTO deleteUrl(Long urlId); + + /** + * 查询角色可分配的所有菜单列表 + * + * @return + */ + AlitaResult queryAllMenuList(Long roleId, Integer platformCode); + + + /** + * 资源列表 + * + * @param queryDTO + * @return + */ + List list(UrlPageQueryDTO queryDTO); + + + /** + * 查询角色/菜单下对应的组件或接口 + * + * @param permissionPageQueryDTO @return + * @return + */ + List queryAllResourceList( + PermissionPageQueryDTO permissionPageQueryDTO); + + void saveUrlResourcesOperateDTO(PermissionResourcesDTO permissionResourcesDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/resource/service/impl/UcComponentServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/resource/service/impl/UcComponentServiceImpl.java new file mode 100644 index 0000000..2238946 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/resource/service/impl/UcComponentServiceImpl.java @@ -0,0 +1,63 @@ +package com.senmesh.usercenter.resource.service.impl; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.cache.SecurityCacheUtils; +import com.senmesh.usercenter.constants.SecurityConstants; +import com.senmesh.usercenter.resource.dao.UcComponentMapper; +import com.senmesh.usercenter.resource.dto.ComponentDTO; +import com.senmesh.usercenter.resource.dto.ComponentPageQueryDTO; +import com.senmesh.usercenter.resource.entity.Component; +import com.senmesh.usercenter.resource.mapstruct.ResourceMapMapper; +import com.senmesh.usercenter.resource.service.UcComponentService; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 组件 + * + * @author sr on 2019-10-15 + */ +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +//TODO 目前只有本地引用,需提供cloud调用,然后放开注释 +@ConditionalOnProperty(name = SecurityConstants.PROP_KEY_SECURITY_USELOCAL, havingValue = "true", matchIfMissing = true) +public class UcComponentServiceImpl implements UcComponentService { + + private final UcComponentMapper ucComponentMapper; + + @Override + public ComponentDTO creatComponent(ComponentDTO componentDTO) { + Component component = ResourceMapMapper.instance.exchange(componentDTO); + ucComponentMapper.saveEntity(component, UserContextHolder.getExistLoginSuperiorId()); + SecurityCacheUtils.flushAll(); + return ResourceMapMapper.instance.exchange(component); + } + + @Override + public ComponentDTO updateComponent(ComponentDTO componentDTO) { + Component component = ResourceMapMapper.instance.exchange(componentDTO); + Assert.isTrue(ucComponentMapper.updateEntitySelective(component, UserContextHolder.getExistLoginSuperiorId()) == 1 + , "更新组件失败"); + SecurityCacheUtils.flushAll(); + return ResourceMapMapper.instance.exchange(component); + } + + @Override + public ComponentDTO deleteComponent(Long componentId) { + Component component = Component.builder().id(componentId).build(); + Assert.isTrue(ucComponentMapper.deleteEntity(component, UserContextHolder.getExistLoginSuperiorId()) == 1, + "删除组件失败"); + SecurityCacheUtils.flushAll(); + return ResourceMapMapper.instance.exchange(component); + } + + @Override + public List list(ComponentPageQueryDTO queryDTO) { + return ucComponentMapper.list(queryDTO); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/resource/service/impl/UcResourceServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/resource/service/impl/UcResourceServiceImpl.java new file mode 100644 index 0000000..b3c760c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/resource/service/impl/UcResourceServiceImpl.java @@ -0,0 +1,190 @@ +package com.senmesh.usercenter.resource.service.impl; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.google.common.collect.Lists; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.util.ExceptionUtils; +import com.senmesh.usercenter.authority.constants.PermissionConstants; +import com.senmesh.usercenter.authority.dao.UcPermissionMapper; +import com.senmesh.usercenter.authority.dao.UcRoleMapper; +import com.senmesh.usercenter.authority.dto.PermissionOperateDTO; +import com.senmesh.usercenter.authority.entity.Permission; +import com.senmesh.usercenter.cache.SecurityCacheEvict; +import com.senmesh.usercenter.constants.RoleConstants; +import com.senmesh.usercenter.constants.SecurityExceptionMsg; +import com.senmesh.usercenter.dto.ResourceDTO; +import com.senmesh.usercenter.resource.dao.UcComponentMapper; +import com.senmesh.usercenter.resource.dao.UcUrlMapper; +import com.senmesh.usercenter.resource.dto.ComponentDTO; +import com.senmesh.usercenter.resource.dto.UrlDTO; +import com.senmesh.usercenter.resource.service.UcResourceService; +import com.senmesh.usercenter.utils.PermissionUtils; + +/** + * 所有资源 + * + * @author sr on 2019-10-16 + */ +@Service +public class UcResourceServiceImpl implements UcResourceService { + + @Autowired + private UcComponentMapper ucComponentMapper; + + @Autowired + private UcUrlMapper ucUrlMapper; + + @Autowired + private UcPermissionMapper permissionMapper; + + @Autowired + private UcRoleMapper roleMapper; + + @Override + @Transactional(rollbackFor = RuntimeException.class) + @SecurityCacheEvict + public void saveBusinessPermission(Long orgId, PermissionOperateDTO permissionDTO, Long operateUserId) { + Long roleId = permissionDTO.getRoleId(); + checkRoleType(orgId, roleId, RoleConstants.ROLE_TYPE_BUSINESS); + dealResourceIds(roleId, permissionDTO.getResourceIds(), operateUserId); + } + + /** + * 校验对应机构下是否有对应角色 + * @param orgId + * @param roleId + * @param roleType + * @author sr on 2019-10-17 + */ + private void checkRoleType(Long orgId, Long roleId, String roleType) { + int num = roleMapper.existRole(orgId, roleId, roleType); + ExceptionUtils.throwBusinessException(num == 0, SecurityExceptionMsg.ORG_ROLE_NOT_EXIST); + } + + /** + * 根据给定权限资源id列表重新分配权限 + * @param operateUserId + * @author sr on 2019-10-21 + */ + private void dealResourceIds(Long roleId, List resourceIdStrings, Long operateUserId){ + // 获取roleId已存在的权限 + List permissions = permissionMapper.findByRoleId(roleId); + + Map permissionMap = permissions.stream() + .collect(Collectors.toMap(p -> StringUtils.join(p.getResourceType(), CommonConstants.UNDERLINE, p.getResourceId()), p -> p, (p1, p2) -> p1)); + + List createPermissions = Lists.newArrayList(); + List deletePermissions = null; + + resourceIdStrings.forEach(resourceIdString -> { + String[] resourceArray = resourceIdString.split(CommonConstants.UNDERLINE); + String resourceType = resourceArray[0]; + Long resourceId = Long.valueOf(resourceArray[1]); + Permission permission = permissionMap.get(resourceIdString); + if (permission == null) { + // 新增 + createPermissions.add(PermissionUtils.createPermission(roleId, resourceType, resourceId)); + return ; + } + // 不变 + permissionMap.remove(resourceIdString); + }); + // 删除 + deletePermissions = Lists.newArrayList(permissionMap.values()); + if (CollectionUtils.isNotEmpty(deletePermissions)) { + permissionMapper.deleteEntites(deletePermissions, operateUserId); + } + permissionMapper.saveEntites(createPermissions, operateUserId); + } + + + /** + * 处理前端传入角色权限树,变更已存在角色权限 + * @param permissionDTO + * @param operateUserId + * @author sr on 2019-10-17 + */ + @SuppressWarnings("unused") + private void dealResource(PermissionOperateDTO permissionDTO, Long operateUserId) { + Long roleId = permissionDTO.getRoleId(); + List urlDTOs = permissionDTO.getUrlDTOs(); + // 获取roleId已存在的权限 + List permissions = permissionMapper.findByRoleId(roleId); + + Map permissionMap = permissions.stream() + .collect(Collectors.toMap(p -> StringUtils.join(p.getResourceType(), CommonConstants.UNDERLINE, p.getResourceId()), p -> p)); + + List createPermissions = Lists.newArrayList(); + List deletePermissions = Lists.newArrayList(); + urlDTOs.stream().forEach(urlDTO -> dealUrlDTO(roleId, urlDTO, permissionMap, createPermissions, deletePermissions)); + permissionMapper.saveEntites(createPermissions, operateUserId); + permissionMapper.deleteEntites(deletePermissions, operateUserId); + + } + + /** + * 处理菜单权限(包含自己,子菜单,子组件) + * @param roleId + * @param urlDTO + * @param permissionMap + * @param createPermissions + * @param deletePermissions + * @author sr on 2019-10-17 + */ + private void dealUrlDTO(Long roleId, UrlDTO urlDTO, Map permissionMap, List createPermissions, List deletePermissions) { + // 处理当前菜单 + dealResource(roleId, urlDTO, permissionMap, createPermissions, deletePermissions); + List components = urlDTO.getComponents(); + // 处理组件 + if (CollectionUtils.isNotEmpty(components)) { + components.forEach(component -> dealResource(roleId, component, permissionMap, createPermissions, deletePermissions)); + } + // 处理子菜单 + List childrenUrlDTOs = urlDTO.getChildren(); + if (CollectionUtils.isEmpty(childrenUrlDTOs)) { + return ; + } + childrenUrlDTOs.stream().forEach(childrenUrlDTO -> dealUrlDTO(roleId, urlDTO, permissionMap, createPermissions, deletePermissions)); + } + + /** + * 处理单个资源权限(菜单/组件) + * @param roleId + * @param resourceDTO + * @param permissionMap + * @param createPermissions + * @param deletePermissions + * @author sr on 2019-10-17 + */ + private void dealResource(Long roleId, ResourceDTO resourceDTO, Map permissionMap, List createPermissions, List deletePermissions) { + String resourceType = null; + if (resourceDTO instanceof UrlDTO) { + resourceType = PermissionConstants.RESOURCE_TYPE_URL; + } else if (resourceDTO instanceof ComponentDTO) { + resourceType = PermissionConstants.RESOURCE_TYPE_COMPONENT; + } else { + return; + } + Long resourceId = resourceDTO.getId(); + Boolean selected = resourceDTO.getSelected(); + String key = StringUtils.join(resourceType, CommonConstants.UNDERLINE, resourceId); + Permission permission = permissionMap.get(key); + if (permission != null && !Boolean.TRUE.equals(selected)) { + // 删除 + deletePermissions.add(permission); + } else if (permission == null && Boolean.TRUE.equals(selected)) { + // 新增 + createPermissions.add(PermissionUtils.createPermission(roleId, PermissionConstants.RESOURCE_TYPE_COMPONENT, resourceId)); + } + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/resource/service/impl/UcUrlServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/resource/service/impl/UcUrlServiceImpl.java new file mode 100644 index 0000000..d82db71 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/resource/service/impl/UcUrlServiceImpl.java @@ -0,0 +1,184 @@ +package com.senmesh.usercenter.resource.service.impl; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.exception.util.ExceptionUtils; +import com.senmesh.common.util.TreeHelper; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.authority.constants.PermissionConstants; +import com.senmesh.usercenter.authority.dao.UcPermissionMapper; +import com.senmesh.usercenter.authority.dto.PermissionDTO; +import com.senmesh.usercenter.authority.dto.PermissionOperateDTO; +import com.senmesh.usercenter.authority.dto.PermissionPageQueryDTO; +import com.senmesh.usercenter.authority.dto.PermissionResourcesDTO; +import com.senmesh.usercenter.cache.SecurityCacheUtils; +import com.senmesh.usercenter.constants.SecurityConstants; +import com.senmesh.usercenter.resource.dao.UcUrlMapper; +import com.senmesh.usercenter.resource.dto.UrlDTO; +import com.senmesh.usercenter.resource.dto.UrlPageQueryDTO; +import com.senmesh.usercenter.resource.entity.Url; +import com.senmesh.usercenter.resource.mapstruct.ResourceMapMapper; +import com.senmesh.usercenter.resource.service.UcUrlService; +import com.senmesh.usercenter.utils.UrlUtils; +import lombok.RequiredArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 菜单 + * + * @author sr on 2019-10-15 + */ +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +//TODO 目前只有本地引用,需提供cloud调用,然后放开注释 +@ConditionalOnProperty(name = SecurityConstants.PROP_KEY_SECURITY_USELOCAL, havingValue = "true", matchIfMissing = true) +public class UcUrlServiceImpl implements UcUrlService { + + private final UcUrlMapper ucUrlMapper; + + private final UcPermissionMapper ucPermissionMapper; + + @Override + public UrlDTO creatUrl(UrlDTO urlDTO) { + Url url = UrlUtils.toCreateUrl(urlDTO); + ucUrlMapper.saveEntity(url, UserContextHolder.getExistLoginSuperiorId()); + SecurityCacheUtils.flushAll(); + return ResourceMapMapper.instance.exchange(url); + } + + @Override + public UrlDTO updateUrl(UrlDTO urlDTO) { + Url url = UrlUtils.toUpdateUrl(urlDTO); + Assert.isTrue( + ucUrlMapper.updateEntity(url, UserContextHolder.getExistLoginSuperiorId()) == 1, + "更新菜单失败"); + SecurityCacheUtils.flushAll(); + return ResourceMapMapper.instance.exchange(url); + } + + @Override + @Transactional(rollbackFor = RuntimeException.class) + public UrlDTO deleteUrl(Long urlId) { + Url history = ucUrlMapper.getById(urlId); + ExceptionUtils.throwBusinessException(history == null || history.getDeleted(), "菜单已被删除"); + + Url url = Url.builder().id(urlId).build(); + ExceptionUtils.throwBusinessException( + ucUrlMapper.deleteEntity(url, UserContextHolder.getExistLoginSuperiorId()) != 1, "删除菜单失败"); + + // 递归删除子菜单 + Integer platformCode = history.getPlatformCode(); + /*Arrays.stream(SystemCodeEnum.values()) + .filter(systemCodeEnum -> systemCodeEnum.getCode().equals(platformCode)) + .findFirst() + .orElseThrow(() -> new RuntimeException("菜单应用码异常"));*/ + + UrlPageQueryDTO urlQueryDTO = new UrlPageQueryDTO(); + urlQueryDTO.setNeedPage(false); + urlQueryDTO.setPlatformCode(platformCode); + List list = ucUrlMapper.list(urlQueryDTO); + if (CollectionUtils.isNotEmpty(list)) { + Set childrenNodeIds = TreeHelper.childrenNodeIds(urlId, list); + if (!childrenNodeIds.isEmpty()) { + ucUrlMapper.batchDeleted(childrenNodeIds); + } + } + SecurityCacheUtils.flushAll(); + return ResourceMapMapper.instance.exchange(url); + } + + @Override + public AlitaResult queryAllMenuList(Long roleId, Integer platformCode) { + PermissionOperateDTO permissionDTO = new PermissionOperateDTO(); + permissionDTO.setUrlDTOs(TreeHelper.buildTree(0L, ucUrlMapper.findAllUrl(platformCode, + UserContextHolder.getLoginOrgId()))); + //查询已分配的资源列表 + Set tempResourceIdSet = ucPermissionMapper.findResourceIdByRoleId(roleId, 1); + permissionDTO.setResourceIdList(new ArrayList<>(tempResourceIdSet)); + return AlitaResult.success(permissionDTO); + } + + @Override + public List list(UrlPageQueryDTO urlQueryDTO) { + List list = ucUrlMapper.list(urlQueryDTO); + if (Boolean.TRUE.equals(urlQueryDTO.getTree())) { + return TreeHelper.buildTree(0L, list); + } + return list; + } + + @Override + public List queryAllResourceList( + PermissionPageQueryDTO permissionPageQueryDTO) { + if (PermissionConstants.RESOURCE_TYPE_COMPONENT + .equals(permissionPageQueryDTO.getResourceType())) { + return + ucPermissionMapper.urlComponentList(permissionPageQueryDTO + ); + } else if (PermissionConstants.RESOURCE_TYPE_INTERFACE + .equals(permissionPageQueryDTO.getResourceType())) { + return ucPermissionMapper.urlInterfaceList(permissionPageQueryDTO); + } + return null; + } + + @Override + public void saveUrlResourcesOperateDTO(PermissionResourcesDTO permissionResourcesDTO) { + List permissionDTOList = permissionResourcesDTO + .getPermissionDTOList(); + // 获取原来已有的 + permissionResourcesDTO.setOrgId(UserContextHolder.getLoginOrgId()); + permissionResourcesDTO.setNeedPage(false); + permissionResourcesDTO.setSelected(Boolean.TRUE); + List originalPermissionDTOList = this + .queryAllResourceList(permissionResourcesDTO); + Set oldResourceIdSet = originalPermissionDTOList.stream() + .map(PermissionDTO::getResourceId) + .collect(Collectors.toSet()); + + // 获取新增的资源,顺便将旧的列表中移出已存在的资源 + if(CollectionUtils.isNotEmpty(permissionDTOList)){ + List selectedList = permissionDTOList.stream() + .filter(permissionDTO -> { + permissionDTO.setAttribute("ROLE_" + permissionDTO.getRoleId()); + Long newResourceId = permissionDTO.getResourceId(); + boolean exist = oldResourceIdSet.contains(newResourceId); + // 移出已存在的资源 + if (exist) { + oldResourceIdSet.remove(newResourceId); + }else{ + permissionDTO.setId(null); + } + return !exist; + }) + .collect(Collectors.toList()); + + // 新增(在新的中排除老的就是新增的) + if (CollectionUtils.isNotEmpty(selectedList)) { + ucPermissionMapper + .saveEntites(ResourceMapMapper.instance.exchange(selectedList), + UserContextHolder.getLoginUserId()); + } + } + + // 删除(将老的中排除新增的就是要删除的) + List removeList = originalPermissionDTOList.stream() + .filter(permissionDTO -> oldResourceIdSet.contains(permissionDTO.getResourceId())) + .collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(removeList)) { + ucPermissionMapper + .deleteEntites(ResourceMapMapper.instance.exchange(removeList), + UserContextHolder.getLoginUserId()); + } + + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/searchHistory/controller/SearchHistoryController.java b/backend/src/main/java/com/senmesh/usercenter/searchHistory/controller/SearchHistoryController.java new file mode 100644 index 0000000..c0fa49a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/searchHistory/controller/SearchHistoryController.java @@ -0,0 +1,45 @@ +package com.senmesh.usercenter.searchHistory.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.searchHistory.dto.SearchHistoryCreateDTO; +import com.senmesh.usercenter.searchHistory.dto.SearchHistoryInfoDTO; +import com.senmesh.usercenter.searchHistory.dto.SearchHistoryPageQueryDTO; +import com.senmesh.usercenter.searchHistory.service.SearchHistoryService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * @author czy on 2021-03-25 + */ +@RestController +@RequestMapping("search_history") +@Api(tags = "搜索记录") +public class SearchHistoryController { + + @Autowired + private SearchHistoryService searchHistoryService; + + @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create(@RequestBody SearchHistoryCreateDTO createDTO) { + searchHistoryService.create(createDTO); + return AlitaResult.success(); + } + + @GetMapping("/page") + @ApiOperation("列表") + public AlitaResult> page(SearchHistoryPageQueryDTO pageQueryDTO) { + searchHistoryService.page(pageQueryDTO); + return AlitaResult.success(pageQueryDTO.getPageResult()); + } + + @PostMapping("/clean_all") + @ApiOperation("删除") + public AlitaResult cleanAll() { + searchHistoryService.cleanAll(); + return AlitaResult.success(); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/searchHistory/dao/SearchHistoryMapper.java b/backend/src/main/java/com/senmesh/usercenter/searchHistory/dao/SearchHistoryMapper.java new file mode 100644 index 0000000..241af56 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/searchHistory/dao/SearchHistoryMapper.java @@ -0,0 +1,22 @@ +package com.senmesh.usercenter.searchHistory.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.senmesh.usercenter.searchHistory.dto.SearchHistoryInfoDTO; +import com.senmesh.usercenter.searchHistory.dto.SearchHistoryPageQueryDTO; +import com.senmesh.usercenter.searchHistory.entity.SearchHistory; + +import java.util.List; + + +/** + * 搜索历史映射器 + * + * @author Carlye + * @date 2021/10/22 + */ +public interface SearchHistoryMapper extends BaseMapper { + + + List page(SearchHistoryPageQueryDTO queryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/searchHistory/dto/SearchHistoryCreateDTO.java b/backend/src/main/java/com/senmesh/usercenter/searchHistory/dto/SearchHistoryCreateDTO.java new file mode 100644 index 0000000..d279ae1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/searchHistory/dto/SearchHistoryCreateDTO.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.searchHistory.dto; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseDTO; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + + +/** + * 搜索历史记录 + * + * @author Carlye + * @date 2021/10/22 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Data +public class SearchHistoryCreateDTO extends BaseDTO{ + + + private static final long serialVersionUID = -4903984190748073753L; + /** + * 搜索内容 + */ + @NotEmpty(message = "搜索内容不能为空") + private String context; + + /** + * 搜索类目 1:招聘系统搜索记录 + */ + @NotNull(message = "搜索类目不能为空") + private Integer type; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/searchHistory/dto/SearchHistoryInfoDTO.java b/backend/src/main/java/com/senmesh/usercenter/searchHistory/dto/SearchHistoryInfoDTO.java new file mode 100644 index 0000000..3c75fb3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/searchHistory/dto/SearchHistoryInfoDTO.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.searchHistory.dto; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + + +/** + * 搜索历史记录 + * + * @author Carlye + * @date 2021/10/22 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Data +@ApiModel("搜索历史记录") +public class SearchHistoryInfoDTO extends BaseDTO{ + + private static final long serialVersionUID = 4107885503029801211L; + /** + * 搜索内容 + */ + @ApiModelProperty("搜索内容") + private String context; + + + @ApiModelProperty("搜索次数") + private Integer count; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/searchHistory/dto/SearchHistoryPageQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/searchHistory/dto/SearchHistoryPageQueryDTO.java new file mode 100644 index 0000000..53f39b1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/searchHistory/dto/SearchHistoryPageQueryDTO.java @@ -0,0 +1,42 @@ +package com.senmesh.usercenter.searchHistory.dto; + +import com.senmesh.common.dto.PageQueryDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + + +/** + * 搜索历史记录 + * + * @author Carlye + * @date 2021/10/22 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Data +@ApiModel("搜索历史记录 - 查询DTO") +public class SearchHistoryPageQueryDTO extends PageQueryDTO { + + private static final long serialVersionUID = 6186970573776391657L; + + /** + * 搜索内容 + */ + @ApiModelProperty("搜索内容") + private String context; + + /** + * 搜索类目 1:招聘系统搜索记录 + */ + @ApiModelProperty("搜索类目") + private Integer type; + + private Long userId; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/searchHistory/entity/SearchHistory.java b/backend/src/main/java/com/senmesh/usercenter/searchHistory/entity/SearchHistory.java new file mode 100644 index 0000000..97f0129 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/searchHistory/entity/SearchHistory.java @@ -0,0 +1,46 @@ +package com.senmesh.usercenter.searchHistory.entity; + +import java.io.Serializable; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + + +/** + * 搜索历史记录 + * + * @author Carlye + * @date 2021/10/22 + */ +@TableName("xs_search_history") +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Data +public class SearchHistory extends BaseEntity implements Serializable { + + private static final long serialVersionUID = 3512068172003223792L; + + /** + * 搜索内容 + */ + private String context; + + /** + * 搜索类目 1:招聘系统搜索记录 + */ + private Integer type; + + /** + * 用户ID + */ + private Long userId; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/searchHistory/enums/SearchHistoryTypeEnum.java b/backend/src/main/java/com/senmesh/usercenter/searchHistory/enums/SearchHistoryTypeEnum.java new file mode 100644 index 0000000..1ee5618 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/searchHistory/enums/SearchHistoryTypeEnum.java @@ -0,0 +1,38 @@ +package com.senmesh.usercenter.searchHistory.enums; + +import com.baomidou.mybatisplus.annotation.EnumValue; +import com.senmesh.mybatis.handle.BaseEnum; + + +/** + * 关联类型枚举 + * + * @author Carlye + * @date 2021/01/21 + */ +public enum SearchHistoryTypeEnum implements BaseEnum { + POST(1, "招聘系统搜索记录"); + + @EnumValue + private final Integer type; + + private final String desc; + + SearchHistoryTypeEnum(Integer type, String desc) { + this.type = type; + this.desc = desc; + } + + public Integer getType() { + return type; + } + + public String getDesc() { + return desc; + } + + @Override + public Integer getValue() { + return type; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/searchHistory/mapper/SearchHistoryMapper.xml b/backend/src/main/java/com/senmesh/usercenter/searchHistory/mapper/SearchHistoryMapper.xml new file mode 100644 index 0000000..0925f25 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/searchHistory/mapper/SearchHistoryMapper.xml @@ -0,0 +1,20 @@ + + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/searchHistory/service/SearchHistoryService.java b/backend/src/main/java/com/senmesh/usercenter/searchHistory/service/SearchHistoryService.java new file mode 100644 index 0000000..e3e04c7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/searchHistory/service/SearchHistoryService.java @@ -0,0 +1,42 @@ +package com.senmesh.usercenter.searchHistory.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.senmesh.usercenter.searchHistory.dto.SearchHistoryCreateDTO; +import com.senmesh.usercenter.searchHistory.dto.SearchHistoryInfoDTO; +import com.senmesh.usercenter.searchHistory.dto.SearchHistoryPageQueryDTO; +import com.senmesh.usercenter.searchHistory.entity.SearchHistory; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.groups.Default; +import java.util.List; + +/** + * 搜索历史记录服务 + * + * @author Carlye + * @date 2021/10/22 + */ +@Validated(Default.class) +public interface SearchHistoryService extends IService { + + /** + * 新建搜索记录 + * + * @param createDTO 创建dto + */ + void create(@Valid SearchHistoryCreateDTO createDTO); + + /** + * 分页查询搜索记录 + * + * @param queryDTO 查询dto + * @return {@link List}<{@link SearchHistoryInfoDTO}> + */ + List page(SearchHistoryPageQueryDTO queryDTO); + + /** + * 清楚所有的搜搜记录 + */ + void cleanAll(); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/searchHistory/service/impl/SearchHistoryServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/searchHistory/service/impl/SearchHistoryServiceImpl.java new file mode 100644 index 0000000..a38795a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/searchHistory/service/impl/SearchHistoryServiceImpl.java @@ -0,0 +1,47 @@ +package com.senmesh.usercenter.searchHistory.service.impl; + +import cn.hutool.core.date.DateUtil; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.searchHistory.dao.SearchHistoryMapper; +import com.senmesh.usercenter.searchHistory.dto.SearchHistoryCreateDTO; +import com.senmesh.usercenter.searchHistory.dto.SearchHistoryInfoDTO; +import com.senmesh.usercenter.searchHistory.dto.SearchHistoryPageQueryDTO; +import com.senmesh.usercenter.searchHistory.entity.SearchHistory; +import com.senmesh.usercenter.searchHistory.service.SearchHistoryService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Slf4j +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class SearchHistoryServiceImpl extends ServiceImpl implements SearchHistoryService { + + + @Override + public void create(SearchHistoryCreateDTO createDTO) { + save(SearchHistory.builder().context(createDTO.getContext()).type(createDTO.getType()).userId(UserContextHolder.getExistLoginUserId()).build()); + } + + @Override + public List page(SearchHistoryPageQueryDTO queryDTO) { + queryDTO.setUserId(UserContextHolder.getExistLoginUserId()); + return getBaseMapper().page(queryDTO); + } + + @Override + public void cleanAll() { + update(Wrappers.lambdaUpdate() + .set(SearchHistory::getDeleted,true) + .set(SearchHistory::getUpdateBy,UserContextHolder.getExistLoginUserId()) + .set(SearchHistory::getUpdateTime, DateUtil.date()) + .eq(SearchHistory::getUserId,UserContextHolder.getExistLoginUserId()) + .eq(SearchHistory::getDeleted,false) + ); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/service/AuthService.java b/backend/src/main/java/com/senmesh/usercenter/service/AuthService.java new file mode 100644 index 0000000..7e46376 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/service/AuthService.java @@ -0,0 +1,4 @@ +package com.senmesh.usercenter.service; + +public interface AuthService { +} diff --git a/backend/src/main/java/com/senmesh/usercenter/service/UcDictionaryService.java b/backend/src/main/java/com/senmesh/usercenter/service/UcDictionaryService.java new file mode 100644 index 0000000..4142d7c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/service/UcDictionaryService.java @@ -0,0 +1,85 @@ +package com.senmesh.usercenter.service; + +import com.senmesh.common.AlitaResult; +import com.senmesh.component.dict.dto.DictDTO; +import com.senmesh.component.dict.dto.DictDetailDTO; +import com.senmesh.component.dict.dto.DictDetailQueryDTO; +import com.senmesh.component.dict.dto.DictQueryDTO; +import com.senmesh.component.dict.service.DictDetailService; +import com.senmesh.component.dict.service.DictService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @author: Jerry.li + * @description: 数据字典服务 + * @create: 2020-06-18 14:19 + **/ +@Slf4j +@Service +public class UcDictionaryService { + + @Autowired + private DictService dictService; + + @Autowired + private DictDetailService dictDetailService; + + + /** + * 新增或者修改字典数据 + * + * @param dictDTO + * @param operateUserId + * @return + */ + public AlitaResult editDictionary(DictDTO dictDTO, Long operateUserId) { + if (null == dictDTO.getId()) { + return AlitaResult.success(dictService.createDict(dictDTO, operateUserId)); + } else { + return AlitaResult.success(dictService.modifyDict(dictDTO, operateUserId)); + } + } + + /** + * 新增或者修改字典数据详情 + * + * @param detailDTO + * @param operateUserId + * @return + */ + public AlitaResult editDictionaryDetail(DictDetailDTO detailDTO, Long operateUserId) { + if (null == detailDTO.getId()) { + dictDetailService.createDictDetail(detailDTO, operateUserId); + } else { + dictDetailService.modifyDictDetail(detailDTO, operateUserId); + } + return AlitaResult.success(true); + } + + /** + * 分页查询数据字典列表 + * + * @return + */ + public void pageDictionaryList(DictQueryDTO query) { + query.setDictCode(StringUtils.trim(query.getDictCode())); + query.setDictName(StringUtils.trim(query.getDictName())); + dictService.page(query); + } + + /** + * 查询数据字典详情列表 + * + * @param detailQueryDTO + * @return + */ + public List getDictDetailList(DictDetailQueryDTO detailQueryDTO) { + return dictDetailService.list(detailQueryDTO); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/service/UcRoleStandardTypeService.java b/backend/src/main/java/com/senmesh/usercenter/service/UcRoleStandardTypeService.java new file mode 100644 index 0000000..079f0ca --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/service/UcRoleStandardTypeService.java @@ -0,0 +1,16 @@ +package com.senmesh.usercenter.service; + +import java.util.List; + +import com.senmesh.usercenter.dto.RoleStandardTypeDTO; +import com.senmesh.usercenter.query.RoleStandardTypeQuery; + +/** + * @Author dylanyuan + * @Date 2021/2/19 2:21 下午 + * @Version 1.0 + */ +public interface UcRoleStandardTypeService { + + List page(RoleStandardTypeQuery query); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/service/UcSmsService.java b/backend/src/main/java/com/senmesh/usercenter/service/UcSmsService.java new file mode 100644 index 0000000..758ea2a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/service/UcSmsService.java @@ -0,0 +1,43 @@ +package com.senmesh.usercenter.service; + +import com.senmesh.common.AlitaResult; +import com.senmesh.usercenter.enums.SmsScenesEnum; + +/** + * @author chenyun + * @description 短信验证码 + * @date 2020/8/26 14:23 + */ +public interface UcSmsService { + + + /** + * 发送手机验证码 + * + * @param smsScenesEnum + * @param phone + * @return + */ + AlitaResult sendPhoneCode(SmsScenesEnum smsScenesEnum, String phone); + + /** + * 校验手机验证码 + * + * @param smsScenesEnum + * @param phone + * @param code + * @return + */ + AlitaResult checkPhoneCode(SmsScenesEnum smsScenesEnum, String phone, String code); + + /** + * 使用手机验证码 + * + * @param smsScenesEnum + * @param phone 手机号 + * @param code 验证码 + * @return + */ + AlitaResult usePhoneCode(SmsScenesEnum smsScenesEnum, String phone, String code); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/service/impl/UcRoleStandardTypeServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/service/impl/UcRoleStandardTypeServiceImpl.java new file mode 100644 index 0000000..ff339a4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/service/impl/UcRoleStandardTypeServiceImpl.java @@ -0,0 +1,29 @@ +package com.senmesh.usercenter.service.impl; + +import com.senmesh.usercenter.dao.XsRoleStandardTypeMapper; +import com.senmesh.usercenter.dto.RoleStandardTypeDTO; +import com.senmesh.usercenter.query.RoleStandardTypeQuery; +import com.senmesh.usercenter.service.UcRoleStandardTypeService; +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * @Author dylanyuan + * @Date 2021/2/19 2:21 下午 + * @Version 1.0 + */ +@Slf4j +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class UcRoleStandardTypeServiceImpl implements UcRoleStandardTypeService { + + private final XsRoleStandardTypeMapper xsRoleStandardTypeMapper; + + @Override + public List page(RoleStandardTypeQuery query) { + return xsRoleStandardTypeMapper.page(query); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/constant/DomainSettingConstant.java b/backend/src/main/java/com/senmesh/usercenter/sys/constant/DomainSettingConstant.java new file mode 100644 index 0000000..ad9077c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/constant/DomainSettingConstant.java @@ -0,0 +1,13 @@ +package com.senmesh.usercenter.sys.constant; + +/** + * @description: + * @author: guixinman + * @create: 2024-05-20 15:57 + **/ +public interface DomainSettingConstant { + + Integer QUICK = 3; + + Integer BANNER = 2; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/controller/DomainAnonController.java b/backend/src/main/java/com/senmesh/usercenter/sys/controller/DomainAnonController.java new file mode 100644 index 0000000..c820b7e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/controller/DomainAnonController.java @@ -0,0 +1,39 @@ +package com.senmesh.usercenter.sys.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.usercenter.dto.DomainSettingReqDTO; +import com.senmesh.usercenter.dto.DomainSettingResDTO; +import com.senmesh.usercenter.sys.service.DomainSettingService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * @author sr on 2021-05-24 + */ +//@RestController +@RequestMapping("/anon") +@Api(tags = "域名") +public class DomainAnonController { + + @Autowired + private DomainSettingService domainSettingService; + + @ApiOperation(value = "域名配置查询", notes = "域名配置查询") + @GetMapping("/domain_setting/list") + public AlitaResult> list(DomainSettingReqDTO reqDTO) { + return AlitaResult.success(domainSettingService.list(reqDTO)); + } + + @ApiOperation(value = "清理缓存", notes = "清理缓存") + @GetMapping("/domain_setting/clean_cache") + public AlitaResult cleanCache() { + domainSettingService.cleanCache(); + return AlitaResult.success(); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/controller/DomainAuthController.java b/backend/src/main/java/com/senmesh/usercenter/sys/controller/DomainAuthController.java new file mode 100644 index 0000000..ffddd22 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/controller/DomainAuthController.java @@ -0,0 +1,58 @@ +package com.senmesh.usercenter.sys.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.sys.dto.DomainAuthDTO; +import com.senmesh.usercenter.sys.dto.DomainAuthOperateDTO; +import com.senmesh.usercenter.sys.dto.DomainAuthQueryDTO; +import com.senmesh.usercenter.sys.service.DomainAuthService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +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; + +import java.util.Set; + +/** + * @author sr on 2021-05-24 + */ +@RestController +@RequestMapping("domain_auth") +@Api(tags = "域名授权") +public class DomainAuthController { + + @Autowired + private DomainAuthService domainAuthService; + + @PostMapping("/link") + @ApiOperation("关联") + public AlitaResult> link(@RequestBody DomainAuthOperateDTO domainAuthOperateDTO) { + return AlitaResult.success(domainAuthService.link(domainAuthOperateDTO)); + } + + @PostMapping("/cancel_link") + @ApiOperation("取消关联") + public AlitaResult> cancelLink(@RequestBody DomainAuthOperateDTO domainAuthOperateDTO) { + return AlitaResult.success(domainAuthService.cancelLink(domainAuthOperateDTO)); + } + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(DomainAuthQueryDTO domainAuthQueryDTO) { + domainAuthService.list(domainAuthQueryDTO); + return AlitaResult.success(domainAuthQueryDTO.getPageResult()); + } + + @GetMapping("/not_link_list") + @ApiOperation("分页查询未关联的引用列表") + public AlitaResult> notLinkList(DomainAuthQueryDTO domainAuthQueryDTO) { + domainAuthService.notLinkList(domainAuthQueryDTO); + return AlitaResult.success(domainAuthQueryDTO.getPageResult()); + } + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/controller/DomainController.java b/backend/src/main/java/com/senmesh/usercenter/sys/controller/DomainController.java new file mode 100644 index 0000000..bf6da24 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/controller/DomainController.java @@ -0,0 +1,65 @@ +package com.senmesh.usercenter.sys.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.sys.dto.DomainDTO; +import com.senmesh.usercenter.sys.dto.DomainOperateDTO; +import com.senmesh.usercenter.sys.dto.DomainQueryDTO; +import com.senmesh.usercenter.sys.service.DomainService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Set; + +/** + * @author sr on 2021-05-24 + */ +//@RestController +@Api(tags = "域名") +public class DomainController { + + @Autowired + private DomainService domainService; + + @PostMapping("domain/create") + @ApiOperation("创建") + public AlitaResult create(@RequestBody DomainOperateDTO domainOperateDTO){ + return AlitaResult.success(domainService.create(domainOperateDTO)); + } + + @PutMapping("domain/modify") + @ApiOperation("修改") + public AlitaResult modify(@RequestBody DomainOperateDTO domainOperateDTO){ + domainService.modify(domainOperateDTO); + return AlitaResult.success(true); + } + + @GetMapping("domain/detail/{id}") + @ApiOperation("详情") + public AlitaResult detail(@PathVariable Long id){ + return AlitaResult.success(domainService.detail(id)); + } + + @DeleteMapping("domain/remove/{id}") + @ApiOperation("删除") + public AlitaResult remove(@PathVariable Long id){ + domainService.remove(id); + return AlitaResult.success(true); + } + + @GetMapping("domain/page") + @ApiOperation("分页查询") + public AlitaResult> page(DomainQueryDTO domainQueryDTO){ + domainService.page(domainQueryDTO); + return AlitaResult.success(domainQueryDTO.getPageResult()); + } + + @GetMapping("/anon/domain/list_org_id") + @ApiOperation("获取请求相关机构列表") + public AlitaResult> listOrgId(){ + return domainService.listOrgId(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/controller/DomainSettingController.java b/backend/src/main/java/com/senmesh/usercenter/sys/controller/DomainSettingController.java new file mode 100644 index 0000000..9580cf2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/controller/DomainSettingController.java @@ -0,0 +1,105 @@ +package com.senmesh.usercenter.sys.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.validation.Update; +import com.senmesh.usercenter.dto.DomainSettingOperateDTO; +import com.senmesh.usercenter.dto.DomainSettingReqDTO; +import com.senmesh.usercenter.dto.DomainSettingResDTO; +import com.senmesh.usercenter.sys.dto.DomainSettingBannerOperateDTO; +import com.senmesh.usercenter.sys.dto.DomainSettingQuickOperateDTO; +import com.senmesh.usercenter.sys.service.DomainSettingService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * @author sr on 2021-05-24 + */ +@RestController +@RequestMapping("/domain_setting") +@Api(tags = "域名配置") +public class DomainSettingController { + + @Autowired + private DomainSettingService domainSettingService; + + @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create(@RequestBody DomainSettingOperateDTO domainOperateDTO){ + return AlitaResult.success(domainSettingService.create(domainOperateDTO)); + } + + @PutMapping("/modify") + @ApiOperation("修改") + public AlitaResult modify(@RequestBody DomainSettingOperateDTO domainOperateDTO){ + domainSettingService.modify(domainOperateDTO); + return AlitaResult.success(true); + } + + @DeleteMapping("/remove/{id}") + @ApiOperation("删除") + public AlitaResult remove(@PathVariable Long id) { + domainSettingService.remove(id); + return AlitaResult.success(true); + } + + @GetMapping("/list/no_cache") + @ApiOperation("列表查询(没有缓存)") + public AlitaResult> listNoCache(DomainSettingReqDTO reqDTO) { + return AlitaResult.success(domainSettingService.listNoCache(reqDTO)); + } + + @PostMapping("/quick/create") + @ApiOperation("快捷入口") + public AlitaResult quickCreate(@RequestBody DomainSettingQuickOperateDTO quickCreateDTO){ + return AlitaResult.success(domainSettingService.quickCreate(quickCreateDTO)); + } + @PutMapping("/quick/modify") + @ApiOperation("快捷入口") + public AlitaResult quickModify(@RequestBody @Validated(Update.class) DomainSettingQuickOperateDTO quickModifyDTO){ + domainSettingService.quickModify(quickModifyDTO); + return AlitaResult.success(); + } + + @DeleteMapping("/quick/delete") + @ApiOperation("快捷入口") + public AlitaResult quickDelete(@RequestParam("id") String id){ + domainSettingService.quickDelete(id); + return AlitaResult.success(); + } + + @GetMapping("/quick/list") + @ApiOperation("快捷入口查看") + public AlitaResult> quickList(){ + return AlitaResult.success(domainSettingService.quickList()); + } + + @PostMapping("/banner/create") + @ApiOperation("banner创建") + public AlitaResult bannerCreate(@RequestBody DomainSettingBannerOperateDTO bannerOperateDTO){ + return AlitaResult.success(domainSettingService.bannerCreate(bannerOperateDTO)); + } + @PutMapping("/banner/modify") + @ApiOperation("banner修改") + public AlitaResult bannerModify(@RequestBody @Validated(Update.class) DomainSettingBannerOperateDTO bannerOperateDTO){ + domainSettingService.bannerModify(bannerOperateDTO); + return AlitaResult.success(); + } + + @GetMapping("/banner/list") + @ApiOperation("banner查看") + public AlitaResult> bannerList(){ + return AlitaResult.success(domainSettingService.bannerList()); + } + + @DeleteMapping("/banner/delete") + @ApiOperation("banner") + public AlitaResult bannerDelete(@RequestParam("id") String id){ + domainSettingService.bannerDelete(id); + return AlitaResult.success(); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/controller/FaqController.java b/backend/src/main/java/com/senmesh/usercenter/sys/controller/FaqController.java new file mode 100644 index 0000000..97e8178 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/controller/FaqController.java @@ -0,0 +1,70 @@ +package com.senmesh.usercenter.sys.controller; + +import com.senmesh.common.validation.Create; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.PathVariable; + +import com.senmesh.common.validation.Update; +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.sys.dto.FaqQueryDTO; +import com.senmesh.usercenter.sys.service.FaqService; +import com.senmesh.usercenter.sys.dto.FaqDTO; +import com.senmesh.usercenter.sys.dto.FaqOperateDTO; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2021-05-24 + */ +//@RestController +@Api(tags = "常见问题表") +public class FaqController { + + @Autowired + private FaqService faqService; + + @PostMapping("/faq/create") + @ApiOperation("创建") + public AlitaResult create( + @Validated(Create.class) @RequestBody FaqOperateDTO faqOperateDTO){ + return AlitaResult.success(faqService.create(faqOperateDTO)); + } + + @PutMapping("/faq/modify") + @ApiOperation("修改") + public AlitaResult modify( + @Validated(Update.class) @RequestBody FaqOperateDTO faqOperateDTO){ + faqService.modify(faqOperateDTO); + return AlitaResult.success(true); + } + + @DeleteMapping("/faq/remove/{id}") + @ApiOperation("删除") + public AlitaResult remove(@PathVariable Long id){ + faqService.remove(id); + return AlitaResult.success(true); + } + + @GetMapping("/anon/faq/page") + @ApiOperation("分页查询") + public AlitaResult> page(FaqQueryDTO faqQueryDTO){ + faqService.list(faqQueryDTO); + return AlitaResult.success(faqQueryDTO.getPageResult()); + } + + @GetMapping("/anon/faq/{id}") + @ApiOperation("获取单个") + AlitaResult get(@PathVariable Long id){ + return AlitaResult.success(faqService.get(id)); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/controller/FaqFileController.java b/backend/src/main/java/com/senmesh/usercenter/sys/controller/FaqFileController.java new file mode 100644 index 0000000..d504ec1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/controller/FaqFileController.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.sys.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.usercenter.sys.dto.FaqFileDTO; +import com.senmesh.usercenter.sys.dto.FaqFileQueryDTO; +import com.senmesh.usercenter.sys.service.FaqFileService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@Api(tags = "常见问题表") +public class FaqFileController { + + @Autowired + private FaqFileService faqFileService; + + @GetMapping("/anon/faq_file/list") + @ApiOperation("查询常见问题附件列表") + public AlitaResult> list(FaqFileQueryDTO queryDTO) { + return AlitaResult.success(faqFileService.list(queryDTO)); + } + + @PostMapping("/faq_file/create") + @ApiOperation("创建常见问题附件") + public AlitaResult create(@RequestBody FaqFileDTO operateDTO) { + return AlitaResult.success(faqFileService.create(operateDTO)); + } + + @DeleteMapping("/faq_file/delete/{id}") + @ApiOperation("根据文件Id删除常见问题附件") + public AlitaResult delete(@PathVariable Long id) { + faqFileService.delete(id); + return AlitaResult.success(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/controller/FeedbackController.java b/backend/src/main/java/com/senmesh/usercenter/sys/controller/FeedbackController.java new file mode 100644 index 0000000..ba784bb --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/controller/FeedbackController.java @@ -0,0 +1,66 @@ +package com.senmesh.usercenter.sys.controller; + +import com.senmesh.common.validation.Create; +import com.senmesh.usercenter.sys.dto.FeedbackDTO; +import com.senmesh.usercenter.sys.dto.FeedbackOperateDTO; +import com.senmesh.usercenter.sys.dto.FeedbackQueryDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.PathVariable; + +import com.senmesh.common.validation.Update; +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.sys.service.FeedbackService; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2021-05-24 + */ +//@RestController +@RequestMapping("/anon/feedback") +@Api(tags = "反馈表") +public class FeedbackController { + + @Autowired + private FeedbackService feedbackService; + + @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create( + @Validated(Create.class) @RequestBody FeedbackOperateDTO feedbackOperateDTO){ + return AlitaResult.success(feedbackService.create(feedbackOperateDTO)); + } + + @PutMapping("/modify") + @ApiOperation("修改") + public AlitaResult modify( + @Validated(Update.class) @RequestBody FeedbackOperateDTO feedbackOperateDTO){ + feedbackService.modify(feedbackOperateDTO); + return AlitaResult.success(true); + } + + @DeleteMapping("/remove/{id}") + @ApiOperation("删除") + public AlitaResult remove(@PathVariable Long id){ + feedbackService.remove(id); + return AlitaResult.success(true); + } + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(FeedbackQueryDTO feedbackQueryDTO){ + feedbackService.list(feedbackQueryDTO); + return AlitaResult.success(feedbackQueryDTO.getPageResult()); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/controller/PlatformController.java b/backend/src/main/java/com/senmesh/usercenter/sys/controller/PlatformController.java new file mode 100644 index 0000000..26ba3ac --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/controller/PlatformController.java @@ -0,0 +1,65 @@ +package com.senmesh.usercenter.sys.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.validation.Update; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.sys.dto.PlatformDTO; +import com.senmesh.usercenter.sys.dto.PlatformOperateDTO; +import com.senmesh.usercenter.sys.dto.PlatformPageQueryDTO; +import com.senmesh.usercenter.sys.dto.PlatformQueryDTO; +import com.senmesh.usercenter.sys.service.PlatformService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * @author sr on 2021-05-24 + */ +@RestController +@RequestMapping("platform") +@Api(tags = "系统应用") +public class PlatformController { + + @Autowired + private PlatformService platformService; + + @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create( + @Validated @RequestBody PlatformOperateDTO platformOperateDTO){ + return AlitaResult.success(platformService.create(platformOperateDTO)); + } + + @PutMapping("/modify") + @ApiOperation("修改") + public AlitaResult modify( + @Validated(Update.class) @RequestBody PlatformOperateDTO platformOperateDTO){ + platformService.modify(platformOperateDTO); + return AlitaResult.success(true); + } + + @DeleteMapping("/remove/{id}") + @ApiOperation("删除") + public AlitaResult remove(@PathVariable Long id) { + platformService.remove(id); + return AlitaResult.success(true); + } + + @GetMapping("list") + @ApiOperation("列表查询") + public AlitaResult> list(PlatformQueryDTO queryDTO) { + return AlitaResult.success(platformService.list(queryDTO)); + } + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(PlatformPageQueryDTO platformPageQueryDTO) { + platformService.page(platformPageQueryDTO); + return AlitaResult.success(platformPageQueryDTO.getPageResult()); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dao/DomainAuthMapper.java b/backend/src/main/java/com/senmesh/usercenter/sys/dao/DomainAuthMapper.java new file mode 100644 index 0000000..a3c1fe6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dao/DomainAuthMapper.java @@ -0,0 +1,28 @@ +package com.senmesh.usercenter.sys.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.senmesh.usercenter.sys.dto.DomainAuthDTO; +import com.senmesh.usercenter.sys.dto.DomainAuthQueryDTO; +import com.senmesh.usercenter.sys.entity.DomainAuth; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 域名授权 + * + * @author sr on 2021-05-24 + */ +public interface DomainAuthMapper extends BaseMapper { + + /** + * 查询 + * + * @param domainAuthQueryDTO + * @return + * @author sr on 2021-05-24 + */ + List listDomainAuthDTO(@Param("param") DomainAuthQueryDTO domainAuthQueryDTO); + + List notLinkList(@Param("param") DomainAuthQueryDTO domainAuthQueryDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dao/DomainMapper.java b/backend/src/main/java/com/senmesh/usercenter/sys/dao/DomainMapper.java new file mode 100644 index 0000000..c309fb0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dao/DomainMapper.java @@ -0,0 +1,28 @@ +package com.senmesh.usercenter.sys.dao; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.sys.dto.DomainDTO; +import com.senmesh.usercenter.sys.dto.DomainQueryDTO; +import com.senmesh.usercenter.sys.entity.Domain; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 域名 + * + * @author sr on 2021-05-24 + */ +public interface DomainMapper extends MyMapper { + + /** + * 查询 + * + * @param domainQueryDTO + * @return + * @author sr on 2021-05-24 + */ + List listDomainDTO(@Param("param") DomainQueryDTO domainQueryDTO); + + DomainDTO selectByDomainOrIp(@Param("domainOrIp") String domainOrIp); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dao/DomainSettingMapper.java b/backend/src/main/java/com/senmesh/usercenter/sys/dao/DomainSettingMapper.java new file mode 100644 index 0000000..414de5f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dao/DomainSettingMapper.java @@ -0,0 +1,24 @@ +package com.senmesh.usercenter.sys.dao; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.dto.DomainSettingReqDTO; +import com.senmesh.usercenter.dto.DomainSettingResDTO; +import com.senmesh.usercenter.sys.entity.DomainSetting; + + +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + *

+ * 域名配置表 Mapper 接口 + *

+ * + * @author Carlye + * @since 2021-06-17 + */ +public interface DomainSettingMapper extends MyMapper { + + List list(@Param("param") DomainSettingReqDTO reqDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dao/FaqFileMapper.java b/backend/src/main/java/com/senmesh/usercenter/sys/dao/FaqFileMapper.java new file mode 100644 index 0000000..e319d0d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dao/FaqFileMapper.java @@ -0,0 +1,26 @@ +package com.senmesh.usercenter.sys.dao; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.sys.dto.FaqFileDTO; +import com.senmesh.usercenter.sys.dto.FaqFileQueryDTO; +import com.senmesh.usercenter.sys.entity.FaqFile; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 常见问题附件表 + * + */ +public interface FaqFileMapper extends MyMapper { + + /** + * 查询 + * + * @param faqQueryDTO + * @return + * @author sr on 2021-05-24 + */ + List filePage(@Param("param") FaqFileQueryDTO faqQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dao/FaqMapper.java b/backend/src/main/java/com/senmesh/usercenter/sys/dao/FaqMapper.java new file mode 100644 index 0000000..3b5a239 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dao/FaqMapper.java @@ -0,0 +1,28 @@ +package com.senmesh.usercenter.sys.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.usercenter.sys.dto.FaqDTO; +import com.senmesh.usercenter.sys.dto.FaqQueryDTO; +import com.senmesh.usercenter.sys.entity.Faq; +import com.senmesh.tkmybatis.mybatis.MyMapper; + +/** + * 常见问题表 + * + * @author sr on 2021-05-24 + */ +public interface FaqMapper extends MyMapper { + + /** + * 查询 + * + * @param faqQueryDTO + * @return + * @author sr on 2021-05-24 + */ + List listFaqDTO(@Param("param") FaqQueryDTO faqQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dao/FeedbackMapper.java b/backend/src/main/java/com/senmesh/usercenter/sys/dao/FeedbackMapper.java new file mode 100644 index 0000000..1043e9e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dao/FeedbackMapper.java @@ -0,0 +1,28 @@ +package com.senmesh.usercenter.sys.dao; + +import java.util.List; + +import com.senmesh.usercenter.sys.dto.FeedbackDTO; +import com.senmesh.usercenter.sys.dto.FeedbackQueryDTO; +import org.apache.ibatis.annotations.Param; + +import com.senmesh.usercenter.sys.entity.Feedback; +import com.senmesh.tkmybatis.mybatis.MyMapper; + +/** + * 反馈表 + * + * @author sr on 2021-05-24 + */ +public interface FeedbackMapper extends MyMapper { + + /** + * 查询 + * + * @param feedbackQueryDTO + * @return + * @author sr on 2021-05-24 + */ + List listFeedbackDTO(@Param("param") FeedbackQueryDTO feedbackQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dao/PlatformMapper.java b/backend/src/main/java/com/senmesh/usercenter/sys/dao/PlatformMapper.java new file mode 100644 index 0000000..cde2f4d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dao/PlatformMapper.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.sys.dao; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.sys.dto.PlatformDTO; +import com.senmesh.usercenter.sys.dto.PlatformPageQueryDTO; +import com.senmesh.usercenter.sys.dto.PlatformQueryDTO; +import com.senmesh.usercenter.sys.entity.Platform; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 系统应用 + * + * @author sr on 2021-05-24 + */ +public interface PlatformMapper extends MyMapper { + + /** + * 查询 + * + * @param platformPageQueryDTO + * @return + * @author sr on 2021-05-24 + */ + List page(@Param("param") PlatformPageQueryDTO platformPageQueryDTO); + + /** + * 列表 + * + * @param queryDTO 查询dto + * @return {@link List}<{@link PlatformDTO}> + */ + List list(@Param("param") PlatformQueryDTO queryDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainAuthDTO.java b/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainAuthDTO.java new file mode 100644 index 0000000..c9d9464 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainAuthDTO.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.sys.dto; + +import com.senmesh.common.dto.OrgBaseDTO; + +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-05-24 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "域名授权") +public class DomainAuthDTO extends OrgBaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + /** 域名id */ + private Long domainId ; + /** 授权类型标识 */ + private Integer authTypeCode ; + /** 授权客户端id */ + private Long authClientId ; + /** + * 授权类型名称 + */ + private String authTypeName; + /** + * 授权应用名称 + */ + private String clientName; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainAuthOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainAuthOperateDTO.java new file mode 100644 index 0000000..5a83265 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainAuthOperateDTO.java @@ -0,0 +1,46 @@ +package com.senmesh.usercenter.sys.dto; + +import com.senmesh.common.dto.BaseOperateDTO; +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Set; + +/** + * @author sr on 2021-05-24 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "域名授权操作") +public class DomainAuthOperateDTO extends BaseOperateDTO implements Serializable{ + + + private static final long serialVersionUID = -2610902048033082892L; + @ApiModelProperty("id") + @NotNull(message = "id不能为空", groups = {Update.class}) + private Long id; + + /** 域名id */ + @ApiModelProperty("域名id") + @NotNull( + message = "域名id不能为空", + groups = {Create.class, Update.class}) + private Long domainId; + /** 授权客户端id */ + @ApiModelProperty("授权客户端id") + @NotNull(message = "授权客户端id不能为空",groups = {Create.class,Update.class}) + private Set authClientIds ; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainAuthQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainAuthQueryDTO.java new file mode 100644 index 0000000..cf4c73b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainAuthQueryDTO.java @@ -0,0 +1,29 @@ +package com.senmesh.usercenter.sys.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * @author sr on 2021-05-24 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "域名授权查询条件") +public class DomainAuthQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("域名id") + private Long domainId; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainDTO.java b/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainDTO.java new file mode 100644 index 0000000..ff4b3ce --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainDTO.java @@ -0,0 +1,34 @@ +package com.senmesh.usercenter.sys.dto; + +import com.senmesh.common.dto.OrgBaseDTO; +import io.swagger.annotations.ApiModel; +import lombok.*; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-05-24 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "域名") +public class DomainDTO extends OrgBaseDTO{ + + /** **/ + private static final long serialVersionUID = 1L; + /** 平台编码 */ + private Integer platformCode ; + /** 域名 */ + private String domainName ; + /** ip:port */ + private String ipPort ; + /** 是否公共 */ + private Boolean publiced ; + + /** + * 机构名称 + */ + private String orgName; +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainOperateDTO.java new file mode 100644 index 0000000..9663fb1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainOperateDTO.java @@ -0,0 +1,61 @@ +package com.senmesh.usercenter.sys.dto; + +import com.senmesh.common.dto.BaseOperateDTO; +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + * @author sr on 2021-05-24 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "域名操作") +public class DomainOperateDTO extends BaseOperateDTO implements Serializable { + + /** + * + **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + @NotNull(message = "id不能为空", groups = {Update.class}) + private Long id; + + /** + * 平台编码 + */ + @NotNull(message = "平台不能为空", groups = {Create.class}) + private Integer platformCode; + /** + * 域名 + */ + @NotEmpty(message = "域名不能为空", groups = {Create.class}) + private String domainName; + /** + * ip:port + */ + @NotEmpty(message = "ip端口不能为空", groups = {Create.class}) + private String ipPort; + /** + * 是否公共 + */ + @NotNull(message = "是否公共不能为空", groups = {Create.class}) + private Boolean publiced; + + /** + * 机构名称 + */ +// @NotNull(message = "所属机构不能为空", groups = {Create.class}) + private Long orgId; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainQueryDTO.java new file mode 100644 index 0000000..94822d6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainQueryDTO.java @@ -0,0 +1,33 @@ +package com.senmesh.usercenter.sys.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * @author sr on 2021-05-24 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "域名查询条件") +public class DomainQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + @ApiModelProperty("orgId") + private Long orgId; + @ApiModelProperty("域名或ip") + private String domainOrIp; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainSettingBannerOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainSettingBannerOperateDTO.java new file mode 100644 index 0000000..4a00245 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainSettingBannerOperateDTO.java @@ -0,0 +1,30 @@ +package com.senmesh.usercenter.sys.dto; + +import com.senmesh.common.validation.Update; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Builder; +import lombok.Data; + +/** + * @description: BannerDTO + * @author: guixinman + * @create: 2024-05-20 15:03 + **/ +@Data +@Builder +public class DomainSettingBannerOperateDTO implements Serializable { + + @NotBlank(message = "id不能为空",groups = Update.class) + private String id; + + @ApiModelProperty("图标") + private String icon; + + @ApiModelProperty("链接") + private String link; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainSettingQuickOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainSettingQuickOperateDTO.java new file mode 100644 index 0000000..cbf4dfc --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dto/DomainSettingQuickOperateDTO.java @@ -0,0 +1,39 @@ +package com.senmesh.usercenter.sys.dto; + +import com.senmesh.common.validation.Update; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Builder; +import lombok.Data; + +/** + * @description: BannerDTO + * @author: guixinman + * @create: 2024-05-20 15:03 + **/ +@Data +@Builder +public class DomainSettingQuickOperateDTO implements Serializable { + + @NotBlank(message = "id不能为空",groups = Update.class) + private String id; + + @ApiModelProperty("描述") + private String remark; + + @ApiModelProperty("图标") + private String icon; + + @ApiModelProperty("标题") + private String title; + + @ApiModelProperty("链接") + private String link; + + @ApiModelProperty("排序") + private int sort; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dto/FaqDTO.java b/backend/src/main/java/com/senmesh/usercenter/sys/dto/FaqDTO.java new file mode 100644 index 0000000..12e19f6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dto/FaqDTO.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.sys.dto; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-05-24 + */ +/** @EqualsAndHashCode(callSuper = true) */ +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@Data +@ApiModel(description = "常见问题表") +public class FaqDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 主键 */ + private Long id; + /** 排序字段 */ + private Integer faqOrder; + /** 类型 */ + private String faqType; + /** 问题 */ + private String question ; + /** 回答 */ + private String answer ; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dto/FaqFileDTO.java b/backend/src/main/java/com/senmesh/usercenter/sys/dto/FaqFileDTO.java new file mode 100644 index 0000000..7cb6c15 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dto/FaqFileDTO.java @@ -0,0 +1,45 @@ +package com.senmesh.usercenter.sys.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@ApiModel("常见问题附件DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FaqFileDTO implements Serializable { + + + private static final long serialVersionUID = 8851173648134487125L; + + @ApiModelProperty("主键") + private Long id; + + @ApiModelProperty("文件名称") + private String fileName; + + @ApiModelProperty("文件编码") + private String fileCode; + + @ApiModelProperty("文件后缀") + private String fileSuffix; + + @ApiModelProperty("文件描述") + private String description; + + @ApiModelProperty("排序") + private Integer sort; + + @ApiModelProperty("问题ID") + private Long questionId; + + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dto/FaqFileQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/sys/dto/FaqFileQueryDTO.java new file mode 100644 index 0000000..801d99b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dto/FaqFileQueryDTO.java @@ -0,0 +1,21 @@ +package com.senmesh.usercenter.sys.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +@EqualsAndHashCode(callSuper = true) +@ApiModel("常见问题附件查询DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FaqFileQueryDTO extends PageQueryDTO { + + private static final long serialVersionUID = -6211701785572927530L; + + @ApiModelProperty("常见问题ID") + private Long questionId; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dto/FaqOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/sys/dto/FaqOperateDTO.java new file mode 100644 index 0000000..cca1c47 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dto/FaqOperateDTO.java @@ -0,0 +1,47 @@ +package com.senmesh.usercenter.sys.dto; + +import java.io.Serializable; + +import com.senmesh.common.validation.Create; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; +import javax.validation.constraints.NotNull; +import com.senmesh.common.validation.Update; + +import com.senmesh.common.dto.BaseOperateDTO; + +/** + * @author sr on 2021-05-24 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "常见问题表操作") +public class FaqOperateDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + @NotNull(message = "id不能为空", groups = {Update.class}) + private Long id; + + /** 排序字段 */ + private Integer faqOrder; + /** 类型 */ + @NotNull(message = "类型不能为空", groups = {Create.class, Update.class}) + private String faqType; + /** 问题 */ + @NotNull(message = "问题不能为空", groups = {Create.class, Update.class}) + private String question ; + /** 回答 */ + @NotNull(message = "回答不能为空", groups = {Create.class, Update.class}) + private String answer ; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dto/FaqQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/sys/dto/FaqQueryDTO.java new file mode 100644 index 0000000..647878c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dto/FaqQueryDTO.java @@ -0,0 +1,51 @@ +package com.senmesh.usercenter.sys.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.senmesh.common.annotation.trimAndUpper.TrimAndUpper; +import com.senmesh.common.dto.PageQueryDTO; + +import org.springframework.format.annotation.DateTimeFormat; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Date; + +/** + * @author sr on 2021-05-24 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "常见问题表查询条件") +public class FaqQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + + /** 问题 */ + @TrimAndUpper(TrimAndUpper.ExecuteType.TRIM) + private String question ; + /** 平台类型 */ + private String faqType; + + @ApiModelProperty("创建时间起,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTimeStart; + + @ApiModelProperty("创建时间止,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTimeEnd; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dto/FeedbackDTO.java b/backend/src/main/java/com/senmesh/usercenter/sys/dto/FeedbackDTO.java new file mode 100644 index 0000000..4fd7cb1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dto/FeedbackDTO.java @@ -0,0 +1,47 @@ +package com.senmesh.usercenter.sys.dto; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import lombok.*; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-05-24 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "反馈表") +public class FeedbackDTO extends BaseDTO { + + /** + * + **/ + private static final long serialVersionUID = 1L; + + /** + * 类型 + */ + private String type; + /** + * 用户id + */ + private Long userId; + /** + * 用户昵称 + */ + private String nickname; + /** + * 手机号 + */ + private String phone; + /** + * 反馈内容 + */ + private String content; + + private String sourceType; +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dto/FeedbackOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/sys/dto/FeedbackOperateDTO.java new file mode 100644 index 0000000..aa7fa6b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dto/FeedbackOperateDTO.java @@ -0,0 +1,60 @@ +package com.senmesh.usercenter.sys.dto; + +import com.senmesh.common.dto.BaseOperateDTO; +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; +import com.senmesh.common.validation.annotation.Phone; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +import java.io.Serializable; + +/** + * @author sr on 2021-05-24 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "反馈表操作") +public class FeedbackOperateDTO extends BaseOperateDTO implements Serializable { + + /** + * + **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + @NotNull(message = "id不能为空", groups = {Update.class}) + private Long id; + + /** + * 类型 + */ + private String type; + /** + * 用户id + */ + private Long userId; + /** + * 手机号 + */ + @Phone(groups = {Create.class, Update.class}) + private String phone; + + /** + * 反馈内容 + */ + private String content; + + private String sourceType; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dto/FeedbackQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/sys/dto/FeedbackQueryDTO.java new file mode 100644 index 0000000..b539b77 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dto/FeedbackQueryDTO.java @@ -0,0 +1,54 @@ +package com.senmesh.usercenter.sys.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.senmesh.common.dto.PageQueryDTO; + +import org.springframework.format.annotation.DateTimeFormat; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Date; + +/** + * @author sr on 2021-05-24 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "反馈表查询条件") +public class FeedbackQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + + /** 类型 */ + private String type ; + /** 用户昵称 */ + private String nickname ; + /** 手机号 */ + private String phone ; + + + @ApiModelProperty("创建时间起,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTimeStart; + + @ApiModelProperty("创建时间止,格式 (yyyy-MM-dd HH:mm:ss)") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTimeEnd; + + private String sourceType; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dto/PlatformDTO.java b/backend/src/main/java/com/senmesh/usercenter/sys/dto/PlatformDTO.java new file mode 100644 index 0000000..c6857cc --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dto/PlatformDTO.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.sys.dto; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-05-24 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "系统应用") +public class PlatformDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 平台编码 */ + private Integer platformCode ; + /** 名称 */ + private String name ; + /** 全称 */ + private String fullName ; + /** 简称 */ + private String shortName ; + /** 是否业务系统 */ + private Boolean business ; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dto/PlatformOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/sys/dto/PlatformOperateDTO.java new file mode 100644 index 0000000..805a14c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dto/PlatformOperateDTO.java @@ -0,0 +1,33 @@ +package com.senmesh.usercenter.sys.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; +import javax.validation.constraints.NotNull; +import com.senmesh.common.validation.Update; + +import com.senmesh.common.dto.BaseOperateDTO; + +/** + * @author sr on 2021-05-24 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "系统应用操作") +public class PlatformOperateDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + @NotNull(message = "id不能为空", groups = {Update.class}) + private Long id; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dto/PlatformPageQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/sys/dto/PlatformPageQueryDTO.java new file mode 100644 index 0000000..448816a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dto/PlatformPageQueryDTO.java @@ -0,0 +1,31 @@ +package com.senmesh.usercenter.sys.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import java.io.Serializable; + +/** + * @author sr on 2021-05-24 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@EqualsAndHashCode(callSuper = true) +@ApiModel(description = "系统应用查询条件") +public class PlatformPageQueryDTO extends PageQueryDTO implements Serializable { + + /** + * + **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + + @ApiModelProperty("是否业务系统") + private Boolean business; +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/dto/PlatformQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/sys/dto/PlatformQueryDTO.java new file mode 100644 index 0000000..a6f2a35 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/dto/PlatformQueryDTO.java @@ -0,0 +1,32 @@ +package com.senmesh.usercenter.sys.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * @author sr on 2021-05-24 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "系统应用查询条件") +public class PlatformQueryDTO implements Serializable { + + /** + * + **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + + @ApiModelProperty("是否业务系统") + private Boolean business; +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/entity/Domain.java b/backend/src/main/java/com/senmesh/usercenter/sys/entity/Domain.java new file mode 100644 index 0000000..9fe89fa --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/entity/Domain.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.OrgBaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 域名 + * + * @author sr on 2021-05-24 + */ +@TableName("uc_domain") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class Domain extends OrgBaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + /** 平台编码 */ + private Integer platformCode ; + /** 域名 */ + private String domainName ; + /** ip:port */ + private String ipPort ; + /** 是否公共 */ + private Boolean publiced ; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/entity/DomainAuth.java b/backend/src/main/java/com/senmesh/usercenter/sys/entity/DomainAuth.java new file mode 100644 index 0000000..aa78b02 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/entity/DomainAuth.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 域名授权 + * + * @author sr on 2021-05-24 + */ +@TableName("uc_domain_auth") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class DomainAuth extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 域名id */ + private Long domainId ; + /** 授权类型标识 */ + private Integer authTypeCode ; + /** 授权客户端id */ + private Long authClientId ; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/entity/DomainSetting.java b/backend/src/main/java/com/senmesh/usercenter/sys/entity/DomainSetting.java new file mode 100644 index 0000000..1756570 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/entity/DomainSetting.java @@ -0,0 +1,47 @@ +package com.senmesh.usercenter.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; +import lombok.*; +import lombok.experimental.Accessors; + +/** + *

+ * 域名配置表 + *

+ * + * @author Carlye + * @since 2021-06-17 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableName("uc_domain_setting") +public class DomainSetting extends BaseEntity { + + + private static final long serialVersionUID = 8042528746194876802L; + /** + * 域名id + */ + private Long domainId; + + /** + * 类型 + */ + private Integer type; + + /** + * 配置数据 + */ + private String data; + + /** + * 备注 + */ + private String remark; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/entity/Faq.java b/backend/src/main/java/com/senmesh/usercenter/sys/entity/Faq.java new file mode 100644 index 0000000..1d8c9de --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/entity/Faq.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 常见问题表 + * + * @author sr on 2021-05-24 + */ +@TableName("uc_faq") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class Faq extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 排序字段 */ + private Integer faqOrder; + /** 类型 */ + private String faqType; + /** 问题 */ + private String question ; + /** 回答 */ + private String answer ; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/entity/FaqFile.java b/backend/src/main/java/com/senmesh/usercenter/sys/entity/FaqFile.java new file mode 100644 index 0000000..14fd667 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/entity/FaqFile.java @@ -0,0 +1,53 @@ +package com.senmesh.usercenter.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 常见问题 文件 + */ +@TableName("uc_faq_file") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class FaqFile extends BaseEntity { + + private static final long serialVersionUID = -1L; + /** + * 常见问题ID + */ + private Long questionId; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件编码 + */ + private String fileCode; + + /** + * 文件后缀 + */ + private String fileSuffix; + + /** + * 排序 + */ + private Integer sort; + + /** + * 描述 + */ + private String description; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/entity/Feedback.java b/backend/src/main/java/com/senmesh/usercenter/sys/entity/Feedback.java new file mode 100644 index 0000000..ad43096 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/entity/Feedback.java @@ -0,0 +1,53 @@ +package com.senmesh.usercenter.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; +import com.senmesh.common.validation.annotation.Phone; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 反馈表 + * + * @author sr on 2021-05-24 + */ +@TableName("uc_feedback") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class Feedback extends BaseEntity { + + /** + * + **/ + private static final long serialVersionUID = 1L; + + /** + * 类型 + */ + private String type; + /** + * 用户id + */ + private Long userId; + /** + * 手机号 + */ + + @Phone(groups = {Create.class, Update.class}) + private String phone; + /** + * 反馈内容 + */ + private String content; + + private String sourceType; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/entity/Platform.java b/backend/src/main/java/com/senmesh/usercenter/sys/entity/Platform.java new file mode 100644 index 0000000..62962b0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/entity/Platform.java @@ -0,0 +1,39 @@ +package com.senmesh.usercenter.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 系统应用 + * + * @author sr on 2021-05-24 + */ +@TableName("uc_platform") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class Platform extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 平台编码 */ + private Integer platformCode ; + /** 名称 */ + private String name ; + /** 全称 */ + private String fullName ; + /** 简称 */ + private String shortName ; + /** 是否业务系统 */ + private Boolean business ; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/mapper/DomainAuthMapper.xml b/backend/src/main/java/com/senmesh/usercenter/sys/mapper/DomainAuthMapper.xml new file mode 100644 index 0000000..492b42a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/mapper/DomainAuthMapper.xml @@ -0,0 +1,42 @@ + + + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/mapper/DomainMapper.xml b/backend/src/main/java/com/senmesh/usercenter/sys/mapper/DomainMapper.xml new file mode 100644 index 0000000..cbd3140 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/mapper/DomainMapper.xml @@ -0,0 +1,33 @@ + + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/mapper/DomainSettingMapper.xml b/backend/src/main/java/com/senmesh/usercenter/sys/mapper/DomainSettingMapper.xml new file mode 100644 index 0000000..82e7d31 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/mapper/DomainSettingMapper.xml @@ -0,0 +1,34 @@ + + + + + + diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/mapper/FaqFileMapper.xml b/backend/src/main/java/com/senmesh/usercenter/sys/mapper/FaqFileMapper.xml new file mode 100644 index 0000000..d7ab4b8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/mapper/FaqFileMapper.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/mapper/FaqMapper.xml b/backend/src/main/java/com/senmesh/usercenter/sys/mapper/FaqMapper.xml new file mode 100644 index 0000000..2666ecd --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/mapper/FaqMapper.xml @@ -0,0 +1,27 @@ + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/mapper/FeedbackMapper.xml b/backend/src/main/java/com/senmesh/usercenter/sys/mapper/FeedbackMapper.xml new file mode 100644 index 0000000..ffb1e31 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/mapper/FeedbackMapper.xml @@ -0,0 +1,38 @@ + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/mapper/PlatformMapper.xml b/backend/src/main/java/com/senmesh/usercenter/sys/mapper/PlatformMapper.xml new file mode 100644 index 0000000..5ee87a5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/mapper/PlatformMapper.xml @@ -0,0 +1,32 @@ + + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/mapstruct/DomainAuthMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/sys/mapstruct/DomainAuthMapMapper.java new file mode 100644 index 0000000..ab3ba2b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/mapstruct/DomainAuthMapMapper.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.sys.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.sys.dto.DomainAuthDTO; +import com.senmesh.usercenter.sys.entity.DomainAuth; +import com.senmesh.usercenter.sys.dto.DomainAuthOperateDTO; + +/** + * @author sr on 2021-05-24 + */ +@Mapper +public interface DomainAuthMapMapper { + + DomainAuthMapMapper INSTANCE = + Mappers.getMapper(DomainAuthMapMapper.class); + + /** + * dto to entity + * + * @param domainAuthDto + * @return + * @author sr on 2021-05-24 + */ + DomainAuth toEntity( + DomainAuthDTO domainAuthDto); + + + /** + * @param domainAuthOperateDTO + * @return + * @author sr on 2021-05-24 + */ + DomainAuth toEntity(DomainAuthOperateDTO domainAuthOperateDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/mapstruct/DomainMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/sys/mapstruct/DomainMapMapper.java new file mode 100644 index 0000000..fd3139a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/mapstruct/DomainMapMapper.java @@ -0,0 +1,43 @@ +package com.senmesh.usercenter.sys.mapstruct; + +import com.senmesh.usercenter.dto.DomainSettingOperateDTO; +import com.senmesh.usercenter.sys.entity.DomainSetting; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.sys.dto.DomainDTO; +import com.senmesh.usercenter.sys.entity.Domain; +import com.senmesh.usercenter.sys.dto.DomainOperateDTO; + +/** + * @author sr on 2021-05-24 + */ +@Mapper +public interface DomainMapMapper { + + DomainMapMapper INSTANCE = + Mappers.getMapper(DomainMapMapper.class); + + /** + * dto to entity + * + * @param domainDto + * @return + * @author sr on 2021-05-24 + */ + Domain toEntity( + DomainDTO domainDto); + + + /** + * @param domainOperateDTO + * @return + * @author sr on 2021-05-24 + */ + Domain toEntity(DomainOperateDTO domainOperateDTO); + + DomainSetting exchange(DomainSettingOperateDTO operateDTO); + + DomainDTO exchange(Domain domain); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/mapstruct/FaqFileMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/sys/mapstruct/FaqFileMapMapper.java new file mode 100644 index 0000000..b5ce384 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/mapstruct/FaqFileMapMapper.java @@ -0,0 +1,16 @@ +package com.senmesh.usercenter.sys.mapstruct; + +import com.senmesh.usercenter.sys.dto.FaqFileDTO; +import com.senmesh.usercenter.sys.entity.FaqFile; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface FaqFileMapMapper { + + FaqFileMapMapper INSTANCE = Mappers.getMapper(FaqFileMapMapper.class); + + FaqFile toEntity(FaqFileDTO dto); + + FaqFileDTO toDTO(FaqFile file); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/mapstruct/FaqMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/sys/mapstruct/FaqMapMapper.java new file mode 100644 index 0000000..c901bb2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/mapstruct/FaqMapMapper.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.sys.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.sys.dto.FaqDTO; +import com.senmesh.usercenter.sys.entity.Faq; +import com.senmesh.usercenter.sys.dto.FaqOperateDTO; + +/** + * @author sr on 2021-05-24 + */ +@Mapper +public interface FaqMapMapper { + + FaqMapMapper INSTANCE = + Mappers.getMapper(FaqMapMapper.class); + + /** + * dto to entity + * + * @param faqDto + * @return + * @author sr on 2021-05-24 + */ + Faq toEntity( + FaqDTO faqDto); + + + /** + * @param faqOperateDTO + * @return + * @author sr on 2021-05-24 + */ + Faq toEntity(FaqOperateDTO faqOperateDTO); + + + FaqDTO toDTO(Faq faq); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/mapstruct/FeedbackMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/sys/mapstruct/FeedbackMapMapper.java new file mode 100644 index 0000000..1c5247f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/mapstruct/FeedbackMapMapper.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.sys.mapstruct; + +import com.senmesh.usercenter.sys.dto.FeedbackDTO; +import com.senmesh.usercenter.sys.dto.FeedbackOperateDTO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.sys.entity.Feedback; + +/** + * @author sr on 2021-05-24 + */ +@Mapper +public interface FeedbackMapMapper { + + FeedbackMapMapper INSTANCE = + Mappers.getMapper(FeedbackMapMapper.class); + + /** + * dto to entity + * + * @param feedbackDto + * @return + * @author sr on 2021-05-24 + */ + Feedback toEntity( + FeedbackDTO feedbackDto); + + + /** + * @param feedbackOperateDTO + * @return + * @author sr on 2021-05-24 + */ + Feedback toEntity(FeedbackOperateDTO feedbackOperateDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/mapstruct/PlatformMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/sys/mapstruct/PlatformMapMapper.java new file mode 100644 index 0000000..19ef2a9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/mapstruct/PlatformMapMapper.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.sys.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.sys.dto.PlatformDTO; +import com.senmesh.usercenter.sys.entity.Platform; +import com.senmesh.usercenter.sys.dto.PlatformOperateDTO; + +/** + * @author sr on 2021-05-24 + */ +@Mapper +public interface PlatformMapMapper { + + PlatformMapMapper INSTANCE = + Mappers.getMapper(PlatformMapMapper.class); + + /** + * dto to entity + * + * @param platformDto + * @return + * @author sr on 2021-05-24 + */ + Platform toEntity( + PlatformDTO platformDto); + + + /** + * @param platformOperateDTO + * @return + * @author sr on 2021-05-24 + */ + Platform toEntity(PlatformOperateDTO platformOperateDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/service/DomainAuthService.java b/backend/src/main/java/com/senmesh/usercenter/sys/service/DomainAuthService.java new file mode 100644 index 0000000..5f8ffd9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/service/DomainAuthService.java @@ -0,0 +1,60 @@ +package com.senmesh.usercenter.sys.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.senmesh.common.validation.Create; +import com.senmesh.usercenter.sys.dto.DomainAuthDTO; +import com.senmesh.usercenter.sys.dto.DomainAuthOperateDTO; +import com.senmesh.usercenter.sys.dto.DomainAuthQueryDTO; +import com.senmesh.usercenter.sys.entity.DomainAuth; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.List; +import java.util.Set; + +/** + * 域名授权 + * + * @author sr on 2021-05-24 + */ +@Validated +public interface DomainAuthService extends IService { + + /** + * 新增 + * + * @param domainAuthOperateDTO + * @return + * @author sr on 2021-05-24 + */ + @Validated(Create.class) + Set link(@Valid DomainAuthOperateDTO domainAuthOperateDTO); + + /** + * 删除 + * + * @param domainAuthOperateDTO + * @author sr on 2021-05-24 + */ + @Validated(Create.class) + Set cancelLink(@Valid DomainAuthOperateDTO domainAuthOperateDTO); + + /** + * 查询 + * + * @param domainAuthQueryDTO + * @return + * @author sr on 2021-05-24 + */ + List list(DomainAuthQueryDTO domainAuthQueryDTO); + + /** + * 查询 + * + * @param domainAuthQueryDTO + * @return + * @author sr on 2021-05-24 + */ + List notLinkList(DomainAuthQueryDTO domainAuthQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/service/DomainService.java b/backend/src/main/java/com/senmesh/usercenter/sys/service/DomainService.java new file mode 100644 index 0000000..7e74640 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/service/DomainService.java @@ -0,0 +1,93 @@ +package com.senmesh.usercenter.sys.service; + +import java.util.List; + +import javax.validation.Valid; +import javax.validation.groups.Default; + +import org.springframework.validation.annotation.Validated; + +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; +import com.senmesh.usercenter.sys.dto.DomainDTO; +import com.senmesh.usercenter.sys.dto.DomainOperateDTO; +import com.senmesh.usercenter.sys.dto.DomainQueryDTO; + +/** + * 域名 + * + * @author sr on 2021-05-24 + */ +@Validated(Default.class) +public interface DomainService extends IDomainOrgService{ + + /** + * 新增 + * + * @param domainOperateDTO + * @return + * @author sr on 2021-05-24 + */ + @Validated(Create.class) + Long create(@Valid DomainOperateDTO domainOperateDTO); + + /** + * 修改 + * + * @param domainOperateDTO + * @author sr on 2021-05-24 + */ + @Validated(Update.class) + void modify(@Valid DomainOperateDTO domainOperateDTO); + + /** + * 删除 + * + * @param id + * @author sr on 2021-05-24 + */ + void remove(Long id); + + /** + * 查询 + * + * @param domainQueryDTO + * @return + * @author sr on 2021-05-24 + */ + List list(DomainQueryDTO domainQueryDTO); + + /** + * 分页查询 + * @param domainQueryDTO + * @author sr on 2022-02-28 + */ + void page(DomainQueryDTO domainQueryDTO); + + /** + * 查询单个(无异常) + * @param domainQueryDTO + * @return + * @author sr on 2022-02-28 + */ + DomainDTO findOne(DomainQueryDTO domainQueryDTO); + + /** + * 查询当前请求host对应系统编码 + * + * @return + * @author sr on 2021-11-16 + */ + Integer findPlatformCode(); + Integer findPlatformCode(String domainOrIp); + + /** + * 细节 + * + * @param id id + * @return {@link DomainDTO} + */ + DomainDTO detail(Long id); + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/service/DomainSettingService.java b/backend/src/main/java/com/senmesh/usercenter/sys/service/DomainSettingService.java new file mode 100644 index 0000000..0e85ab6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/service/DomainSettingService.java @@ -0,0 +1,79 @@ +package com.senmesh.usercenter.sys.service; + + +import com.baomidou.mybatisplus.extension.service.IService; +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; +import com.senmesh.usercenter.dto.DomainSettingOperateDTO; +import com.senmesh.usercenter.dto.DomainSettingReqDTO; +import com.senmesh.usercenter.dto.DomainSettingResDTO; +import com.senmesh.usercenter.sys.dto.DomainSettingBannerOperateDTO; +import com.senmesh.usercenter.sys.dto.DomainSettingQuickOperateDTO; +import com.senmesh.usercenter.sys.entity.DomainSetting; + +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; + +import java.util.List; + +/** + * 域设置服务 + * + * @author Carlye + * @date 2021/08/02 + */ +@Validated +public interface DomainSettingService extends IService { + + /** + * 新增 + * + * @param domainOperateDTO + * @return + * @author sr on 2021-05-24 + */ + @Validated(Create.class) + Long create(@Valid DomainSettingOperateDTO domainOperateDTO); + + /** + * 修改 + * + * @param domainOperateDTO + * @author sr on 2021-05-24 + */ + @Validated(Update.class) + void modify(@Valid DomainSettingOperateDTO domainOperateDTO); + + /** + * 删除 + * + * @param id + * @author sr on 2021-05-24 + */ + void remove(Long id); + + List list(@Valid DomainSettingReqDTO reqDTO); + + List listNoCache(DomainSettingReqDTO reqDTO); + + String findSettingData(DomainSettingReqDTO reqDTO); + + void cleanCache(); + + String quickCreate(DomainSettingQuickOperateDTO quickCreateOrModifyDTO); + + void quickModify(DomainSettingQuickOperateDTO quickCreateOrModifyDTO); + + List quickList(); + + String bannerCreate(DomainSettingBannerOperateDTO bannerOperateDTO); + + void bannerModify(DomainSettingBannerOperateDTO bannerOperateDTO); + + List bannerList(); + + void quickDelete(String id); + + void bannerDelete(String id); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/service/FaqFileService.java b/backend/src/main/java/com/senmesh/usercenter/sys/service/FaqFileService.java new file mode 100644 index 0000000..dc42ca8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/service/FaqFileService.java @@ -0,0 +1,20 @@ +package com.senmesh.usercenter.sys.service; + +import com.senmesh.usercenter.sys.dto.FaqFileDTO; +import com.senmesh.usercenter.sys.dto.FaqFileQueryDTO; + +import java.util.List; + +/** + * 常见问题表 + * + */ +public interface FaqFileService { + + List list(FaqFileQueryDTO queryDTO); + + FaqFileDTO create(FaqFileDTO queryDTO) ; + + void delete(Long id) ; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/service/FaqService.java b/backend/src/main/java/com/senmesh/usercenter/sys/service/FaqService.java new file mode 100644 index 0000000..12f6795 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/service/FaqService.java @@ -0,0 +1,56 @@ +package com.senmesh.usercenter.sys.service; + +import java.util.List; + +import com.senmesh.usercenter.sys.dto.FaqQueryDTO; +import com.senmesh.usercenter.sys.dto.FaqOperateDTO; +import com.senmesh.usercenter.sys.dto.FaqDTO; + +/** + * 常见问题表 + * + * @author sr on 2021-05-24 + */ +public interface FaqService { + + /** + * 新增 + * + * @param faqOperateDTO + * @return + * @author sr on 2021-05-24 + */ + Long create(FaqOperateDTO faqOperateDTO); + + /** + * 修改 + * + * @param faqOperateDTO + * @author sr on 2021-05-24 + */ + void modify(FaqOperateDTO faqOperateDTO); + + /** + * 删除 + * + * @param id + * @author sr on 2021-05-24 + */ + void remove(Long id); + + /** + * 查询 + * + * @param faqQueryDTO + * @return + * @author sr on 2021-05-24 + */ + List list(FaqQueryDTO faqQueryDTO); + + /** + * 获取单个 + * @param id + * @return + */ + FaqDTO get(Long id); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/service/FeedbackService.java b/backend/src/main/java/com/senmesh/usercenter/sys/service/FeedbackService.java new file mode 100644 index 0000000..328ea44 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/service/FeedbackService.java @@ -0,0 +1,50 @@ +package com.senmesh.usercenter.sys.service; + +import com.senmesh.usercenter.sys.dto.FeedbackDTO; +import com.senmesh.usercenter.sys.dto.FeedbackOperateDTO; +import com.senmesh.usercenter.sys.dto.FeedbackQueryDTO; + +import java.util.List; + +/** + * 反馈表 + * + * @author sr on 2021-05-24 + */ +public interface FeedbackService { + + /** + * 新增 + * + * @param feedbackOperateDTO + * @return + * @author sr on 2021-05-24 + */ + Long create(FeedbackOperateDTO feedbackOperateDTO); + + /** + * 修改 + * + * @param feedbackOperateDTO + * @author sr on 2021-05-24 + */ + void modify(FeedbackOperateDTO feedbackOperateDTO); + + /** + * 删除 + * + * @param id + * @author sr on 2021-05-24 + */ + void remove(Long id); + + /** + * 查询 + * + * @param feedbackQueryDTO + * @return + * @author sr on 2021-05-24 + */ + List list(FeedbackQueryDTO feedbackQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/service/IDomainOrgService.java b/backend/src/main/java/com/senmesh/usercenter/sys/service/IDomainOrgService.java new file mode 100644 index 0000000..d7ac932 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/service/IDomainOrgService.java @@ -0,0 +1,16 @@ +package com.senmesh.usercenter.sys.service; + +import java.util.Set; + +import com.senmesh.common.AlitaResult; + +public interface IDomainOrgService { + + /** + * 获取请求相关机构列表 + * @return + * @author sr on 2022-02-28 + */ + AlitaResult> listOrgId(); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/service/PlatformService.java b/backend/src/main/java/com/senmesh/usercenter/sys/service/PlatformService.java new file mode 100644 index 0000000..306d505 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/service/PlatformService.java @@ -0,0 +1,59 @@ +package com.senmesh.usercenter.sys.service; + +import com.senmesh.usercenter.sys.dto.PlatformDTO; +import com.senmesh.usercenter.sys.dto.PlatformOperateDTO; +import com.senmesh.usercenter.sys.dto.PlatformPageQueryDTO; +import com.senmesh.usercenter.sys.dto.PlatformQueryDTO; + +import java.util.List; + +/** + * 系统应用 + * + * @author sr on 2021-05-24 + */ +public interface PlatformService { + + /** + * 新增 + * + * @param platformOperateDTO + * @return + * @author sr on 2021-05-24 + */ + Long create(PlatformOperateDTO platformOperateDTO); + + /** + * 修改 + * + * @param platformOperateDTO + * @author sr on 2021-05-24 + */ + void modify(PlatformOperateDTO platformOperateDTO); + + /** + * 删除 + * + * @param id + * @author sr on 2021-05-24 + */ + void remove(Long id); + + /** + * 列表 + * + * @param queryDTO 查询dto + * @return {@link List}<{@link PlatformDTO}> + */ + List list(PlatformQueryDTO queryDTO); + + /** + * 查询 + * + * @param platformPageQueryDTO + * @return + * @author sr on 2021-05-24 + */ + List page(PlatformPageQueryDTO platformPageQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/service/impl/DomainAuthServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/sys/service/impl/DomainAuthServiceImpl.java new file mode 100644 index 0000000..e2cd2cf --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/service/impl/DomainAuthServiceImpl.java @@ -0,0 +1,94 @@ +package com.senmesh.usercenter.sys.service.impl; + +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.collect.Sets; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.auth.dto.AuthClientDTO; +import com.senmesh.usercenter.auth.dto.AuthClientQueryDTO; +import com.senmesh.usercenter.auth.service.AuthClientService; +import com.senmesh.usercenter.sys.dao.DomainAuthMapper; +import com.senmesh.usercenter.sys.dto.DomainAuthDTO; +import com.senmesh.usercenter.sys.dto.DomainAuthOperateDTO; +import com.senmesh.usercenter.sys.dto.DomainAuthQueryDTO; +import com.senmesh.usercenter.sys.entity.DomainAuth; +import com.senmesh.usercenter.sys.service.DomainAuthService; + +import cn.hutool.core.date.DateUtil; + +/** + * @author sr on 2021-05-24 + */ +@Service +public class DomainAuthServiceImpl extends ServiceImpl implements DomainAuthService { + + @Autowired + private AuthClientService authClientService; + + @Override + public Set link(DomainAuthOperateDTO domainAuthOperateDTO) { + Set res = Sets.newHashSet(); + for (Long authClientId : domainAuthOperateDTO.getAuthClientIds()) { + DomainAuth domainAuth = getOne(Wrappers.lambdaQuery() + .eq(DomainAuth::getDomainId,domainAuthOperateDTO.getDomainId()) + .eq(DomainAuth::getAuthClientId,authClientId) + .eq(DomainAuth::getDeleted,false) + ); + if (Objects.isNull(domainAuth)){ + AuthClientDTO authClient = authClientService + .findAuthClientDTO(AuthClientQueryDTO.builder().id(authClientId).build()); + Assert.notNull(authClient,"s授权客户端不存在"); + DomainAuth build = DomainAuth.builder() + .authClientId(authClientId) + .domainId(domainAuthOperateDTO.getDomainId()) + .authTypeCode(authClient.getAuthTypeCode()) + .build(); + save(build); + res.add(build.getId()); + }else { + res.add(domainAuth.getId()); + } + } + return res; + } + + @Override + public Set cancelLink(DomainAuthOperateDTO domainAuthOperateDTO) { + Set res = Sets.newHashSet(); + for (Long authClientId : domainAuthOperateDTO.getAuthClientIds()) { + DomainAuth domainAuth = getOne(Wrappers.lambdaQuery() + .eq(DomainAuth::getDomainId,domainAuthOperateDTO.getDomainId()) + .eq(DomainAuth::getAuthClientId,authClientId) + .eq(DomainAuth::getDeleted,false) + ); + Assert.notNull(domainAuth,"关联授权不存在"); + + update(Wrappers.lambdaUpdate() + .set(DomainAuth::getDeleted, true) + .set(DomainAuth::getUpdateBy, UserContextHolder.getExistLoginUserId()) + .set(DomainAuth::getUpdateTime, DateUtil.date()) + .eq(DomainAuth::getId,domainAuth.getId())); + res.add(domainAuth.getId()); + } + return res; + } + + + @Override + public List list(DomainAuthQueryDTO domainAuthQueryDTO) { + return getBaseMapper().listDomainAuthDTO(domainAuthQueryDTO); + } + + @Override + public List notLinkList(DomainAuthQueryDTO domainAuthQueryDTO) { + return getBaseMapper().notLinkList(domainAuthQueryDTO); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/service/impl/DomainServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/sys/service/impl/DomainServiceImpl.java new file mode 100644 index 0000000..8cfd26b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/service/impl/DomainServiceImpl.java @@ -0,0 +1,99 @@ +package com.senmesh.usercenter.sys.service.impl; + +import com.google.common.collect.Sets; +import com.senmesh.common.AlitaResult; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.ListUtil; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.security.util.HostContextHolder; +import com.senmesh.usercenter.sys.dao.DomainMapper; +import com.senmesh.usercenter.sys.dto.DomainDTO; +import com.senmesh.usercenter.sys.dto.DomainOperateDTO; +import com.senmesh.usercenter.sys.dto.DomainQueryDTO; +import com.senmesh.usercenter.sys.entity.Domain; +import com.senmesh.usercenter.sys.mapstruct.DomainMapMapper; +import com.senmesh.usercenter.sys.service.DomainService; +import com.senmesh.usercenter.sys.util.DomainUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Set; + +/** + * @author sr on 2021-05-24 + */ +@Service +public class DomainServiceImpl implements DomainService { + + @Autowired + private DomainMapper domainMapper; + + @Override + public Long create(DomainOperateDTO domainOperateDTO) { + if (!Boolean.TRUE.equals(domainOperateDTO.getPubliced())) { + Assert.notNull(domainOperateDTO.getOrgId(), "所属机构不能为空"); + } + Domain domain = DomainMapMapper.INSTANCE.toEntity(domainOperateDTO); + domainMapper.saveEntity(domain); + return domain.getId(); + } + + @Override + public void modify(DomainOperateDTO domainOperateDTO) { + Domain oldDomain = domainMapper.getById(domainOperateDTO.getId()); + Assert.notNull(oldDomain, "域名配置不存在"); + domainMapper.updateEntitySelective(DomainMapMapper.INSTANCE.toEntity(domainOperateDTO)); + } + + @Override + public void remove(Long id) { + domainMapper.deleteEntity(Domain.builder().id(id).build(), + UserContextHolder.getLoginUserId()); + } + + @Override + public List list(DomainQueryDTO domainQueryDTO) { + domainQueryDTO.disablePage(); + return domainMapper.listDomainDTO(domainQueryDTO); + } + + @Override + public void page(DomainQueryDTO domainQueryDTO) { + domainMapper.listDomainDTO(domainQueryDTO); + } + + @Override + public DomainDTO findOne(DomainQueryDTO domainQueryDTO) { + List domainDTOs = list(domainQueryDTO); + Assert.isTrue(!domainDTOs.isEmpty(), "请求host配置信息异常,请联系管理员"); + return ListUtil.first(domainDTOs); + } + + @Override + public Integer findPlatformCode() { + return this.findPlatformCode(null); + } + @Override + public Integer findPlatformCode(String domainOrIp) { + return findOne(DomainQueryDTO.builder() + .domainOrIp(DomainUtils.getOrDefault(domainOrIp)).build()).getPlatformCode(); + } + + @Override + public DomainDTO detail(Long id) { + return this.findOne(DomainQueryDTO.builder().id(id).build()); + } + + @Override + public AlitaResult> listOrgId() { + DomainDTO domainDTO = findOne(DomainQueryDTO.builder() + .domainOrIp(HostContextHolder.getHost()).build()); + Long orgId = domainDTO.getOrgId(); + Set orgIds = Sets.newHashSet(); + if (Boolean.FALSE.equals(domainDTO.getPubliced())) { + orgIds.add(orgId); + } + return AlitaResult.success(orgIds); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/service/impl/DomainSettingServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/sys/service/impl/DomainSettingServiceImpl.java new file mode 100644 index 0000000..c423ca3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/service/impl/DomainSettingServiceImpl.java @@ -0,0 +1,323 @@ +package com.senmesh.usercenter.sys.service.impl; + + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import javax.annotation.Resource; + +import org.apache.commons.compress.utils.Lists; +import org.apache.commons.lang3.StringUtils; +import org.springframework.aop.framework.AopContext; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.exception.util.UUIDUtils; +import com.senmesh.common.util.ListUtil; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.security.util.HostContextHolder; +import com.senmesh.usercenter.dto.DomainSettingOperateDTO; +import com.senmesh.usercenter.dto.DomainSettingReqDTO; +import com.senmesh.usercenter.dto.DomainSettingResDTO; +import com.senmesh.usercenter.sys.constant.DomainSettingConstant; +import com.senmesh.usercenter.sys.dao.DomainMapper; +import com.senmesh.usercenter.sys.dao.DomainSettingMapper; +import com.senmesh.usercenter.sys.dto.DomainDTO; +import com.senmesh.usercenter.sys.dto.DomainQueryDTO; +import com.senmesh.usercenter.sys.dto.DomainSettingBannerOperateDTO; +import com.senmesh.usercenter.sys.dto.DomainSettingQuickOperateDTO; +import com.senmesh.usercenter.sys.entity.DomainSetting; +import com.senmesh.usercenter.sys.mapstruct.DomainMapMapper; +import com.senmesh.usercenter.sys.service.DomainService; +import com.senmesh.usercenter.sys.service.DomainSettingService; +import com.senmesh.usercenter.sys.util.DomainUtils; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; + +/** + * 域设置服务 + * + * @author Carlye + * @date 2021/08/02 + */ +@Slf4j +@Service +public class DomainSettingServiceImpl extends ServiceImpl implements DomainSettingService { + + @Resource + private DomainMapper domainMapper; + @Autowired + private DomainService domainService; + + @Override + public Long create(DomainSettingOperateDTO domainOperateDTO) { + DomainSetting domain = DomainMapMapper.INSTANCE.exchange(domainOperateDTO); + baseMapper.saveEntity(domain); + DomainSettingServiceImpl domainSettingService = (DomainSettingServiceImpl) AopContext.currentProxy(); + domainSettingService.cleanCache(); + return domain.getId(); + } + + @Override + public void modify(DomainSettingOperateDTO domainOperateDTO) { + DomainSetting domainSetting = getOne(Wrappers.lambdaUpdate() + .eq(DomainSetting::getDeleted, false) + .eq(DomainSetting::getId, domainOperateDTO.getId()) + ); + Assert.notNull(domainSetting, "配置不存在"); + DomainSetting domain = DomainMapMapper.INSTANCE.exchange(domainOperateDTO); + baseMapper.updateEntitySelective(domain); + DomainSettingServiceImpl domainSettingService = (DomainSettingServiceImpl) AopContext.currentProxy(); + domainSettingService.cleanCache(); + } + + @Override + public void remove(Long id) { + DomainSetting domainSetting = getOne(Wrappers.lambdaUpdate() + .eq(DomainSetting::getDeleted, false) + .eq(DomainSetting::getId, id) + ); + Assert.notNull(domainSetting, "配置不存在"); + update(Wrappers.lambdaUpdate() + .set(DomainSetting::getDeleted, true) + .set(DomainSetting::getUpdateBy, UserContextHolder.getExistLoginUserId()) + .set(DomainSetting::getUpdateTime, DateUtil.date()) + .eq(DomainSetting::getId, id)); + DomainSettingServiceImpl domainSettingService = (DomainSettingServiceImpl) AopContext.currentProxy(); + domainSettingService.cleanCache(); + } + + @Override + public List list(DomainSettingReqDTO reqDTO) { + Long domainId = reqDTO.getDomainId(); + if (Objects.isNull(domainId)) { + String domainOrIp = DomainUtils.getOrDefault(reqDTO.getDomainOrIp()); + DomainDTO domainDTO = domainMapper.selectByDomainOrIp(domainOrIp); + if (Objects.isNull(domainDTO)) { + return Lists.newArrayList(); + } + domainId = domainDTO.getId(); + } + DomainSettingReqDTO reqDTO1 = new DomainSettingReqDTO(); + reqDTO1.setDomainId(domainId); + //查询缓存 + DomainSettingServiceImpl domainSettingServiceProxy = (DomainSettingServiceImpl) AopContext.currentProxy(); + List domainSettingResDTOS = domainSettingServiceProxy.listByCache(reqDTO1); + + if (CollectionUtils.isNotEmpty(reqDTO.getTypes())) { + return domainSettingResDTOS.stream().filter(d -> reqDTO.getTypes().contains(d.getType())).collect(Collectors.toList()); + } + return domainSettingResDTOS; + } + + @Cacheable(value = "domain_setting", key = " #reqDTO.toString() ") + public List listByCache(DomainSettingReqDTO reqDTO) { + return getBaseMapper().list(reqDTO); + } + + public List listNoCache(DomainSettingReqDTO reqDTO) { + return getBaseMapper().list(reqDTO); + } + + @Override + @CacheEvict(value = "domain_setting", allEntries = true) + public void cleanCache() { + //doNothing + } + + @Override + public String findSettingData(DomainSettingReqDTO reqDTO) { + List settings = ((DomainSettingService) AopContext.currentProxy()).list(reqDTO); + if (settings.isEmpty()) { + return null; + } + Assert.isTrue(settings.size() == 1, "查询到多个匹配配置,请检查数据"); + return ListUtil.first(settings).getData(); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public String quickCreate(DomainSettingQuickOperateDTO quickCreateDTO) { + + DomainDTO domainDTO = domainService.findOne(DomainQueryDTO.builder() + .domainOrIp(HostContextHolder.getHost()).build()); + + String uuid = UUIDUtils.generateUUID(); + quickCreateDTO.setId(uuid); + + List list = this.list(DomainSettingReqDTO.builder().type(DomainSettingConstant.QUICK).build()); + DomainSettingResDTO first = ListUtil.first(list); + + DomainSettingServiceImpl domainSettingService = (DomainSettingServiceImpl) AopContext.currentProxy(); + + JSONArray jsonArray = new JSONArray(); + jsonArray.add(quickCreateDTO); + + if (Objects.isNull(first)) { + domainSettingService.create(DomainSettingOperateDTO.builder() + .domainId(domainDTO.getId()) + .type(DomainSettingConstant.QUICK) + .remark(quickCreateDTO.getRemark()) + .data(JSONUtil.toJsonStr(jsonArray)) + .build()); + }else { + List domainSettingQuickOperateDTOS = JSONUtil.toList(first.getData(), DomainSettingQuickOperateDTO.class); + domainSettingQuickOperateDTOS.add(quickCreateDTO); + first.setData(JSONUtil.toJsonStr(domainSettingQuickOperateDTOS)); + DomainSettingOperateDTO modifyDto = new DomainSettingOperateDTO(); + BeanUtils.copyProperties(first,modifyDto); + domainSettingService.modify(modifyDto); + } + return uuid; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void quickModify(DomainSettingQuickOperateDTO quickModifyDTO) { + List list = this.list(DomainSettingReqDTO.builder().type(DomainSettingConstant.QUICK).build()); + DomainSettingResDTO first = ListUtil.first(list); + if (Objects.isNull(first)) { + return; + } + DomainSettingServiceImpl domainSettingService = (DomainSettingServiceImpl) AopContext.currentProxy(); + + List resultList = JSONUtil.toList(first.getData(), DomainSettingQuickOperateDTO.class); + for (DomainSettingQuickOperateDTO modifyDTO : resultList) { + if (StringUtils.equals(quickModifyDTO.getId(),modifyDTO.getId())) { + BeanUtils.copyProperties(quickModifyDTO,modifyDTO); + } + } + DomainSettingOperateDTO modifyDto = new DomainSettingOperateDTO(); + BeanUtils.copyProperties(first,modifyDto); + modifyDto.setData(JSONUtil.toJsonStr(resultList)); + domainSettingService.modify(modifyDto); + } + + @Override + public List quickList() { + List list = this.list(DomainSettingReqDTO.builder().type(DomainSettingConstant.QUICK).build()); + DomainSettingResDTO first = ListUtil.first(list); + if (Objects.isNull(first)) { + return new ArrayList<>(); + } + List resultList = JSONUtil.toList(first.getData(), DomainSettingQuickOperateDTO.class); + resultList = resultList.stream().sorted(Comparator.comparing(DomainSettingQuickOperateDTO::getSort)).collect(Collectors.toList()); + return resultList; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public String bannerCreate(DomainSettingBannerOperateDTO bannerOperateDTO) { + + DomainDTO domainDTO = domainService.findOne(DomainQueryDTO.builder() + .domainOrIp(HostContextHolder.getHost()).build()); + + String uuid = UUIDUtils.generateUUID(); + bannerOperateDTO.setId(uuid); + + List list = this.list(DomainSettingReqDTO.builder().type(DomainSettingConstant.BANNER).build()); + DomainSettingResDTO first = ListUtil.first(list); + + DomainSettingServiceImpl domainSettingService = (DomainSettingServiceImpl) AopContext.currentProxy(); + + JSONArray jsonArray = new JSONArray(); + jsonArray.add(bannerOperateDTO); + + if (Objects.isNull(first)) { + domainSettingService.create(DomainSettingOperateDTO.builder() + .domainId(domainDTO.getId()) + .type(DomainSettingConstant.BANNER) + .data(JSONUtil.toJsonStr(jsonArray)) + .build()); + }else { + List domainSettingBannerOperateDTOS = JSONUtil.toList(first.getData(), DomainSettingBannerOperateDTO.class); + domainSettingBannerOperateDTOS.add(bannerOperateDTO); + first.setData(JSONUtil.toJsonStr(domainSettingBannerOperateDTOS)); + DomainSettingOperateDTO modifyDto = new DomainSettingOperateDTO(); + BeanUtils.copyProperties(first,modifyDto); + domainSettingService.modify(modifyDto); + } + return uuid; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void bannerModify(DomainSettingBannerOperateDTO bannerOperateDTO) { + List list = this.list(DomainSettingReqDTO.builder().type(DomainSettingConstant.BANNER).build()); + DomainSettingResDTO first = ListUtil.first(list); + if (Objects.isNull(first)) { + return; + } + DomainSettingServiceImpl domainSettingService = (DomainSettingServiceImpl) AopContext.currentProxy(); + + List resultList = JSONUtil.toList(first.getData(), DomainSettingBannerOperateDTO.class); + for (DomainSettingBannerOperateDTO modifyDTO : resultList) { + if (StringUtils.equals(bannerOperateDTO.getId(),modifyDTO.getId())) { + BeanUtils.copyProperties(bannerOperateDTO,modifyDTO); + } + } + DomainSettingOperateDTO modifyDto = new DomainSettingOperateDTO(); + BeanUtils.copyProperties(first,modifyDto); + modifyDto.setData(JSONUtil.toJsonStr(resultList)); + domainSettingService.modify(modifyDto); + } + + @Override + public List bannerList() { + List list = this.list(DomainSettingReqDTO.builder().type(DomainSettingConstant.BANNER).build()); + DomainSettingResDTO first = ListUtil.first(list); + if (Objects.isNull(first)) { + return new ArrayList<>(); + } + List resultList = JSONUtil.toList(first.getData(), DomainSettingBannerOperateDTO.class); + return resultList; + } + + @Override + public void quickDelete(String id) { + List list = this.list(DomainSettingReqDTO.builder().type(DomainSettingConstant.QUICK).build()); + DomainSettingResDTO first = ListUtil.first(list); + if (Objects.isNull(first)) { + return; + } + DomainSettingServiceImpl domainSettingService = (DomainSettingServiceImpl) AopContext.currentProxy(); + + List resultList = JSONUtil.toList(first.getData(), DomainSettingQuickOperateDTO.class); + resultList = resultList.stream().filter(result -> !StringUtils.equals(result.getId(),id)).collect(Collectors.toList()); + DomainSettingOperateDTO modifyDto = new DomainSettingOperateDTO(); + BeanUtils.copyProperties(first,modifyDto); + modifyDto.setData(JSONUtil.toJsonStr(resultList)); + domainSettingService.modify(modifyDto); + } + + @Override + public void bannerDelete(String id) { + List list = this.list(DomainSettingReqDTO.builder().type(DomainSettingConstant.BANNER).build()); + DomainSettingResDTO first = ListUtil.first(list); + if (Objects.isNull(first)) { + return; + } + DomainSettingServiceImpl domainSettingService = (DomainSettingServiceImpl) AopContext.currentProxy(); + + List resultList = JSONUtil.toList(first.getData(), DomainSettingBannerOperateDTO.class); + resultList = resultList.stream().filter(result -> !StringUtils.equals(result.getId(),id)).collect(Collectors.toList()); + DomainSettingOperateDTO modifyDto = new DomainSettingOperateDTO(); + BeanUtils.copyProperties(first,modifyDto); + modifyDto.setData(JSONUtil.toJsonStr(resultList)); + domainSettingService.modify(modifyDto); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/service/impl/FaqFileServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/sys/service/impl/FaqFileServiceImpl.java new file mode 100644 index 0000000..9244f50 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/service/impl/FaqFileServiceImpl.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.sys.service.impl; + +import com.senmesh.usercenter.sys.dao.FaqFileMapper; +import com.senmesh.usercenter.sys.dto.FaqFileDTO; +import com.senmesh.usercenter.sys.dto.FaqFileQueryDTO; +import com.senmesh.usercenter.sys.entity.FaqFile; +import com.senmesh.usercenter.sys.mapstruct.FaqFileMapMapper; +import com.senmesh.usercenter.sys.service.FaqFileService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class FaqFileServiceImpl implements FaqFileService { + + @Autowired + private FaqFileMapper faqFileMapper; + + @Override + public List list(FaqFileQueryDTO queryDTO){ + return faqFileMapper.filePage(queryDTO); + } + + @Override + public FaqFileDTO create(FaqFileDTO operateDTO) { + FaqFile file = FaqFileMapMapper.INSTANCE.toEntity(operateDTO); + faqFileMapper.saveEntity(file); + return FaqFileMapMapper.INSTANCE.toDTO(file); + } + + @Override + public void delete(Long id) { + faqFileMapper.deleteEntity(FaqFile.builder().id(id).build()); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/service/impl/FaqServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/sys/service/impl/FaqServiceImpl.java new file mode 100644 index 0000000..ca201f6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/service/impl/FaqServiceImpl.java @@ -0,0 +1,54 @@ +package com.senmesh.usercenter.sys.service.impl; + +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.sys.dao.FaqMapper; +import com.senmesh.usercenter.sys.dto.FaqDTO; +import com.senmesh.usercenter.sys.dto.FaqOperateDTO; +import com.senmesh.usercenter.sys.dto.FaqQueryDTO; +import com.senmesh.usercenter.sys.entity.Faq; +import com.senmesh.usercenter.sys.mapstruct.FaqMapMapper; +import com.senmesh.usercenter.sys.service.FaqService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * @author sr on 2021-05-24 + */ +@Service +public class FaqServiceImpl implements FaqService { + + @Autowired + private FaqMapper faqMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long create(FaqOperateDTO faqOperateDTO) { + Faq faq = FaqMapMapper.INSTANCE.toEntity(faqOperateDTO); + faqMapper.saveEntity(faq); + return faq.getId(); + } + + @Override + public void modify(FaqOperateDTO faqOperateDTO) { + Faq faq = FaqMapMapper.INSTANCE.toEntity(faqOperateDTO); + faqMapper.updateEntitySelective(faq, UserContextHolder.getLoginUserId()); + } + + @Override + public void remove(Long id) { + faqMapper.deleteEntity(Faq.builder().id(id).build()); + } + + @Override + public List list(FaqQueryDTO faqQueryDTO) { + return faqMapper.listFaqDTO(faqQueryDTO); + } + + @Override + public FaqDTO get(Long id) { + return FaqMapMapper.INSTANCE.toDTO(faqMapper.getById(id)); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/service/impl/FeedbackServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/sys/service/impl/FeedbackServiceImpl.java new file mode 100644 index 0000000..ab1835d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/service/impl/FeedbackServiceImpl.java @@ -0,0 +1,63 @@ +package com.senmesh.usercenter.sys.service.impl; + +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.exception.util.ExceptionUtils; +import com.senmesh.common.util.SensitiveWordUtils; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.sys.dao.FeedbackMapper; +import com.senmesh.usercenter.sys.dto.FeedbackDTO; +import com.senmesh.usercenter.sys.dto.FeedbackOperateDTO; +import com.senmesh.usercenter.sys.dto.FeedbackQueryDTO; +import com.senmesh.usercenter.sys.entity.Feedback; +import com.senmesh.usercenter.sys.mapstruct.FeedbackMapMapper; +import com.senmesh.usercenter.sys.service.FeedbackService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @author sr on 2021-05-24 + */ +@Service +public class FeedbackServiceImpl implements FeedbackService { + + @Autowired + private FeedbackMapper feedbackMapper; + + @Override + public Long create(FeedbackOperateDTO feedbackOperateDTO) { + if (!SensitiveWordUtils.check(feedbackOperateDTO.getContent())) { + throw new BusinessException("非法反馈内容"); + } + + Feedback feedback = FeedbackMapMapper.INSTANCE.toEntity(feedbackOperateDTO); + if(feedback.getUserId() == null ){ + feedback.setUserId(UserContextHolder.getLoginUserId()); + } + ExceptionUtils.throwBusinessException( + StringUtils.isNotBlank(feedback.getContent()) && feedback.getContent().length() > 200 , + "反馈内容过长"); + + feedbackMapper.saveEntity(feedback); + return feedback.getId(); + } + + @Override + public void modify(FeedbackOperateDTO feedbackOperateDTO) { + Feedback feedback = FeedbackMapMapper.INSTANCE.toEntity(feedbackOperateDTO); + feedbackMapper.updateEntitySelective(feedback,UserContextHolder.getLoginUserId()); + } + + @Override + public void remove(Long id) { + feedbackMapper.deleteEntity(Feedback.builder().id(id).build()); + } + + @Override + public List list(FeedbackQueryDTO feedbackQueryDTO) { + return feedbackMapper.listFeedbackDTO(feedbackQueryDTO); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/service/impl/PlatformServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/sys/service/impl/PlatformServiceImpl.java new file mode 100644 index 0000000..1761899 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/service/impl/PlatformServiceImpl.java @@ -0,0 +1,53 @@ +package com.senmesh.usercenter.sys.service.impl; + +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.sys.dao.PlatformMapper; +import com.senmesh.usercenter.sys.dto.PlatformDTO; +import com.senmesh.usercenter.sys.dto.PlatformOperateDTO; +import com.senmesh.usercenter.sys.dto.PlatformPageQueryDTO; +import com.senmesh.usercenter.sys.dto.PlatformQueryDTO; +import com.senmesh.usercenter.sys.entity.Platform; +import com.senmesh.usercenter.sys.service.PlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @author sr on 2021-05-24 + */ +@Service +public class PlatformServiceImpl implements PlatformService { + + @Autowired + private PlatformMapper platformMapper; + + @Override + public Long create(PlatformOperateDTO platformOperateDTO) { + // TODO Auto-generated method stub + return null; + } + + @Override + public void modify(PlatformOperateDTO platformOperateDTO) { + // TODO Auto-generated method stub + + } + + @Override + public void remove(Long id) { + platformMapper.deleteEntity(Platform.builder().id(id).build(), + UserContextHolder.getLoginUserId()); + } + + @Override + public List list(PlatformQueryDTO queryDTO) { + return platformMapper.list(queryDTO); + } + + @Override + public List page(PlatformPageQueryDTO platformPageQueryDTO) { + return platformMapper.page(platformPageQueryDTO); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/util/DomainOrgUtils.java b/backend/src/main/java/com/senmesh/usercenter/sys/util/DomainOrgUtils.java new file mode 100644 index 0000000..2cbe70c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/util/DomainOrgUtils.java @@ -0,0 +1,26 @@ +package com.senmesh.usercenter.sys.util; + +import java.util.Set; + +import org.springframework.stereotype.Component; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.usercenter.sys.service.IDomainOrgService; + +@Component +public class DomainOrgUtils { + + private static IDomainOrgService domainOrgService; + + public DomainOrgUtils(IDomainOrgService domainOrgService) { + DomainOrgUtils.domainOrgService = domainOrgService; + } + + public static Set list(){ + AlitaResult> result = domainOrgService.listOrgId(); + Assert.isTrue(result.getSuccess(), result.getMsg()); + return result.getData(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/sys/util/DomainUtils.java b/backend/src/main/java/com/senmesh/usercenter/sys/util/DomainUtils.java new file mode 100644 index 0000000..9d77d22 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/sys/util/DomainUtils.java @@ -0,0 +1,15 @@ +package com.senmesh.usercenter.sys.util; + +import org.apache.commons.lang3.StringUtils; + +import com.senmesh.security.util.HostContextHolder; + +/** + * @author sr on 2021-05-24 + */ +public class DomainUtils { + + public static String getOrDefault(String domainOrIp) { + return StringUtils.isBlank(domainOrIp) ? HostContextHolder.getHost() : domainOrIp; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/controller/AnonTagRelationshipController.java b/backend/src/main/java/com/senmesh/usercenter/tag/controller/AnonTagRelationshipController.java new file mode 100644 index 0000000..9c035e8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/controller/AnonTagRelationshipController.java @@ -0,0 +1,48 @@ +package com.senmesh.usercenter.tag.controller; + + +import com.senmesh.common.AlitaResult; +import com.senmesh.usercenter.tag.dto.TagRelationshipMapQueryDTO; +import com.senmesh.usercenter.tag.dto.TagRelationshipQueryDTO; +import com.senmesh.usercenter.tag.service.ITagRelationshipService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + *

+ * 前端控制器 + *

+ * + * @author Carlye + * @since 2021-01-21 + */ +@Api(tags = "标签关系信息") +//@RestController +@RequestMapping("/anon/tag_relationship") +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class AnonTagRelationshipController { + + private final ITagRelationshipService tagRelationshipsService; + + @GetMapping("/source_id_map") + @ApiOperation("创建标签关系信息") + public AlitaResult>> sourceIdMap(TagRelationshipMapQueryDTO queryDTO) { + return AlitaResult.success(tagRelationshipsService.sourceIdMap(queryDTO)); + } + + @GetMapping("/source_ids") + @ApiOperation("查询source_id集合") + public AlitaResult> sourceIds(TagRelationshipQueryDTO queryDTO) { + return AlitaResult.success(tagRelationshipsService.sourceIds(queryDTO)); + } +} + diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/controller/TagController.java b/backend/src/main/java/com/senmesh/usercenter/tag/controller/TagController.java new file mode 100644 index 0000000..36e0f80 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/controller/TagController.java @@ -0,0 +1,89 @@ +package com.senmesh.usercenter.tag.controller; + + +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.tag.dto.*; +import com.senmesh.usercenter.tag.service.ITagService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + *

+ * 标签表 前端控制器 + *

+ * + * @author Carlye + * @since 2021-01-21 + */ +@Api(tags = "标签信息") +@RestController +@RequestMapping("/tag") +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class TagController { + + private final ITagService tagService; + + /** + * 创建 + * + * @param tagDTO 标签dto + * @return {@link AlitaResult} + */ + @PostMapping("/create") + @ApiOperation("创建岗位信息") + public AlitaResult create(@RequestBody TagCreateDTO tagDTO) { + return AlitaResult.success(tagService.create(tagDTO)); + } + + /** + * 批量创建 + * + * @param tagDTO 标签dto + * @return {@link AlitaResult>} + */ + @PostMapping("/batch_create") + @ApiOperation("创建岗位信息") + public AlitaResult> batchCreate(@RequestBody TagBatchCreateDTO tagDTO) { + return AlitaResult.success(tagService.batchCreate(tagDTO)); + } + + /** + * 分页查询 + * + * @param pageQueryDTO 页面查询dto + * @return {@link AlitaResult>} + */ + @GetMapping("/list") + @ApiOperation("列表查询") + public AlitaResult> list(TagPageQueryDTO pageQueryDTO) { + pageQueryDTO.setNeedPage(Boolean.FALSE); + return AlitaResult.success(tagService.page(pageQueryDTO)); + } + + /** + * 分页查询 + * + * @param pageQueryDTO 页面查询dto + * @return {@link AlitaResult>} + */ + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(TagPageQueryDTO pageQueryDTO) { + tagService.page(pageQueryDTO); + return AlitaResult.success(pageQueryDTO.getPageResult()); + } + + @PostMapping("/update") + @ApiOperation("更新") + public AlitaResult update(@RequestBody TagUpdateDTO updateDTO) { + tagService.update(updateDTO); + return AlitaResult.success(); + } +} + diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/controller/TagRelationshipController.java b/backend/src/main/java/com/senmesh/usercenter/tag/controller/TagRelationshipController.java new file mode 100644 index 0000000..c536ea7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/controller/TagRelationshipController.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.tag.controller; + + +import com.senmesh.common.AlitaResult; +import com.senmesh.usercenter.tag.dto.TagRelationshipDTO; +import com.senmesh.usercenter.tag.service.ITagRelationshipService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + *

+ * 前端控制器 + *

+ * + * @author Carlye + * @since 2021-01-21 + */ +@Api(tags = "标签关系信息") +//@RestController +@RequestMapping("/tag_relationship") +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class TagRelationshipController { + + private final ITagRelationshipService tagRelationshipsService; + + @PostMapping("/create") + @ApiOperation("创建标签关系信息") + public AlitaResult create(@RequestBody TagRelationshipDTO tagRelationshipDTO) { + return AlitaResult.success(tagRelationshipsService.create(tagRelationshipDTO)); + } +} + diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/dao/TagMapper.java b/backend/src/main/java/com/senmesh/usercenter/tag/dao/TagMapper.java new file mode 100644 index 0000000..e9aaef2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/dao/TagMapper.java @@ -0,0 +1,21 @@ +package com.senmesh.usercenter.tag.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.senmesh.usercenter.tag.dto.TagDTO; +import com.senmesh.usercenter.tag.dto.TagPageQueryDTO; +import com.senmesh.usercenter.tag.entity.Tag; + +import java.util.List; + +/** + *

+ * 标签表 Mapper 接口 + *

+ * + * @author Carlye + * @since 2021-01-21 + */ +public interface TagMapper extends BaseMapper { + + List page(TagPageQueryDTO queryDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/dao/TagRelationshipMapper.java b/backend/src/main/java/com/senmesh/usercenter/tag/dao/TagRelationshipMapper.java new file mode 100644 index 0000000..762d19b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/dao/TagRelationshipMapper.java @@ -0,0 +1,31 @@ +package com.senmesh.usercenter.tag.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.senmesh.usercenter.tag.dto.HrOperatingPostDTO; +import com.senmesh.usercenter.tag.dto.TagRelationshipInfoDTO; +import com.senmesh.usercenter.tag.dto.TagRelationshipMapQueryDTO; +import com.senmesh.usercenter.tag.dto.TagRelationshipQueryDTO; +import com.senmesh.usercenter.tag.entity.TagRelationship; + +import java.util.List; +import java.util.Set; + +/** + *

+ * Mapper 接口 + *

+ * + * @author Carlye + * @since 2021-01-21 + */ +public interface TagRelationshipMapper extends BaseMapper { + + HrOperatingPostDTO findById(Long id); + + int updatePost(HrOperatingPostDTO postDTO); + + List sourceIdMap(TagRelationshipMapQueryDTO queryDTO); + + Set sourceIds(TagRelationshipQueryDTO queryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/dto/HrOperatingPostDTO.java b/backend/src/main/java/com/senmesh/usercenter/tag/dto/HrOperatingPostDTO.java new file mode 100644 index 0000000..6f7e5a6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/dto/HrOperatingPostDTO.java @@ -0,0 +1,102 @@ +package com.senmesh.usercenter.tag.dto; + +import com.senmesh.common.entity.BaseEntity; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; + +/** + *

+ * 招聘系统-岗位信息表 + *

+ * + * @author chenyun + * @since 2021-01-08 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +public class HrOperatingPostDTO extends BaseEntity { + + private static final long serialVersionUID = -6380138352828899597L; + /** + * 机构ID + */ + private Long orgId; + + /** + * 公司ID (hr_company) + */ + private Long companyId; + + /** + * 岗位名称 + */ + private String postName; + + /** + * 岗位所在地 + */ + private String postLocation; + + /** + * 岗位薪酬福利单位 1:CNY + */ + private Integer postSalaryUnit; + + /** + * 岗位薪酬福利下限 + */ + private BigDecimal postSalaryLow; + + /** + * 岗位薪酬福利上限 + */ + private BigDecimal postSalaryUp; + + /** + * 岗位薪酬福利类型 1:日薪 2:月薪 3:年薪 99:面议 + */ + private Integer postSalaryType; + + /** + * 岗位招聘人数 + */ + private Integer postNumber; + + /** + * 岗位福利待遇 + */ + private String postBeneft; + + /** + * 岗位描述 + */ + private String postDescription; + + /** + * 岗位要求 + */ + private String postRequire; + + /** + * 状态 + */ + private Integer status; + + /** + * 关联岗位Id集合 + */ + private String affiliationPosts; + + /** + * 关联标签集合 + */ + private String affiliationTags; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagBatchCreateDTO.java b/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagBatchCreateDTO.java new file mode 100644 index 0000000..20ebf29 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagBatchCreateDTO.java @@ -0,0 +1,43 @@ +package com.senmesh.usercenter.tag.dto; + +import com.senmesh.common.entity.BaseEntity; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotNull; + +/** + *

+ * 标签表 + *

+ * + * @author Carlye + * @since 2021-01-21 + */ +@ApiModel("标签批量创建信息DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +public class TagBatchCreateDTO extends BaseEntity { + private static final long serialVersionUID = 5250371091927498053L; + @ApiModelProperty("标签名称集合") + private String tagNames; + + @ApiModelProperty("标签业务分类 1:岗位福利待遇") + @NotNull(message = "标签类型不能为空") + private Integer tagType; + + @ApiModelProperty("关联到哪个表 1:hr_operating_post") + @NotNull(message = "关联表不能为空") + private Integer sourceType; + + @ApiModelProperty("关联ID") + @NotNull(message = "关联id不能为空") + private Long sourceId; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagCreateDTO.java b/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagCreateDTO.java new file mode 100644 index 0000000..f3ea62d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagCreateDTO.java @@ -0,0 +1,43 @@ +package com.senmesh.usercenter.tag.dto; + +import com.senmesh.common.entity.BaseEntity; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + *

+ * 标签表 + *

+ * + * @author Carlye + * @since 2021-01-21 + */ +@ApiModel("标签信息创建DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +public class TagCreateDTO extends BaseEntity { + private static final long serialVersionUID = 5250371091927498053L; + @ApiModelProperty("标签名称") + @NotEmpty(message = "标签名称不能为空") + private String tagName; + + @ApiModelProperty("标签业务分类 1:岗位福利待遇") + @NotNull(message = "标签类型不能为空") + private Integer tagType; + + @ApiModelProperty("关联到哪个表 1:hr_operating_post") + private Integer sourceType; + + @ApiModelProperty("关联ID") + private Long sourceId; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagDTO.java b/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagDTO.java new file mode 100644 index 0000000..2d70c9b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagDTO.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.tag.dto; + +import com.senmesh.common.entity.BaseEntity; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + *

+ * 标签表 + *

+ * + * @author Carlye + * @since 2021-01-21 + */ +@ApiModel("标签信息DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +public class TagDTO extends BaseEntity { + private static final long serialVersionUID = 5250371091927498053L; + @ApiModelProperty("标签名称") + @NotEmpty(message = "标签名称不能为空") + private String tagName; + + @ApiModelProperty("标签业务分类 1:岗位福利待遇") + @NotNull(message = "标签类型不能为空") + private Integer tagType; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagPageQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagPageQueryDTO.java new file mode 100644 index 0000000..79b8c90 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagPageQueryDTO.java @@ -0,0 +1,33 @@ +package com.senmesh.usercenter.tag.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + *

+ * 标签表 + *

+ * + * @author Carlye + * @since 2021-01-21 + */ +@ApiModel("标签查询DTO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +public class TagPageQueryDTO extends PageQueryDTO { + private static final long serialVersionUID = 5250371091927498053L; + @ApiModelProperty("标签名称") + private String tagName; + + @ApiModelProperty("标签业务分类 1-岗位福利待遇 2-技能") + private Integer tagType; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagRelationshipDTO.java b/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagRelationshipDTO.java new file mode 100644 index 0000000..9a20e18 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagRelationshipDTO.java @@ -0,0 +1,42 @@ +package com.senmesh.usercenter.tag.dto; + +import com.senmesh.common.entity.BaseEntity; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotNull; + +/** + *

+ * + *

+ * + * @author Carlye + * @since 2021-01-21 + */ +@ApiModel("标签关系信息DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +public class TagRelationshipDTO extends BaseEntity { + + + private static final long serialVersionUID = -519594241373286878L; + + @ApiModelProperty("标签ID") + @NotNull(message = "标签ID不能为空") + private Long tagId; + + @ApiModelProperty("关联到哪个表 1:hr_operating_post") + @NotNull(message = "关联类型不能为空") + private Integer sourceType; + + @ApiModelProperty("关联ID") + @NotNull(message = "关联ID不能为空") + private Long sourceId; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagRelationshipInfoDTO.java b/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagRelationshipInfoDTO.java new file mode 100644 index 0000000..5ebdc8e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagRelationshipInfoDTO.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.tag.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + *

+ * + *

+ * + * @author Carlye + * @since 2021-01-21 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Accessors(chain = true) +public class TagRelationshipInfoDTO implements Serializable { + + private static final long serialVersionUID = 3725333598124945060L; + + private Long id; + + @ApiModelProperty("标签ID") + private String tagName; + + @ApiModelProperty("关联ID") + private Long sourceId; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagRelationshipMapQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagRelationshipMapQueryDTO.java new file mode 100644 index 0000000..5a14654 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagRelationshipMapQueryDTO.java @@ -0,0 +1,39 @@ +package com.senmesh.usercenter.tag.dto; + +import com.senmesh.common.entity.BaseEntity; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotNull; +import java.util.Set; + +/** + *

+ * + *

+ * + * @author Carlye + * @since 2021-01-21 + */ +@ApiModel("标签关系信息DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +public class TagRelationshipMapQueryDTO extends BaseEntity { + + + private static final long serialVersionUID = -519594241373286878L; + + @ApiModelProperty("关联到哪个表 1:hr_operating_post") + @NotNull(message = "关联类型不能为空") + private Integer sourceType; + + @ApiModelProperty("关联ID") + @NotNull(message = "关联ID不能为空") + private Set sourceIds; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagRelationshipQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagRelationshipQueryDTO.java new file mode 100644 index 0000000..0808a58 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagRelationshipQueryDTO.java @@ -0,0 +1,38 @@ +package com.senmesh.usercenter.tag.dto; + +import com.senmesh.common.entity.BaseEntity; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotNull; +import java.util.Set; + +/** + *

+ * + *

+ * + * @author Carlye + * @since 2021-01-21 + */ +@ApiModel("标签关系信息DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +public class TagRelationshipQueryDTO extends BaseEntity { + + + private static final long serialVersionUID = -519594241373286878L; + + @ApiModelProperty("关联到哪个表 1:hr_operating_post") + @NotNull(message = "关联类型不能为空") + private Integer sourceType; + + @ApiModelProperty("标签名") + private Set tagNames; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagUpdateDTO.java b/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagUpdateDTO.java new file mode 100644 index 0000000..2941f25 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/dto/TagUpdateDTO.java @@ -0,0 +1,31 @@ +package com.senmesh.usercenter.tag.dto; + +import com.senmesh.common.entity.BaseEntity; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotEmpty; + +/** + *

+ * 标签表 + *

+ * + * @author Carlye + * @since 2021-01-21 + */ +@ApiModel("标签信息修改DTO") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +public class TagUpdateDTO extends BaseEntity { + private static final long serialVersionUID = 5250371091927498053L; + @ApiModelProperty("标签名称") + @NotEmpty(message = "标签名称不能为空") + private String tagName; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/entity/Tag.java b/backend/src/main/java/com/senmesh/usercenter/tag/entity/Tag.java new file mode 100644 index 0000000..b0a6e12 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/entity/Tag.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.tag.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; +import lombok.*; +import lombok.experimental.Accessors; + +/** + *

+ * 标签表 + *

+ * + * @author Carlye + * @since 2021-01-21 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableName("xs_tag") +public class Tag extends BaseEntity { + +private static final long serialVersionUID=1L; + + /** + * 标签名称 + */ + private String tagName; + + /** + * 标签业务分类 1:岗位福利待遇 2:技能标签 + */ + private Integer tagType; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/entity/TagRelationship.java b/backend/src/main/java/com/senmesh/usercenter/tag/entity/TagRelationship.java new file mode 100644 index 0000000..64b2676 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/entity/TagRelationship.java @@ -0,0 +1,41 @@ +package com.senmesh.usercenter.tag.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; +import lombok.*; +import lombok.experimental.Accessors; + +/** + *

+ * + *

+ * + * @author Carlye + * @since 2021-01-21 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableName("xs_tag_relationship") +public class TagRelationship extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** + * 标签表ID + */ + private Long tagId; + + /** + * 关联到哪个表 1:hr_operating_post + */ + private Integer sourceType; + + /** + * 关联ID + */ + private Long sourceId; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/enums/SourceTypeEnum.java b/backend/src/main/java/com/senmesh/usercenter/tag/enums/SourceTypeEnum.java new file mode 100644 index 0000000..fd025da --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/enums/SourceTypeEnum.java @@ -0,0 +1,39 @@ +package com.senmesh.usercenter.tag.enums; + +import com.baomidou.mybatisplus.annotation.EnumValue; +import com.senmesh.mybatis.handle.BaseEnum; + + +/** + * 关联类型枚举 + * + * @author Carlye + * @date 2021/01/21 + */ +public enum SourceTypeEnum implements BaseEnum { + POST(1, "关联岗位"), + WORKSTATION(3,"关联零工驿站"); + + @EnumValue + private final Integer sourceType; + + private final String desc; + + SourceTypeEnum(Integer sourceType, String desc) { + this.sourceType = sourceType; + this.desc = desc; + } + + public Integer getSourceType() { + return sourceType; + } + + public String getDesc() { + return desc; + } + + @Override + public Integer getValue() { + return sourceType; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/enums/TagTypeEnum.java b/backend/src/main/java/com/senmesh/usercenter/tag/enums/TagTypeEnum.java new file mode 100644 index 0000000..a76400d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/enums/TagTypeEnum.java @@ -0,0 +1,39 @@ +package com.senmesh.usercenter.tag.enums; + +import com.baomidou.mybatisplus.annotation.EnumValue; +import com.senmesh.mybatis.handle.BaseEnum; + + +/** + * 标签类型枚举 + * + * @author Carlye + * @date 2021/01/21 + */ +public enum TagTypeEnum implements BaseEnum { + POST(1, "岗位福利标签"), + WORKSTATION(3,"零工驿站标签"); + + @EnumValue + private final Integer tagType; + + private final String desc; + + TagTypeEnum(Integer tagType, String desc) { + this.tagType = tagType; + this.desc = desc; + } + + public Integer getTagType() { + return tagType; + } + + public String getDesc() { + return desc; + } + + @Override + public Integer getValue() { + return tagType; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/mapper/TagMapper.xml b/backend/src/main/java/com/senmesh/usercenter/tag/mapper/TagMapper.xml new file mode 100644 index 0000000..e6368f3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/mapper/TagMapper.xml @@ -0,0 +1,17 @@ + + + + + + diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/mapper/TagRelationshipMapper.xml b/backend/src/main/java/com/senmesh/usercenter/tag/mapper/TagRelationshipMapper.xml new file mode 100644 index 0000000..3464e15 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/mapper/TagRelationshipMapper.xml @@ -0,0 +1,56 @@ + + + + + update hr_operating_post + set update_time = now(), + update_by = 1, + affiliation_tags = #{affiliationTags} + where deleted = FALSE + and id = #{id} + + + + + + diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/mapstruct/TagMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/tag/mapstruct/TagMapMapper.java new file mode 100644 index 0000000..6b0b968 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/mapstruct/TagMapMapper.java @@ -0,0 +1,30 @@ +package com.senmesh.usercenter.tag.mapstruct; + +import com.senmesh.usercenter.tag.dto.TagCreateDTO; +import com.senmesh.usercenter.tag.dto.TagDTO; +import com.senmesh.usercenter.tag.dto.TagRelationshipDTO; +import com.senmesh.usercenter.tag.entity.Tag; +import com.senmesh.usercenter.tag.entity.TagRelationship; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * @author sr on 2020-08-27 + */ +@Mapper +public interface TagMapMapper { + + TagMapMapper instance = Mappers.getMapper(TagMapMapper.class); + + + Tag exchange(TagDTO tagDTO); + + Tag exchange(TagCreateDTO tagDTO); + + TagDTO exchange(Tag tag); + + TagRelationship exchange(TagRelationshipDTO tagRelationshipDTO); + + TagRelationshipDTO exchange(TagRelationship tagRelationship); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/service/ITagRelationshipService.java b/backend/src/main/java/com/senmesh/usercenter/tag/service/ITagRelationshipService.java new file mode 100644 index 0000000..bb8f729 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/service/ITagRelationshipService.java @@ -0,0 +1,60 @@ +package com.senmesh.usercenter.tag.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.senmesh.usercenter.tag.dto.TagBatchCreateDTO; +import com.senmesh.usercenter.tag.dto.TagRelationshipDTO; +import com.senmesh.usercenter.tag.dto.TagRelationshipMapQueryDTO; +import com.senmesh.usercenter.tag.dto.TagRelationshipQueryDTO; +import com.senmesh.usercenter.tag.entity.TagRelationship; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.groups.Default; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + *

+ * 服务类 + *

+ * + * @author Carlye + * @since 2021-01-21 + */ +@Validated(Default.class) +public interface ITagRelationshipService extends IService { + + + /** + * 创建标签关联关系 + * + * @param tagRelationshipDTO 标签dto的关系 + * @return {@link TagRelationshipDTO} + * @throws RuntimeException 运行时异常 + */ + TagRelationshipDTO create(@Valid TagRelationshipDTO tagRelationshipDTO) throws RuntimeException; + + + /** + * 删除标签关联关系 + * + */ + void deleted(TagBatchCreateDTO createDTO); + + /** + * 源id映射 + * + * @param queryDTO 查询dto + * @return {@link Map}<{@link Long}, {@link List}<{@link String}>> + */ + Map> sourceIdMap(TagRelationshipMapQueryDTO queryDTO); + + /** + * 查询资源ID集合 + * + * @param queryDTO 查询dto + * @return {@link Set}<{@link Long}> + */ + Set sourceIds(TagRelationshipQueryDTO queryDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/service/ITagService.java b/backend/src/main/java/com/senmesh/usercenter/tag/service/ITagService.java new file mode 100644 index 0000000..c8578ea --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/service/ITagService.java @@ -0,0 +1,57 @@ +package com.senmesh.usercenter.tag.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.senmesh.usercenter.tag.dto.*; +import com.senmesh.usercenter.tag.entity.Tag; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.groups.Default; +import java.util.List; + +/** + *

+ * 标签表 服务类 + *

+ * + * @author Carlye + * @since 2021-01-21 + */ +@Validated(Default.class) +public interface ITagService extends IService { + + + /** + * 新建标签 + * + * @param tagDTO 标签dto + * @return {@link TagDTO} + */ + TagDTO create(@Valid TagCreateDTO tagDTO) throws RuntimeException; + + /** + * 批量创建 + * + * @param createDTO 创建dto + * @return {@link List} + * @throws RuntimeException 运行时异常 + */ + List batchCreate(@Valid TagBatchCreateDTO createDTO) throws RuntimeException; + + /** + * 分页查询 + * + * @param queryDTO 查询dto + * @return {@link List} + */ + List page(TagPageQueryDTO queryDTO); + + /** + * 更新 + * + * @param updateDTO 更新dto + * @return {@link TagDTO} + */ + void update(TagUpdateDTO updateDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/service/impl/ITagRelationshipServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/tag/service/impl/ITagRelationshipServiceImpl.java new file mode 100644 index 0000000..8903303 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/service/impl/ITagRelationshipServiceImpl.java @@ -0,0 +1,96 @@ +package com.senmesh.usercenter.tag.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.senmesh.usercenter.tag.dao.TagRelationshipMapper; +import com.senmesh.usercenter.tag.dto.*; +import com.senmesh.usercenter.tag.entity.TagRelationship; +import com.senmesh.usercenter.tag.mapstruct.TagMapMapper; +import com.senmesh.usercenter.tag.service.ITagRelationshipService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.validation.Valid; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collector; +import java.util.stream.Collectors; + + +/** + *

+ * 服务实现类 + *

+ * + * @author Carlye + * @since 2021-01-21 + */ +@Slf4j +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class ITagRelationshipServiceImpl extends ServiceImpl implements ITagRelationshipService { + + @Override + @Transactional + public TagRelationshipDTO create(@Valid TagRelationshipDTO tagRelationshipDTO) throws RuntimeException { + TagRelationship exchange = TagMapMapper.instance.exchange(tagRelationshipDTO); + TagRelationship one = getOne(Wrappers.lambdaQuery() + .eq(TagRelationship::getTagId, tagRelationshipDTO.getTagId()) + .eq(TagRelationship::getSourceId, tagRelationshipDTO.getSourceId()) + .eq(TagRelationship::getSourceType, tagRelationshipDTO.getSourceType()) + ); + if (Objects.nonNull(one) && one.getDeleted()) { + update(Wrappers.lambdaUpdate().set(TagRelationship::getDeleted, Boolean.FALSE).eq(TagRelationship::getId, one.getId())); + return TagMapMapper.instance.exchange(one); + } + save(exchange); +// if (save(exchange) && tagRelationshipsDTO.getSourceType().equals(SourceTypeEnum.POST.getSourceType())) { +// //需要同步更新岗位表信息 +// HrOperatingPostDTO postDTO = getBaseMapper().findById(tagRelationshipsDTO.getSourceId()); +// String affiliationTags; +// Tag tag; +// if (Objects.nonNull(postDTO) && Objects.nonNull(tag = tagService.getById(tagRelationshipsDTO)) +// && StringUtils.isNotEmpty(affiliationTags = postDTO.getAffiliationTags()) +// && !affiliationTags.contains(tag.getTagName())) { +// affiliationTags = String.join(",", affiliationTags, tag.getTagName()); +// postDTO.setAffiliationTags(affiliationTags); +// getBaseMapper().updatePost(postDTO); +// } +// } + return TagMapMapper.instance.exchange(exchange); + } + + @Override + public void deleted(TagBatchCreateDTO createDTO) { + update(Wrappers.lambdaUpdate().set(TagRelationship::getDeleted, Boolean.TRUE) + .eq(TagRelationship::getSourceType, createDTO.getSourceType()) + .eq(TagRelationship::getSourceId, createDTO.getSourceId()) + ); + } + + @Override + public Map> sourceIdMap(TagRelationshipMapQueryDTO queryDTO) { + List relationshipInfoDTOS = getBaseMapper().sourceIdMap(queryDTO); + if (CollUtil.isEmpty(relationshipInfoDTOS)) { + return Maps.newHashMap(); + } + return relationshipInfoDTOS.stream().collect(Collectors.groupingBy(TagRelationshipInfoDTO::getSourceId, Collector.of(Lists::newArrayList, List::add, + (left, right) -> { + left.addAll(right); + return left; + }, (List list) -> list.stream().sorted((v1, v2) -> v2.getId().compareTo(v1.getId())).map(TagRelationshipInfoDTO::getTagName).collect(Collectors.toList())))); + } + + @Override + public Set sourceIds(TagRelationshipQueryDTO queryDTO) { + return getBaseMapper().sourceIds(queryDTO); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/tag/service/impl/ITagServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/tag/service/impl/ITagServiceImpl.java new file mode 100644 index 0000000..122ce55 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/tag/service/impl/ITagServiceImpl.java @@ -0,0 +1,134 @@ +package com.senmesh.usercenter.tag.service.impl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import javax.validation.Valid; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.aop.framework.AopContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.tag.dao.TagMapper; +import com.senmesh.usercenter.tag.dto.TagBatchCreateDTO; +import com.senmesh.usercenter.tag.dto.TagCreateDTO; +import com.senmesh.usercenter.tag.dto.TagDTO; +import com.senmesh.usercenter.tag.dto.TagPageQueryDTO; +import com.senmesh.usercenter.tag.dto.TagRelationshipDTO; +import com.senmesh.usercenter.tag.dto.TagUpdateDTO; +import com.senmesh.usercenter.tag.entity.Tag; +import com.senmesh.usercenter.tag.mapstruct.TagMapMapper; +import com.senmesh.usercenter.tag.service.ITagRelationshipService; +import com.senmesh.usercenter.tag.service.ITagService; + +import cn.hutool.core.date.DateUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + + +/** + *

+ * 标签表 服务实现类 + *

+ * + * @author Carlye + * @since 2021-01-21 + */ +@Slf4j +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class ITagServiceImpl extends ServiceImpl implements ITagService { + + private final ITagRelationshipService tagRelationshipsService; + + @Override + @Transactional + public TagDTO create(@Valid TagCreateDTO tagDTO) { + //查询历史是否存在相同标签 + List tags = list(Wrappers.lambdaQuery() + .eq(Tag::getTagType, tagDTO.getTagType()) + .eq(Tag::getTagName, tagDTO.getTagName())); + if (CollectionUtils.isNotEmpty(tags)) { + Tag tag = tags.get(0); + if (tag.getDeleted()) { + //更新已经删除的标签未 + update(Wrappers.lambdaUpdate().set(Tag::getDeleted, Boolean.FALSE).eq(Tag::getId, tag.getId())); + tag.setDeleted(Boolean.FALSE); + } + if (Objects.nonNull(tagDTO.getSourceType()) && Objects.nonNull(tagDTO.getSourceId())) { + //创建标签关系 + tagRelationshipsService.create(TagRelationshipDTO.builder().tagId(tag.getId()).sourceType(tagDTO.getSourceType()).sourceId(tagDTO.getSourceId()).build()); + } + return TagMapMapper.instance.exchange(tag); + } + //新增标签 + Tag exchange = TagMapMapper.instance.exchange(tagDTO); + save(exchange); + if (Objects.nonNull(tagDTO.getSourceType()) && Objects.nonNull(tagDTO.getSourceId())) { + //创建标签关系 + tagRelationshipsService.create(TagRelationshipDTO.builder().tagId(exchange.getId()).sourceType(tagDTO.getSourceType()).sourceId(tagDTO.getSourceId()).build()); + } + return TagMapMapper.instance.exchange(exchange); + } + + @Override + @Transactional + public List batchCreate(@Valid TagBatchCreateDTO createDTO) throws RuntimeException { + // 先删除关联关系 + tagRelationshipsService.deleted(createDTO); + // 后创建关联关系 + String tagNames = createDTO.getTagNames(); + if(StringUtils.isBlank(tagNames)){ + return new ArrayList<>(); + } + return Arrays.stream(tagNames.split(",")) + .map(tagName -> + ((ITagServiceImpl) AopContext.currentProxy()).create( + TagCreateDTO.builder() + .tagType(createDTO.getTagType()) + .tagName(tagName) + .sourceType(createDTO.getSourceType()) + .sourceId(createDTO.getSourceId()) + .build()) + ).collect(Collectors.toList()); + } + + @Override + public List page(TagPageQueryDTO queryDTO) { + return getBaseMapper().page(queryDTO); + } + + @Override + public void update(TagUpdateDTO updateDTO) { + Tag tag = getOne(Wrappers.lambdaQuery() + .eq(Tag::getDeleted, false) + .eq(Tag::getId, updateDTO.getId()) + ); + if (Objects.nonNull(tag)){ + if (Boolean.TRUE.equals(updateDTO.getDeleted())){ + update(Wrappers.lambdaUpdate() + .set(Tag::getDeleted,true) + .set(Tag::getUpdateBy, UserContextHolder.getExistLoginUserId()) + .set(Tag::getUpdateTime, DateUtil.now()) + .eq(Tag::getId,updateDTO.getId()) + ); + }else if (!StringUtils.equals(tag.getTagName(),updateDTO.getTagName())){ + update(Wrappers.lambdaUpdate() + .set(Tag::getTagName,updateDTO.getTagName()) + .set(Tag::getUpdateBy, UserContextHolder.getExistLoginUserId()) + .set(Tag::getUpdateTime, DateUtil.now()) + .eq(Tag::getId,updateDTO.getId()) + ); + } + } + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/constant/UserBizAuthStatusEnum.java b/backend/src/main/java/com/senmesh/usercenter/user/constant/UserBizAuthStatusEnum.java new file mode 100644 index 0000000..f59fbde --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/constant/UserBizAuthStatusEnum.java @@ -0,0 +1,21 @@ +package com.senmesh.usercenter.user.constant; + +/** + * 用户类型 + * @author czy on 2021-06-10 + */ +public enum UserBizAuthStatusEnum { + + PASS(1), NOT_PASS(2); + + private Integer type; + + UserBizAuthStatusEnum(Integer type) { + this.type = type; + } + + public Integer getType() { + return type; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/constant/UserCancelConstants.java b/backend/src/main/java/com/senmesh/usercenter/user/constant/UserCancelConstants.java new file mode 100644 index 0000000..35ca226 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/constant/UserCancelConstants.java @@ -0,0 +1,17 @@ +package com.senmesh.usercenter.user.constant; + + +/** + * 用户取消常量 + * + * @author cheny + * @date 2023/03/07 + */ +public interface UserCancelConstants { + + /** + * 申请状态 1:已申请 2:已注销 + */ + Integer USER_CANCEL_STATUS_APPLY = 1; + Integer USER_CANCEL_STATUS_SUCCESS = 2; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/constant/UserConfigConstants.java b/backend/src/main/java/com/senmesh/usercenter/user/constant/UserConfigConstants.java new file mode 100644 index 0000000..1f030d4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/constant/UserConfigConstants.java @@ -0,0 +1,13 @@ +package com.senmesh.usercenter.user.constant; + +/** + * @author sr on 2021-08-12 + */ +public interface UserConfigConstants { + + /** 忽略初始密码 **/ + String IGNORE_INIT_PWD_CODE = "ignore_init_pwd"; + + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/constant/UserIdentityPhotoConstants.java b/backend/src/main/java/com/senmesh/usercenter/user/constant/UserIdentityPhotoConstants.java new file mode 100644 index 0000000..4401d7c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/constant/UserIdentityPhotoConstants.java @@ -0,0 +1,12 @@ +package com.senmesh.usercenter.user.constant; + +/** + * @author sr on 2021-05-24 + */ +public interface UserIdentityPhotoConstants { + + /**身份证图片认证状态 1.未认证 3.认证成功**/ + public static final Integer PHOTO_STATUS_NOT_AUTH = 1; + public static final Integer PHOTO_STATUS_SUCCESS = 3; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/constant/UserStatusEnum.java b/backend/src/main/java/com/senmesh/usercenter/user/constant/UserStatusEnum.java new file mode 100644 index 0000000..8f56b5c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/constant/UserStatusEnum.java @@ -0,0 +1,27 @@ +package com.senmesh.usercenter.user.constant; + +/** + * 用户类型 + * @author sr on 2021-05-31 + */ +public enum UserStatusEnum { + + /** 1待激活 **/ + INIT(1), + /** 2已激活 **/ + ACTIVE(2), + /** 3已注销 **/ + CLOSED(3); + + private Integer status; + + UserStatusEnum(Integer status) { + this.status = status; + } + + public Integer getStatus() { + return status; + } + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/constant/UserTypeEnum.java b/backend/src/main/java/com/senmesh/usercenter/user/constant/UserTypeEnum.java new file mode 100644 index 0000000..89b3bcf --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/constant/UserTypeEnum.java @@ -0,0 +1,47 @@ +package com.senmesh.usercenter.user.constant; + +import java.util.Map; + +import com.google.common.collect.Maps; +import com.senmesh.common.exception.util.Assert; + +/** + * 用户类型 + * @author sr on 2021-05-31 + */ +public enum UserTypeEnum { + + /** 机构 **/ + ORG(1), + /** 个人 **/ + PERSON(2), + /** api机构用户 **/ + API_ORG(3); + + private static Map userTypeMap; + + static { + UserTypeEnum[] userTypeEnums = UserTypeEnum.values(); + userTypeMap = Maps.newHashMapWithExpectedSize(userTypeEnums.length); + for (UserTypeEnum userTypeEnum : userTypeEnums) { + userTypeMap.put(userTypeEnum.getType(), userTypeEnum); + } + } + + private Integer type; + + UserTypeEnum(Integer type) { + this.type = type; + } + + public Integer getType() { + return type; + } + + public static UserTypeEnum one(Integer userType) { + UserTypeEnum userTypeEnum = userTypeMap.get(userType); + Assert.notNull(userTypeEnum, "用户类型异常"); + return userTypeEnum; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/controller/OrgUserController.java b/backend/src/main/java/com/senmesh/usercenter/user/controller/OrgUserController.java new file mode 100644 index 0000000..40be2a5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/controller/OrgUserController.java @@ -0,0 +1,57 @@ +package com.senmesh.usercenter.user.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.common.validation.Create; +import com.senmesh.security.jwt.JwtTokenUtils; +import com.senmesh.usercenter.user.dto.OrgUserInfoDTO; +import com.senmesh.usercenter.user.dto.OrgUserInfoQueryDTO; +import com.senmesh.usercenter.user.dto.OrgUserOperateDTO; +import com.senmesh.usercenter.user.login.dto.OrgDetailDTO; +import com.senmesh.usercenter.user.service.OrgUserService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * @author sr on 2021-05-24 + */ +@RestController +@RequestMapping("org_user") +@Api(tags = "机构用户表") +public class OrgUserController { + + @Autowired + private OrgUserService orgUserService; + + @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create( + @Validated(Create.class) @RequestBody OrgUserOperateDTO orgUserOperateDTO) { + return AlitaResult.success(orgUserService.create(orgUserOperateDTO)); + } + + @GetMapping("/list") + @ApiOperation("查询机构用户信息列表") + public AlitaResult> list(OrgUserInfoQueryDTO queryDTO) { + return AlitaResult.success(orgUserService.list(queryDTO)); + } + + @GetMapping("/list_login_org") + @ApiOperation("查询登录用户所有机构列表") + public AlitaResult> listLoginOrg() { + return AlitaResult.success(orgUserService.listLoginOrgByUser(UserContextHolder.getExistLoginUserId(), null)); + } + + @GetMapping("/change_login_org") + @ApiOperation("修改登录用户机构") + public AlitaResult changeLoginOrg(@RequestParam Long orgId) { + JwtTokenUtils.changeToken(UserContextHolder.getExistLoginUserId(), orgId); + return AlitaResult.success(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/controller/UserAuthController.java b/backend/src/main/java/com/senmesh/usercenter/user/controller/UserAuthController.java new file mode 100644 index 0000000..ffdd94c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/controller/UserAuthController.java @@ -0,0 +1,65 @@ +package com.senmesh.usercenter.user.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.PathVariable; + +import com.senmesh.common.validation.Update; +import com.senmesh.common.AlitaResult; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.user.dto.UserAuthQueryDTO; +import com.senmesh.usercenter.user.service.UserAuthService; +import com.senmesh.usercenter.user.dto.UserAuthDTO; +import com.senmesh.usercenter.user.dto.UserAuthOperateDTO; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2021-05-24 + */ +@RestController +@RequestMapping("user_auth") +@Api(tags = "用户授权中间表") +public class UserAuthController { + + @Autowired + private UserAuthService userAuthService; + + @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create( + @Validated @RequestBody UserAuthOperateDTO userAuthOperateDTO){ + return AlitaResult.success(userAuthService.create(userAuthOperateDTO)); + } + + @PutMapping("/modify") + @ApiOperation("修改") + public AlitaResult modify( + @Validated(Update.class) @RequestBody UserAuthOperateDTO userAuthOperateDTO){ + userAuthService.modify(userAuthOperateDTO); + return AlitaResult.success(true); + } + + @DeleteMapping("/remove/{id}") + @ApiOperation("删除") + public AlitaResult remove(@PathVariable Long id){ + userAuthService.remove(id); + return AlitaResult.success(true); + } + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(UserAuthQueryDTO userAuthQueryDTO){ + userAuthService.page(userAuthQueryDTO); + return AlitaResult.success(userAuthQueryDTO.getPageResult()); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/controller/UserCancelController.java b/backend/src/main/java/com/senmesh/usercenter/user/controller/UserCancelController.java new file mode 100644 index 0000000..0aba2ce --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/controller/UserCancelController.java @@ -0,0 +1,55 @@ +package com.senmesh.usercenter.user.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.user.dto.UserCancelApplyReqDTO; +import com.senmesh.usercenter.user.dto.UserCancelDTO; +import com.senmesh.usercenter.user.dto.UserCancelPageQueryDTO; +import com.senmesh.usercenter.user.service.UserCancelService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +/** + * 用户取消控制器 + * + * @author cheny + * @date 2023/03/07 + */ +@RestController +@Api(tags = "用户注销") +@RequestMapping("user/cancel") +public class UserCancelController { + + @Autowired + private UserCancelService userCancelService; + + @PostMapping("apply") + @ApiOperation("用户注销申请") + public AlitaResult apply(@RequestBody @Validated UserCancelApplyReqDTO applyDTO) { + return AlitaResult.success(userCancelService.apply(applyDTO)); + } + + @GetMapping() + @ApiOperation("查询用户注销状态") + public AlitaResult find() { + Long existLoginUserId = UserContextHolder.getExistLoginUserId(); + return AlitaResult.success(userCancelService.find(UserCancelPageQueryDTO.builder().userId(existLoginUserId).build())); + } + + @PostMapping("agree/{userId}") + @ApiOperation("同意注销") + public AlitaResult agreeCancel(@PathVariable("userId") Long userId) { + return AlitaResult.success(userCancelService.agreeCancel(userId)); + } + + @GetMapping("page") + @ApiOperation("用户取消申请分页查询") + public AlitaResult> page(UserCancelPageQueryDTO queryDTO) { + userCancelService.page(queryDTO); + return AlitaResult.success(queryDTO.getPageResult()); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/controller/UserConfigController.java b/backend/src/main/java/com/senmesh/usercenter/user/controller/UserConfigController.java new file mode 100644 index 0000000..c929f33 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/controller/UserConfigController.java @@ -0,0 +1,66 @@ +package com.senmesh.usercenter.user.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.user.dto.UserConfigDTO; +import com.senmesh.usercenter.user.dto.UserConfigOperateDTO; +import com.senmesh.usercenter.user.dto.UserConfigQueryDTO; +import com.senmesh.usercenter.user.service.UserConfigService; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2021-08-12 + */ +@RestController +@RequestMapping("user_config") +@Api(tags = "用户配置") +public class UserConfigController { + + @Autowired + private UserConfigService userConfigService; + + @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create( + @Validated(Create.class) @RequestBody UserConfigOperateDTO userConfigOperateDTO){ + return AlitaResult.success(userConfigService.create(userConfigOperateDTO)); + } + + @PutMapping("/modify") + @ApiOperation("修改") + public AlitaResult modify( + @Validated(Update.class) @RequestBody UserConfigOperateDTO userConfigOperateDTO){ + userConfigService.modify(userConfigOperateDTO); + return AlitaResult.success(true); + } + + @DeleteMapping("/remove/{id}") + @ApiOperation("删除") + public AlitaResult remove(@PathVariable Long id){ + userConfigService.remove(id); + return AlitaResult.success(true); + } + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(UserConfigQueryDTO userConfigQueryDTO){ + userConfigService.list(userConfigQueryDTO); + return AlitaResult.success(userConfigQueryDTO.getPageResult()); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/controller/UserController.java b/backend/src/main/java/com/senmesh/usercenter/user/controller/UserController.java new file mode 100644 index 0000000..08cfcc7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/controller/UserController.java @@ -0,0 +1,319 @@ +package com.senmesh.usercenter.user.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.common.validation.Update; +import com.senmesh.security.dto.UserInfoDTO; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.dto.OrgUserEditDTO; +import com.senmesh.usercenter.dto.SuperResetPasswordDTO; +import com.senmesh.usercenter.user.constant.UserConfigConstants; +import com.senmesh.usercenter.user.dto.*; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeProviderEnum; +import com.senmesh.usercenter.user.phone.dto.PhoneCodeSmsDTO; +import com.senmesh.usercenter.user.phone.util.PhoneCodeUtils; +import com.senmesh.usercenter.user.service.UserConfigService; +import com.senmesh.usercenter.user.service.UserService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** + * @author sr on 2021-05-24 + */ +@RestController +@Api(tags = "用户") +public class UserController { + + @Autowired + private UserService userService; + + @Autowired + private UserConfigService userConfigService; + + @PostMapping("user/modify") + @ApiOperation("编辑用户信息") + public AlitaResult modify( + @Validated(Update.class) @RequestBody UserOperateDTO userOperateDTO) { + userService.modify(userOperateDTO); + return AlitaResult.success(); + } + + @GetMapping("user/page") + @ApiOperation("分页查询") + public AlitaResult> page(UserQueryDTO userQueryDTO) { + userService.page(userQueryDTO); + return AlitaResult.success(userQueryDTO.getPageResult()); + } + + @GetMapping("user/list") + @ApiOperation("用户列表查询") + public AlitaResult> list(UserQueryDTO userQueryDTO) { + userQueryDTO.setNeedPage(false); + return AlitaResult.success(userService.list(userQueryDTO)); + } + + @GetMapping("user/get_by_id") + @ApiOperation("获取用户信息") + public AlitaResult getById(@RequestParam("userId") Long userId) { + return AlitaResult.success(userService.get(userId)); + } + + @GetMapping("user/find") + @ApiOperation("获取用户信息") + public AlitaResult find(UserQueryDTO userQueryDTO) { + return AlitaResult.success(userService.find(userQueryDTO)); + } + + @GetMapping("unac/user/get") + @ApiOperation("用户信息查询") + public AlitaResult get(@RequestParam(value = "userId",required = false) Long userId) { + userId = Objects.nonNull(userId) ? userId : UserContextHolder.getLoginUserId(); + return AlitaResult.success(userService.get(userId)); + } + +// @GetMapping("anon/person_in_charge") + @ApiOperation("企业负责人查询") + public AlitaResult> personInCharge(@RequestParam("userIds") Set userIds) { + return AlitaResult.success(userService.personInCharge(userIds)); + } + + @PostMapping("user/create_person_user_by_card") + @ApiOperation("创建个人用户-证件") + public AlitaResult createPersonUser( + @Validated @RequestBody PersonUserCardCreateDTO personUserCardCreateDTO) { + return AlitaResult.success(userService.createPersonUser(personUserCardCreateDTO).getId()); + } + + @PostMapping("user/batch_create_person_user_by_card") + @ApiOperation("批量创建个人用户-证件") + public AlitaResult> createPersonUser( + @Validated @RequestBody List personUserCardCreateDTOs) { + return AlitaResult.success(userService.batchCreatePersonUser(personUserCardCreateDTOs)); + } + + @PostMapping("user/create_person_user_by_phone") + @ApiOperation("创建个人用户-手机号") + public AlitaResult createPersonUser( + @Validated @RequestBody PersonUserPhoneCreateDTO personUserPhoneCreateDTO) { + return AlitaResult.success(userService.modifyAndCreatePersonUser(personUserPhoneCreateDTO).getId()); + } + + + @PostMapping("user/create_org_user") + @ApiOperation("创建机构用户") + public AlitaResult createOrgUser(@Validated @RequestBody OrgUserCreateDTO orgUserCreateDTO) { + orgUserCreateDTO.setOrgId(UserContextHolder.getExistLoginOrgId()); + return AlitaResult.success(userService.createOrgUser(orgUserCreateDTO)); + } + + @PostMapping("user/batch_create_org_user") + @ApiOperation("批量创建机构用户(单条失败不影响其他条目,返回逐条结果)") + public AlitaResult> batchCreateOrgUser( + @Validated @RequestBody List orgUserCreateDTOs) { + orgUserCreateDTOs.forEach(orgUserCreateDTO -> + orgUserCreateDTO.setOrgId(UserContextHolder.getExistLoginOrgId())); + return AlitaResult.success(userService.batchCreateOrgUser(orgUserCreateDTOs)); + } + + @PutMapping("user/modify_org_user") + @ApiOperation("修改机构用户") + public AlitaResult modifyOrgUser(@Validated @RequestBody OrgUserModifyDTO orgUserModifyDTO) { + //获取当前登录人的机构信息 + orgUserModifyDTO.setOrgId(UserContextHolder.getExistLoginOrgId()); + userService.modifyOrgUser(orgUserModifyDTO); + return AlitaResult.success(); + } + + @PostMapping("unac/user/init_user_password") + @ApiOperation("初始账号密码") + public AlitaResult initUserPassword( + @Validated @RequestBody InitUserPasswordDTO initUserPasswordDTO) { + userService.initUserPassword(initUserPasswordDTO); + return AlitaResult.success(); + } + + @PostMapping("unac/user/modify_username") + @ApiOperation("修改账号") + public AlitaResult modifyUsername(@RequestParam String username) { + userService.modifyUsername(username); + return AlitaResult.success(); + } + + @PostMapping("unac/user/modify_password") + @ApiOperation("修改密码") + public AlitaResult modifyPassword( + @Validated @RequestBody ModifyPasswordDTO modifyPasswordDTO) { + userService.modifyPassword(modifyPasswordDTO); + return AlitaResult.success(); + } + + @PostMapping("unac/user/bind_phone_sms/{phone}") + @ApiOperation("个人绑定手机号验证码") + public AlitaResult bindPhoneSms(@PathVariable String phone) { + PhoneCodeUtils.send(PhoneCodeSmsDTO.builder().providerType(PhoneCodeProviderEnum.PERSON_BIND_PHONE.getType()) + .phone(phone).build()); + return AlitaResult.success(); + } + + @PostMapping("unac/user/bind_phone") + @ApiOperation("(个人)绑定手机号") + public AlitaResult bindPhone(@Validated @RequestBody BindPhoneDTO bindPhoneDTO) { + userService.bindPersonPhone(bindPhoneDTO); + return AlitaResult.success(); + } + + @GetMapping("user/page/platform_user") + @ApiOperation("获取平台用户信息") + public AlitaResult> pagePlatformUser(PlatformUserInfoReqDTO reqDTO) { + userService.pagePlatformUser(reqDTO); + return AlitaResult.success(reqDTO.getPageResult()); + } + + @GetMapping("user/list/platform_user") + @ApiOperation("获取平台用户信息") + public AlitaResult> listPlatformUser(PlatformUserListQueryDTO reqDTO) { + return AlitaResult.success(userService.listPlatformUser(reqDTO)); + } + + @PostMapping("user/cancel") + @ApiOperation("注销用户信息") + public AlitaResult cancel(@RequestBody UserCancelReqDTO reqDTO) { + userService.userCancel(reqDTO); + return AlitaResult.success(); + } + +// @PostMapping("anon/user/sms") + @ApiOperation("获取验证码-不同操作") + public AlitaResult sms(@Validated @RequestBody UserPhoneCodeSmsDTO userPhoneCodeSmsDTO) { + PhoneCodeUtils.send(userPhoneCodeSmsDTO); + return AlitaResult.success(); + } + + @ApiOperation("获取验证码-不同操作(带防水墙验证)") +// @PostMapping("anon/user/sms_captcha") + public AlitaResult smsCaptcha( + @Validated @RequestBody UserPhoneCodeSmsCaptchaDTO userPhoneCodeSmsCaptchaDTO) { + PhoneCodeUtils.send(userPhoneCodeSmsCaptchaDTO); + return AlitaResult.success(); + } + +// @PostMapping("anon/user/reset_pwd") + @ApiOperation("重置密码") + public AlitaResult resetPwd(@Validated @RequestBody ResetPwdDTO resetPwdDTO) { + userService.resetPwd(resetPwdDTO); + return AlitaResult.success(); + } + + @ApiOperation("获取当前登录人信息(机构用户)") + @GetMapping("user/info") + public AlitaResult getLoginUserInfo() { + return AlitaResult.success(userService.findUserInfo(UserContextHolder.getLoginUserId(), + UserContextHolder.getLoginOrgId())); + } + + @PostMapping("unac/user/ignore_init_pwd") + @ApiOperation("忽略初始密码") + public AlitaResult ignoreInitPwd() { + userConfigService + .create(UserConfigOperateDTO.builder().userId(UserContextHolder.getExistLoginUserId()) + .configCode(UserConfigConstants.IGNORE_INIT_PWD_CODE) + .configValue(CommonConstants.CONFIG_TRUE).build()); + return AlitaResult.success(); + } + + @PostMapping("unac/user/reset_security_code") + @ApiOperation("重置安全码") + public AlitaResult resetSecurityCode(@Validated @RequestBody ResetSecurityCodeDTO resetSecurityCodeDTO) { + userService.resetSecurityCode(resetSecurityCodeDTO); + return AlitaResult.success(); + } + + + @PostMapping("user/check_security_code") + @ApiOperation("校验用户安全码信息") + public AlitaResult checkSecurityCode(@RequestBody CheckSecurityCodeReqDTO reqDTO) { + return AlitaResult.success(userService.checkSecurityCode(reqDTO)); + } + + @PostMapping("unac/user/change_phone") + @ApiOperation("换绑手机") + public AlitaResult changePhone(@Validated @RequestBody ChangePhoneDTO changePhoneDTO) { + userService.changePhone(changePhoneDTO); + return AlitaResult.success(); + } + + @ApiOperation("管理员修改企业用户信息") + @PostMapping("user/modify_org_user_info") + public AlitaResult modifyOrgUserInfo( + @RequestBody @Validated(Update.class) OrgUserEditDTO orgUserEditDTO) { + return AlitaResult.success(userService.modifyOrgUserInfo(orgUserEditDTO)); + } + + @ApiOperation("超级管理员重置企业用户密码") + @PostMapping("user/reset_org_user_pwd") + public AlitaResult resetOrgUserPassword(@Validated @RequestBody + SuperResetPasswordDTO resetPasswordDTO) { + return AlitaResult.success(userService.resetOrgUserPassword(resetPasswordDTO)); + } + + @PostMapping("user/exist_org_user") + @ApiOperation("验证机构用户是否存在") + public AlitaResult existOrgUser(@Validated @RequestBody OrgUserCreateDTO orgUserCreateDTO) { + return AlitaResult.success(userService.existOrgUser(orgUserCreateDTO)); + } + + @GetMapping("user/list_by_role") + @ApiOperation("通过角色信息查询用户列表") + public AlitaResult> listByRole(@Validated UserQueryByRoleDTO userQueryByRoleDTO) { + userQueryByRoleDTO.setOrgId(UserContextHolder.getLoginOrgId()); + userQueryByRoleDTO.setPlatformCode(EnvironmentUtils.getSystemCode()); + return AlitaResult.success(userService.listByRole(userQueryByRoleDTO)); + } + + @GetMapping("user/list_by_realName_or_phone") + @ApiOperation("通过姓名或手机号查询用户列表") + public AlitaResult> listByRealNameOrPhone(@RequestParam("realNames") Set realNames, @RequestParam("phones") Set phones) { + return AlitaResult.success(userService.listByRealNameOrPhone(realNames,phones)); + } + + @PostMapping("user/enable") + @ApiOperation("启用用户(系统管理员)") + public AlitaResult enableUser(@Validated @RequestBody UserStatusOperateDTO reqDTO) { + return AlitaResult.success(userService.enableUser(reqDTO)); + } + + @PostMapping("user/disable") + @ApiOperation("禁用用户(系统管理员)") + public AlitaResult disableUser(@Validated @RequestBody UserStatusOperateDTO reqDTO) { + return AlitaResult.success(userService.disableUser(reqDTO)); + } + + @PostMapping("user/admin_cancel") + @ApiOperation("注销用户(系统管理员,直接注销不进入注销申请流程)") + public AlitaResult adminCancelUser(@Validated @RequestBody UserStatusOperateDTO reqDTO) { + userService.adminCancelUser(reqDTO); + return AlitaResult.success(); + } + + @GetMapping("user/page/org_account") + @ApiOperation("分页查询机构账号信息(系统管理员)") + public AlitaResult> pageOrgAccount(OrgAccountQueryDTO queryDTO) { + userService.pageOrgAccount(queryDTO); + return AlitaResult.success(queryDTO.getPageResult()); + } + + @PostMapping("user/modify_real_name") + @ApiOperation("修改用户姓名(系统管理员)") + public AlitaResult modifyRealName(@Validated @RequestBody UserRealNameModifyDTO reqDTO) { + return AlitaResult.success(userService.modifyRealName(reqDTO)); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/controller/UserExtensionController.java b/backend/src/main/java/com/senmesh/usercenter/user/controller/UserExtensionController.java new file mode 100644 index 0000000..6706931 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/controller/UserExtensionController.java @@ -0,0 +1,59 @@ +package com.senmesh.usercenter.user.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +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.RestController; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.user.dto.UserExtendStatusDTO; +import com.senmesh.usercenter.user.dto.UserExtensionDTO; +import com.senmesh.usercenter.user.dto.UserExtensionOperateDTO; +import com.senmesh.usercenter.user.service.UserExtensionService; +import com.senmesh.usercenter.user.service.UserService; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2021-05-24 + */ +@RestController +@Api(tags = "用户扩展信息") +public class UserExtensionController { + + @Autowired + private UserService userService; + + @Autowired + private UserExtensionService userExtensionService; + + @GetMapping("user/extension/delete_user_file") + @ApiOperation("删除用户扩展信息简历附件") + public AlitaResult deleteUserFile(){ + userExtensionService.deleteUserFile(); + return AlitaResult.success(); + } + + @PostMapping("user/extension/edit") + @ApiOperation("编辑用户扩展信息") + public AlitaResult edit(@Validated @RequestBody UserExtensionOperateDTO userExtensionOperateDTO){ + return AlitaResult.success(userExtensionService.edit(userExtensionOperateDTO)); + } + + @GetMapping("/unac/user/extension/get") + @ApiOperation("编辑用户扩展信息") + public AlitaResult get(){ + return AlitaResult.success(userExtensionService.getByUserId(UserContextHolder.getLoginUserId())); + } + + @GetMapping("/unac/user/extend/status") + @ApiOperation("获取扩展状态") + public AlitaResult getUserExtendStatus() { + return AlitaResult.success(userService.getUserExtendStatus(UserContextHolder.getLoginUserId())); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/controller/UserPostalInfoController.java b/backend/src/main/java/com/senmesh/usercenter/user/controller/UserPostalInfoController.java new file mode 100644 index 0000000..919892f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/controller/UserPostalInfoController.java @@ -0,0 +1,70 @@ +package com.senmesh.usercenter.user.controller; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.validation.Update; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.user.dto.UserPostalInfoDTO; +import com.senmesh.usercenter.user.dto.UserPostalInfoOperateDTO; +import com.senmesh.usercenter.user.dto.UserPostalInfoQueryDTO; +import com.senmesh.usercenter.user.service.UserPostalInfoService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * @author fzp on 2022-01-19 + */ +@RestController +@RequestMapping("user_postal_info") +@Api(tags = "用户邮寄信息") +public class UserPostalInfoController { + + @Autowired + private UserPostalInfoService userPostalInfoService; + + @PostMapping("/create") + @ApiOperation("创建") + public AlitaResult create( + @Validated @RequestBody UserPostalInfoOperateDTO userPostalInfoOperateDTO){ + return AlitaResult.success(userPostalInfoService.create(userPostalInfoOperateDTO)); + } + + @PutMapping("/modify") + @ApiOperation("修改") + public AlitaResult modify( + @Validated(Update.class) @RequestBody UserPostalInfoOperateDTO userPostalInfoOperateDTO){ + userPostalInfoService.modify(userPostalInfoOperateDTO); + return AlitaResult.success(true); + } + + @DeleteMapping("/remove/{id}") + @ApiOperation("删除") + public AlitaResult remove(@PathVariable Long id){ + userPostalInfoService.remove(id); + return AlitaResult.success(true); + } + + @GetMapping("/list") + @ApiOperation("查询") + public AlitaResult> list(UserPostalInfoQueryDTO userPostalInfoQueryDTO){ + return AlitaResult.success(userPostalInfoService.list(userPostalInfoQueryDTO)); + } + + @GetMapping("/page") + @ApiOperation("分页查询") + public AlitaResult> page(UserPostalInfoQueryDTO userPostalInfoQueryDTO){ + userPostalInfoService.page(userPostalInfoQueryDTO); + return AlitaResult.success(userPostalInfoQueryDTO.getPageResult()); + } + + @GetMapping("/find/{id}") + @ApiOperation("查询单个") + public AlitaResult find(@PathVariable("id") Long id){ + return AlitaResult.success(userPostalInfoService.find(UserPostalInfoQueryDTO.builder().id(id).build())); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/controller/UserRegisterController.java b/backend/src/main/java/com/senmesh/usercenter/user/controller/UserRegisterController.java new file mode 100644 index 0000000..4a50fae --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/controller/UserRegisterController.java @@ -0,0 +1,55 @@ +package com.senmesh.usercenter.user.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +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; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.tkmybatis.pojo.Page; +import com.senmesh.usercenter.user.dto.UserRegisterCodeDTO; +import com.senmesh.usercenter.user.dto.UserRegisterCodeInfoDTO; +import com.senmesh.usercenter.user.dto.UserRegisterInfoDTO; +import com.senmesh.usercenter.user.dto.UserRegisterInfoQueryDTO; +import com.senmesh.usercenter.user.service.UserRegisterService; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * @author sr on 2021-11-16 + */ +@RestController +@RequestMapping("user_register") +@Api(tags = "用户注册信息") +public class UserRegisterController { + + @Autowired + private UserRegisterService userRegisterService; + + @PostMapping("/get_code") + @ApiOperation("获取(自己)邀请码") + public AlitaResult getCode( + @Validated @RequestBody UserRegisterCodeDTO userInvitationCreateCodeDTO){ + return AlitaResult.success(userRegisterService.getCode(userInvitationCreateCodeDTO)); + } + + @PostMapping("/up_get_code") + @ApiOperation("获取(指定)邀请码") + public AlitaResult upGetCode(@Validated @RequestBody UserRegisterCodeInfoDTO upUserRegisterCodeDTO){ + return AlitaResult.success(userRegisterService.getCode(upUserRegisterCodeDTO)); + } + + @GetMapping("/page_invitee_info") + @ApiOperation("分页查询受邀人信息") + public AlitaResult> pageInviteeInfo(UserRegisterInfoQueryDTO userRegisterInfoQueryDTO){ + userRegisterInfoQueryDTO.setInviterId(UserContextHolder.getExistLoginUserId()); + userRegisterService.page(userRegisterInfoQueryDTO); + return AlitaResult.success(userRegisterInfoQueryDTO.getPageResult()); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dao/OrgUserMapper.java b/backend/src/main/java/com/senmesh/usercenter/user/dao/OrgUserMapper.java new file mode 100644 index 0000000..a54536c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dao/OrgUserMapper.java @@ -0,0 +1,57 @@ +package com.senmesh.usercenter.user.dao; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.user.dto.OrgUserDTO; +import com.senmesh.usercenter.user.dto.OrgUserInfoDTO; +import com.senmesh.usercenter.user.dto.OrgUserInfoQueryDTO; +import com.senmesh.usercenter.user.dto.OrgUserQueryDTO; +import com.senmesh.usercenter.user.entity.OrgUser; +import com.senmesh.usercenter.user.login.dto.OrgDetailDTO; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 机构用户表 + * + * @author sr on 2021-05-24 + */ +public interface OrgUserMapper extends MyMapper { + + /** + * 查询 + * + * @param orgUserQueryDTO + * @return + * @author sr on 2021-05-24 + */ + List listOrgUserDTO(@Param("param") OrgUserQueryDTO orgUserQueryDTO); + + /** + * 校验是否可创建管理员用户(机构下是否存在指定userId,是否存在其他管理员userId) + * @param orgId + * @param userId + * @return + * @author sr on 2021-06-10 + */ + Boolean checkCreateAdministratorUser(Long orgId, Long userId); + + /** + * 是否存在对应手机号机构用户 + * @param phone + * @return + * @author sr on 2021-06-17 + */ + boolean existOrgUser(String phone); + + /** + * 根据用户id获取机构信息 + * + * @param userId + * @return + * @author sr on 2019-11-05 + */ + List listLoginOrgByUser(@Param("userId") Long userId, @Param("orgId") Long orgId); + + List list(@Param("param") OrgUserInfoQueryDTO queryDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dao/UserAuthMapper.java b/backend/src/main/java/com/senmesh/usercenter/user/dao/UserAuthMapper.java new file mode 100644 index 0000000..52d6997 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dao/UserAuthMapper.java @@ -0,0 +1,31 @@ +package com.senmesh.usercenter.user.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.usercenter.user.dto.UserAuthDTO; +import com.senmesh.usercenter.user.dto.UserAuthQueryDTO; +import com.senmesh.usercenter.user.entity.UserAuth; +import com.senmesh.tkmybatis.mybatis.MyMapper; + +/** + * 用户授权中间表 + * + * @author sr on 2021-05-24 + */ +public interface UserAuthMapper extends MyMapper { + + /** + * 查询 + * + * @param userAuthQueryDTO + * @return + * @author sr on 2021-05-24 + */ + List listUserAuthDTO(@Param("param") UserAuthQueryDTO userAuthQueryDTO); + + int mergeAuth(Long retainUserId, Long deletedUserId); + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dao/UserCancelMapper.java b/backend/src/main/java/com/senmesh/usercenter/user/dao/UserCancelMapper.java new file mode 100644 index 0000000..ee16412 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dao/UserCancelMapper.java @@ -0,0 +1,31 @@ +package com.senmesh.usercenter.user.dao; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.user.dto.UserCancelDTO; +import com.senmesh.usercenter.user.dto.UserCancelPageQueryDTO; +import com.senmesh.usercenter.user.entity.UserCancel; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + + +/** + * 用户申请注销Mapper + * + * @author cheny + * @date 2023/03/07 + */ +public interface UserCancelMapper extends MyMapper { + + + List page(@Param("param") UserCancelPageQueryDTO queryDTO); + + /** + * 查询需要通知的数据 + * + * @return {@link List}<{@link UserCancelDTO}> + */ + List toNotify(); + + UserCancelDTO findNotifyInfo(Long userId); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dao/UserConfigMapper.java b/backend/src/main/java/com/senmesh/usercenter/user/dao/UserConfigMapper.java new file mode 100644 index 0000000..45fa518 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dao/UserConfigMapper.java @@ -0,0 +1,28 @@ +package com.senmesh.usercenter.user.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.usercenter.user.dto.UserConfigDTO; +import com.senmesh.usercenter.user.dto.UserConfigQueryDTO; +import com.senmesh.usercenter.user.entity.UserConfig; +import com.senmesh.tkmybatis.mybatis.MyMapper; + +/** + * 用户配置 + * + * @author sr on 2021-08-12 + */ +public interface UserConfigMapper extends MyMapper { + + /** + * 查询 + * + * @param userConfigQueryDTO + * @return + * @author sr on 2021-08-12 + */ + List listUserConfigDTO(@Param("param") UserConfigQueryDTO userConfigQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dao/UserExtensionMapper.java b/backend/src/main/java/com/senmesh/usercenter/user/dao/UserExtensionMapper.java new file mode 100644 index 0000000..fc0baa9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dao/UserExtensionMapper.java @@ -0,0 +1,19 @@ +package com.senmesh.usercenter.user.dao; + +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.user.dto.UserExtensionDTO; +import com.senmesh.usercenter.user.entity.UserExtension; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +/** + * 用户扩展信息 + * + * @author czy on 2021-06-15 + */ +public interface UserExtensionMapper extends MyMapper { + + @Select("select * from uc_user_extension where deleted = false and user_id = #{userId}") + UserExtensionDTO getByUserId(@Param("userId") Long userId); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dao/UserMapper.java b/backend/src/main/java/com/senmesh/usercenter/user/dao/UserMapper.java new file mode 100644 index 0000000..e5cac47 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dao/UserMapper.java @@ -0,0 +1,210 @@ +package com.senmesh.usercenter.user.dao; + +import com.senmesh.security.dto.UserInfoDTO; +import com.senmesh.tkmybatis.mybatis.MyMapper; +import com.senmesh.usercenter.user.dto.*; +import com.senmesh.usercenter.user.entity.User; +import com.senmesh.usercenter.user.login.dto.UserDetailDTO; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Set; + +/** + * 用户 + * + * @author sr on 2021-05-24 + */ +public interface UserMapper extends MyMapper { + + /** + * 查询 + * 用户注册表存在重复数据,取用户最开始注册平台的code + * @param userQueryDTO + * @return + * @author sr on 2021-05-24 + */ + List listUserDTO(@Param("param") UserQueryDTO userQueryDTO); + + /** + * 初始账号密码 + * + * @param username + * @param encodedPassword + * @param operateUserId + * @return + * @author sr on 2021-08-04 + */ + int initUserPassword(String username, String encodedPassword, Long operateUserId); + + /** + * 注销用户 + * + * @param userId 用户id + * @param operateUserId 操作用户id + * @return int + */ + int cancel(Long userId, Long operateUserId); + + /** + * 根据登录信息查询用户信息 + * + * @param userDetailQueryDto + * @return + */ + List listUserDetailDTO(@Param("param") UserDetailQueryDTO userDetailQueryDto); + + /** + * 根据授权信息查询用户信息 + * @param userAuthQueryDTO + * @return + * @author sr on 2021-06-28 + */ + List listAuthUserDetailDTO(@Param("param") UserAuthQueryDTO userAuthQueryDTO); + + /** + * 清理其他个人用户手机号 + * @param userId + * @return + * @author sr on 2021-07-01 + */ + int cleanOtherPersonUserPhone(Long userId, String phone); + + /** + * 实名个人用户 + * @param authenticateUserDTO + * @return + * @author sr on 2021-07-01 + */ + int authenticatePersonUser(@Param("param") AuthenticateUserDTO authenticateUserDTO); + + /** + * 修改绑定手机 + * @param userId + * @param phone 可以为空,但前提是用户手机号不为空 + * @return + * @author sr on 2021-07-02 + */ + int bindingPhone(Long userId, String phone); + + /** + * 获取指定用户的阔转状态(实名认证、证件正反面照上传、手机绑定、微信绑定状态) + * @param userId + * @return + * @author czy on 2021-06-10 + */ + UserExtendStatusDTO getUserExtendStatus(@Param("userId") Long userId); + + /** + * 将手机状态同步到选择的用户上 + * @param retainUserId + * @param phoneUserId + * @return + * @author sr on 2021-07-06 + */ + int mergeUser(Long retainUserId, Long phoneUserId); + + /** + * 页面平台用户 + * + * @param reqDTO 点播dto + * @return {@link List} + */ + List pagePlatformUser(@Param("param") PlatformUserInfoReqDTO reqDTO); + + /** + * 根据用户ID和机构ID查询用户信息 + * + * @param userId 用户id + * @param existLoginOrgId 存在登录org id + * @return {@link UserDTO} + */ + UserDTO getUserInfoByOrg(@Param("userId") Long userId,@Param("existLoginOrgId") Long existLoginOrgId); + + UserInfoDTO findUserInfo(@Param("userId") Long userId, @Param("orgId") Long orgId); + + /** + * 查询是否存在相同账号 + * + * @param username 账号 + * @return + */ + boolean existUsername(@Param("username") String username,@Param("userId") Long userId); + /** + * 更新用户信息 + * + * @param user + * @return + */ + int updateOrgUserById(User user); + + /** + * 超级管理员重置用户密码 + * + * @param userId + * @param password + * @param operateUserId + * @return + * @author sr on 2019-10-22 + */ + int updatePassword( + @Param("userId") Long userId, + @Param("password") String password, + @Param("operateUserId") Long operateUserId); + + /** + * 查询企业负责人信息 + * + * @param userIds 用户ID集合 + * @return + * @author sr on 2019-10-22 + */ + List personInCharge(@Param("userIds") Set userIds); + + /** + * 通过角色信息查询用户列表 + * @param userQueryByRoleDTO + * @return + * @author sr on 2022-05-25 + */ + List listByRole(@Param("param") UserQueryByRoleDTO userQueryByRoleDTO); + + /** + * 未激活用户,登录激活用户 + * + * @param userId + * @return + * @author sr on 2022-09-01 + */ + int loginActive(Long userId); + + List listPlatformUser(@Param("param") PlatformUserListQueryDTO queryDTO); + + List listByRealNameOrPhone(@Param("orgId") Long orgId, @Param("realNames") Set realNames, @Param("phones") Set phones); + + /** + * 根据手机号和用户类型精确查询未注销用户 + * + * @param phone 手机号 + * @param type 用户类型 + * @return 用户列表 + */ + List listUncanceledByExactPhoneAndType(@Param("phone") String phone, @Param("type") Integer type); + + /** + * 管理员注销用户(状态置为已注销,并禁用账号) + * + * @param userId 用户id + * @param operateUserId 操作用户id + * @return int + */ + int adminCancel(@Param("userId") Long userId, @Param("operateUserId") Long operateUserId); + + /** + * 分页查询机构账号信息(系统管理员) + * + * @param queryDTO 查询dto + * @return {@link List} + */ + List listOrgAccount(@Param("param") OrgAccountQueryDTO queryDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dao/UserPostalInfoMapper.java b/backend/src/main/java/com/senmesh/usercenter/user/dao/UserPostalInfoMapper.java new file mode 100644 index 0000000..1f3085d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dao/UserPostalInfoMapper.java @@ -0,0 +1,29 @@ +package com.senmesh.usercenter.user.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.usercenter.user.dto.UserPostalInfoDTO; +import com.senmesh.usercenter.user.dto.UserPostalInfoQueryDTO; +import com.senmesh.usercenter.user.entity.UserPostalInfo; +import com.senmesh.tkmybatis.mybatis.MyMapper; + +/** + * 用户邮寄信息 + * + * @author fzp on 2022-01-19 + */ +public interface UserPostalInfoMapper extends MyMapper { + + /** + * 查询 + * + * @param userPostalInfoQueryDTO + * @return + * @author fzp on 2022-01-19 + */ + List listUserPostalInfoDTO(@Param("param") UserPostalInfoQueryDTO userPostalInfoQueryDTO); + + void cancelDefaultedById(Long id,Long userId); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dao/UserRegisterMapper.java b/backend/src/main/java/com/senmesh/usercenter/user/dao/UserRegisterMapper.java new file mode 100644 index 0000000..a8e7d28 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dao/UserRegisterMapper.java @@ -0,0 +1,38 @@ +package com.senmesh.usercenter.user.dao; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.senmesh.usercenter.user.dto.UserRegisterDTO; +import com.senmesh.usercenter.user.dto.UserRegisterInfoDTO; +import com.senmesh.usercenter.user.dto.UserRegisterInfoQueryDTO; +import com.senmesh.usercenter.user.dto.UserRegisterQueryDTO; +import com.senmesh.usercenter.user.entity.UserRegister; +import com.senmesh.tkmybatis.mybatis.MyMapper; + +/** + * 用户注册表 + * + * @author sr on 2021-11-16 + */ +public interface UserRegisterMapper extends MyMapper { + + /** + * 查询 + * + * @param userRegisterQueryDTO + * @return + * @author sr on 2021-11-16 + */ + List listUserRegisterDTO(@Param("param") UserRegisterQueryDTO userRegisterQueryDTO); + + /** + * 查询注册详情 + * @param userRegisterQueryDTO + * @return + * @author sr on 2021-11-18 + */ + List listUserRegisterInfoDTO(@Param("param") UserRegisterInfoQueryDTO userRegisterInfoQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/AuthenticateUserDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/AuthenticateUserDTO.java new file mode 100644 index 0000000..986a202 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/AuthenticateUserDTO.java @@ -0,0 +1,43 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.senmesh.common.validation.annotation.Expression; +import com.senmesh.common.validation.annotation.Phone; +import com.senmesh.common.validation.constants.ValidProviderEnum; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2021-07-01 + */ +@ApiModel("用户实名-认证已通过") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthenticateUserDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 3807697853918276660L; + + @ApiModelProperty("姓名") + @Expression(type = ValidProviderEnum.REAL_NAME, message = "姓名不正确") + private String realName; + @ApiModelProperty("证件号") + @Expression(type = ValidProviderEnum.CARD_NO, message = "身份证号不正确") + private String cardNo; + @ApiModelProperty("手机号码") + @Phone(message = "手机号码格式不正确") + private String phone ; + @JsonIgnore + @ApiModelProperty("指定用户id(db使用更新用户实名状态;为空[认证成功通知]则根据身份证号查找对应用户实名,不为空则只更新指定id用户)") + private Long userId; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/BindPhoneDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/BindPhoneDTO.java new file mode 100644 index 0000000..4243de1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/BindPhoneDTO.java @@ -0,0 +1,22 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.usercenter.user.phone.constant.UserPhoneCodeOperateEnum; + +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.NoArgsConstructor; + +@ApiModel(description = "绑定手机号") +@Data +@NoArgsConstructor +public class BindPhoneDTO extends UserPhoneCodeDTO{ + + /** **/ + private static final long serialVersionUID = 1885543530652690308L; + + @Override + public String getOperateType() { + return UserPhoneCodeOperateEnum.BIND_PHONE.getOperate(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/ChangePhoneDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/ChangePhoneDTO.java new file mode 100644 index 0000000..eee92c3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/ChangePhoneDTO.java @@ -0,0 +1,22 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.usercenter.user.phone.constant.UserPhoneCodeOperateEnum; + +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.NoArgsConstructor; + +@ApiModel(description = "换绑手机号") +@Data +@NoArgsConstructor +public class ChangePhoneDTO extends UserPhoneCodeDTO{ + + /** **/ + private static final long serialVersionUID = 1885543530652690308L; + + @Override + public String getOperateType() { + return UserPhoneCodeOperateEnum.CHANGE_PHONE.getOperate(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/ChangePhoneMqDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/ChangePhoneMqDTO.java new file mode 100644 index 0000000..71484e5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/ChangePhoneMqDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2021-09-13 + */ +@ApiModel(description = "换绑手机号mq消息") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ChangePhoneMqDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = -3187518200627395525L; + + @ApiModelProperty("手机号码") + @NotBlank(message = "手机号码不能为空") + private String phone; + @ApiModelProperty("用户id") + @NotNull(message = "用户id不能为空") + private Long userId; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/CheckSecurityCodeReqDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/CheckSecurityCodeReqDTO.java new file mode 100644 index 0000000..2ef271f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/CheckSecurityCodeReqDTO.java @@ -0,0 +1,46 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.common.validation.util.ValidateUtils; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Pattern; +import java.io.Serializable; +import java.util.Objects; + + +/** + * 检查安全代码要求的dto + * + * @author Carlye + * @date 2021/08/09 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "校验用户安全码操作") +public class CheckSecurityCodeReqDTO implements Serializable { + + private static final long serialVersionUID = -4219278463333163768L; + @ApiModelProperty("用户ID,") + private Long userId; + + @ApiModelProperty("安全码") + @NotEmpty(message = "安全码不能为空") + @Pattern(regexp = ValidateUtils.SECURITY_CODE_PATTERN,message = "安全码不符合规则") + private String securityCode; + + public Long getUserId() { + if (Objects.isNull(userId)){ + userId = UserContextHolder.getLoginUserId(); + } + return userId; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/IUserPhoneCode.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/IUserPhoneCode.java new file mode 100644 index 0000000..21b63f0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/IUserPhoneCode.java @@ -0,0 +1,11 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.usercenter.user.phone.dto.ICode; + +/** + * 用户短信验证码-验证 + * @author sr on 2021-09-02 + */ +public interface IUserPhoneCode extends IUserPhoneCodeSms, ICode { + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/IUserPhoneCodeSms.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/IUserPhoneCodeSms.java new file mode 100644 index 0000000..013b56c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/IUserPhoneCodeSms.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.usercenter.user.phone.constant.UserPhoneCodeOperateEnum; +import com.senmesh.usercenter.user.phone.dto.IPhoneCodeSmsDTO; + +/** + * 用户短信验证码-发送 + * @author sr on 2021-09-02 + */ +public interface IUserPhoneCodeSms extends IPhoneCodeSmsDTO { + + /** + * 用户类型 + * @return + * @author sr on 2021-09-02 + */ + Integer getUserType(); + + /** + * 操作类型 + * {@link UserPhoneCodeOperateEnum} + * @return + * @author sr on 2021-09-02 + */ + String getOperateType(); + + /** + * 设置提供者类型 + * @param providerType + * @author sr on 2021-09-02 + */ + void setProviderType(String providerType); + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/InitUserPasswordDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/InitUserPasswordDTO.java new file mode 100644 index 0000000..fc7e01a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/InitUserPasswordDTO.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.user.dto; + +import javax.validation.constraints.NotBlank; + +import com.senmesh.common.dto.BaseOperateDTO; +import com.senmesh.common.validation.annotation.Expression; +import com.senmesh.common.validation.constants.ValidProviderEnum; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@ApiModel(description = "初始设置账号密码") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InitUserPasswordDTO extends BaseOperateDTO { + + /** **/ + private static final long serialVersionUID = 8327018614562710138L; + + @ApiModelProperty("账号") + @NotBlank(message = "账号不能为空") + @Expression(type = ValidProviderEnum.USERNAME, message = "账号格式不正确") + private String username; + @ApiModelProperty("密码") + @Expression(type = ValidProviderEnum.PASSWORD, message = "密码格式不正确") + private String password; + @ApiModelProperty("二次确认密码") + @NotBlank(message = "二次确认密码不能为空") + private String rePassword; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/ModifyPasswordDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/ModifyPasswordDTO.java new file mode 100644 index 0000000..8899488 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/ModifyPasswordDTO.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.user.dto; + +import javax.validation.constraints.NotBlank; + +import com.senmesh.common.dto.BaseOperateDTO; +import com.senmesh.common.validation.annotation.Expression; +import com.senmesh.common.validation.constants.ValidProviderEnum; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@ApiModel(description = "修改密码") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ModifyPasswordDTO extends BaseOperateDTO { + + /** **/ + private static final long serialVersionUID = 8327018614562710138L; + + @ApiModelProperty("原密码") + @Expression(type = ValidProviderEnum.PASSWORD, message = "密码格式不正确") + private String oldPassword; + @ApiModelProperty("新密码") + @Expression(type = ValidProviderEnum.PASSWORD, message = "密码格式不正确") + private String newPassword; + @ApiModelProperty("二次确认密码") + @NotBlank(message = "二次确认密码不能为空") + private String reNewPassword; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgAccountDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgAccountDTO.java new file mode 100644 index 0000000..33ea9b9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgAccountDTO.java @@ -0,0 +1,75 @@ +package com.senmesh.usercenter.user.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Date; + +/** + * 机构账号信息DTO + * 一行代表一个机构下的一个账号(用户可在多个机构,同一账号会在多个机构下各出现一行) + * + * @author liu on 2026-09-14 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(description = "机构账号信息") +public class OrgAccountDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("机构id") + private Long orgId; + + @ApiModelProperty("机构名称") + private String orgName; + + @ApiModelProperty("是否该机构的管理员") + private Boolean administrator; + + @ApiModelProperty("用户id") + private Long userId; + + @ApiModelProperty("账号") + private String username; + + @ApiModelProperty("昵称") + private String nickname; + + @ApiModelProperty("真实姓名") + private String realName; + + @ApiModelProperty("手机号") + private String phone; + + @ApiModelProperty("邮箱") + private String email; + + @ApiModelProperty("用户类型:1企业用户,2个人用户") + private Integer userType; + + @ApiModelProperty("是否启用") + private Boolean enabled; + + @ApiModelProperty("状态:1待激活,2已激活,3已注销") + private Integer status; + + @ApiModelProperty("创建时间") + @JsonFormat( + shape = JsonFormat.Shape.STRING, + pattern = "yyyy-MM-dd HH:mm:ss", + timezone = "GMT+8" + ) + private Date createTime; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgAccountQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgAccountQueryDTO.java new file mode 100644 index 0000000..3e56ca9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgAccountQueryDTO.java @@ -0,0 +1,72 @@ +package com.senmesh.usercenter.user.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.senmesh.common.dto.PageQueryDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +/** + * 机构账号信息查询DTO + * + * @author liu on 2026-09-14 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@ApiModel(description = "机构账号信息查询") +public class OrgAccountQueryDTO extends PageQueryDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("机构id(不传查全部机构)") + private Long orgId; + + @ApiModelProperty("机构名称(模糊查询)") + private String orgNameLike; + + @ApiModelProperty("账号(模糊查询)") + private String usernameLike; + + @ApiModelProperty("真实姓名(模糊查询)") + private String realNameLike; + + @ApiModelProperty("手机号(模糊查询)") + private String phoneLike; + + @ApiModelProperty("是否启用") + private Boolean enabled; + + @ApiModelProperty("状态:1待激活,2已激活,3已注销") + private Integer status; + + @ApiModelProperty("创建时间起") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat( + shape = JsonFormat.Shape.STRING, + pattern = "yyyy-MM-dd HH:mm:ss", + timezone = "GMT+8" + ) + private Date createTimeStart; + + @ApiModelProperty("创建时间止") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat( + shape = JsonFormat.Shape.STRING, + pattern = "yyyy-MM-dd HH:mm:ss", + timezone = "GMT+8" + ) + private Date createTimeEnd; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserCreateDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserCreateDTO.java new file mode 100644 index 0000000..2e31f7e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserCreateDTO.java @@ -0,0 +1,51 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.dto.BaseOperateDTO; +import com.senmesh.common.validation.annotation.Expression; +import com.senmesh.common.validation.constants.ValidProviderEnum; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 机构内手机号唯一 + * @author sr on 2021-05-26 + */ +@ApiModel(description = "机构用户创建") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OrgUserCreateDTO extends BaseOperateDTO{ + + /** **/ + private static final long serialVersionUID = 3741954861451945309L; + + @ApiModelProperty("昵称") + private String nickname; + + @ApiModelProperty("姓名") + private String realName; + + @ApiModelProperty("手机号") + @Expression(type = ValidProviderEnum.PHONE, message = "手机号格式不正确") + private String phone; + @ApiModelProperty("邮箱") + private String email; + @ApiModelProperty("机构id") +// @NotNull(message = "所属机构id不能为空") + private Long orgId; + @ApiModelProperty("是否管理员") + private Boolean administrator; + + + /** + * 微信二维码 + */ + @ApiModelProperty("微信二维码") + private String wechatQrCode; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserCreateResultDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserCreateResultDTO.java new file mode 100644 index 0000000..ef49d96 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserCreateResultDTO.java @@ -0,0 +1,38 @@ +package com.senmesh.usercenter.user.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 批量创建机构用户单条结果 + * + * @author liu on 2026-10-27 + */ +@ApiModel(description = "批量创建机构用户结果") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OrgUserCreateResultDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("手机号") + private String phone; + + @ApiModelProperty("姓名") + private String realName; + + @ApiModelProperty("是否创建成功") + private Boolean success; + + @ApiModelProperty("用户id,失败时为null") + private Long userId; + + @ApiModelProperty("失败原因,成功时为null") + private String msg; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserDTO.java new file mode 100644 index 0000000..f3aa258 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserDTO.java @@ -0,0 +1,31 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.dto.OrgBaseDTO; + +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-05-24 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "机构用户表") +public class OrgUserDTO extends OrgBaseDTO{ + + /** **/ + private static final long serialVersionUID = 1L; + + /** 用户id */ + private Long userId ; + /** 是否管理员 */ + private Boolean administrator ; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserInfoDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserInfoDTO.java new file mode 100644 index 0000000..cb79533 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserInfoDTO.java @@ -0,0 +1,25 @@ +package com.senmesh.usercenter.user.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +/** + * 机构用户信息dto + * + * @author Carlye + * @date 2021/10/13 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OrgUserInfoDTO extends UserDTO { + private static final long serialVersionUID = -344843668258323983L; + + @ApiModelProperty("机构ID") + private Long orgId; + @ApiModelProperty("用户ID") + private Long userId; + @ApiModelProperty("是否管理员") + private Boolean administrator; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserInfoQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserInfoQueryDTO.java new file mode 100644 index 0000000..4b1ad4c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserInfoQueryDTO.java @@ -0,0 +1,27 @@ +package com.senmesh.usercenter.user.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import java.io.Serializable; + +/** + * 机构用户信息 查询 dto + * + * @author Carlye + * @date 2021/10/13 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OrgUserInfoQueryDTO implements Serializable { + + private static final long serialVersionUID = -5132218121861795737L; + @ApiModelProperty("机构ID") + private Long orgId; + @ApiModelProperty("用户ID") + private Long userId; + @ApiModelProperty("用户类型:1企业用户,2个人用户") + private Integer type; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserModifyDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserModifyDTO.java new file mode 100644 index 0000000..aae2562 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserModifyDTO.java @@ -0,0 +1,53 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.dto.BaseOperateDTO; +import com.senmesh.common.validation.annotation.Expression; +import com.senmesh.common.validation.constants.ValidProviderEnum; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * 机构内手机号唯一 + * @author sr on 2021-05-26 + */ +@ApiModel(description = "机构用户修改") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OrgUserModifyDTO extends BaseOperateDTO{ + + /** **/ + private static final long serialVersionUID = 3741954861451945309L; + + @NotNull(message = "ID不能为空") + private Long id; + + @ApiModelProperty("昵称") + private String nickname; + + @ApiModelProperty("姓名") + private String realName; + + @Expression(type = ValidProviderEnum.PHONE, message = "手机号格式不正确") + @ApiModelProperty("手机号") + private String phone; + + @ApiModelProperty("邮箱") + private String email; + + @ApiModelProperty("机构id") + private Long orgId; + + /** + * 微信二维码 + */ + @ApiModelProperty("微信二维码") + private String wechatQrCode; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserOperateDTO.java new file mode 100644 index 0000000..ec65999 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserOperateDTO.java @@ -0,0 +1,43 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseOperateDTO; +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2021-05-24 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "机构用户表操作") +public class OrgUserOperateDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + @NotNull(message = "id不能为空", groups = {Update.class}) + private Long id; + @ApiModelProperty("用户id") + @NotNull(message = "用户id不能为空", groups = {Create.class}) + private Long userId ; + @ApiModelProperty("机构id") + @NotNull(message = "机构id不能为空", groups = {Create.class}) + private Long orgId; + @ApiModelProperty("是否管理员") + private Boolean administrator ; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserQueryDTO.java new file mode 100644 index 0000000..096aac4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/OrgUserQueryDTO.java @@ -0,0 +1,38 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import com.senmesh.common.dto.PageQueryDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2021-05-24 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "机构用户表查询条件") +public class OrgUserQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + @ApiModelProperty("用户id") + private Long userId ; + @ApiModelProperty("机构id") + private Long orgId; + /** 是否管理员 */ + private Boolean administrator ; + private String orgName; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/PersonUserCardCreateDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/PersonUserCardCreateDTO.java new file mode 100644 index 0000000..3dd3c4d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/PersonUserCardCreateDTO.java @@ -0,0 +1,39 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.annotation.trimAndUpper.TrimAndUpper; +import com.senmesh.common.dto.BaseOperateDTO; +import com.senmesh.common.validation.annotation.Expression; +import com.senmesh.common.validation.annotation.Phone; +import com.senmesh.common.validation.constants.ValidProviderEnum; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@ApiModel(description = "个人用户(证件)创建") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PersonUserCardCreateDTO extends BaseOperateDTO{ + + /** **/ + private static final long serialVersionUID = 7658014752415774002L; + + @ApiModelProperty("真实姓名") + @TrimAndUpper + private String realName ; + @ApiModelProperty("身份证号") + @Expression(type = ValidProviderEnum.CARD_NO, message = "身份证号不正确") + @TrimAndUpper + private String cardNo ; + @ApiModelProperty("手机号码") + @Phone(message = "手机号码格式不正确") + private String phone ; + @ApiModelProperty("绑定机构id") + private Long bindOrgId; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/PersonUserCardCreateResultDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/PersonUserCardCreateResultDTO.java new file mode 100644 index 0000000..ff6d0b7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/PersonUserCardCreateResultDTO.java @@ -0,0 +1,27 @@ +package com.senmesh.usercenter.user.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@ApiModel(description = "个人用户(证件)创建") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PersonUserCardCreateResultDTO extends UserDTO{ + + /** **/ + private static final long serialVersionUID = 7658014752415774002L; + + @ApiModelProperty("是否操作成功") + private boolean success; + @ApiModelProperty("成功创建用户id") + private Long userId; + @ApiModelProperty("失败原因") + private String msg; + + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/PersonUserPhoneCreateDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/PersonUserPhoneCreateDTO.java new file mode 100644 index 0000000..bb5a01f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/PersonUserPhoneCreateDTO.java @@ -0,0 +1,28 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.dto.BaseOperateDTO; +import com.senmesh.common.validation.annotation.Expression; +import com.senmesh.common.validation.constants.ValidProviderEnum; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@ApiModel(description = "个人用户(手机号登录)创建") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PersonUserPhoneCreateDTO extends BaseOperateDTO{ + + /** **/ + private static final long serialVersionUID = 7658014752415774002L; + + @ApiModelProperty("手机号码") + @Expression(type = ValidProviderEnum.PHONE, message = "手机号格式不正确") + private String phone ; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/PlatformUserInfoDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/PlatformUserInfoDTO.java new file mode 100644 index 0000000..4f37a1c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/PlatformUserInfoDTO.java @@ -0,0 +1,86 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.dto.BaseDTO; +import com.senmesh.usercenter.user.constant.UserStatusEnum; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import java.util.Objects; + + +/** + * 平台用户信息dto + * + * @author Carlye + * @date 2021/08/03 + */ +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@Data +@ToString +public class PlatformUserInfoDTO extends BaseDTO { + + private static final long serialVersionUID = 5085940488169971625L; + + @ApiModelProperty("账号") + private String username; + + @ApiModelProperty("用户昵称") + private String nickname; + + @ApiModelProperty("用户真实姓名") + private String realName; + + @ApiModelProperty("用户手机号") + private String phone; + + @ApiModelProperty("用户手机号绑定状态") + private Boolean phoneBinding; + + @ApiModelProperty("用户邮箱") + private String email; + + @ApiModelProperty("是否启用") + private Boolean enabled; + + @ApiModelProperty("是否实名") + private Boolean authenticated; + + @ApiModelProperty("状态:1.待激活,2已激活,3已注销") + private Integer status; + + @ApiModelProperty("微信二维码") + private String wechatQrCode; + + + public Boolean getPhoneBinding() { + if (Objects.isNull(phoneBinding)) { + phoneBinding = Boolean.FALSE; + } + return phoneBinding; + } + + public Boolean getEnabled() { + if (Objects.isNull(enabled)) { + enabled = Boolean.FALSE; + } + return enabled; + } + + public Integer getStatus() { + if (Objects.isNull(status)) { + status = UserStatusEnum.INIT.getStatus(); + } + return status; + } + + public Boolean getAuthenticated() { + if (Objects.isNull(authenticated)) { + authenticated = Boolean.FALSE; + } + return authenticated; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/PlatformUserInfoReqDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/PlatformUserInfoReqDTO.java new file mode 100644 index 0000000..ad0ab02 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/PlatformUserInfoReqDTO.java @@ -0,0 +1,83 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.annotation.trimAndUpper.TrimAndUpper; +import com.senmesh.common.dto.PageQueryDTO; +import com.senmesh.common.util.UserContextHolder; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import java.util.Objects; + + +/** + * 平台用户信息查询dto + * + * @author Carlye + * @date 2021/08/03 + */ +@EqualsAndHashCode(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Data +@ToString +public class PlatformUserInfoReqDTO extends PageQueryDTO { + + private static final long serialVersionUID = 5085940488169971625L; + + @ApiModelProperty("账号") + @TrimAndUpper(TrimAndUpper.ExecuteType.TRIM) + private String username; + + @ApiModelProperty("用户昵称") + @TrimAndUpper(TrimAndUpper.ExecuteType.TRIM) + private String nickname; + + @ApiModelProperty("用户真实姓名") + @TrimAndUpper(TrimAndUpper.ExecuteType.TRIM) + private String realName; + + @ApiModelProperty("用户手机号") + @TrimAndUpper(TrimAndUpper.ExecuteType.TRIM) + private String phone; + + @ApiModelProperty("用户手机号绑定状态") + private Boolean phoneBinding; + + @ApiModelProperty("用户邮箱") + @TrimAndUpper(TrimAndUpper.ExecuteType.TRIM) + private String email; + + @ApiModelProperty("是否启用") + private Boolean enabled; + + @ApiModelProperty("状态:1.待激活,2已激活,3已注销") + private Integer status; + + @ApiModelProperty("当前登录机构ID") + private Long orgId; + + public Long getOrgId() { + if (Objects.isNull(orgId)) { + orgId = UserContextHolder.getLoginOrgId(); + } + return orgId; + } + + @ApiModelProperty("平台编码") + private Integer platformCode; + @ApiModelProperty("所属机构ID") + private Long roleId; + @ApiModelProperty("是否分配 0否 1是") + private Integer allocation; + + @ApiModelProperty("微信二维码0:未上传 1:已上传 ") + private Integer wechatQrCodeUpload; + + public Integer getAllocation() { + if (Objects.isNull(allocation)) { + allocation = 1; + } + return allocation; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/PlatformUserListQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/PlatformUserListQueryDTO.java new file mode 100644 index 0000000..505e5ff --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/PlatformUserListQueryDTO.java @@ -0,0 +1,75 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.util.UserContextHolder; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import java.io.Serializable; +import java.util.Objects; + + +/** + * 平台用户信息查询dto + * + * @author Carlye + * @date 2021/08/03 + */ +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Data +@ToString +public class PlatformUserListQueryDTO implements Serializable { + + private static final long serialVersionUID = 8465879683905791458L; + @ApiModelProperty("账号") + private String username; + + @ApiModelProperty("用户昵称") + private String nickname; + + @ApiModelProperty("用户真实姓名") + private String realName; + + @ApiModelProperty("用户手机号") + private String phone; + + @ApiModelProperty("用户手机号绑定状态") + private Boolean phoneBinding; + + @ApiModelProperty("用户邮箱") + private String email; + + @ApiModelProperty("是否启用") + private Boolean enabled; + + @ApiModelProperty("状态:1.待激活,2已激活,3已注销") + private Integer status; + + @ApiModelProperty("当前登录机构ID") + private Long orgId; + + /**是否查所有。查所有传true,默认查非管理员**/ + private Boolean allUser; + + public Long getOrgId() { + if (Objects.isNull(orgId)) { + orgId = UserContextHolder.getLoginOrgId(); + } + return orgId; + } + + @ApiModelProperty("平台编码") + private Integer platformCode; + @ApiModelProperty("所属机构ID") + private Long roleId; + @ApiModelProperty("是否分配 0否 1是") + private Integer allocation; + + public Integer getAllocation() { + if (Objects.isNull(allocation)) { + allocation = 1; + } + return allocation; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/RealNameTwoResponseDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/RealNameTwoResponseDTO.java new file mode 100644 index 0000000..4a954f8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/RealNameTwoResponseDTO.java @@ -0,0 +1,41 @@ +package com.senmesh.usercenter.user.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * @author fzp + * @date 2021年7月13日18:25:11 + */ + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class RealNameTwoResponseDTO { + + /** 用户Id **/ + private Long userId; + /** 姓名 **/ + private String realName; + /** 性别 **/ + private String sex; + /** 年龄 **/ + private int age; + /** 证件号 **/ + private String cardNo; + /** 身份证有效期起始日期 **/ + private Date idCardValidPeriodStart; + /** 身份证有效期结束日期 **/ + private Date idCardValidPeriodEnd; + + /** 身份证正面照片FileCode */ + private String positiveCardFileCode; + /** 身份证反面照片FileCode */ + private String inverseCardFileCode; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/ResetPwdDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/ResetPwdDTO.java new file mode 100644 index 0000000..a328b79 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/ResetPwdDTO.java @@ -0,0 +1,38 @@ +package com.senmesh.usercenter.user.dto; + +import javax.validation.constraints.NotBlank; + +import com.senmesh.common.validation.annotation.Expression; +import com.senmesh.common.validation.constants.ValidProviderEnum; +import com.senmesh.usercenter.user.phone.constant.UserPhoneCodeOperateEnum; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@ApiModel(description = "重置密码") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public class ResetPwdDTO extends UserPhoneCodeDTO{ + + /** **/ + private static final long serialVersionUID = -354146751167115968L; + + @ApiModelProperty("密码") + @Expression(type = ValidProviderEnum.PASSWORD, message = "密码格式不正确") + private String password; + @ApiModelProperty("二次确认密码") + @NotBlank(message = "二次确认密码不能为空") + private String rePassword; + + public String getOperateType() { + return UserPhoneCodeOperateEnum.RESET_PWD.getOperate(); + + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/ResetSecurityCodeDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/ResetSecurityCodeDTO.java new file mode 100644 index 0000000..4bd96d1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/ResetSecurityCodeDTO.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.user.dto; + +import javax.validation.constraints.NotBlank; + +import com.senmesh.common.validation.annotation.Expression; +import com.senmesh.common.validation.constants.ValidProviderEnum; +import com.senmesh.usercenter.user.phone.constant.UserPhoneCodeOperateEnum; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@ApiModel(description = "重置密码") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public class ResetSecurityCodeDTO extends UserPhoneCodeDTO{ + + /** **/ + private static final long serialVersionUID = -354146751167115968L; + + @ApiModelProperty("安全码") + @Expression(type = ValidProviderEnum.PASSWORD, message = "安全码格式不正确") + private String securityCode; + @ApiModelProperty("二次安全码") + @NotBlank(message = "二次安全码不能为空") + private String resecurityCode; + + public String getOperateType() { + return UserPhoneCodeOperateEnum.RESET_SECURITY_CODE.getOperate(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/SelectUserDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/SelectUserDTO.java new file mode 100644 index 0000000..d8b3f91 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/SelectUserDTO.java @@ -0,0 +1,30 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(description = "用户信息(供选择)") +@Builder +public class SelectUserDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 59302802862397459L; + + @ApiModelProperty("用户id") + private Long id; + + @ApiModelProperty("用户昵称") + private String nickname; + + @ApiModelProperty("用户姓名") + private String realName; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/SuperChangePhoneDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/SuperChangePhoneDTO.java new file mode 100644 index 0000000..bc197bb --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/SuperChangePhoneDTO.java @@ -0,0 +1,33 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotNull; + +import com.senmesh.common.validation.annotation.Expression; +import com.senmesh.common.validation.constants.ValidProviderEnum; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2021-09-24 + */ +@ApiModel(description = "代管-换绑手机号") +@Data +@NoArgsConstructor +public class SuperChangePhoneDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = -1664185349533051511L; + + @ApiModelProperty("用户id") + @NotNull(message = "用户id不能为空") + private Long userId; + @ApiModelProperty("手机号") + @Expression(type = ValidProviderEnum.PHONE, message = "手机号格式不正确") + private String phone; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/SuperRealNameTwoAuthDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/SuperRealNameTwoAuthDTO.java new file mode 100644 index 0000000..6602cc3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/SuperRealNameTwoAuthDTO.java @@ -0,0 +1,34 @@ +package com.senmesh.usercenter.user.dto; + +import javax.validation.constraints.NotBlank; + +import com.senmesh.common.annotation.trimAndUpper.TrimAndUpper; +import com.senmesh.common.dto.BaseOperateDTO; +import com.senmesh.common.validation.annotation.Expression; +import com.senmesh.common.validation.annotation.Phone; +import com.senmesh.common.validation.constants.ValidProviderEnum; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +@ApiModel(description = "上级二要素-认证") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class SuperRealNameTwoAuthDTO extends BaseOperateDTO{ + + private static final long serialVersionUID = 932738794127665634L; + @ApiModelProperty("姓名") + @NotBlank(message = "姓名不能为空") + @TrimAndUpper + private String realName; + @ApiModelProperty("身份证号") + @Expression(type = ValidProviderEnum.CARD_NO, message = "身份证号不正确") + @TrimAndUpper + private String cardNo; + @ApiModelProperty("手机号") + @Phone + private String phone; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserAuthDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserAuthDTO.java new file mode 100644 index 0000000..367246b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserAuthDTO.java @@ -0,0 +1,34 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-05-24 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "用户授权中间表") +public class UserAuthDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("授权大类") + private Integer authMainType ; + @ApiModelProperty("授权唯一id") + private String uniqueId ; + @ApiModelProperty("用户id") + private Long userId ; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserAuthOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserAuthOperateDTO.java new file mode 100644 index 0000000..b9d4e40 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserAuthOperateDTO.java @@ -0,0 +1,39 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; +import javax.validation.constraints.NotNull; +import com.senmesh.common.validation.Update; + +import com.senmesh.common.dto.BaseOperateDTO; + +/** + * @author sr on 2021-05-24 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "用户授权中间表操作") +public class UserAuthOperateDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + @NotNull(message = "id不能为空", groups = {Update.class}) + private Long id; + @ApiModelProperty("授权大类") + private Integer authMainType ; + @ApiModelProperty("授权唯一id") + private String uniqueId ; + @ApiModelProperty("用户id") + private Long userId ; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserAuthQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserAuthQueryDTO.java new file mode 100644 index 0000000..cdeafb2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserAuthQueryDTO.java @@ -0,0 +1,39 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; +import java.util.Set; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; + +import com.senmesh.common.dto.PageQueryDTO; + +/** + * @author sr on 2021-05-24 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "用户授权中间表查询条件") +public class UserAuthQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + @ApiModelProperty("授权大类") + private Integer authMainType ; + @ApiModelProperty("授权唯一id") + private String uniqueId ; + @ApiModelProperty("用户类型") + private Integer userType; + @ApiModelProperty("用户ids") + private Set userIds; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserCancelApplyReqDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserCancelApplyReqDTO.java new file mode 100644 index 0000000..1a35e21 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserCancelApplyReqDTO.java @@ -0,0 +1,24 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; + +import lombok.Data; + +/** + * @description: 用户注销申请dto + * @author: guixinman + * @create: 2024-07-03 17:24 + **/ +@Data +public class UserCancelApplyReqDTO implements Serializable { + + /** + * 注销原因类型 数据字典 + */ + @NotBlank(message = "申请原因类型必填") + private String cancellationType; + + private String remark; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserCancelDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserCancelDTO.java new file mode 100644 index 0000000..b19af5b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserCancelDTO.java @@ -0,0 +1,34 @@ +package com.senmesh.usercenter.user.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +import com.senmesh.common.dto.BaseDTO; + +@NoArgsConstructor +@AllArgsConstructor +@Data +@SuperBuilder +public class UserCancelDTO extends BaseDTO { + private static final long serialVersionUID = -6017193900382901567L; + /** + * 申请状态 1:已申请 2:已注销 + */ + private Integer status; + + /** + * 昵称 + */ + private String nickName; + + /** + * 真实姓名 + */ + private String realName; + + private String phone; + + private String cardNo; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserCancelPageQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserCancelPageQueryDTO.java new file mode 100644 index 0000000..df8457c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserCancelPageQueryDTO.java @@ -0,0 +1,24 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import lombok.*; + +@NoArgsConstructor +@AllArgsConstructor +@Data +@Builder +@EqualsAndHashCode(callSuper = true) +public class UserCancelPageQueryDTO extends PageQueryDTO { + private static final long serialVersionUID = -6017193900382901567L; + /** + * 申请状态 1:已申请 2:已注销 + */ + private Integer status; + + /** + * 名字(模糊匹配) + */ + private String nameLike; + + private Long userId; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserCancelReqDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserCancelReqDTO.java new file mode 100644 index 0000000..104c353 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserCancelReqDTO.java @@ -0,0 +1,30 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.NotNull; + +/** + * @author sr on 2021-05-24 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "用户注销操作") +public class UserCancelReqDTO extends BaseOperateDTO{ + + private static final long serialVersionUID = 5879202711902198878L; + + + + @ApiModelProperty("userId") + @NotNull(message = "userId不能为空") + private Long userId; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserConfigDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserConfigDTO.java new file mode 100644 index 0000000..81ba40b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserConfigDTO.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-08-12 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "用户配置") +public class UserConfigDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("用户id") + private Long userId; + @ApiModelProperty("编码") + private String configCode; + @ApiModelProperty("配置值") + private String configValue; + @ApiModelProperty("备注") + private String remark; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserConfigOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserConfigOperateDTO.java new file mode 100644 index 0000000..ee6724f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserConfigOperateDTO.java @@ -0,0 +1,46 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.Update; + +import com.senmesh.common.dto.BaseOperateDTO; + +/** + * @author sr on 2021-08-12 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "用户配置操作") +public class UserConfigOperateDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + @NotNull(message = "id不能为空", groups = {Update.class}) + private Long id; + @ApiModelProperty("用户id") + @NotNull(message = "id不能为空", groups = {Create.class}) + private Long userId; + @ApiModelProperty("编码") + @NotBlank(message = "编码不能为空", groups = {Create.class}) + private String configCode; + @ApiModelProperty("配置值") + @NotBlank(message = "配置值不能为空", groups = {Create.class}) + private String configValue; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserConfigQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserConfigQueryDTO.java new file mode 100644 index 0000000..987ec9b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserConfigQueryDTO.java @@ -0,0 +1,34 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; + +import com.senmesh.common.dto.PageQueryDTO; + +/** + * @author sr on 2021-08-12 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "用户配置查询条件") +public class UserConfigQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + @ApiModelProperty("用户id") + private Long userId; + @ApiModelProperty("编码") + private String configCode; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserDTO.java new file mode 100644 index 0000000..219fa21 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserDTO.java @@ -0,0 +1,113 @@ +package com.senmesh.usercenter.user.dto; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.senmesh.common.dto.BaseDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Date; + +/** + * @author czy + * @date 2021-06-10 + */ + +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "用户", value = "UcUserDTO") +public class UserDTO extends BaseDTO { + + private static final long serialVersionUID = 19560736481829489L; + + @ApiModelProperty("账号") + private String username; + + @JsonIgnore + @ApiModelProperty("密码") + private String password; + + @ApiModelProperty("是否已初始密码") + private Boolean initialedPassword; + + @ApiModelProperty("用户类型:1企业用户,2个人用户") + private Integer type; + + @ApiModelProperty("是否超管") + private Boolean supeiror; + + @ApiModelProperty("安全码") + private String securityCode; + + @ApiModelProperty("昵称") + private String nickname; + + @ApiModelProperty("头像") + private String avatar; + + @ApiModelProperty("手机号码") + private String phone; + + @ApiModelProperty("手机号绑定状态") + private Boolean phoneBinding; + + @ApiModelProperty("真实姓名") + private String realName; + + @ApiModelProperty("身份证号") + private String cardNo; + + @ApiModelProperty("是否实名") + private Boolean authenticated ; + + @ApiModelProperty("状态:1.待激活,2已激活,3已注销") + private Integer status ; + + @ApiModelProperty("邮箱") + private String email; + + @ApiModelProperty("用户所在地") + private String address; + + @ApiModelProperty("学历") + private Integer education; + + @ApiModelProperty("是否启用") + private Boolean enabled; + + @ApiModelProperty("账号是否未过期") + private Boolean accountNonExpired; + + @ApiModelProperty("是否未锁定") + private Boolean accountNonLocked; + + @ApiModelProperty("凭据是否未过期") + private Boolean credentialsNonExpired; + + @ApiModelProperty("平台编码") + private Integer platformCode; + + @ApiModelProperty("微信二维码") + private String wechatQrCode; + + @ApiModelProperty("是否申请注销 null:未申请 1:已申请 2:已通过") + private Integer cancelStatus; + + /** 性别:1男2女 **/ + private Integer gender; + + /** 生日 **/ + private Date birthday; + + + public void setPassword(String password) { + this.password = password; + this.initialedPassword = StringUtils.isNotBlank(password); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserDetailQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserDetailQueryDTO.java new file mode 100644 index 0000000..25c4a0e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserDetailQueryDTO.java @@ -0,0 +1,42 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 登录用户查询 + * @author sr on 2020-06-15 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class UserDetailQueryDTO implements Serializable { + + /** + * + **/ + private static final long serialVersionUID = -8912916458925736955L; + + private Long userId; + + private Integer userType; + + /** (暂)对外网关需要feign匿名获取用户信息,账号不能为空 **/ + @NotBlank(message = "账号不能为空") + private String username; + + private String phone; + + private Long orgId; + + /** 身份证号 **/ + private String cardNo; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserExtendStatusDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserExtendStatusDTO.java new file mode 100644 index 0000000..b05f65f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserExtendStatusDTO.java @@ -0,0 +1,38 @@ +package com.senmesh.usercenter.user.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author czy + * @date 2021-06-10 + */ + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class UserExtendStatusDTO { + + @ApiModelProperty("用户Id") + private Long userId; + + @ApiModelProperty("实名认证") + private Boolean authenticatedStatus; + + @ApiModelProperty("证件正反面照上传") + private Boolean cardUploadStatus; + + @ApiModelProperty("银行卡认证(三要素)") + private Integer bankCardAuthStatus; + + @ApiModelProperty("手机绑定") + private Boolean phoneBindStatus; + + @ApiModelProperty("微信绑定") + private Boolean wxBindStatus; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserExtensionDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserExtensionDTO.java new file mode 100644 index 0000000..cee8760 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserExtensionDTO.java @@ -0,0 +1,39 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author czy + * @date 2021-06-15 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class UserExtensionDTO extends BaseDTO { + + @ApiModelProperty(value = "userId") + private Long userId; + + @ApiModelProperty(value = "常住地区") + private String residenceAddress; + + @ApiModelProperty(value = "技能标签") + private String techniqueTag; + + @ApiModelProperty("简历附件名称") + private String fileName; + + @ApiModelProperty("简历附件编码") + private String fileCode; + + @ApiModelProperty("新冠疫苗") + private Integer covidVaccine; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserExtensionOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserExtensionOperateDTO.java new file mode 100644 index 0000000..5f6d9a5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserExtensionOperateDTO.java @@ -0,0 +1,42 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.dto.BaseOperateDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author czy + * @date 2021-06-15 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel("用户扩展信息") +public class UserExtensionOperateDTO extends BaseOperateDTO { + + @ApiModelProperty(value = "常住地区") + private String residenceAddress; + + @ApiModelProperty(value = "技能标签") + private String techniqueTag; + + @ApiModelProperty("简历附件名称") + private String fileName; + + @ApiModelProperty("简历附件编码") + private String fileCode; + + @ApiModelProperty("新冠疫苗") + private Integer covidVaccine; + + /** + * 微信二维码 + */ + @ApiModelProperty("微信二维码") + private String wechatQrCode; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserOperateDTO.java new file mode 100644 index 0000000..c9db9b5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserOperateDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.dto.BaseOperateDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +/** + * @author sr on 2021-05-24 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "用户操作") +public class UserOperateDTO extends BaseOperateDTO{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("昵称") + private String nickname; + + @ApiModelProperty("头像") + private String avatar; + + @ApiModelProperty("邮箱") + private String email; + + @ApiModelProperty("用户所在地") + private String address; + @ApiModelProperty("学历") + private Integer education; +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserPhoneCodeDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserPhoneCodeDTO.java new file mode 100644 index 0000000..814bed4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserPhoneCodeDTO.java @@ -0,0 +1,25 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.usercenter.user.phone.dto.PhoneCodeDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@ApiModel(description = "用户验证短信验证码-不同操作类型") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public abstract class UserPhoneCodeDTO extends PhoneCodeDTO implements IUserPhoneCode{ + + /** **/ + private static final long serialVersionUID = -354146751167115968L; + + @ApiModelProperty("用户类型(未登录必填)") + private Integer userType; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserPhoneCodeSmsCaptchaDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserPhoneCodeSmsCaptchaDTO.java new file mode 100644 index 0000000..6048dca --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserPhoneCodeSmsCaptchaDTO.java @@ -0,0 +1,29 @@ +package com.senmesh.usercenter.user.dto; + +import javax.validation.constraints.NotBlank; + +import com.senmesh.usercenter.user.phone.dto.CaptchaPhoneCodeSmsDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@ApiModel(description = "用户获取验证码(带防水墙)-不同操作类型") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public class UserPhoneCodeSmsCaptchaDTO extends CaptchaPhoneCodeSmsDTO implements IUserPhoneCodeSms{ + + /** **/ + private static final long serialVersionUID = -354146751167115968L; + + @ApiModelProperty("用户类型(未登录必填)") + private Integer userType; + @NotBlank(message = "操作类型不能为空") + private String operateType; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserPhoneCodeSmsDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserPhoneCodeSmsDTO.java new file mode 100644 index 0000000..22472c1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserPhoneCodeSmsDTO.java @@ -0,0 +1,31 @@ +package com.senmesh.usercenter.user.dto; + +import javax.validation.constraints.NotBlank; + +import com.senmesh.usercenter.user.phone.constant.UserPhoneCodeOperateEnum; +import com.senmesh.usercenter.user.phone.dto.PhoneCodeSmsDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@ApiModel(description = "用户发送短信验证码-不同操作类型") +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public class UserPhoneCodeSmsDTO extends PhoneCodeSmsDTO implements IUserPhoneCodeSms{ + + /** **/ + private static final long serialVersionUID = -354146751167115968L; + + @ApiModelProperty("用户类型(未登录必填)") + private Integer userType; + /** {@link UserPhoneCodeOperateEnum} **/ + @NotBlank(message = "操作类型不能为空") + private String operateType; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserPostalInfoDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserPostalInfoDTO.java new file mode 100644 index 0000000..73064d5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserPostalInfoDTO.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author fzp on 2022-01-19 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "用户邮寄信息") +public class UserPostalInfoDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("是否默认") + private Boolean defaulted; + @ApiModelProperty("收货人") + private String name; + @ApiModelProperty("手机号") + private String phone; + @ApiModelProperty("地区编号") + private String addressCode; + @ApiModelProperty("地区名称") + private String addressName; + @ApiModelProperty("详细地址") + private String addressDetail; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserPostalInfoOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserPostalInfoOperateDTO.java new file mode 100644 index 0000000..f4b7804 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserPostalInfoOperateDTO.java @@ -0,0 +1,51 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import com.senmesh.common.validation.Create; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; +import javax.validation.constraints.NotNull; +import com.senmesh.common.validation.Update; + +import com.senmesh.common.dto.BaseOperateDTO; + +/** + * @author fzp on 2022-01-19 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "用户邮寄信息操作") +public class UserPostalInfoOperateDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + @NotNull(message = "id不能为空", groups = {Update.class}) + private Long id; + + @ApiModelProperty("是否默认") + private Boolean defaulted; + @NotNull(message = "收货人不能为空", groups = {Update.class, Create.class}) + @ApiModelProperty("收货人") + private String name; + @NotNull(message = "手机号不能为空", groups = {Update.class, Create.class}) + @ApiModelProperty("手机号") + private String phone; + @NotNull(message = "地区编号不能为空", groups = {Update.class, Create.class}) + @ApiModelProperty("地区编号") + private String addressCode; + @NotNull(message = "地区名称不能为空", groups = {Update.class, Create.class}) + @ApiModelProperty("地区名称") + private String addressName; + @ApiModelProperty("详细地址") + private String addressDetail; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserPostalInfoQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserPostalInfoQueryDTO.java new file mode 100644 index 0000000..b95b06e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserPostalInfoQueryDTO.java @@ -0,0 +1,39 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; + +import com.senmesh.common.dto.PageQueryDTO; + +/** + * @author fzp on 2022-01-19 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "用户邮寄信息查询条件") +public class UserPostalInfoQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + + @ApiModelProperty("是否默认") + private Boolean defaulted; + @ApiModelProperty("收货人") + private String name; + @ApiModelProperty("手机号") + private String phone; + @ApiModelProperty("创建人ID") + private Long createBy; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserQueryByRoleDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserQueryByRoleDTO.java new file mode 100644 index 0000000..aec4b6f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserQueryByRoleDTO.java @@ -0,0 +1,34 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(description = "用户信息查询(通过角色相关信息)") +@Builder +public class UserQueryByRoleDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = -2498786188653251282L; + + @ApiModelProperty("标准角色类型") + @NotBlank(message = "标准角色类型不能为空") + private String roleStandardTypeCode; + + @ApiModelProperty("平台编码") + private Integer platformCode; + + @ApiModelProperty("机构id") + private Long orgId; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserQueryDTO.java new file mode 100644 index 0000000..7baa5ea --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserQueryDTO.java @@ -0,0 +1,103 @@ +package com.senmesh.usercenter.user.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.senmesh.common.annotation.trimAndUpper.TrimAndUpper; +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; +import java.util.Set; + +/** + * @author czy + * @date 2021-06-10 + */ + +@Data +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(description = "用户信息查询") +@Builder +public class UserQueryDTO extends PageQueryDTO { + + /** **/ + private static final long serialVersionUID = 2636844352691455030L; + + @ApiModelProperty("用户id") + private Long id; + + @ApiModelProperty("用户ids") + private Set ids; + + @ApiModelProperty("用户类型:1企业用户,2个人用户") + private Integer type; + + @ApiModelProperty("手机号码") + @TrimAndUpper(TrimAndUpper.ExecuteType.TRIM) + private String phone; + + @ApiModelProperty("手机号绑定状态") + private Boolean phoneBinding; + + @ApiModelProperty("身份证号") + @TrimAndUpper(TrimAndUpper.ExecuteType.TRIM) + private String cardNo; + + @ApiModelProperty("未注销") + private Boolean uncanceled; + + @ApiModelProperty("姓名(模糊匹配)") + @TrimAndUpper(TrimAndUpper.ExecuteType.TRIM) + private String realNameLike; + + @ApiModelProperty("账号") + @TrimAndUpper(TrimAndUpper.ExecuteType.TRIM) + private String usernameLike; + + @ApiModelProperty("昵称") + @TrimAndUpper(TrimAndUpper.ExecuteType.TRIM) + private String nicknameLike; + + @ApiModelProperty("邮箱") + @TrimAndUpper(TrimAndUpper.ExecuteType.TRIM) + private String emailLike; + + @ApiModelProperty("是否启用") + private Boolean enabled; + + @ApiModelProperty("状态:1.待激活,2已激活,3已注销") + private Integer status; + + @ApiModelProperty("是否申请注销 null:未申请 1:已申请 2:已通过") + private Integer cancelStatus; + + /** + * 是否实名 + */ + private Boolean authenticated; + + @ApiModelProperty("创建时间起") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat( + shape = JsonFormat.Shape.STRING, + pattern = "yyyy-MM-dd HH:mm:ss", + timezone = "GMT+8" + ) + private Date createTimeStart; + @ApiModelProperty("创建时间止") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat( + shape = JsonFormat.Shape.STRING, + pattern = "yyyy-MM-dd HH:mm:ss", + timezone = "GMT+8" + ) + private Date createTimeEnd; + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRealNameModifyDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRealNameModifyDTO.java new file mode 100644 index 0000000..de12a71 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRealNameModifyDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 修改用户姓名操作DTO + * + * @author liu on 2026-10-27 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "修改用户姓名操作") +public class UserRealNameModifyDTO extends BaseOperateDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("用户id") + @NotNull(message = "用户id不能为空") + private Long userId; + + @ApiModelProperty("姓名") + @NotBlank(message = "姓名不能为空") + private String realName; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterCodeDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterCodeDTO.java new file mode 100644 index 0000000..591c516 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterCodeDTO.java @@ -0,0 +1,28 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@ApiModel(description = "生成(当前自己)用户注册邀请码") +public class UserRegisterCodeDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 2118502786779163962L; + + @ApiModelProperty("系统应用标识(为空则用请求域名匹配)") +// @NotNull(message = "系统应用标识不能为空") + private Integer platformCode; + @ApiModelProperty("关联id(小程序码id)") + private Long unionId; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterCodeInfoDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterCodeInfoDTO.java new file mode 100644 index 0000000..c1c6db0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterCodeInfoDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotNull; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(description = "用户注册邀请码信息") +@SuperBuilder +public class UserRegisterCodeInfoDTO extends UserRegisterCodeDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 2118502786779163962L; + + @ApiModelProperty("邀请人用户类型") + @NotNull(message = "邀请人id不能为空") + private Integer inviterType; + + @ApiModelProperty("邀请人id") + @NotNull(message = "邀请人id不能为空") + private Long inviterId; + + @ApiModelProperty("邀请人机构id(机构用户该属性不能为空)") + private Long inviterOrgId; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterCreateDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterCreateDTO.java new file mode 100644 index 0000000..6ff86c2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterCreateDTO.java @@ -0,0 +1,34 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "用户邀请注册") +public class UserRegisterCreateDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 2118502786779163962L; + + @ApiModelProperty("邀请码(为空则自主注册)") + private String registerCode; + @NotNull(message = "用户id不能为空") + @ApiModelProperty("用户id") + private Long userId; + @ApiModelProperty("入口点") + private String entrypoint; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterDTO.java new file mode 100644 index 0000000..d2f99f8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterDTO.java @@ -0,0 +1,48 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-11-16 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "用户注册信息") +public class UserRegisterDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("系统应用标识") + private Integer platformCode; + + @ApiModelProperty("用户id") + private Long userId; + + @ApiModelProperty("邀请人id") + private Long inviterId; + + @ApiModelProperty("邀请人用户类型") + private Integer inviterType; + + @ApiModelProperty("邀请人机构id") + private Long inviterOrgId; + + @ApiModelProperty("入口点类型") + private String entrypoint; + + @ApiModelProperty("关联id(小程序码id)") + private Long unionId; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterInfoDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterInfoDTO.java new file mode 100644 index 0000000..f18637c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterInfoDTO.java @@ -0,0 +1,27 @@ +package com.senmesh.usercenter.user.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2021-11-16 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Data +@ApiModel(description = "用户注册详细信息") +public class UserRegisterInfoDTO extends UserRegisterDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("用户昵称") + private String userNickname; + @ApiModelProperty("用户头像") + private String userAvatar; +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterInfoQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterInfoQueryDTO.java new file mode 100644 index 0000000..c25e347 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterInfoQueryDTO.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import com.senmesh.common.dto.PageQueryDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2021-11-16 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "用户注册表查询条件") +public class UserRegisterInfoQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("系统应用标识") + private Integer platformCode; + + @ApiModelProperty("用户id") + private Long userId; + + @ApiModelProperty("邀请人id") + private Long inviterId; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterOperateDTO.java new file mode 100644 index 0000000..08fbeb2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterOperateDTO.java @@ -0,0 +1,33 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; +import javax.validation.constraints.NotNull; +import com.senmesh.common.validation.Update; + +import com.senmesh.common.dto.BaseOperateDTO; + +/** + * @author sr on 2021-11-16 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "用户注册表操作") +public class UserRegisterOperateDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + @NotNull(message = "id不能为空", groups = {Update.class}) + private Long id; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterQueryDTO.java new file mode 100644 index 0000000..4265eb0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserRegisterQueryDTO.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; + +import com.senmesh.common.dto.PageQueryDTO; + +/** + * @author sr on 2021-11-16 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "用户注册表查询条件") +public class UserRegisterQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + + @ApiModelProperty("系统应用标识") + private Integer platformCode; + + @ApiModelProperty("用户id") + private Long userId; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserSelfUpdateDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserSelfUpdateDTO.java new file mode 100644 index 0000000..07d19f5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserSelfUpdateDTO.java @@ -0,0 +1,33 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2021-01-15 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "用户修改个人信息") +public class UserSelfUpdateDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 8864167560336812469L; + + @ApiModelProperty("姓名") + private String name; + + @ApiModelProperty("身份证") + private String cardNo; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserSignDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserSignDTO.java new file mode 100644 index 0000000..f73a335 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserSignDTO.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.user.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import java.util.Date; + +/** + * @author fzp on 2022-01-18 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "用户签到表") +public class UserSignDTO extends BaseDTO { + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + + @ApiModelProperty("用户Id") + private Long userId; + + @ApiModelProperty("系统编码") + private Integer platformCode; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @ApiModelProperty("签到") + private Date signTime; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserSignOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserSignOperateDTO.java new file mode 100644 index 0000000..986cfca --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserSignOperateDTO.java @@ -0,0 +1,44 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.dto.BaseOperateDTO; +import com.senmesh.common.validation.Update; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Date; + +/** + * @author fzp on 2022-01-18 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "用户签到表操作") +public class UserSignOperateDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + @NotNull(message = "id不能为空", groups = {Update.class}) + private Long id; + + @NotNull(message = "用户id") + private Long userId; + + @ApiModelProperty("系统编码") + private Integer platformCode; + + @NotNull(message = "签到时间") + private Date signTime; + + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserSignQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserSignQueryDTO.java new file mode 100644 index 0000000..908aea2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserSignQueryDTO.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.dto.PageQueryDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + * @author fzp on 2022-01-18 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "用户签到表查询条件") +public class UserSignQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("id") + private Long id; + + @NotNull(message = "用户id") + private Long userId; + + @NotNull(message = "签到时间") + private String signTime; + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/UserStatusOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserStatusOperateDTO.java new file mode 100644 index 0000000..2b29fae --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/UserStatusOperateDTO.java @@ -0,0 +1,30 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.dto.BaseOperateDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.NotNull; + +/** + * 用户启用/禁用/注销操作DTO + * + * @author liu on 2026-09-14 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "用户启用/禁用/注销操作") +public class UserStatusOperateDTO extends BaseOperateDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("用户id") + @NotNull(message = "用户id不能为空") + private Long userId; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/WechatUserBindPhoneDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/WechatUserBindPhoneDTO.java new file mode 100644 index 0000000..796534a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/WechatUserBindPhoneDTO.java @@ -0,0 +1,44 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; + +import com.senmesh.common.dto.BaseOperateDTO; +import com.senmesh.common.validation.annotation.Phone; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2021-01-13 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(description = "微信用户查询条件") +public class WechatUserBindPhoneDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = -8981587236777596678L; + + @ApiModelProperty("姓名") +// @NotBlank(message = "姓名不能为空") + private String name; + @ApiModelProperty("手机号") + @Phone + private String phone; + @ApiModelProperty("验证码") + @NotBlank(message = "验证码不能为空") + private String phoneCode; + @ApiModelProperty("身份证") + private String cardNo; + @ApiModelProperty("用户类型:3企业,4个人") + @NotBlank(message = "用户类型不能为空") + private Integer userType; + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/WechatUserDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/WechatUserDTO.java new file mode 100644 index 0000000..3154ec9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/WechatUserDTO.java @@ -0,0 +1,51 @@ +package com.senmesh.usercenter.user.dto; + +import com.senmesh.common.dto.BaseDTO; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import java.io.Serializable; + +/** + * @author sr on 2021-01-12 + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@ApiModel(description = "微信用户") +public class WechatUserDTO extends BaseDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("微信openid") + private String openId; + @ApiModelProperty("用户id") + private Long userId; + @ApiModelProperty("昵称") + private String nickname; + @ApiModelProperty("用户的性别,值为1时是男性,值为2时是女性,值为0时是未知") + private Integer sex; + @ApiModelProperty("用户个人资料填写的省份") + private String province; + @ApiModelProperty("普通用户个人资料填写的城市") + private String city; + @ApiModelProperty("国家,如中国为CN") + private String country; + @ApiModelProperty("用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效") + private String headimgurl; + @ApiModelProperty("只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段") + private String unionid; + @ApiModelProperty("是否为默认") + private Boolean setDefault; + @ApiModelProperty("注册来源 1.小程序 2.H5") + private Integer registeredChannel; + @ApiModelProperty("登录用户身份类型") + private String type; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/WechatUserInfoDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/WechatUserInfoDTO.java new file mode 100644 index 0000000..36ae601 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/WechatUserInfoDTO.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.user.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2021-01-14 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(description = "微信用户查询条件") +public class WechatUserInfoDTO extends WechatUserDTO{ + + /** **/ + private static final long serialVersionUID = 138610870654616159L; + + @ApiModelProperty("姓名") + private String name; + @ApiModelProperty("手机号") + private String phone; + @ApiModelProperty("身份证") + private String cardNo; +// @ApiModelProperty("二要素认证状态 1:待认证 2:认证成功 3:认证失败") +// private String authStatu; + @ApiModelProperty("是否实名") + private Boolean authenticated; + @ApiModelProperty("是否存在企业账号信息,默认为否; 是:true 否: false") + private Boolean enterpriseInfo; + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/WechatUserOperateDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/WechatUserOperateDTO.java new file mode 100644 index 0000000..8b56fb0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/WechatUserOperateDTO.java @@ -0,0 +1,55 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import io.swagger.annotations.ApiModel; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import com.senmesh.common.dto.BaseOperateDTO; + +/** + * @author sr on 2021-01-12 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ApiModel(description = "微信用户操作") +public class WechatUserOperateDTO extends BaseOperateDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("微信openid") + @NotBlank(message = "微信openid不能为空") + private String openId; + @ApiModelProperty("用户id") + private Long userId; + @ApiModelProperty("昵称") + private String nickname; + @ApiModelProperty("用户的性别,值为1时是男性,值为2时是女性,值为0时是未知") + private Integer sex; + @ApiModelProperty("用户个人资料填写的省份") + private String province; + @ApiModelProperty("普通用户个人资料填写的城市") + private String city; + @ApiModelProperty("国家,如中国为CN") + private String country; + @ApiModelProperty("用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效") + private String headimgurl; + @ApiModelProperty("只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段") + private String unionid; + @ApiModelProperty("是否为默认") + private Boolean setDefault; + @ApiModelProperty("注册来源 1.小程序 2.H5") + @NotNull(message = "来源不能为空") + private Integer registeredChannel; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/dto/WechatUserQueryDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/dto/WechatUserQueryDTO.java new file mode 100644 index 0000000..7b201f0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/dto/WechatUserQueryDTO.java @@ -0,0 +1,43 @@ +package com.senmesh.usercenter.user.dto; + +import java.io.Serializable; + +import com.senmesh.common.dto.PageQueryDTO; +import com.senmesh.tkmybatis.pojo.Page; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2021-01-12 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(description = "微信用户查询条件") +public class WechatUserQueryDTO extends PageQueryDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("微信openid") + private String openId; + @ApiModelProperty("用户id") + private Long userId; + @ApiModelProperty("注册来源 1.小程序 2.H5") + private Integer registeredChannel; + + @Builder + public WechatUserQueryDTO(Integer pageNo, Integer pageSize, Boolean needPage, + Page pageResult, String openId, Long userId, Integer registeredChannel) { + super(pageNo, pageSize, needPage, pageResult); + this.openId = openId; + this.userId = userId; + this.registeredChannel = registeredChannel; + } + +} \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/entity/OrgUser.java b/backend/src/main/java/com/senmesh/usercenter/user/entity/OrgUser.java new file mode 100644 index 0000000..b9eb5a4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/entity/OrgUser.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.user.entity; + +import org.apache.ibatis.type.Alias; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.OrgBaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 机构用户表 + * + * @author sr on 2021-05-24 + */ +@TableName("uc_org_user") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@Alias("UcOrgUser") +public class OrgUser extends OrgBaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 用户id */ + private Long userId ; + /** 是否管理员 */ + private Boolean administrator ; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/entity/User.java b/backend/src/main/java/com/senmesh/usercenter/user/entity/User.java new file mode 100644 index 0000000..40bd68a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/entity/User.java @@ -0,0 +1,77 @@ +package com.senmesh.usercenter.user.entity; + +import java.util.Date; + +import org.apache.ibatis.type.Alias; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 用户 + * + * @author sr on 2021-05-24 + */ +@TableName("uc_user") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +@Alias("UcUser") +public class User extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + /** 账号 */ + private String username ; + /** 密码 */ + private String password ; + /** 用户类型:1企业用户,2个人用户 */ + private Integer type ; + /** 是否超管 */ + private Boolean supeiror ; + /** 安全码 */ + private String securityCode ; + /** 昵称 */ + private String nickname ; + /** 头像 */ + private String avatar ; + /** 手机号码 */ + private String phone ; + /** 手机号绑定状态 */ + private Boolean phoneBinding ; + /** 真实姓名 */ + private String realName ; + /** 身份证号 */ + private String cardNo ; + /** 性别:1男2女 **/ + private Integer gender ; + /** 生日 **/ + private Date birthday ; + /** 是否实名 */ + private Boolean authenticated ; + /** 状态:1.待激活,2已激活,3已注销 */ + private Integer status ; + /** 邮箱 */ + private String email ; + /** 用户所在地 */ + private String address; + /** 文化程度:1博士、2硕士、3本科、4大专、5高中、6中专/中技、7初中及以下、8不限*/ + private Integer education; + /** 是否启用 */ + private Boolean enabled ; + /** 账号是否未过期 */ + private Boolean accountNonExpired ; + /** 是否未锁定 */ + private Boolean accountNonLocked ; + /** 凭据是否未过期 */ + private Boolean credentialsNonExpired ; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/entity/UserAuth.java b/backend/src/main/java/com/senmesh/usercenter/user/entity/UserAuth.java new file mode 100644 index 0000000..2e2d43b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/entity/UserAuth.java @@ -0,0 +1,34 @@ +package com.senmesh.usercenter.user.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 用户授权中间表 + * + * @author sr on 2021-05-24 + */ +@TableName("uc_user_auth") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class UserAuth extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 授权大类 */ + private Integer authMainType ; + /** 授权唯一id */ + private String uniqueId ; + /** 用户id */ + private Long userId ; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/entity/UserCancel.java b/backend/src/main/java/com/senmesh/usercenter/user/entity/UserCancel.java new file mode 100644 index 0000000..9721345 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/entity/UserCancel.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.user.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@TableName("uc_user_cancel") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class UserCancel extends BaseEntity { + + private static final long serialVersionUID = -8939983320960850273L; + /** + * 用户id + */ + private Long userId; + /** + * 申请状态 1:已申请 2:已注销 + */ + private Integer status; + + /** + * 注销原因类型 数据字典 + */ + private String cancellationType; + + private String remark; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/entity/UserConfig.java b/backend/src/main/java/com/senmesh/usercenter/user/entity/UserConfig.java new file mode 100644 index 0000000..8282a2b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/entity/UserConfig.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.user.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 用户配置 + * + * @author sr on 2021-08-12 + */ +@TableName("uc_user_config") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class UserConfig extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 用户id **/ + private Long userId; + /** 编码 **/ + private String configCode; + /** 配置值 **/ + private String configValue; + /** 备注 **/ + private String remark; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/entity/UserExtension.java b/backend/src/main/java/com/senmesh/usercenter/user/entity/UserExtension.java new file mode 100644 index 0000000..8060f6f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/entity/UserExtension.java @@ -0,0 +1,54 @@ +package com.senmesh.usercenter.user.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author czy + * @date 2021-06-15 + */ +@TableName("uc_user_extension") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class UserExtension extends BaseEntity { + + /** + * 用户Id + */ + private Long userId; + + /** + *常住地区 + */ + private String residenceAddress; + + /** + *技能标签 + */ + private String techniqueTag; + /** + * 简历Code + */ + private String fileCode; + /** + * 简历名称 + */ + private String fileName; + + /** 新冠疫苗 **/ + private Integer covidVaccine; + + /** + * 微信二维码 + */ + private String wechatQrCode; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/entity/UserPostalInfo.java b/backend/src/main/java/com/senmesh/usercenter/user/entity/UserPostalInfo.java new file mode 100644 index 0000000..da53f2d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/entity/UserPostalInfo.java @@ -0,0 +1,51 @@ +package com.senmesh.usercenter.user.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 用户邮寄信息 + * + * @author fzp on 2022-01-19 + */ +@TableName("uc_user_postal_info") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class UserPostalInfo extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 是否默认 **/ + private Boolean defaulted; + /** + * 收货人 + */ + private String name; + /** + * 手机号 + */ + private String phone; + /** + * 地区编号 + */ + private String addressCode; + /** + * 地区名称 + */ + private String addressName; + /** + * 地区地址 + */ + private String addressDetail; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/entity/UserRegister.java b/backend/src/main/java/com/senmesh/usercenter/user/entity/UserRegister.java new file mode 100644 index 0000000..e67a337 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/entity/UserRegister.java @@ -0,0 +1,49 @@ +package com.senmesh.usercenter.user.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.senmesh.common.entity.BaseEntity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 用户注册表 + * + * @author sr on 2021-11-16 + */ +@TableName("uc_user_register") +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@Data +public class UserRegister extends BaseEntity { + + /** **/ + private static final long serialVersionUID = 1L; + + /** 系统应用标识 **/ + private Integer platformCode; + + /** 用户id **/ + private Long userId; + + /** 邀请人id **/ + private Long inviterId; + + /** 邀请人用户类型 **/ + private Integer inviterType; + + /** 邀请人机构id **/ + private Long inviterOrgId; + + /** 入口点类型 **/ + private String entrypoint; + + /** 关联id(小程序码id) **/ + private Long unionId; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/login/controller/UserLoginController.java b/backend/src/main/java/com/senmesh/usercenter/user/login/controller/UserLoginController.java new file mode 100644 index 0000000..4f64cfb --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/login/controller/UserLoginController.java @@ -0,0 +1,30 @@ +package com.senmesh.usercenter.user.login.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import com.senmesh.common.AlitaResult; +import com.senmesh.usercenter.user.dto.UserDetailQueryDTO; +import com.senmesh.usercenter.user.login.dto.UserDetailDTO; +import com.senmesh.usercenter.user.login.service.UserLoginService; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +//@RestController +@Api(tags = "用户登录") +public class UserLoginController { + + @Autowired + private UserLoginService userLoginService; + + @ApiOperation("根据登录信息获取用户信息") + @PostMapping("anon/user/find_user_detail_dto") + public AlitaResult findUserDetailDTO(@RequestBody UserDetailQueryDTO userDetailQueryDto){ + return userLoginService.findUserDetailDTOResult(userDetailQueryDto); + } + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/login/dto/LoginPhoneDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/login/dto/LoginPhoneDTO.java new file mode 100644 index 0000000..154eed3 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/login/dto/LoginPhoneDTO.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.user.login.dto; + +import com.senmesh.usercenter.user.dto.UserPhoneCodeDTO; +import com.senmesh.usercenter.user.phone.constant.UserPhoneCodeOperateEnum; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@NoArgsConstructor +@AllArgsConstructor +@Data +@SuperBuilder +@ApiModel(description = "手机号登录") +public class LoginPhoneDTO extends UserPhoneCodeDTO{ + + /** **/ + private static final long serialVersionUID = 1982976901464380354L; + + @ApiModelProperty("注册邀请码") + private String registerCode; + @ApiModelProperty("入口点") + private String entrypoint; + @ApiModelProperty("没有验证码(默认需要验证码)") + private Boolean withoutCode; + + + @Override + public String getOperateType() { + return UserPhoneCodeOperateEnum.LOGIN.getOperate(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/login/dto/LoginPhoneToken.java b/backend/src/main/java/com/senmesh/usercenter/user/login/dto/LoginPhoneToken.java new file mode 100644 index 0000000..4a384b1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/login/dto/LoginPhoneToken.java @@ -0,0 +1,27 @@ +package com.senmesh.usercenter.user.login.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@SuperBuilder +@ApiModel(description = "手机号token登录-个人用户选用户") +public class LoginPhoneToken extends PhoneToken{ + + /** **/ + private static final long serialVersionUID = -4972872069055864454L; + +// @NotNull(message = "用户id不能为空") + /** **/ + @ApiModelProperty("用户id(无则新增)") + private Long userId; + @ApiModelProperty("注册邀请码") + private String registerCode; + @ApiModelProperty("入口点") + private String entrypoint; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/login/dto/LoginUCardDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/login/dto/LoginUCardDTO.java new file mode 100644 index 0000000..0531eeb --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/login/dto/LoginUCardDTO.java @@ -0,0 +1,29 @@ +package com.senmesh.usercenter.user.login.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.io.Serializable; +import javax.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@AllArgsConstructor +@Data +@Builder +@ApiModel(description = "身份证登录") +public class LoginUCardDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = -5406549736684905311L; + + @ApiModelProperty("姓名") + @NotBlank(message = "姓名不能为空") + private String realName; + @ApiModelProperty("身份证号") + @NotBlank(message = "身份证号不能为空") + private String cardNo; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/login/dto/LoginUserToken.java b/backend/src/main/java/com/senmesh/usercenter/user/login/dto/LoginUserToken.java new file mode 100644 index 0000000..eb585e6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/login/dto/LoginUserToken.java @@ -0,0 +1,22 @@ +package com.senmesh.usercenter.user.login.dto; + +import javax.validation.constraints.NotNull; + +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@SuperBuilder +@ApiModel(description = "用户token登录-企业用户选机构") +public class LoginUserToken extends UserToken{ + + /** **/ + private static final long serialVersionUID = -6996668235244805301L; + + @NotNull(message = "机构id不能为空") + private Long orgId; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/login/dto/LoginUsernamePasswordDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/login/dto/LoginUsernamePasswordDTO.java new file mode 100644 index 0000000..4d6c72c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/login/dto/LoginUsernamePasswordDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.user.login.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@AllArgsConstructor +@Data +@Builder +@ApiModel(description = "账号密码登录") +public class LoginUsernamePasswordDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = -5406549736684905311L; + + @ApiModelProperty("账号") + @NotBlank(message = "账号不能为空") + private String username; + @ApiModelProperty("密码") + @NotBlank(message = "密码不能为空") + private String password; + @ApiModelProperty("用户类型") + @NotNull(message = "用户类型不能为空") + private Integer userType; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/login/dto/OrgDetailDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/login/dto/OrgDetailDTO.java new file mode 100644 index 0000000..3ff0f0d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/login/dto/OrgDetailDTO.java @@ -0,0 +1,29 @@ +package com.senmesh.usercenter.user.login.dto; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OrgDetailDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = -8169657080151873030L; + + /** 机构id **/ + private Long orgId; + + /** 机构名称 **/ + private String orgName; + + /** 机构类型 **/ + private String orgType; + + /** 是否机构管理员 **/ + private Boolean administrator; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/login/dto/PhoneToken.java b/backend/src/main/java/com/senmesh/usercenter/user/login/dto/PhoneToken.java new file mode 100644 index 0000000..2817621 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/login/dto/PhoneToken.java @@ -0,0 +1,17 @@ +package com.senmesh.usercenter.user.login.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@SuperBuilder +public abstract class PhoneToken extends TempTokenDTO{ + + /** **/ + private static final long serialVersionUID = -4972872069055864454L; + + private final String type = TempTokenDTO.TYPE_PHONE; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/login/dto/TempTokenDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/login/dto/TempTokenDTO.java new file mode 100644 index 0000000..b213d69 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/login/dto/TempTokenDTO.java @@ -0,0 +1,24 @@ +package com.senmesh.usercenter.user.login.dto; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public abstract class TempTokenDTO implements Serializable { + + public static final String TYPE_PHONE = "phone"; + public static final String TYPE_USER = "user"; + + @NotBlank(message = "临时token不能为空") + private String tempToken; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/login/dto/UserDetailDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/login/dto/UserDetailDTO.java new file mode 100644 index 0000000..58b47f0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/login/dto/UserDetailDTO.java @@ -0,0 +1,110 @@ +package com.senmesh.usercenter.user.login.dto; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.senmesh.security.util.PasswordUtils; +import com.senmesh.usercenter.user.util.UserUtils; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import java.io.Serializable; +import java.util.List; +import lombok.Builder.Default; + +/** + * 用户 + * + * @author sr on 2019-11-05 + */ +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Data +@ToString +public class UserDetailDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 1074707536155659372L; + + @ApiModelProperty("用户id") + private Long id; + + @ApiModelProperty("是否超管") + private Boolean supeiror ; + + @ApiModelProperty("类型") + private Integer type; + + /** ----------------仅限机构用户--------------- **/ + @ApiModelProperty("当前操作机构") + private Long orgId; + + @ApiModelProperty("当前操作机构名称") + private String orgName; + + @ApiModelProperty("当前操作机构类型") + private String orgType; + + @ApiModelProperty("是否机构管理员") + private Boolean administrator; + /** ----------------仅限机构用户--------------- **/ + + @ApiModelProperty("账号") + @JsonIgnore + private String username; + + @ApiModelProperty("密码") + @JsonIgnore + private String password; + + @ApiModelProperty("是否启用") + private Boolean enabled; + + @ApiModelProperty("是否新注册") + private Boolean register; + + @ApiModelProperty("状态:1.待激活,2已激活,3已注销") + private Integer status; + + @ApiModelProperty("帐号是否未过期") + private Boolean accountNonExpired; + + @ApiModelProperty("是否未锁定") + private Boolean accountNonLocked; + + @ApiModelProperty("凭据是否未过期") + private Boolean credentialsNonExpired; + + @JsonIgnore + @ApiModelProperty("真实姓名") + private String realName; + + @JsonIgnore + @ApiModelProperty("身份证号") + private String cardNo; + + @ApiModelProperty("手机号绑定状态") + private Boolean phoneBinding; + + @ApiModelProperty("是否实名") + private Boolean authenticated ; + + @ApiModelProperty("机构列表") + @JsonIgnore + private List orgs; + + @ApiModelProperty("用户列表") + @JsonIgnore + private List users; + + @ApiModelProperty("是否初始密码") + @Default + private Boolean originPassword = Boolean.TRUE; + + public void setPassword(String password){ + this.password = password; + if (!PasswordUtils.match(password, UserUtils.getDefaultOrgUserPassword())) { + originPassword = Boolean.FALSE; + } + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/login/dto/UserDetailSelectDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/login/dto/UserDetailSelectDTO.java new file mode 100644 index 0000000..a01a7f6 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/login/dto/UserDetailSelectDTO.java @@ -0,0 +1,35 @@ +package com.senmesh.usercenter.user.login.dto; + +import java.io.Serializable; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2021-07-29 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(description = "用户登录待选择列表") +public class UserDetailSelectDTO implements Serializable{ + + /** **/ + private static final long serialVersionUID = 6863140269432883663L; + + @ApiModelProperty("用户id") + private Long id; + + @ApiModelProperty("账号") + private String username; + + @ApiModelProperty("真实姓名") + private String realName; + + @ApiModelProperty("身份证号") + private String cardNo; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/login/dto/UserToken.java b/backend/src/main/java/com/senmesh/usercenter/user/login/dto/UserToken.java new file mode 100644 index 0000000..14ed9ef --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/login/dto/UserToken.java @@ -0,0 +1,17 @@ +package com.senmesh.usercenter.user.login.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@SuperBuilder +public class UserToken extends TempTokenDTO{ + + /** **/ + private static final long serialVersionUID = -6996668235244805301L; + + private final String type = TempTokenDTO.TYPE_USER; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/login/service/UserLoginService.java b/backend/src/main/java/com/senmesh/usercenter/user/login/service/UserLoginService.java new file mode 100644 index 0000000..69cf68d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/login/service/UserLoginService.java @@ -0,0 +1,46 @@ +package com.senmesh.usercenter.user.login.service; + +import com.senmesh.usercenter.user.login.dto.LoginUCardDTO; +import javax.servlet.http.HttpServletRequest; + +import com.senmesh.security.service.IUserSecurityService; +import com.senmesh.usercenter.auth.dto.AuthClientDTO; +import com.senmesh.usercenter.auth.dto.AuthClientQueryDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailLoginDTO; +import com.senmesh.usercenter.user.dto.UserDetailQueryDTO; +import com.senmesh.usercenter.user.login.dto.LoginPhoneDTO; +import com.senmesh.usercenter.user.login.dto.LoginPhoneToken; +import com.senmesh.usercenter.user.login.dto.LoginUserToken; +import com.senmesh.usercenter.user.login.dto.LoginUsernamePasswordDTO; +import com.senmesh.usercenter.user.login.dto.UserDetailDTO; + +/** + * 用户登录 + * @author sr on 2021-06-17 + */ +public interface UserLoginService extends IUserSecurityService { + + UserDetailDTO loadUser(LoginUsernamePasswordDTO loginUsernamePasswordDTO); + + UserDetailDTO loadUser(LoginUCardDTO loginUCardDTO); + + UserDetailDTO loadUser(LoginPhoneDTO loginPhoneDTO); + + UserDetailDTO loadUser(LoginPhoneToken loginPhoneToken); + + UserDetailDTO loadUser(LoginUserToken loginUserToken); + + UserDetailDTO findUserDetailDTO(UserDetailQueryDTO userDetailQueryDto); + + AuthClientDTO findAuthClientDTO(AuthClientQueryDTO authClientQueryDTO); + + UserDetailDTO findUserDetailDTO(AuthDetailLoginDTO authDetailDTO); + + /** + * 如果需激活请求,判断上下文用户激活状态,如果待激活,查询数据库用户状态,直接拦截 + * @return + * @author sr on 2021-06-30 + */ + void checkActive(HttpServletRequest request); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/login/service/impl/UserLoginServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/user/login/service/impl/UserLoginServiceImpl.java new file mode 100644 index 0000000..8645929 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/login/service/impl/UserLoginServiceImpl.java @@ -0,0 +1,419 @@ +package com.senmesh.usercenter.user.login.service.impl; + +import com.senmesh.usercenter.user.login.dto.LoginUCardDTO; +import java.util.List; +import java.util.stream.Collectors; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.exception.ChangeTokenException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.ListUtil; +import com.senmesh.common.util.RandomUtils; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.common.validation.util.ValidateUtils; +import com.senmesh.frame.redis.util.RedisUtils; +import com.senmesh.security.expection.BadLoginException; +import com.senmesh.security.expection.DuplicateOrgException; +import com.senmesh.security.expection.DuplicateUserException; +import com.senmesh.security.temptoken.dto.DuplMobileToken; +import com.senmesh.security.temptoken.dto.DuplUserToken; +import com.senmesh.security.temptoken.dto.PhoneTokenCreateDTO; +import com.senmesh.security.temptoken.dto.UserTokenCreateDTO; +import com.senmesh.security.util.PasswordUtils; +import com.senmesh.security.util.SecurityPropertyUtils; +import com.senmesh.usercenter.auth.dto.AuthClientDTO; +import com.senmesh.usercenter.auth.dto.AuthClientQueryDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailLoginDTO; +import com.senmesh.usercenter.auth.service.AuthClientService; +import com.senmesh.usercenter.dto.IUserDetail; +import com.senmesh.usercenter.user.constant.UserStatusEnum; +import com.senmesh.usercenter.user.constant.UserTypeEnum; +import com.senmesh.usercenter.user.dao.OrgUserMapper; +import com.senmesh.usercenter.user.dao.UserMapper; +import com.senmesh.usercenter.user.dto.PersonUserPhoneCreateDTO; +import com.senmesh.usercenter.user.dto.UserDetailQueryDTO; +import com.senmesh.usercenter.user.dto.UserRegisterCreateDTO; +import com.senmesh.usercenter.user.entity.User; +import com.senmesh.usercenter.user.login.dto.LoginPhoneDTO; +import com.senmesh.usercenter.user.login.dto.LoginPhoneToken; +import com.senmesh.usercenter.user.login.dto.LoginUserToken; +import com.senmesh.usercenter.user.login.dto.LoginUsernamePasswordDTO; +import com.senmesh.usercenter.user.login.dto.OrgDetailDTO; +import com.senmesh.usercenter.user.login.dto.UserDetailDTO; +import com.senmesh.usercenter.user.login.dto.UserDetailSelectDTO; +import com.senmesh.usercenter.user.login.service.UserLoginService; +import com.senmesh.usercenter.user.mapstruct.UserMapMapper; +import com.senmesh.usercenter.user.phone.util.PhoneCodeUtils; +import com.senmesh.usercenter.user.service.UserRegisterService; +import com.senmesh.usercenter.user.service.UserService; + +/** + * 用户登录 + * @author sr on 2021-06-17 + */ +@Service +public class UserLoginServiceImpl implements UserLoginService { + + /** tempToken前缀 **/ + public static final String TEMP_TOKEN_PREFIX = "login:tempToken"; + /** 过期时间-秒 **/ + public static final long TEMP_TOKEN_EXPIRE_TIME = 600; + + @Autowired + private UserMapper userMapper; + + @Autowired + private UserService userService; + + @Autowired + private OrgUserMapper orgUserMapper; + + @Autowired + private AuthClientService authClientService; + + @Autowired + private UserRegisterService userRegisterService; + + + + + @Override + public UserDetailDTO loadUser(LoginUsernamePasswordDTO loginUsernamePasswordDTO) { + // 校验参数 + String errMsg = ValidateUtils.validate(loginUsernamePasswordDTO); + Assert.isTrue(errMsg == null, new BadLoginException(errMsg)); + Integer userType = loginUsernamePasswordDTO.getUserType(); + UserDetailDTO userDetailDTO = findUserDetailDTO( + UserDetailQueryDTO.builder() + .username(loginUsernamePasswordDTO.getUsername()) + .userType(userType) + .build()); + // 校验密码 + boolean correct = + PasswordUtils.match(loginUsernamePasswordDTO.getPassword(), userDetailDTO.getPassword()); + Assert.isTrue(correct, new BadLoginException("账号和密码不匹配")); + if (UserTypeEnum.ORG.getType().equals(userType)) { + checkDuplOrg(userDetailDTO); + } + dealActiveStatus(userDetailDTO); + return userDetailDTO; + } + + @Override + @Transactional + public UserDetailDTO loadUser(LoginPhoneToken loginPhoneToken) { + // 校验参数 + String errMsg = ValidateUtils.validate(loginPhoneToken); + Assert.isTrue(errMsg == null, new BadLoginException(errMsg)); + Long userId = loginPhoneToken.getUserId(); + PhoneTokenCreateDTO phoneTokenCreateDTO = + (PhoneTokenCreateDTO) RedisUtils.get(getTempTokenKey(loginPhoneToken.getTempToken())); + Assert.isTrue(phoneTokenCreateDTO != null, new BadLoginException("无效登录token")); + String phone = phoneTokenCreateDTO.getPhone(); + // 无userId则新增用户 + if (userId == null) { + return userService.createPersonUser(PersonUserPhoneCreateDTO.builder().phone(phone).build()); + } + UserDetailDTO userDetailDTO = findUserDetailDTO( + UserDetailQueryDTO.builder() + .phone(phone) + .userType(UserTypeEnum.PERSON.getType()) + .userId(userId).build()); + Assert.isTrue(userDetailDTO.getUsers() == null, + new BadLoginException(phone + "-个人用户信息异常,请联系管理员")); + // 未绑定手机号,绑定 + dealBinding(userDetailDTO, phone); + dealActiveStatus(userDetailDTO); + // 处理注册信息 + boolean register = userRegister(userDetailDTO.getId(), loginPhoneToken.getRegisterCode(), + loginPhoneToken.getEntrypoint()); + userDetailDTO.setRegister(register); + return userDetailDTO; + } + + @Override + public UserDetailDTO loadUser(LoginUserToken loginUserToken) { + // 校验参数 + String errMsg = ValidateUtils.validate(loginUserToken); + Assert.isTrue(errMsg == null, new BadLoginException(errMsg)); + UserTokenCreateDTO userTokenCreateDTO = + (UserTokenCreateDTO) RedisUtils.get(getTempTokenKey(loginUserToken.getTempToken())); + Assert.isTrue(userTokenCreateDTO != null, new BadLoginException("无效登录token")); + Long userId = userTokenCreateDTO.getUserId(); + UserDetailDTO userDetailDTO = this.findUserDetailDTO( + UserDetailQueryDTO.builder() + .userType(UserTypeEnum.ORG.getType()) + .userId(userId) + .orgId(loginUserToken.getOrgId()).build()); + // 根据token信息找到多个企业用户-异常 + Assert.isTrue(userDetailDTO.getOrgs() == null, + new BadLoginException(userId + "-机构用户信息异常,请联系管理员")); + dealBinding(userDetailDTO, null); + dealActiveStatus(userDetailDTO); + return userDetailDTO; + } + + public UserDetailDTO loadUser(LoginPhoneDTO loginPhoneDTO) { + if (!Boolean.TRUE.equals(loginPhoneDTO.getWithoutCode())) { + boolean match = PhoneCodeUtils.match(loginPhoneDTO); + Assert.isTrue(match, new BadLoginException("验证码错误")); + } + String phone = loginPhoneDTO.getPhone(); + Integer userType = loginPhoneDTO.getUserType(); + // 查询用户 + UserDetailDTO userDetailDTO = findUserDetailDTO( + UserDetailQueryDTO.builder().phone(phone).userType(userType).build()); + if (UserTypeEnum.PERSON.getType().equals(userType)) { + List users = userDetailDTO.getUsers(); + Assert.isTrue(users == null, + new DuplicateUserException(generateMobileToken(userType, phone, users))); + // 处理注册信息 + boolean register = userRegister(userDetailDTO.getId(), loginPhoneDTO.getRegisterCode(), + loginPhoneDTO.getEntrypoint()); + userDetailDTO.setRegister(register); + } else { + checkDuplOrg(userDetailDTO); + } + dealBinding(userDetailDTO, phone); + dealActiveStatus(userDetailDTO); + return userDetailDTO; + } + + private void checkDuplOrg(UserDetailDTO userDetailDTO) { + // 如果存在多机构,生成用户token + List orgs = userDetailDTO.getOrgs(); + Assert.isTrue(orgs == null, + new DuplicateOrgException( + generateUserToken(UserTypeEnum.ORG.getType(), userDetailDTO.getId(), orgs))); + } + + private String getTempTokenKey(String token) { + return String.join(CommonConstants.COLON, UserLoginServiceImpl.TEMP_TOKEN_PREFIX, token); + } + + private DuplUserToken generateUserToken(Integer userType, Long userId, List orgs) { + String tempToken = RandomUtils.generateUUID(); + RedisUtils.add(getTempTokenKey(tempToken), + UserTokenCreateDTO.builder().userType(userType).userId(userId).build(), + TEMP_TOKEN_EXPIRE_TIME); + return DuplUserToken.builder().tempToken(tempToken).orgs(orgs).build(); + } + + private DuplMobileToken generateMobileToken(Integer userType, String phone, + List users) { + String tempToken = RandomUtils.generateUUID(); + RedisUtils.add(getTempTokenKey(tempToken), + PhoneTokenCreateDTO.builder().userType(userType).phone(phone).build(), + TEMP_TOKEN_EXPIRE_TIME); + return DuplMobileToken.builder().tempToken(tempToken).users(users).build(); + } + + @Override + public UserDetailDTO findUserDetailDTO(UserDetailQueryDTO userDetailQueryDto) { + // 查询用户 + List userDetailDTOs = userMapper.listUserDetailDTO(userDetailQueryDto); + Integer userSize = userDetailDTOs.size(); + Integer userType = userDetailQueryDto.getUserType(); + if (userType == null && userSize == 1) { + userType = ListUtil.first(userDetailDTOs).getType(); + } + Assert.notNull(userType, "未知用户"); + UserDetailDTO userDetailDTO = null; + if (UserTypeEnum.ORG.getType().equals(userType) + || UserTypeEnum.API_ORG.getType().equals(userType)) { + // 如果企业用户,只可能查到唯一匹配的用户 + switch (userSize) { + case 0: + throw new BadLoginException("用户不存在!"); + case 1: + userDetailDTO = userDetailDTOs.get(0); + break; + default: + throw new BadLoginException("用户数据异常,请联系管理员!"); + } + Assert.isTrue(userDetailDTO.getEnabled(), new BadLoginException("用户不可用!")); + return loadOrg(userDetailDTO, userDetailQueryDto.getOrgId()); + } + // 个人用户 + switch (userSize) { + case 0: + String phone = userDetailQueryDto.getPhone(); + if (StringUtils.isNotBlank(phone) && userDetailQueryDto.getUserId() == null) { + // 手机号登录可注册用户 & 非手机号选用户登录 + return userService + .createPersonUser(PersonUserPhoneCreateDTO.builder().phone(phone).build()); + } + throw new BadLoginException("用户不存在!"); + case 1: + userDetailDTO = userDetailDTOs.get(0); + return userDetailDTO; + default: + // 转换用户列表信息 + List selectDTOs = userDetailDTOs.stream() + .map(UserMapMapper.INSTANCE::toSelectDTO) + .collect(Collectors.toList()); + return UserDetailDTO.builder().users(selectDTOs).build(); + } + } + + public UserDetailDTO loadOrg(UserDetailDTO userDetailDTO, Long orgId) { + // 查询机构信息 + List orgDTOs = + orgUserMapper.listLoginOrgByUser(userDetailDTO.getId(), + orgId); + Assert.isTrue(!orgDTOs.isEmpty(), new BadLoginException("未找到对应有效机构!")); + if (orgDTOs.size() == 1) { + // 如果只查到一个机构,则直接回写机构属性到用户信息对象 + OrgDetailDTO orgDetailDTO = orgDTOs.get(0); + userDetailDTO.setOrgId(orgDetailDTO.getOrgId()); + userDetailDTO.setOrgName(orgDetailDTO.getOrgName()); + userDetailDTO.setOrgType(orgDetailDTO.getOrgType()); + userDetailDTO.setAdministrator(orgDetailDTO.getAdministrator()); + } else { + userDetailDTO.setOrgs(orgDTOs); + } + return userDetailDTO; + } + + @Override + @Transactional + public UserDetailDTO findUserDetailDTO(AuthDetailLoginDTO authDetailLoginDTO) { + try { + UserDetailDTO userDetailDTO = userService.loadUser(authDetailLoginDTO); + if (UserTypeEnum.ORG.getType().equals(userDetailDTO.getType())) { + loadOrg(userDetailDTO, null); + checkDuplOrg(userDetailDTO); + } else { + // 个人授权信息登录,不注册,判断有无注册信息 + Assert.isTrue(userRegisterService.existRegister(userDetailDTO.getId()), + new BadLoginException("该授权信息未登录注册过")); + } + dealActiveStatus(userDetailDTO); + return userDetailDTO; + } catch (BusinessException e) { + throw new BadLoginException(e.getMessage(), e); + } + } + + private boolean userRegister(Long userId, String registerCode, String entrypoint) { + try { + return userRegisterService.create(UserRegisterCreateDTO.builder().userId(userId) + .registerCode(registerCode) + .entrypoint(entrypoint).build()); + } catch (Exception e) { + throw new BadLoginException(e.getMessage(), e); + } + } + + @Override + public AlitaResult findUserDetailDTOResult(UserDetailQueryDTO userDetailQueryDto) { + try { + UserDetailDTO userDetailDTO = this.findUserDetailDTO(userDetailQueryDto); + Assert.isTrue(userDetailDTO.getOrgs() == null, "获取用户失败,找到多个机构"); + Assert.isTrue(userDetailDTO.getUsers() == null, "获取用户失败,找到多个用户"); + return AlitaResult.success(userDetailDTO); + } catch (Exception e) { + return AlitaResult.bizError(e.getMessage()); + } + } + + @Override + public AuthClientDTO findAuthClientDTO(AuthClientQueryDTO authClientQueryDTO) { + try { + AuthClientDTO authClientDTO = authClientService.findAuthClientDTO(authClientQueryDTO); + Assert.isTrue(authClientDTO != null, new IllegalArgumentException("未找到对应的oauth客户端")); + return authClientDTO; + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + } + + @Override + public void checkActive(HttpServletRequest request) { + try { + IUserDetail userDetail = UserContextHolder.getLoginUser(); + // 判断路径是否是已实名 + boolean authRequest = SecurityPropertyUtils.isAuthed(request); + if (UserTypeEnum.API_ORG.getType().equals(userDetail.getType()) + || !authRequest) { + // api用户 或 已绑定&非实名路径 + return; + } + User user = userMapper.getById(UserContextHolder.getExistLoginUserId()); + Assert.isTrue(user != null, new BadLoginException(AlitaResult.unLogin())); + boolean authed = user.getAuthenticated(); + if (authRequest) { + // 实名路径 + Assert.isTrue(authed, new BadLoginException(AlitaResult.unAuth())); + } + } catch (BadLoginException be) { + throw be; + } catch (ChangeTokenException ce) { + throw new BadLoginException(ce.getResult()); + } catch (Exception e) { + throw new BadLoginException("用户数据异常,请联系管理员", e); + } + } + + /** + * 处理未激活状态 + * @param userDetailDTO + * @author sr on 2022-09-01 + */ + private void dealActiveStatus(UserDetailDTO userDetailDTO) { + if (UserStatusEnum.INIT.getStatus().equals(userDetailDTO.getStatus())) { + userMapper.loginActive(userDetailDTO.getId()); + userDetailDTO.setStatus(UserStatusEnum.ACTIVE.getStatus()); + } + } + + /** + * 处理未绑定 + * @param userDetailDTO + * @param phone + * @author sr on 2022-09-01 + */ + private void dealBinding(UserDetailDTO userDetailDTO, String phone) { + // 未绑定 + if (!userDetailDTO.getPhoneBinding()) { + Long userId = userDetailDTO.getId(); + if (UserTypeEnum.PERSON.getType().equals(userDetailDTO.getType())) { + userService.updatePersonPhoneBinding(userId, phone); + userDetailDTO.setPhoneBinding(Boolean.TRUE); + } else { + userDetailDTO.setPhoneBinding(Boolean.TRUE); + userMapper.bindingPhone(userId, phone); + } + } + } + + @Override + public UserDetailDTO loadUser(LoginUCardDTO loginUCardDTO) { + String cardNo = loginUCardDTO.getCardNo(); + String realName = loginUCardDTO.getRealName(); + // 查询用户 + List userDetailDTOs = userMapper.listUserDetailDTO(UserDetailQueryDTO.builder() + .cardNo(cardNo).userType(UserTypeEnum.PERSON.getType()).build()); + Assert.isTrue(userDetailDTOs.size() < 2, new BadLoginException("用户数据异常,请联系管理员!")); + if (userDetailDTOs.size() == 1) { + UserDetailDTO userDetailDTO = userDetailDTOs.get(0); + if (userDetailDTO.getAuthenticated()) { + Assert.isTrue(realName.equals(userDetailDTO.getRealName()), + new BadLoginException("用户实名信息错误")); + return userDetailDTO; + } + } + // 未实名,调第三方实名校验 + throw new BadLoginException("未实名"); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/mapper/OrgUserMapper.xml b/backend/src/main/java/com/senmesh/usercenter/user/mapper/OrgUserMapper.xml new file mode 100644 index 0000000..0468602 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/mapper/OrgUserMapper.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + diff --git a/backend/src/main/java/com/senmesh/usercenter/user/mapper/UserAuthMapper.xml b/backend/src/main/java/com/senmesh/usercenter/user/mapper/UserAuthMapper.xml new file mode 100644 index 0000000..894e02f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/mapper/UserAuthMapper.xml @@ -0,0 +1,41 @@ + + + + + + + update uc_user_auth + set + user_id = #{retainUserId}, + update_time = now() + where + user_id = #{deletedUserId} + and deleted = FALSE + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/mapper/UserCancelMapper.xml b/backend/src/main/java/com/senmesh/usercenter/user/mapper/UserCancelMapper.xml new file mode 100644 index 0000000..d9dd630 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/mapper/UserCancelMapper.xml @@ -0,0 +1,50 @@ + + + + + + + + diff --git a/backend/src/main/java/com/senmesh/usercenter/user/mapper/UserConfigMapper.xml b/backend/src/main/java/com/senmesh/usercenter/user/mapper/UserConfigMapper.xml new file mode 100644 index 0000000..b988659 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/mapper/UserConfigMapper.xml @@ -0,0 +1,22 @@ + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/mapper/UserMapper.xml b/backend/src/main/java/com/senmesh/usercenter/user/mapper/UserMapper.xml new file mode 100644 index 0000000..3fdbb3f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/mapper/UserMapper.xml @@ -0,0 +1,652 @@ + + + + + update + uc_user + set status = 3, + update_by = #{operateUserId}, + update_time = now() + where id = #{userId} + and deleted = FALSE + and status != 3 + + + + + + + update + uc_user + set + username = #{username}, + password = #{encodedPassword}, + update_by = #{operateUserId}, + update_time = now() + where + id = #{operateUserId} + and deleted = FALSE and status != 3 + + + + + + + + update uc_user + set + phone = null, + update_by = #{userId}, + update_time = now() + where + id != #{userId} + and deleted = FALSE and status != 3 + and type = 2 + and phone = #{phone} + + + + + update uc_user + set + real_name = #{param.realName}, + card_no = #{param.cardNo}, + birthday = SUBSTR(#{param.cardNo},7,8), + gender = CASE WHEN SUBSTR(#{param.cardNo},17,1)%2 =1 THEN 1 ELSE 2 END, + authenticated = TRUE, + update_time = now() + where + type = 2 + + and card_no = #{param.cardNo} + + and deleted = FALSE and status != 3 + and authenticated = FALSE + + and id = #{param.userId} + + + + + update uc_user + set + phone_binding = TRUE, + + phone = #{phone}, + + update_time = now() + where + id = #{userId} + + and length(phone) = 11 + + and deleted = FALSE and status != 3 + + + + + + + + + update uc_user + set phone = (select phone from uc_user where id = #{phoneUserId}), + phone_binding = TRUE, + update_time = now() + where + id = #{retainUserId} + and deleted = FALSE and status != 3 + and phone_binding = FALSE + + + + + + + + + update uc_user + + + username = #{username}, + + + nickname = #{nickname}, + + + enabled = #{enabled}, + + + email = #{email}, + + update_by = #{updateBy}, + update_time = now() + + where id = #{id} + + + + update uc_user set password = #{password}, update_by = #{operateUserId}, update_time = now() where id = #{userId} + + + + + + + + + update uc_user + set status = 2, + update_time = now() + where id = #{userId} + and deleted = FALSE + and status != 3 + + + + update uc_user + set status = 3, + enabled = FALSE, + update_by = #{operateUserId}, + update_time = now() + where id = #{userId} + and deleted = FALSE + and status != 3 + + + + + + diff --git a/backend/src/main/java/com/senmesh/usercenter/user/mapper/UserPostalInfoMapper.xml b/backend/src/main/java/com/senmesh/usercenter/user/mapper/UserPostalInfoMapper.xml new file mode 100644 index 0000000..5b2921e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/mapper/UserPostalInfoMapper.xml @@ -0,0 +1,33 @@ + + + + + update uc_user_postal_info set defaulted = FALSE where create_by = #{userId} and id != #{id} and deleted = FALSE + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/mapper/UserRegisterMapper.xml b/backend/src/main/java/com/senmesh/usercenter/user/mapper/UserRegisterMapper.xml new file mode 100644 index 0000000..c6c68ac --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/mapper/UserRegisterMapper.xml @@ -0,0 +1,44 @@ + + + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/senmesh/usercenter/user/mapstruct/OrgUserMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/user/mapstruct/OrgUserMapMapper.java new file mode 100644 index 0000000..243b28e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/mapstruct/OrgUserMapMapper.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.user.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.user.dto.OrgUserDTO; +import com.senmesh.usercenter.user.dto.OrgUserOperateDTO; +import com.senmesh.usercenter.user.entity.OrgUser; + +/** + * @author sr on 2021-05-24 + */ +@Mapper +public interface OrgUserMapMapper { + + OrgUserMapMapper INSTANCE = + Mappers.getMapper(OrgUserMapMapper.class); + + /** + * dto to entity + * + * @param orgUserDto + * @return + * @author sr on 2021-05-24 + */ + OrgUser toEntity( + OrgUserDTO orgUserDto); + + + /** + * @param orgUserOperateDTO + * @return + * @author sr on 2021-05-24 + */ + OrgUser toEntity(OrgUserOperateDTO orgUserOperateDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/mapstruct/UserAuthMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/user/mapstruct/UserAuthMapMapper.java new file mode 100644 index 0000000..938a962 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/mapstruct/UserAuthMapMapper.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.user.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.user.dto.UserAuthDTO; +import com.senmesh.usercenter.user.entity.UserAuth; +import com.senmesh.usercenter.user.dto.UserAuthOperateDTO; + +/** + * @author sr on 2021-05-24 + */ +@Mapper +public interface UserAuthMapMapper { + + UserAuthMapMapper INSTANCE = + Mappers.getMapper(UserAuthMapMapper.class); + + /** + * dto to entity + * + * @param userAuthDto + * @return + * @author sr on 2021-05-24 + */ + UserAuth toEntity( + UserAuthDTO userAuthDto); + + + /** + * @param userAuthOperateDTO + * @return + * @author sr on 2021-05-24 + */ + UserAuth toEntity(UserAuthOperateDTO userAuthOperateDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/mapstruct/UserConfigMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/user/mapstruct/UserConfigMapMapper.java new file mode 100644 index 0000000..869830d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/mapstruct/UserConfigMapMapper.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.user.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.user.dto.UserConfigDTO; +import com.senmesh.usercenter.user.entity.UserConfig; +import com.senmesh.usercenter.user.dto.UserConfigOperateDTO; + +/** + * @author sr on 2021-08-12 + */ +@Mapper +public interface UserConfigMapMapper { + + UserConfigMapMapper INSTANCE = + Mappers.getMapper(UserConfigMapMapper.class); + + /** + * dto to entity + * + * @param userConfigDto + * @return + * @author sr on 2021-08-12 + */ + UserConfig toEntity( + UserConfigDTO userConfigDto); + + + /** + * @param userConfigOperateDTO + * @return + * @author sr on 2021-08-12 + */ + UserConfig toEntity(UserConfigOperateDTO userConfigOperateDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/mapstruct/UserExtensionMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/user/mapstruct/UserExtensionMapMapper.java new file mode 100644 index 0000000..ea62c86 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/mapstruct/UserExtensionMapMapper.java @@ -0,0 +1,38 @@ +package com.senmesh.usercenter.user.mapstruct; + +import com.senmesh.usercenter.user.dto.UserExtensionDTO; +import com.senmesh.usercenter.user.dto.UserExtensionOperateDTO; +import com.senmesh.usercenter.user.entity.UserExtension; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * @author czy on 2021-06-15 + */ +@Mapper +public interface UserExtensionMapMapper { + + UserExtensionMapMapper INSTANCE = + Mappers.getMapper(UserExtensionMapMapper.class); + + /** + * dto to entity + * @author czy on 2021-06-15 + */ + UserExtension toEntity( + UserExtensionDTO userExtensionDTO); + + + /** + * OperateDTO to entity + * @author czy on 2021-06-15 + */ + UserExtension toEntity(UserExtensionOperateDTO userExtensionOperateDTO); + + /** + * entity to dto + * @author czy on 2021-06-15 + */ + UserExtensionDTO toDto(UserExtension userExtension); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/mapstruct/UserMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/user/mapstruct/UserMapMapper.java new file mode 100644 index 0000000..d5445ad --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/mapstruct/UserMapMapper.java @@ -0,0 +1,99 @@ +package com.senmesh.usercenter.user.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.auth.dto.AuthDetailLoginDTO; +import com.senmesh.usercenter.user.dto.AuthenticateUserDTO; +import com.senmesh.usercenter.user.dto.OrgUserCreateDTO; +import com.senmesh.usercenter.user.dto.PersonUserCardCreateDTO; +import com.senmesh.usercenter.user.dto.PersonUserCardCreateResultDTO; +import com.senmesh.usercenter.user.dto.SuperRealNameTwoAuthDTO; +import com.senmesh.usercenter.user.dto.UserDTO; +import com.senmesh.usercenter.user.dto.UserOperateDTO; +import com.senmesh.usercenter.user.entity.User; +import com.senmesh.usercenter.user.login.dto.UserDetailDTO; +import com.senmesh.usercenter.user.login.dto.UserDetailSelectDTO; + +/** + * @author sr on 2021-05-24 + */ +@Mapper +public interface UserMapMapper { + + UserMapMapper INSTANCE = + Mappers.getMapper(UserMapMapper.class); + + /** + * dto to entity + * + * @author sr on 2021-05-24 + */ + User toEntity( + UserDTO userDto); + + + /** + * @author sr on 2021-05-24 + */ + User toEntity(UserOperateDTO userOperateDTO); + + /** + * entity to dto + * + * @author czy on 2021-06-10 + */ + UserDTO toDto(User user); + + /** + * 创建企业用户 + * @param companyUserCreateDTO + * @return + * @author sr on 2021-06-10 + */ + @Mappings( + value = { + @Mapping(target = "type", + expression = "java(com.senmesh.usercenter.user.constant.UserTypeEnum.ORG.getType())"), + @Mapping(target = "phoneBinding", + constant = "false"), + }) + User toCreateCompanyUser(OrgUserCreateDTO companyUserCreateDTO); + + /** + * 创建个人用户 + * @param personUserCardCreateDTO + * @return + * @author sr on 2021-06-10 + */ + @Mappings( + value = { + @Mapping(target = "type", + expression = "java(com.senmesh.usercenter.user.constant.UserTypeEnum.PERSON.getType())"), + @Mapping(target = "phoneBinding", + constant = "false"), + }) + User toCreatePersonUser(PersonUserCardCreateDTO personUserCardCreateDTO); + + PersonUserCardCreateResultDTO toResultDTO(PersonUserCardCreateDTO personUserCardCreateDTO); + PersonUserCardCreateResultDTO toResultDTO(UserDTO userDTO); + + UserDetailDTO toUserDetailDTO(User user); + UserDetailDTO toUserDetailDTO(UserDTO userDTO); + + @Mappings( + value = { + @Mapping(target = "type", source = "authDetailDTO.userType"), + @Mapping(target = "id", ignore = true), + @Mapping(target = "phoneBinding", + constant = "false"), + }) + User toCreate(AuthDetailLoginDTO authDetailDTO); + + UserDetailSelectDTO toSelectDTO(UserDetailDTO userDetailDTO); + + AuthenticateUserDTO to(SuperRealNameTwoAuthDTO authDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/mapstruct/UserPostalInfoMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/user/mapstruct/UserPostalInfoMapMapper.java new file mode 100644 index 0000000..a47660e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/mapstruct/UserPostalInfoMapMapper.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.user.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.user.dto.UserPostalInfoDTO; +import com.senmesh.usercenter.user.entity.UserPostalInfo; +import com.senmesh.usercenter.user.dto.UserPostalInfoOperateDTO; + +/** + * @author fzp on 2022-01-19 + */ +@Mapper +public interface UserPostalInfoMapMapper { + + UserPostalInfoMapMapper INSTANCE = + Mappers.getMapper(UserPostalInfoMapMapper.class); + + /** + * dto to entity + * + * @param userPostalInfoDto + * @return + * @author fzp on 2022-01-19 + */ + UserPostalInfo toEntity( + UserPostalInfoDTO userPostalInfoDto); + + + /** + * @param userPostalInfoOperateDTO + * @return + * @author fzp on 2022-01-19 + */ + UserPostalInfo toEntity(UserPostalInfoOperateDTO userPostalInfoOperateDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/mapstruct/UserRegisterMapMapper.java b/backend/src/main/java/com/senmesh/usercenter/user/mapstruct/UserRegisterMapMapper.java new file mode 100644 index 0000000..f25d542 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/mapstruct/UserRegisterMapMapper.java @@ -0,0 +1,57 @@ +package com.senmesh.usercenter.user.mapstruct; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +import com.senmesh.usercenter.user.dto.UserRegisterCodeInfoDTO; +import com.senmesh.usercenter.user.dto.UserDetailQueryDTO; +import com.senmesh.usercenter.user.dto.UserRegisterCodeDTO; +import com.senmesh.usercenter.user.dto.UserRegisterDTO; +import com.senmesh.usercenter.user.entity.UserRegister; +import com.senmesh.usercenter.user.dto.UserRegisterOperateDTO; + +/** + * @author sr on 2021-11-16 + */ +@Mapper +public interface UserRegisterMapMapper { + + UserRegisterMapMapper INSTANCE = + Mappers.getMapper(UserRegisterMapMapper.class); + + /** + * dto to entity + * + * @param userRegisterDto + * @return + * @author sr on 2021-11-16 + */ + UserRegister toEntity( + UserRegisterDTO userRegisterDto); + + + /** + * @param userRegisterOperateDTO + * @return + * @author sr on 2021-11-16 + */ + UserRegister toEntity(UserRegisterOperateDTO userRegisterOperateDTO); + + @Mappings({ + @Mapping(target = "userType", source = "inviterType"), + @Mapping(target = "userId", source = "inviterId"), + @Mapping(target = "orgId", source = "inviterOrgId"), + }) + UserDetailQueryDTO toDto(UserRegisterCodeInfoDTO dto); + + UserRegisterCodeInfoDTO toDto(UserRegisterCodeDTO userRegisterCodeDTO); + + UserRegisterDTO toDto(UserRegister userRegister); + + UserRegister toEntity(UserRegisterCodeInfoDTO dto); + + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/check/AbstractRedisPhoneCodeChecker.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/check/AbstractRedisPhoneCodeChecker.java new file mode 100644 index 0000000..d68ad14 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/check/AbstractRedisPhoneCodeChecker.java @@ -0,0 +1,20 @@ +package com.senmesh.usercenter.user.phone.check; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.util.Assert; + +/** + * 借用redis校验手机号验证码校验结果的校验器 + * @author sr on 2021-06-16 + */ +public abstract class AbstractRedisPhoneCodeChecker implements IPhoneCodeChecker { + + public static final String REDIS_PREFIX = "phone:code:check"; + + public String getRedisKey(String smsProviderType, String phone) { + Assert.notBlank(smsProviderType, "验证码提供者类型不能为空"); + return String.join(CommonConstants.COLON, REDIS_PREFIX, getType(), smsProviderType, + phone); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/check/CaptchaPhoneCodeChecker.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/check/CaptchaPhoneCodeChecker.java new file mode 100644 index 0000000..778f705 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/check/CaptchaPhoneCodeChecker.java @@ -0,0 +1,42 @@ +package com.senmesh.usercenter.user.phone.check; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.sdk.captcha.service.impl.LoginCaptchaAppProvider; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeCheckerEnum; +import com.senmesh.usercenter.user.phone.dto.CaptchaPhoneCodeSmsDTO; +import com.senmesh.usercenter.user.phone.dto.IPhoneCodeSmsDTO; + +/** + * 防水墙校验器(注意最先添加进提供者) + * @author sr on 2021-06-17 + */ +@Component +public class CaptchaPhoneCodeChecker implements IPhoneCodeChecker { + + /** TODO 当无防水墙提供者,类注入问题 **/ + @Autowired(required = false) + private LoginCaptchaAppProvider loginCaptchaAppProvider; + + @Override + public String getType() { + return PhoneCodeCheckerEnum.CAPTCHA.getType(); + } + + @Override + public boolean supports(Class clazz) { + return CaptchaPhoneCodeSmsDTO.class.isAssignableFrom(clazz); + } + + @Override + public void check(IPhoneCodeSmsDTO phoneCodeSmsDTO) { + CaptchaPhoneCodeSmsDTO captchaDTO = ((CaptchaPhoneCodeSmsDTO) phoneCodeSmsDTO); + AlitaResult captchaResult = + loginCaptchaAppProvider.verify(captchaDTO.getTicket(), captchaDTO.getRandstr()); + Assert.isTrue(captchaResult.getSuccess() && captchaResult.getData(), "防水墙验证失败"); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/check/ChangePhoneChecker.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/check/ChangePhoneChecker.java new file mode 100644 index 0000000..273e6ff --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/check/ChangePhoneChecker.java @@ -0,0 +1,59 @@ +package com.senmesh.usercenter.user.phone.check; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.user.constant.UserTypeEnum; +import com.senmesh.usercenter.user.dto.IUserPhoneCodeSms; +import com.senmesh.usercenter.user.dto.UserDTO; +import com.senmesh.usercenter.user.dto.UserQueryDTO; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeCheckerEnum; +import com.senmesh.usercenter.user.phone.dto.IPhoneCodeSmsDTO; +import com.senmesh.usercenter.user.service.UserService; + + +/** + * 换绑手机 + * @author sr on 2021-09-02 + */ +@Component +public class ChangePhoneChecker implements IPhoneCodeChecker { + + @Autowired + private UserService userService; + + @Override + public String getType() { + return PhoneCodeCheckerEnum.CHANGE_PHONE.getType(); + } + + @Override + public boolean supports(Class clazz) { + return IUserPhoneCodeSms.class.isAssignableFrom(clazz); + } + + @Override + public void check(IPhoneCodeSmsDTO phoneCodeSmsDTO) { + // 未被其它相同用户类型的用户绑定 + UserContextHolder.getExistLoginUserId(); + Integer userType = ((IUserPhoneCodeSms) phoneCodeSmsDTO).getUserType(); + UserQueryDTO userQueryDTO = UserQueryDTO.builder() + .phone(phoneCodeSmsDTO.getPhone()).type(userType).build(); + if (UserTypeEnum.PERSON.getType().equals(userType)) { + // 个人可能存在未绑定的多条记录 + userQueryDTO.setPhoneBinding(Boolean.TRUE); + } else if (UserTypeEnum.ORG.getType().equals(userType)) { + // 机构用户需要绑定态才能换绑 + Assert.isTrue(UserContextHolder.getExistLoginUser().getPhoneBinding(), "请先绑定手机号"); + } else { + throw new BusinessException("当前用户类型不支持换绑手机"); + } + UserDTO userDTO = userService.findUserDTO(userQueryDTO); + + Assert.isNull(userDTO, "该手机号已被其他用户绑定"); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/check/CountRedisPhoneCodeChecker.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/check/CountRedisPhoneCodeChecker.java new file mode 100644 index 0000000..1c14177 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/check/CountRedisPhoneCodeChecker.java @@ -0,0 +1,61 @@ +package com.senmesh.usercenter.user.phone.check; + +import java.time.LocalDate; + +import org.springframework.stereotype.Component; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.util.ExceptionUtils; +import com.senmesh.frame.redis.util.RedisUtils; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeCheckerEnum; +import com.senmesh.usercenter.user.phone.dto.IPhoneCodeSmsDTO; + +/** + * 一天内获取验证码次数 + * @author sr on 2021-06-16 + */ +@Component +public class CountRedisPhoneCodeChecker extends AbstractRedisPhoneCodeChecker { + + /** 验证码登录次数过期时间-秒 **/ + public static final long COUNT_EXPIRE_TIME = 60 * 60 * 24; + + /** 默认每天获取验证码上限 **/ + public static final long DEFAULT_COUNT = 10; + + private Long countLimit = DEFAULT_COUNT; + + public CountRedisPhoneCodeChecker() {} + + public CountRedisPhoneCodeChecker(Long countLimit) { + this.countLimit = countLimit; + } + + @Override + public String getType() { + return PhoneCodeCheckerEnum.COUNT.getType(); + } + + @Override + public String getRedisKey(String smsProviderType, String phone) { + return String.join(CommonConstants.COLON, super.getRedisKey(smsProviderType, phone), + String.valueOf(LocalDate.now().getDayOfYear())); + } + + + @Override + public void check(IPhoneCodeSmsDTO phoneCodeSmsDTO) { + // phone:sms:count:dayOfYear:phone 有效期一天 + Long sendCount = RedisUtils + .increment(getRedisKey(phoneCodeSmsDTO.getProviderType(), phoneCodeSmsDTO.getPhone()), COUNT_EXPIRE_TIME); + ExceptionUtils.throwBusinessException(sendCount > countLimit, + "验证码发送超限,请明天再操作"); + } + + @Override + public void revertCheck(IPhoneCodeSmsDTO phoneCodeSmsDTO) { + RedisUtils.decrement(getRedisKey(phoneCodeSmsDTO.getProviderType(), phoneCodeSmsDTO.getPhone())); + } + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/check/HasLoginChecker.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/check/HasLoginChecker.java new file mode 100644 index 0000000..c91a090 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/check/HasLoginChecker.java @@ -0,0 +1,29 @@ +package com.senmesh.usercenter.user.phone.check; + +import org.springframework.stereotype.Component; + +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeCheckerEnum; +import com.senmesh.usercenter.user.phone.dto.IPhoneCodeSmsDTO; + + +/** + * 已登录 + * @author sr on 2021-09-03 + */ +@Component +public class HasLoginChecker implements IPhoneCodeChecker { + + + @Override + public String getType() { + return PhoneCodeCheckerEnum.HAS_LOGIN.getType(); + } + + + @Override + public void check(IPhoneCodeSmsDTO phoneCodeSmsDTO) { + UserContextHolder.getExistLoginUser(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/check/IPhoneCodeChecker.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/check/IPhoneCodeChecker.java new file mode 100644 index 0000000..098793d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/check/IPhoneCodeChecker.java @@ -0,0 +1,39 @@ +package com.senmesh.usercenter.user.phone.check; + +import com.senmesh.usercenter.user.phone.dto.IPhoneCodeSmsDTO; + +/** + * 手机号验证码校验器 + * @author sr on 2021-06-16 + */ +public interface IPhoneCodeChecker { + + /** + * 类型 + * @return + * @author sr on 2021-06-16 + */ + String getType(); + + default boolean supports(Class clazz) { + return true; + } + + /** + * 校验 + * @param smsProviderType + * @param iIPhoneCodeSmsDTO + * @author sr on 2021-06-16 + */ + void check(IPhoneCodeSmsDTO phoneCodeSmsDTO); + + /** + * 回退校验(如果校验更新为处理成功的数据,其他校验器失败,未触发短信发送,则回退处理成功数据) + * @param smsProviderType + * @param phoneCodeSmsDTO + * @author sr on 2021-06-16 + */ + default void revertCheck(IPhoneCodeSmsDTO phoneCodeSmsDTO) { + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/check/LastRedisPhoneCodeChecker.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/check/LastRedisPhoneCodeChecker.java new file mode 100644 index 0000000..9d8c785 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/check/LastRedisPhoneCodeChecker.java @@ -0,0 +1,39 @@ +package com.senmesh.usercenter.user.phone.check; + +import org.springframework.stereotype.Component; + +import com.senmesh.common.exception.util.ExceptionUtils; +import com.senmesh.frame.redis.util.RedisUtils; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeCheckerEnum; +import com.senmesh.usercenter.user.phone.dto.IPhoneCodeSmsDTO; + +/** + * 校验上一次获取验证码时间间隔是否超过一分钟 + * @author sr on 2021-06-16 + */ +@Component +public class LastRedisPhoneCodeChecker extends AbstractRedisPhoneCodeChecker { + + /** 发送验证码时间间隔-秒 **/ + public static final long LAST_EXPIRE_TIME = 60; + + @Override + public String getType() { + return PhoneCodeCheckerEnum.LAST.getType(); + } + + @Override + public void check(IPhoneCodeSmsDTO phoneCodeSmsDTO) { + Long num = RedisUtils.increment( + getRedisKey(phoneCodeSmsDTO.getProviderType(), phoneCodeSmsDTO.getPhone()), + LAST_EXPIRE_TIME); + ExceptionUtils.throwBusinessException(num > 1L, "操作过于频繁,请60秒后重试"); + } + + @Override + public void revertCheck(IPhoneCodeSmsDTO phoneCodeSmsDTO) { + RedisUtils + .decrement(getRedisKey(phoneCodeSmsDTO.getProviderType(), phoneCodeSmsDTO.getPhone())); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/check/ResetPwdChecker.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/check/ResetPwdChecker.java new file mode 100644 index 0000000..5d145df --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/check/ResetPwdChecker.java @@ -0,0 +1,52 @@ +package com.senmesh.usercenter.user.phone.check; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.user.dto.IUserPhoneCodeSms; +import com.senmesh.usercenter.user.dto.UserDTO; +import com.senmesh.usercenter.user.dto.UserQueryDTO; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeCheckerEnum; +import com.senmesh.usercenter.user.phone.dto.IPhoneCodeSmsDTO; +import com.senmesh.usercenter.user.service.UserService; + + +/** + * 重置密码 + * @author sr on 2021-09-02 + */ +@Component +public class ResetPwdChecker implements IPhoneCodeChecker { + + @Autowired + private UserService userService; + + @Override + public String getType() { + return PhoneCodeCheckerEnum.RESET_PWD.getType(); + } + + @Override + public boolean supports(Class clazz) { + return IUserPhoneCodeSms.class.isAssignableFrom(clazz); + } + + @Override + public void check(IPhoneCodeSmsDTO phoneCodeSmsDTO) { + Integer userType = ((IUserPhoneCodeSms) phoneCodeSmsDTO).getUserType(); + String phone = phoneCodeSmsDTO.getPhone(); + Long userId = UserContextHolder.getLoginUserId(); + if (userId == null) { + // 匿名访问 + Assert.notNull(userType, "无法获取验证码,用户类型不能为空"); + UserDTO userDTO = userService.findUserDTO(UserQueryDTO.builder().type(userType).phone(phone).build()); + Assert.notNull(userDTO, "该手机号用户不存在"); + } else { + UserDTO userDTO = userService.findUserDTO(UserQueryDTO.builder().id(userId).build()); + Assert.isTrue(phone.equals(userDTO.getPhone()), "手机号与当前用户手机号不匹配"); + } + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/constant/PhoneCodeCheckerEnum.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/constant/PhoneCodeCheckerEnum.java new file mode 100644 index 0000000..e574218 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/constant/PhoneCodeCheckerEnum.java @@ -0,0 +1,33 @@ +package com.senmesh.usercenter.user.phone.constant; + +/** + * 校验器枚举 + * @author sr on 2021-09-01 + */ +public enum PhoneCodeCheckerEnum { + + /** 防水墙 **/ + CAPTCHA("captcha"), + /** 一天内获取验证码次数 **/ + COUNT("count"), + /** 校验上一次获取验证码时间间隔 **/ + LAST("last"), + /** 换绑手机 **/ + CHANGE_PHONE("changphone"), + /** 重置密码 **/ + RESET_PWD("resetpwd"), + /** 已登录 **/ + HAS_LOGIN("haslogin"), + ; + + private String type; + + PhoneCodeCheckerEnum(String type) { + this.type = type; + } + + public String getType() { + return type; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/constant/PhoneCodeProviderEnum.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/constant/PhoneCodeProviderEnum.java new file mode 100644 index 0000000..3b3df44 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/constant/PhoneCodeProviderEnum.java @@ -0,0 +1,81 @@ +package com.senmesh.usercenter.user.phone.constant; + +import java.util.Locale; +import java.util.Map; + +import com.google.common.collect.Maps; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.usercenter.user.constant.UserTypeEnum; + +/** + * 手机验证码提供者枚举 + * @author sr on 2021-09-01 + */ +public enum PhoneCodeProviderEnum { + + /** 机构用户登录 **/ + ORG_LOGIN(UserTypeEnum.ORG, UserPhoneCodeOperateEnum.LOGIN), + /** 个人用户登录 **/ + PERSON_LOGIN(UserTypeEnum.PERSON, UserPhoneCodeOperateEnum.LOGIN), + /** 个人用户绑定手机号 **/ + PERSON_BIND_PHONE("personbindphone"), + /** 机构用户重置密码 **/ + ORG_RESET_PWD(UserTypeEnum.ORG, UserPhoneCodeOperateEnum.RESET_PWD), + /** 个人用户重置密码 **/ + PERSON_RESET_PWD(UserTypeEnum.PERSON, UserPhoneCodeOperateEnum.RESET_PWD), + /** 机构用户重置安全码 **/ + ORG_RESET_SECURITY_CODE(UserTypeEnum.ORG, UserPhoneCodeOperateEnum.RESET_SECURITY_CODE), + /** 个人用户重置安全码 **/ + PERSON_RESET_SECURITY_CODE(UserTypeEnum.PERSON, UserPhoneCodeOperateEnum.RESET_SECURITY_CODE), + /** 机构用户换绑手机 **/ + ORG_CHANGE_PHONE(UserTypeEnum.ORG, UserPhoneCodeOperateEnum.CHANGE_PHONE), + /** 个人用户换绑手机 **/ + PERSON_CHANGE_PHONE(UserTypeEnum.PERSON, UserPhoneCodeOperateEnum.CHANGE_PHONE), + /** 重置支付密码 **/ + RESET_PAY_PWD("resetpaypwd"), + /** 机构入驻 **/ + ORG_APPLY("orgapply"), + /** 机构入驻查询 **/ + GET_ORG_APPLY("getorgapply"), + /** 个人用户注销 **/ + USER_CANCEL(UserTypeEnum.PERSON,UserPhoneCodeOperateEnum.USER_CANCEL), + ; + + private static final Map providerMap; + + static { + PhoneCodeProviderEnum[] phoneCodeProviderEnums = PhoneCodeProviderEnum.values(); + providerMap = Maps.newHashMapWithExpectedSize(phoneCodeProviderEnums.length); + for (PhoneCodeProviderEnum phoneCodeProviderEnum : phoneCodeProviderEnums) { + providerMap.put(phoneCodeProviderEnum.getType(), phoneCodeProviderEnum); + } + } + + private String type; + + PhoneCodeProviderEnum(UserTypeEnum userTypeEnum, + UserPhoneCodeOperateEnum userPhoneCodeOperateEnum) { + type = userTypeEnum.name().toLowerCase(Locale.CHINESE) + userPhoneCodeOperateEnum.getOperate(); + } + + PhoneCodeProviderEnum(String type) { + this.type = type; + } + + public String getType() { + return type; + } + + public static void check(String type) { + Assert.isTrue(providerMap.containsKey(type), "未找到对应短信验证码的提供者"); + } + + public static String getType(UserTypeEnum userTypeEnum, String operate) { + PhoneCodeProviderEnum phoneCodeProviderEnum = + providerMap.get(userTypeEnum.name().toLowerCase(Locale.CHINESE) + operate); + Assert.notNull(phoneCodeProviderEnum, "未找到对应验证码提供者"); + return phoneCodeProviderEnum.getType(); + } + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/constant/UserPhoneCodeOperateEnum.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/constant/UserPhoneCodeOperateEnum.java new file mode 100644 index 0000000..3450151 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/constant/UserPhoneCodeOperateEnum.java @@ -0,0 +1,32 @@ +package com.senmesh.usercenter.user.phone.constant; + +/** + * 手机验证码提供者枚举 + * @author sr on 2021-09-01 + */ +public enum UserPhoneCodeOperateEnum { + + /** 登录 **/ + LOGIN("login"), + /** 重置密码 **/ + RESET_PWD("resetpwd"), + /** 绑定手机 **/ + BIND_PHONE("bindphone"), + /** 重置安全码 **/ + RESET_SECURITY_CODE("resetsecuritycode"), + /** 换绑手机 **/ + CHANGE_PHONE("changephone"), + /** 注销 **/ + USER_CANCEL("usercancel"), + ; + + private String operate; + + UserPhoneCodeOperateEnum(String operate) { + this.operate = operate; + } + + public String getOperate() { + return operate; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/CaptchaPhoneCodeSmsDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/CaptchaPhoneCodeSmsDTO.java new file mode 100644 index 0000000..840a5d1 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/CaptchaPhoneCodeSmsDTO.java @@ -0,0 +1,32 @@ +package com.senmesh.usercenter.user.phone.dto; + +import javax.validation.constraints.NotBlank; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-06-17 + */ +@ApiModel("防水墙-手机发送短信验证码") +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class CaptchaPhoneCodeSmsDTO extends PhoneCodeSmsDTO{ + + /** **/ + private static final long serialVersionUID = -5842216049872318987L; + + @ApiModelProperty("防水墙验证票据") + @NotBlank(message = "防水墙验证票据不能为空") + private String ticket; + @ApiModelProperty("防水墙随机字符串") + @NotBlank(message = "防水墙随机字符串不能为空") + private String randstr; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/ICode.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/ICode.java new file mode 100644 index 0000000..609f404 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/ICode.java @@ -0,0 +1,14 @@ +package com.senmesh.usercenter.user.phone.dto; + +/** + * 验证码属性 + * @author sr on 2021-09-02 + */ +public interface ICode { + /** + * 获取验证码 + * @return + * @author sr on 2021-09-02 + */ + String getCode(); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/IPhoneCodeDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/IPhoneCodeDTO.java new file mode 100644 index 0000000..8b58a11 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/IPhoneCodeDTO.java @@ -0,0 +1,9 @@ +package com.senmesh.usercenter.user.phone.dto; + +/** + * 手机号验证码-验证 + * @author sr on 2021-06-17 + */ +public interface IPhoneCodeDTO extends IPhoneCodeSmsDTO, ICode{ + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/IPhoneCodeSmsDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/IPhoneCodeSmsDTO.java new file mode 100644 index 0000000..8ad6a47 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/IPhoneCodeSmsDTO.java @@ -0,0 +1,28 @@ +package com.senmesh.usercenter.user.phone.dto; + +import java.io.Serializable; + +import com.senmesh.usercenter.user.phone.constant.PhoneCodeProviderEnum; + +/** + * 手机号验证码-发送 + * @author sr on 2021-06-17 + */ +public interface IPhoneCodeSmsDTO extends Serializable{ + + /** + * 手机号 + * @return + * @author sr on 2021-09-01 + */ + String getPhone(); + + /** + * 手机验证码提供者 + * {@link PhoneCodeProviderEnum} + * @return + * @author sr on 2021-09-01 + */ + String getProviderType(); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/PhoneCodeDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/PhoneCodeDTO.java new file mode 100644 index 0000000..747b57b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/PhoneCodeDTO.java @@ -0,0 +1,39 @@ +package com.senmesh.usercenter.user.phone.dto; + +import javax.validation.constraints.NotBlank; + +import com.senmesh.common.validation.annotation.Expression; +import com.senmesh.common.validation.constants.ValidProviderEnum; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeProviderEnum; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-08-10 + */ +@ApiModel("短信验证码验证") +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class PhoneCodeDTO implements IPhoneCodeDTO{ + + /** **/ + private static final long serialVersionUID = 2786145404234042468L; + + @ApiModelProperty("验证码") + @NotBlank(message = "验证码不能为空") + private String code; + @ApiModelProperty("手机号码") + @Expression(type = ValidProviderEnum.PHONE, message = "手机号格式不正确") + private String phone; + /** {@link PhoneCodeProviderEnum} **/ + @ApiModelProperty("手机验证码提供者") + private String providerType; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/PhoneCodeMessage.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/PhoneCodeMessage.java new file mode 100644 index 0000000..d72fe8a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/PhoneCodeMessage.java @@ -0,0 +1,29 @@ +package com.senmesh.usercenter.user.phone.dto; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-08-04 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class PhoneCodeMessage implements Serializable { + + /** **/ + private static final long serialVersionUID = -7033284317906791262L; + + /** 手机号 **/ + private String phone; + /** 验证码 **/ + private String code; + /** host **/ + private String domainOrIp; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/PhoneCodeSmsDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/PhoneCodeSmsDTO.java new file mode 100644 index 0000000..e6bcf0c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/PhoneCodeSmsDTO.java @@ -0,0 +1,34 @@ +package com.senmesh.usercenter.user.phone.dto; + +import com.senmesh.common.validation.annotation.Expression; +import com.senmesh.common.validation.constants.ValidProviderEnum; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeProviderEnum; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * @author sr on 2021-06-17 + */ +@ApiModel("手机发送短信验证码") +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class PhoneCodeSmsDTO implements IPhoneCodeSmsDTO{ + + /** **/ + private static final long serialVersionUID = 5540602446456225643L; + + @ApiModelProperty("手机号码") + @Expression(type = ValidProviderEnum.PHONE, message = "手机号格式不正确") + private String phone; + /** {@link PhoneCodeProviderEnum} **/ + @ApiModelProperty("手机验证码提供者") + private String providerType; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/SmsSimpleSendDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/SmsSimpleSendDTO.java new file mode 100644 index 0000000..c5fdb72 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/SmsSimpleSendDTO.java @@ -0,0 +1,27 @@ +package com.senmesh.usercenter.user.phone.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.Singular; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class SmsSimpleSendDTO implements Serializable { + private static final long serialVersionUID = 4409542393509142949L; + + @NotEmpty(message = "模板编码不能为空") + private String templateCode; + + @NotNull(message = "短信发送明细不能为空") + @Singular + private List detailDTOS; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/SmsSimpleSendDetailDTO.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/SmsSimpleSendDetailDTO.java new file mode 100644 index 0000000..1ee3f6e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/dto/SmsSimpleSendDetailDTO.java @@ -0,0 +1,27 @@ +package com.senmesh.usercenter.user.phone.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Map; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class SmsSimpleSendDetailDTO implements Serializable { + private static final long serialVersionUID = 4409542393509142949L; + + /** + * 电话 + */ + private String phone; + + /** + * 参数 + */ + private Map parameters; +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/AbstractAsyncPhoneCodeProvider.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/AbstractAsyncPhoneCodeProvider.java new file mode 100644 index 0000000..b8d46c7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/AbstractAsyncPhoneCodeProvider.java @@ -0,0 +1,55 @@ +package com.senmesh.usercenter.user.phone.provider; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.util.RandomUtils; +import com.senmesh.mq.consumer.handler.ITopicMqHandler; +import com.senmesh.mq.dto.TopicMqMessage; +import com.senmesh.mq.util.MqSendUtils; +import com.senmesh.security.util.HostContextHolder; +import com.senmesh.usercenter.userprod.constant.UcMqSelfConstants; +import com.senmesh.usercenter.user.phone.dto.PhoneCodeMessage; +import com.senmesh.usercenter.user.phone.dto.PhoneCodeSmsDTO; + +import lombok.extern.slf4j.Slf4j; + +/** + * 抽象异步-手机号验证码提供者 + * @author sr on 2021-06-17 + */ +@Slf4j +public abstract class AbstractAsyncPhoneCodeProvider extends AbstractPhoneCodeProvider + implements ITopicMqHandler { + + @Override + public void send(PhoneCodeSmsDTO phoneCodeSmsDTO) { + preSendCheck(phoneCodeSmsDTO); + String phone = phoneCodeSmsDTO.getPhone(); + String code = generatePhoneCode(phone); + // mq发送消息 + MqSendUtils.send(TopicMqMessage.builder().messageId(RandomUtils.generateUUID()).routingKey(getRoutingKey()) + .data(PhoneCodeMessage.builder().phone(phone).code(code) + .domainOrIp(HostContextHolder.getHost()).build()) + .build()); + } + + @Override + public String getRoutingKey() { + return String.join(CommonConstants.UNDERLINE, + UcMqSelfConstants.ROUTING_KEY_PHONE_CODE_SMS_PREFIX, getType()); + } + + @Override + public void onMessage(TopicMqMessage message) { + // TODO messageId幂等 + String messageId = message.getMessageId(); + PhoneCodeMessage loginSms = message.getData(); + String phone = loginSms.getPhone(); + String code = loginSms.getCode(); + String existcode = PhoneCodeRepository.getPhoneSmsCode(getType(), phone); + if (!code.equals(existcode)) { + log.error("phoneCode:{},phone:{},验证码不一致(重发或过期),不发送消息", getType(), phone); + return; + } + super.sendSms(loginSms); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/AbstractPhoneCodeProvider.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/AbstractPhoneCodeProvider.java new file mode 100644 index 0000000..8478794 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/AbstractPhoneCodeProvider.java @@ -0,0 +1,138 @@ +package com.senmesh.usercenter.user.phone.provider; + +import java.util.List; +import java.util.Map; + +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; + +import com.google.common.collect.Lists; +import com.senmesh.common.AlitaResult; +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.common.util.RandomUtils; +import com.senmesh.common.validation.util.ValidateUtils; +import com.senmesh.sdk.sms.dto.VerificationCodeSendDTO; +import com.senmesh.sdk.sms.util.SmsUtils; +import com.senmesh.security.util.HostContextHolder; +import com.senmesh.usercenter.dto.DomainSettingReqDTO; +import com.senmesh.usercenter.constants.DomainSettingTypeEnum; +import com.senmesh.usercenter.sys.service.DomainSettingService; +import com.senmesh.usercenter.user.phone.check.IPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.dto.PhoneCodeMessage; +import com.senmesh.usercenter.user.phone.dto.PhoneCodeSmsDTO; + +import lombok.extern.slf4j.Slf4j; + +/** + * 抽象同步-手机号验证码提供者 + * @author sr on 2021-06-17 + */ +@Slf4j +public abstract class AbstractPhoneCodeProvider implements IPhoneCodeProvider { + + private static final String SMS_TEMPLATE_PROPERTIES = "sms.phoneSms"; + + private List phoneCodeCheckers = Lists.newArrayList(); + + @Autowired + private DomainSettingService domainSettingService; + + protected void addPhoneCodeChecker(IPhoneCodeChecker phoneCodeChecker) { + phoneCodeCheckers.add(phoneCodeChecker); + } + + /** + * 按顺序调用校验器,校验是否可发送短信 + * @param phoneCodeSmsDTO + * @author sr on 2021-06-17 + */ + protected void preSendCheck(PhoneCodeSmsDTO phoneCodeSmsDTO) { + Assert.isTrue(ValidateUtils.isPhone(phoneCodeSmsDTO.getPhone()), "手机号格式有误"); + preSendBizCheck(phoneCodeSmsDTO); + for (int i = 0; i < phoneCodeCheckers.size(); i++) { + IPhoneCodeChecker checker = phoneCodeCheckers.get(i); + try { + // 不支持校验,则跳过 + if (!checker.supports(phoneCodeSmsDTO.getClass())) { + continue; + } + checker.check(phoneCodeSmsDTO); + } catch (BusinessException e) { + // 回退校验 + for (int j = 0; j <= i; j++) { + IPhoneCodeChecker revertChecker = phoneCodeCheckers.get(j); + if (!revertChecker.supports(phoneCodeSmsDTO.getClass())) { + continue; + } + try { + revertChecker.revertCheck(phoneCodeSmsDTO); + } catch (Exception re) { + log.error("回退校验失败:{},{}", revertChecker.getType(), re); + } + } + throw e; + } + } + } + + /** + * 生成短信验证码,并放入redis缓存 + * @param phone + * @return + * @author sr on 2021-06-17 + */ + protected String generatePhoneCode(String phone) { + // 生成缓存验证码,5分钟有效 + String code = RandomUtils.nextSixVerificationCode(); + PhoneCodeRepository.setPhoneSmsCode(getType(), phone, code); + return code; + } + + @Override + public void send(PhoneCodeSmsDTO phoneCodeSmsDTO) { + preSendCheck(phoneCodeSmsDTO); + String phone = phoneCodeSmsDTO.getPhone(); + String code = generatePhoneCode(phone); + String errMsg = this.sendSms(PhoneCodeMessage.builder().phone(phone).code(code) + .domainOrIp(HostContextHolder.getHost()).build()); + Assert.isNull(errMsg, errMsg); + } + + /** + * 真实发送sms短信 + * @param phone + * @param code + * @return + * @author sr on 2021-06-17 + */ + protected String sendSms(PhoneCodeMessage phoneCodeMessage) { + String phone = phoneCodeMessage.getPhone(); + // 获取发送验证码配置 + String signName = null; + String domainOrIp = phoneCodeMessage.getDomainOrIp(); + if (StringUtils.isNotBlank(domainOrIp)) { + String settingData = domainSettingService.findSettingData(DomainSettingReqDTO.builder() + .domainOrIp(domainOrIp).type(DomainSettingTypeEnum.SMS.getType()).build()); + if (settingData != null) { + Map settingDataMap = JsonUtils.toMap(settingData); + signName = MapUtils.getString(settingDataMap, "signName"); + } + } + AlitaResult result = SmsUtils.getService() + .send(VerificationCodeSendDTO.builder() + .templateCode(EnvironmentUtils.getProperty(SMS_TEMPLATE_PROPERTIES)) + .signName(signName) + .phone(phone) + .code(phoneCodeMessage.getCode()) + .build()); + if (!result.getSuccess() || !result.getData()) { + log.error("phoneCode:{},phone:{},发送短信失败:{}", getType(), phone, result.getMsg()); + return result.getMsg(); + } + return null; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/GetOrgApplyProvider.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/GetOrgApplyProvider.java new file mode 100644 index 0000000..7982168 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/GetOrgApplyProvider.java @@ -0,0 +1,31 @@ +package com.senmesh.usercenter.user.phone.provider; + +import com.senmesh.common.util.SpringContextHolder; +import com.senmesh.usercenter.user.phone.check.CountRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.LastRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeProviderEnum; + +import org.springframework.context.annotation.DependsOn; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +/** + * 机构入驻 + */ +@Component +@DependsOn("springContextHolder") +public class GetOrgApplyProvider extends AbstractPhoneCodeProvider{ + + @PostConstruct + public void init() { + super.addPhoneCodeChecker(SpringContextHolder.getBean(LastRedisPhoneCodeChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(CountRedisPhoneCodeChecker.class)); + } + + @Override + public String getType() { + return PhoneCodeProviderEnum.GET_ORG_APPLY.getType(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/IPhoneCodeProvider.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/IPhoneCodeProvider.java new file mode 100644 index 0000000..33e6b53 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/IPhoneCodeProvider.java @@ -0,0 +1,47 @@ +package com.senmesh.usercenter.user.phone.provider; + +import com.senmesh.usercenter.user.phone.dto.PhoneCodeSmsDTO; + +/** + * 手机号验证码提供者 + * @author sr on 2021-06-16 + */ +public interface IPhoneCodeProvider { + + /** + * 类型 + * @return + * @author sr on 2021-06-16 + */ + String getType(); + + /** + * 发送前置业务校验 + * @param phoneCodeSmsDTO + * @author sr on 2021-09-02 + */ + default void preSendBizCheck(PhoneCodeSmsDTO phoneCodeSmsDTO){ + // 需要特殊校验,请重写该方法 + } + + /** + * 发送短信验证码 + * @param phoneCodeSmsDTO + * @author sr on 2021-06-16 + */ + void send(PhoneCodeSmsDTO phoneCodeSmsDTO); + + /** + * 验证码是否匹配 + * @param phone + * @param code + * @return + * @author sr on 2021-06-28 + */ + default boolean match(String phone, String code) { + String smsCode = + PhoneCodeRepository.getPhoneSmsCode(getType(), phone); + return code.equals(smsCode); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/OrgApplyProvider.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/OrgApplyProvider.java new file mode 100644 index 0000000..2c53964 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/OrgApplyProvider.java @@ -0,0 +1,31 @@ +package com.senmesh.usercenter.user.phone.provider; + +import com.senmesh.common.util.SpringContextHolder; +import com.senmesh.usercenter.user.phone.check.CountRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.LastRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeProviderEnum; + +import org.springframework.context.annotation.DependsOn; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +/** + * 机构入驻 + */ +@Component +@DependsOn("springContextHolder") +public class OrgApplyProvider extends AbstractPhoneCodeProvider{ + + @PostConstruct + public void init() { + super.addPhoneCodeChecker(SpringContextHolder.getBean(LastRedisPhoneCodeChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(CountRedisPhoneCodeChecker.class)); + } + + @Override + public String getType() { + return PhoneCodeProviderEnum.ORG_APPLY.getType(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/OrgChangePhoneProvider.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/OrgChangePhoneProvider.java new file mode 100644 index 0000000..ad5e4ea --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/OrgChangePhoneProvider.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.user.phone.provider; + +import javax.annotation.PostConstruct; + +import org.springframework.context.annotation.DependsOn; +import org.springframework.stereotype.Component; + +import com.senmesh.common.util.SpringContextHolder; +import com.senmesh.usercenter.user.phone.check.CaptchaPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.ChangePhoneChecker; +import com.senmesh.usercenter.user.phone.check.CountRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.LastRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeProviderEnum; + +/** + * 机构用户换绑手机号 + * @author sr on 2021-06-28 + */ +@Component +@DependsOn("springContextHolder") +public class OrgChangePhoneProvider extends AbstractPhoneCodeProvider{ + + @PostConstruct + public void init() { + super.addPhoneCodeChecker(SpringContextHolder.getBean(CaptchaPhoneCodeChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(ChangePhoneChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(LastRedisPhoneCodeChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(CountRedisPhoneCodeChecker.class)); + } + + @Override + public String getType() { + return PhoneCodeProviderEnum.ORG_CHANGE_PHONE.getType(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/OrgLoginProvider.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/OrgLoginProvider.java new file mode 100644 index 0000000..e85aa58 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/OrgLoginProvider.java @@ -0,0 +1,49 @@ +package com.senmesh.usercenter.user.phone.provider; + +import javax.annotation.PostConstruct; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.DependsOn; +import org.springframework.stereotype.Component; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.SpringContextHolder; +import com.senmesh.usercenter.user.dao.OrgUserMapper; +import com.senmesh.usercenter.user.phone.check.CaptchaPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.CountRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.LastRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeProviderEnum; +import com.senmesh.usercenter.user.phone.dto.PhoneCodeSmsDTO; + +/** + * 机构用户手机号登录验证码提供者 + * @author sr on 2021-06-17 + */ +@Component +@DependsOn("springContextHolder") +public class OrgLoginProvider extends AbstractPhoneCodeProvider{ + + @Autowired + private OrgUserMapper orgUserMapper; + + @PostConstruct + public void init() { + super.addPhoneCodeChecker(SpringContextHolder.getBean(CaptchaPhoneCodeChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(LastRedisPhoneCodeChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(CountRedisPhoneCodeChecker.class)); + } + + @Override + public String getType() { + return PhoneCodeProviderEnum.ORG_LOGIN.getType(); + } + + @Override + public void preSendBizCheck(PhoneCodeSmsDTO phoneCodeSmsDTO) { + // 验证是否已经绑定企业 + Assert.isTrue(orgUserMapper.existOrgUser(phoneCodeSmsDTO.getPhone()), "未找到手机号对应的企业信息"); + } + + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/OrgResetPwdProvider.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/OrgResetPwdProvider.java new file mode 100644 index 0000000..0503ff8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/OrgResetPwdProvider.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.user.phone.provider; + +import javax.annotation.PostConstruct; + +import org.springframework.context.annotation.DependsOn; +import org.springframework.stereotype.Component; + +import com.senmesh.common.util.SpringContextHolder; +import com.senmesh.usercenter.user.phone.check.CaptchaPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.CountRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.LastRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.ResetPwdChecker; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeProviderEnum; + +/** + * 重置密码 + * @author sr on 2021-07-22 + */ +@Component +@DependsOn("springContextHolder") +public class OrgResetPwdProvider extends AbstractPhoneCodeProvider{ + + @PostConstruct + public void init() { + super.addPhoneCodeChecker(SpringContextHolder.getBean(CaptchaPhoneCodeChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(ResetPwdChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(LastRedisPhoneCodeChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(CountRedisPhoneCodeChecker.class)); + } + + @Override + public String getType() { + return PhoneCodeProviderEnum.ORG_RESET_PWD.getType(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/OrgResetSecurityCodeProvider.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/OrgResetSecurityCodeProvider.java new file mode 100644 index 0000000..9a8acc7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/OrgResetSecurityCodeProvider.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.user.phone.provider; + +import javax.annotation.PostConstruct; + +import org.springframework.context.annotation.DependsOn; +import org.springframework.stereotype.Component; + +import com.senmesh.common.util.SpringContextHolder; +import com.senmesh.usercenter.user.phone.check.CaptchaPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.CountRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.HasLoginChecker; +import com.senmesh.usercenter.user.phone.check.LastRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeProviderEnum; + +/** + * 机构重置安全码 + * @author sr on 2021-09-03 + */ +@Component +@DependsOn("springContextHolder") +public class OrgResetSecurityCodeProvider extends AbstractPhoneCodeProvider{ + + @PostConstruct + public void init() { + super.addPhoneCodeChecker(SpringContextHolder.getBean(CaptchaPhoneCodeChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(HasLoginChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(LastRedisPhoneCodeChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(CountRedisPhoneCodeChecker.class)); + } + + @Override + public String getType() { + return PhoneCodeProviderEnum.ORG_RESET_SECURITY_CODE.getType(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/PersonBindPhoneProvider.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/PersonBindPhoneProvider.java new file mode 100644 index 0000000..2f29ef4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/PersonBindPhoneProvider.java @@ -0,0 +1,44 @@ +package com.senmesh.usercenter.user.phone.provider; + +import javax.annotation.PostConstruct; + +import org.springframework.context.annotation.DependsOn; +import org.springframework.stereotype.Component; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.SpringContextHolder; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.user.constant.UserTypeEnum; +import com.senmesh.usercenter.user.phone.check.CaptchaPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.CountRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.LastRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeProviderEnum; +import com.senmesh.usercenter.user.phone.dto.PhoneCodeSmsDTO; + +/** + * 个人绑定手机号 + * @author sr on 2021-06-28 + */ +@Component +@DependsOn("springContextHolder") +public class PersonBindPhoneProvider extends AbstractPhoneCodeProvider{ + + @PostConstruct + public void init() { + super.addPhoneCodeChecker(SpringContextHolder.getBean(CaptchaPhoneCodeChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(LastRedisPhoneCodeChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(CountRedisPhoneCodeChecker.class)); + } + + @Override + public String getType() { + return PhoneCodeProviderEnum.PERSON_BIND_PHONE.getType(); + } + + @Override + public void preSendBizCheck(PhoneCodeSmsDTO phoneCodeSmsDTO) { + Assert.isTrue(UserTypeEnum.PERSON.getType().equals(UserContextHolder.getUserType()), + "只有个人用户可绑定手机号"); + Assert.isTrue(!UserContextHolder.getExistLoginUser().getPhoneBinding(), "当前用户已绑定手机号"); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/PersonChangePhoneProvider.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/PersonChangePhoneProvider.java new file mode 100644 index 0000000..09f4714 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/PersonChangePhoneProvider.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.user.phone.provider; + +import javax.annotation.PostConstruct; + +import org.springframework.context.annotation.DependsOn; +import org.springframework.stereotype.Component; + +import com.senmesh.common.util.SpringContextHolder; +import com.senmesh.usercenter.user.phone.check.CaptchaPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.ChangePhoneChecker; +import com.senmesh.usercenter.user.phone.check.CountRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.LastRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeProviderEnum; + +/** + * 个人换绑手机号 + * @author sr on 2021-06-28 + */ +@Component +@DependsOn("springContextHolder") +public class PersonChangePhoneProvider extends AbstractPhoneCodeProvider{ + + @PostConstruct + public void init() { + super.addPhoneCodeChecker(SpringContextHolder.getBean(CaptchaPhoneCodeChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(ChangePhoneChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(LastRedisPhoneCodeChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(CountRedisPhoneCodeChecker.class)); + } + + @Override + public String getType() { + return PhoneCodeProviderEnum.PERSON_CHANGE_PHONE.getType(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/PersonLoginProvider.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/PersonLoginProvider.java new file mode 100644 index 0000000..c28c5c4 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/PersonLoginProvider.java @@ -0,0 +1,34 @@ +package com.senmesh.usercenter.user.phone.provider; + +import javax.annotation.PostConstruct; + +import org.springframework.context.annotation.DependsOn; +import org.springframework.stereotype.Component; + +import com.senmesh.common.util.SpringContextHolder; +import com.senmesh.usercenter.user.phone.check.CaptchaPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.CountRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.LastRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeProviderEnum; + +/** + * 个人用户手机号登录验证码提供者 + * @author sr on 2021-06-17 + */ +@Component +@DependsOn("springContextHolder") +public class PersonLoginProvider extends AbstractPhoneCodeProvider{ + + @PostConstruct + public void init() { + super.addPhoneCodeChecker(SpringContextHolder.getBean(CaptchaPhoneCodeChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(LastRedisPhoneCodeChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(CountRedisPhoneCodeChecker.class)); + } + + @Override + public String getType() { + return PhoneCodeProviderEnum.PERSON_LOGIN.getType(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/PersonResetPwdProvider.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/PersonResetPwdProvider.java new file mode 100644 index 0000000..176cc0a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/PersonResetPwdProvider.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.user.phone.provider; + +import javax.annotation.PostConstruct; + +import org.springframework.context.annotation.DependsOn; +import org.springframework.stereotype.Component; + +import com.senmesh.common.util.SpringContextHolder; +import com.senmesh.usercenter.user.phone.check.CaptchaPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.CountRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.LastRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.ResetPwdChecker; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeProviderEnum; + +/** + * 重置密码 + * @author sr on 2021-07-22 + */ +@Component +@DependsOn("springContextHolder") +public class PersonResetPwdProvider extends AbstractPhoneCodeProvider{ + + @PostConstruct + public void init() { + super.addPhoneCodeChecker(SpringContextHolder.getBean(CaptchaPhoneCodeChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(ResetPwdChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(LastRedisPhoneCodeChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(CountRedisPhoneCodeChecker.class)); + } + + @Override + public String getType() { + return PhoneCodeProviderEnum.PERSON_RESET_PWD.getType(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/PersonResetSecurityCodeProvider.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/PersonResetSecurityCodeProvider.java new file mode 100644 index 0000000..eb3bbbf --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/PersonResetSecurityCodeProvider.java @@ -0,0 +1,36 @@ +package com.senmesh.usercenter.user.phone.provider; + +import javax.annotation.PostConstruct; + +import org.springframework.context.annotation.DependsOn; +import org.springframework.stereotype.Component; + +import com.senmesh.common.util.SpringContextHolder; +import com.senmesh.usercenter.user.phone.check.CaptchaPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.CountRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.HasLoginChecker; +import com.senmesh.usercenter.user.phone.check.LastRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeProviderEnum; + +/** + * 个人重置安全码 + * @author sr on 2021-07-22 + */ +@Component +@DependsOn("springContextHolder") +public class PersonResetSecurityCodeProvider extends AbstractPhoneCodeProvider{ + + @PostConstruct + public void init() { + super.addPhoneCodeChecker(SpringContextHolder.getBean(CaptchaPhoneCodeChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(HasLoginChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(LastRedisPhoneCodeChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(CountRedisPhoneCodeChecker.class)); + } + + @Override + public String getType() { + return PhoneCodeProviderEnum.PERSON_RESET_SECURITY_CODE.getType(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/PhoneCodeRepository.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/PhoneCodeRepository.java new file mode 100644 index 0000000..8441987 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/PhoneCodeRepository.java @@ -0,0 +1,60 @@ +package com.senmesh.usercenter.user.phone.provider; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.frame.redis.util.RedisUtils; + +/** + * 短信验证码存储器 + * @author sr on 2021-06-16 + */ +public class PhoneCodeRepository { + + /** 短信验证码前缀 **/ + public static final String PHONE_CODE_PREFIX = "phone:code"; + /** 验证码过期时间-秒 **/ + public static final long CODE_EXPIRE_TIME = 300; + + /** + * 存储验证码的key + * + * @param phone + * @return + * @author sr on 2020-08-05 + */ + public static String getPhoneSmsCodeKey(String providerType, String phone) { + return String.join(CommonConstants.COLON, PhoneCodeRepository.PHONE_CODE_PREFIX, providerType, phone); + } + + /** + * 设置验证码,过期时间5分钟 + * + * @param phone + * @param code + * @author sr on 2020-08-05 + */ + public static void setPhoneSmsCode(String providerType, String phone, String code) { + RedisUtils.add(getPhoneSmsCodeKey(providerType, phone), code, CODE_EXPIRE_TIME); + } + + /** + * 获取验证码 + * + * @param phone + * @return + * @author sr on 2020-08-05 + */ + public static String getPhoneSmsCode(String providerType, String phone) { + return (String) RedisUtils.get(getPhoneSmsCodeKey(providerType, phone)); + } + + /** + * 验证成功,移除验证码 + * + * @param phone + * @author sr on 2020-08-05 + */ + public static void removePhoneSmsCode(String providerType, String phone) { + RedisUtils.remove(getPhoneSmsCodeKey(providerType, phone)); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/ResetPayPwdProvider.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/ResetPayPwdProvider.java new file mode 100644 index 0000000..3dbd682 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/ResetPayPwdProvider.java @@ -0,0 +1,30 @@ +package com.senmesh.usercenter.user.phone.provider; + +import javax.annotation.PostConstruct; + +import org.springframework.context.annotation.DependsOn; +import org.springframework.stereotype.Component; + +import com.senmesh.common.util.SpringContextHolder; +import com.senmesh.usercenter.user.phone.check.CountRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.HasLoginChecker; +import com.senmesh.usercenter.user.phone.check.LastRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeProviderEnum; + +@Component +@DependsOn("springContextHolder") +public class ResetPayPwdProvider extends AbstractPhoneCodeProvider{ + + @PostConstruct + public void init() { + super.addPhoneCodeChecker(SpringContextHolder.getBean(HasLoginChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(LastRedisPhoneCodeChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(CountRedisPhoneCodeChecker.class)); + } + + @Override + public String getType() { + return PhoneCodeProviderEnum.RESET_PAY_PWD.getType(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/UserCancelProvider.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/UserCancelProvider.java new file mode 100644 index 0000000..d813a26 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/UserCancelProvider.java @@ -0,0 +1,32 @@ +package com.senmesh.usercenter.user.phone.provider; + +import com.senmesh.common.util.SpringContextHolder; +import com.senmesh.usercenter.user.phone.check.CountRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.check.LastRedisPhoneCodeChecker; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeProviderEnum; + +import org.springframework.context.annotation.DependsOn; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +/** + * @description: 个人用户注销 + * @author: guixinman + * @create: 2024-06-13 14:28 + **/ +@Component +@DependsOn("springContextHolder") +public class UserCancelProvider extends AbstractPhoneCodeProvider{ + + @PostConstruct + public void init() { + super.addPhoneCodeChecker(SpringContextHolder.getBean(LastRedisPhoneCodeChecker.class)); + super.addPhoneCodeChecker(SpringContextHolder.getBean(CountRedisPhoneCodeChecker.class)); + } + + @Override + public String getType() { + return PhoneCodeProviderEnum.USER_CANCEL.getType(); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/simple/AbstractSimpleSms.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/simple/AbstractSimpleSms.java new file mode 100644 index 0000000..2a7ad06 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/simple/AbstractSimpleSms.java @@ -0,0 +1,47 @@ +package com.senmesh.usercenter.user.phone.provider.simple; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.senmesh.common.AlitaResult; +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.common.validation.util.ValidateUtils; +import com.senmesh.sdk.sms.util.SmsUtils; +import com.senmesh.usercenter.user.phone.dto.SmsSimpleSendDTO; +import com.senmesh.usercenter.user.phone.dto.SmsSimpleSendDetailDTO; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +@Slf4j +public abstract class AbstractSimpleSms implements ISimpleSms { + /** + * 做发送短信 + * + * @param sendDTO 发送请求对象 + * @return int + */ + protected int doSendSms(SmsSimpleSendDTO sendDTO) { + List detailDTOS = sendDTO.getDetailDTOS(); + if (CollUtil.isEmpty(detailDTOS)) { + return 0; + } + String sms = String.join(".", "sms", sendDTO.getTemplateCode()); + String templateCode = EnvironmentUtils.getProperty(sms); + if (StrUtil.isEmpty(templateCode)) { + log.info("发送短信失败,模板配置[{}]不存在", sms); + return 0; + } + int resultNum = 0; + for (SmsSimpleSendDetailDTO detailDTO : detailDTOS) { + if (!ValidateUtils.isPhone(detailDTO.getPhone())) { + continue; + } + AlitaResult result = SmsUtils.getService() + .sendSimple(templateCode, detailDTO.getPhone(), detailDTO.getParameters()); + if (Boolean.TRUE.equals(result.getSuccess()) && Boolean.TRUE.equals(result.getData())) { + resultNum++; + } + } + return resultNum; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/simple/ISimpleSms.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/simple/ISimpleSms.java new file mode 100644 index 0000000..54ed2d2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/simple/ISimpleSms.java @@ -0,0 +1,29 @@ +package com.senmesh.usercenter.user.phone.provider.simple; + +import com.senmesh.usercenter.user.phone.dto.SmsSimpleSendDTO; + +/** + * isimple短信提供者 + * + * @author cheny + * @date 2022/11/07 + */ +public interface ISimpleSms { + + + /** + * 发送短信 + * + * @param sendDTO 发送dto + * @return int + */ + int send(SmsSimpleSendDTO sendDTO); + + + /** + * 发送异步 + * + * @param sendDTO 发送dto + */ + void sendAsync(SmsSimpleSendDTO sendDTO); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/simple/StandardSimpleSms.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/simple/StandardSimpleSms.java new file mode 100644 index 0000000..4b31aeb --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/provider/simple/StandardSimpleSms.java @@ -0,0 +1,61 @@ +package com.senmesh.usercenter.user.phone.provider.simple; + +import com.senmesh.common.util.JsonUtils; +import com.senmesh.common.util.RandomUtils; +import com.senmesh.frame.redis.util.RedisUtils; +import com.senmesh.mq.consumer.handler.ITopicMqHandler; +import com.senmesh.mq.dto.TopicMqMessage; +import com.senmesh.mq.util.MqSendUtils; +import com.senmesh.usercenter.user.phone.dto.SmsSimpleSendDTO; +import com.senmesh.usercenter.userprod.constant.UcMqSelfConstants; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class StandardSimpleSms extends AbstractSimpleSms implements ITopicMqHandler { + @Override + public int send(SmsSimpleSendDTO sendDTO) { + return doSendSms(sendDTO); + } + + @Override + public void sendAsync(SmsSimpleSendDTO sendDTO) { + String messageId = RandomUtils.generateUUID(); + RedisUtils.add(messageId, 1, 24 * 60 * 60L); + MqSendUtils.send(TopicMqMessage.builder().messageId(messageId).routingKey(getRoutingKey()) + .data(sendDTO) + .build()); + } + + @Override + public String getRoutingKey() { + return UcMqSelfConstants.ROUTING_KEY_SIMPLE_SMS_PREFIX; + } + + @Override + public void onMessage(TopicMqMessage message) { + + String messageId = message.getMessageId(); + String value = RedisUtils.get(messageId) + ""; + int i; + try { + i = Integer.parseInt(value); + } catch (NumberFormatException e) { + i = 0; + } + + if (i != 1) { + log.info("短信消息消费异常,消息不存在或者已被消费,message : [{}]", JsonUtils.toJsonString(message)); + return; + } + + try { + send(message.getData()); + } catch (Exception e) { + log.info("短信消息消费异常,message : [{}]", JsonUtils.toJsonString(message), e); + } finally { + RedisUtils.expire(messageId, 0L); + } + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/phone/util/PhoneCodeUtils.java b/backend/src/main/java/com/senmesh/usercenter/user/phone/util/PhoneCodeUtils.java new file mode 100644 index 0000000..b89b5c8 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/phone/util/PhoneCodeUtils.java @@ -0,0 +1,109 @@ +package com.senmesh.usercenter.user.phone.util; + +import java.util.List; +import java.util.Map; + +import org.springframework.stereotype.Component; + +import com.google.common.collect.Maps; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.usercenter.user.constant.UserTypeEnum; +import com.senmesh.usercenter.user.dto.IUserPhoneCodeSms; +import com.senmesh.usercenter.user.phone.constant.PhoneCodeProviderEnum; +import com.senmesh.usercenter.user.phone.dto.PhoneCodeDTO; +import com.senmesh.usercenter.user.phone.dto.PhoneCodeSmsDTO; +import com.senmesh.usercenter.user.phone.provider.IPhoneCodeProvider; +import com.senmesh.usercenter.user.util.UserUtils; + +/** + * @author sr on 2021-06-28 + */ +@Component +public class PhoneCodeUtils { + + private static Map providerMap = Maps.newHashMap(); + + private PhoneCodeUtils(List providers) { + providers.forEach(provider -> providerMap.put(provider.getType(), provider)); + } + + public static IPhoneCodeProvider getProvider(String providerType) { + Assert.notBlank(providerType, "验证码提供者不能为空"); + IPhoneCodeProvider provider = providerMap.get(providerType); + Assert.notNull(provider, providerType + "未找到对应类型短信验证码提供者"); + return provider; + } + + /** + * 发送验证码 + * @param phoneCodeSmsDTO + * @author sr on 2021-09-02 + */ + public static void send(PhoneCodeSmsDTO phoneCodeSmsDTO) { + if(phoneCodeSmsDTO instanceof IUserPhoneCodeSms) { + decorateUserPhoneCode((IUserPhoneCodeSms) phoneCodeSmsDTO); + } + getProvider(phoneCodeSmsDTO.getProviderType()).send(phoneCodeSmsDTO); + } + + /** + * 验证 + * @param providerType + * @param phone + * @param code + * @return + * @author sr on 2021-06-28 + */ + public static boolean match(String providerType, String phone, String code) { + return getProvider(providerType).match(phone, code); + } + + /** + * 验证(失败抛‘验证码错误’异常) + * @param providerType + * @param phone + * @param code + * @author sr on 2021-08-10 + */ + public static void matchBiz(String providerType, String phone, String code) { + boolean match = getProvider(providerType).match(phone, code); + Assert.isTrue(match, "验证码错误"); + } + + /** + * 验证 + * @param phoneCodeDTO + * @return + * @author sr on 2021-08-10 + */ + public static boolean match(PhoneCodeDTO phoneCodeDTO) { + if(phoneCodeDTO instanceof IUserPhoneCodeSms) { + decorateUserPhoneCode((IUserPhoneCodeSms) phoneCodeDTO); + } + return match(phoneCodeDTO.getProviderType(), phoneCodeDTO.getPhone(), phoneCodeDTO.getCode()); + } + + /** + * 验证(失败抛‘验证码错误’异常) + * @param providerType + * @param phoneCodeDTO + * @return + * @author sr on 2021-08-10 + */ + public static void matchBiz(PhoneCodeDTO phoneCodeDTO) { + boolean match = match(phoneCodeDTO); + Assert.isTrue(match, "验证码错误"); + } + + /** + * 处理用户验证码对象,提供通用验证码对象所需属性 + * @param iUserPhoneCode + * @author sr on 2021-09-02 + */ + public static void decorateUserPhoneCode(IUserPhoneCodeSms iUserPhoneCode) { + UserTypeEnum userTypeEnum = UserUtils.getUserType(iUserPhoneCode); + iUserPhoneCode.setProviderType( + PhoneCodeProviderEnum.getType(userTypeEnum, iUserPhoneCode.getOperateType())); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/service/OrgUserService.java b/backend/src/main/java/com/senmesh/usercenter/user/service/OrgUserService.java new file mode 100644 index 0000000..a63707b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/service/OrgUserService.java @@ -0,0 +1,53 @@ +package com.senmesh.usercenter.user.service; + +import com.senmesh.usercenter.user.dto.OrgUserInfoDTO; +import com.senmesh.usercenter.user.dto.OrgUserInfoQueryDTO; +import com.senmesh.usercenter.user.dto.OrgUserOperateDTO; +import com.senmesh.usercenter.user.login.dto.OrgDetailDTO; + +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.groups.Default; +import java.util.List; + +/** + * 机构用户表 + * + * @author sr on 2021-05-24 + */ +@Validated(Default.class) +public interface OrgUserService { + + /** + * 新增 + * + * @param orgUserOperateDTO + * @return + * @author sr on 2021-05-24 + */ + Long create(OrgUserOperateDTO orgUserOperateDTO); + + /** + * 查询机构用户列表 + * + * @param queryDTO 查询dto + * @return {@link List}<{@link OrgUserInfoDTO}> + */ + List list(@Valid OrgUserInfoQueryDTO queryDTO); + + + /** + * 是否存在 + */ + boolean existOrgUser(Long orgId, Long userId); + + /** + * 查询用户所属机构列表 + * @param userId + * @param orgId + * @return + * @author sr on 2022-08-29 + */ + List listLoginOrgByUser(Long userId, Long orgId); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/service/UserAuthService.java b/backend/src/main/java/com/senmesh/usercenter/user/service/UserAuthService.java new file mode 100644 index 0000000..6f8c636 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/service/UserAuthService.java @@ -0,0 +1,52 @@ +package com.senmesh.usercenter.user.service; + +import java.util.List; + +import com.senmesh.usercenter.user.dto.UserAuthQueryDTO; +import com.senmesh.usercenter.user.dto.UserAuthOperateDTO; +import com.senmesh.usercenter.user.dto.UserAuthDTO; + +/** + * 用户授权中间表 + * + * @author sr on 2021-05-24 + */ +public interface UserAuthService { + + /** + * 新增 + * + * @param userAuthOperateDTO + * @return + * @author sr on 2021-05-24 + */ + Long create(UserAuthOperateDTO userAuthOperateDTO); + + /** + * 修改 + * + * @param userAuthOperateDTO + * @author sr on 2021-05-24 + */ + void modify(UserAuthOperateDTO userAuthOperateDTO); + + /** + * 删除 + * + * @param id + * @author sr on 2021-05-24 + */ + void remove(Long id); + + /** + * 查询 + * + * @param userAuthQueryDTO + * @return + * @author sr on 2021-05-24 + */ + List list(UserAuthQueryDTO userAuthQueryDTO); + + void page(UserAuthQueryDTO userAuthQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/service/UserCancelService.java b/backend/src/main/java/com/senmesh/usercenter/user/service/UserCancelService.java new file mode 100644 index 0000000..967a165 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/service/UserCancelService.java @@ -0,0 +1,44 @@ +package com.senmesh.usercenter.user.service; + +import com.senmesh.usercenter.user.dto.UserCancelApplyReqDTO; +import com.senmesh.usercenter.user.dto.UserCancelDTO; +import com.senmesh.usercenter.user.dto.UserCancelPageQueryDTO; + +import java.util.List; + +/** + * 用户申请注销 + * + * @author cheny + * @date 2023/03/07 + */ +public interface UserCancelService { + + /** + * 申请注销 + * + * @return {@link UserCancelDTO} + */ + UserCancelDTO apply(UserCancelApplyReqDTO applyDTO); + + /** + * 找到 + * + * @return {@link UserCancelDTO} + */ + UserCancelDTO find(UserCancelPageQueryDTO queryDTO); + + /** + * 同意注销 + * + * @return {@link UserCancelDTO} + */ + UserCancelDTO agreeCancel(Long userId); + + List page(UserCancelPageQueryDTO queryDTO); + + /** + * 给未处理的注销申请发钉钉消息提醒到运营群 + */ + void toNotify(); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/service/UserConfigService.java b/backend/src/main/java/com/senmesh/usercenter/user/service/UserConfigService.java new file mode 100644 index 0000000..b7c33b2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/service/UserConfigService.java @@ -0,0 +1,59 @@ +package com.senmesh.usercenter.user.service; + +import java.util.List; + +import com.senmesh.usercenter.user.dto.UserConfigQueryDTO; +import com.senmesh.usercenter.user.dto.UserConfigOperateDTO; +import com.senmesh.usercenter.user.dto.UserConfigDTO; + +/** + * 用户配置 + * + * @author sr on 2021-08-12 + */ +public interface UserConfigService { + + /** + * 新增 + * + * @param userConfigOperateDTO + * @return + * @author sr on 2021-08-12 + */ + Long create(UserConfigOperateDTO userConfigOperateDTO); + + /** + * 修改 + * + * @param userConfigOperateDTO + * @author sr on 2021-08-12 + */ + void modify(UserConfigOperateDTO userConfigOperateDTO); + + /** + * 删除 + * + * @param id + * @author sr on 2021-08-12 + */ + void remove(Long id); + + /** + * 查询 + * + * @param userConfigQueryDTO + * @return + * @author sr on 2021-08-12 + */ + List list(UserConfigQueryDTO userConfigQueryDTO); + + /** + * 查询单个 + * + * @param userConfigQueryDTO + * @return + * @author sr on 2021-08-12 + */ + UserConfigDTO find(UserConfigQueryDTO userConfigQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/service/UserExtensionService.java b/backend/src/main/java/com/senmesh/usercenter/user/service/UserExtensionService.java new file mode 100644 index 0000000..73c3de7 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/service/UserExtensionService.java @@ -0,0 +1,42 @@ +package com.senmesh.usercenter.user.service; + +import com.senmesh.usercenter.user.dto.UserExtensionDTO; +import com.senmesh.usercenter.user.dto.UserExtensionOperateDTO; + +/** + * @author czy + * @date 2021-06-15 + */ +public interface UserExtensionService { + + /** + * 编辑 + * + * @param userExtensionOperateDTO + * @return + * @author czy on 2021-06-15 + */ + Long edit(UserExtensionOperateDTO userExtensionOperateDTO); + + /** + * @description: 根据用户id编辑 + * @return: + * @author: guixinman + * @param: + */ + void createOrEditByUserId(UserExtensionOperateDTO userExtensionOperateDTO,Long userId); + + + /** + * 根据userId获取用户扩展信息 + * @param userId + * @return + */ + UserExtensionDTO getByUserId(Long userId); + + /** + * 删除用户扩展信息简历附件 + * + */ + void deleteUserFile(); +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/service/UserPostalInfoService.java b/backend/src/main/java/com/senmesh/usercenter/user/service/UserPostalInfoService.java new file mode 100644 index 0000000..57d9edb --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/service/UserPostalInfoService.java @@ -0,0 +1,68 @@ +package com.senmesh.usercenter.user.service; + +import java.util.List; + +import com.senmesh.usercenter.user.dto.UserPostalInfoQueryDTO; +import com.senmesh.usercenter.user.dto.UserPostalInfoOperateDTO; +import com.senmesh.usercenter.user.dto.UserPostalInfoDTO; + +/** + * 用户邮寄信息 + * + * @author fzp on 2022-01-19 + */ +public interface UserPostalInfoService { + + /** + * 新增 + * + * @param userPostalInfoOperateDTO + * @return + * @author fzp on 2022-01-19 + */ + Long create(UserPostalInfoOperateDTO userPostalInfoOperateDTO); + + /** + * 修改 + * + * @param userPostalInfoOperateDTO + * @author fzp on 2022-01-19 + */ + void modify(UserPostalInfoOperateDTO userPostalInfoOperateDTO); + + /** + * 删除 + * + * @param id + * @author fzp on 2022-01-19 + */ + void remove(Long id); + + /** + * 查询 + * + * @param userPostalInfoQueryDTO + * @return + * @author fzp on 2022-01-19 + */ + List list(UserPostalInfoQueryDTO userPostalInfoQueryDTO); + + /** + * 分页查询 + * + * @param userPostalInfoQueryDTO + * @return + * @author fzp on 2022-01-19 + */ + void page(UserPostalInfoQueryDTO userPostalInfoQueryDTO); + + /** + * 单个查询 + * + * @param userPostalInfoQueryDTO + * @return + * @author fzp on 2022-01-19 + */ + UserPostalInfoDTO find(UserPostalInfoQueryDTO userPostalInfoQueryDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/service/UserRegisterService.java b/backend/src/main/java/com/senmesh/usercenter/user/service/UserRegisterService.java new file mode 100644 index 0000000..5d42fd2 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/service/UserRegisterService.java @@ -0,0 +1,90 @@ +package com.senmesh.usercenter.user.service; + +import java.util.List; + +import com.senmesh.usercenter.user.dto.UserRegisterQueryDTO; +import com.senmesh.usercenter.user.dto.UserRegisterCodeInfoDTO; +import com.senmesh.usercenter.user.dto.UserRegisterCreateDTO; +import com.senmesh.usercenter.user.dto.UserRegisterCodeDTO; +import com.senmesh.usercenter.user.dto.UserRegisterDTO; +import com.senmesh.usercenter.user.dto.UserRegisterInfoQueryDTO; + +/** + * 用户注册表 + * + * @author sr on 2021-11-16 + */ +public interface UserRegisterService { + + /** + * 查询 + * + * @param userRegisterQueryDTO + * @return + * @author sr on 2021-11-16 + */ + List list(UserRegisterQueryDTO userRegisterQueryDTO); + + /** + * 分页查询 + * @param userRegisterQueryDTO + * @author sr on 2021-11-16 + */ + void page(UserRegisterQueryDTO userRegisterQueryDTO); + + /** + * 单个查询 + * @param userRegisterQueryDTO + * @return + * @author sr on 2021-11-16 + */ + UserRegisterDTO find(UserRegisterQueryDTO userRegisterQueryDTO); + + /** + * 获取注册码(自己) + * @param userRegisterCodeDTO + * @return + * @author sr on 2021-11-16 + */ + String getCode(UserRegisterCodeDTO userRegisterCodeDTO); + + /** + * 获取注册码(指定) + * @param upUserRegisterCodeDTO + * @return + * @author sr on 2021-11-16 + */ + String getCode(UserRegisterCodeInfoDTO upUserRegisterCodeDTO); + + /** + * 创建用户注册信息 + * @param userRegisterCreateDTO + * @return 是否新注册 + * @author sr on 2021-11-16 + */ + boolean create(UserRegisterCreateDTO userRegisterCreateDTO); + + /** + * 查询注册详情 + * @param userRegisterInfoQueryDTO + * @author sr on 2021-11-18 + */ + void page(UserRegisterInfoQueryDTO userRegisterInfoQueryDTO); + + /** + * 解析注册码 + * @param registerCode + * @return + * @author sr on 2022-01-12 + */ + UserRegisterCodeInfoDTO analyRegisterCode(String registerCode); + + /** + * 是否存在注册信息 + * @param userId + * @return + * @author sr on 2022-03-17 + */ + boolean existRegister(Long userId); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/service/UserService.java b/backend/src/main/java/com/senmesh/usercenter/user/service/UserService.java new file mode 100644 index 0000000..8547509 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/service/UserService.java @@ -0,0 +1,387 @@ +package com.senmesh.usercenter.user.service; + +import com.senmesh.security.dto.UserInfoDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailBindDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailLoginDTO; +import com.senmesh.usercenter.dto.OrgUserEditDTO; +import com.senmesh.usercenter.dto.SuperResetPasswordDTO; +import com.senmesh.usercenter.user.dto.*; +import com.senmesh.usercenter.user.login.dto.UserDetailDTO; +import org.apache.ibatis.annotations.Param; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.groups.Default; +import java.util.List; +import java.util.Set; + +/** + * 用户 + * + * @author sr on 2021-05-24 + */ +@Validated(Default.class) +public interface UserService { + + /** + * 修改用户信息 + * + * @param userOperateDTO + * @return + * @author czy on 2021-06-15 + */ + void modify(UserOperateDTO userOperateDTO); + + /** + * 用户注销 + * + * @param reqDTO 点播dto + */ + void userCancel(@Valid UserCancelReqDTO reqDTO); + + /** + * 查询-分页 + * @param userQueryDTO + * @author sr on 2021-11-04 + */ + void page(UserQueryDTO userQueryDTO); + + /** + * 查询 + * + * @param userQueryDTO + * @return + * @author sr on 2021-05-24 + */ + List list(UserQueryDTO userQueryDTO); + + /** + * 根据手机号和用户类型精确查询未注销用户 + * + * @param phone 手机号 + * @param type 用户类型 + * @return 用户列表 + */ + List listUncanceledByExactPhoneAndType(String phone, Integer type); + + /** + * 查询单个 + * @param userQueryDTO + * @return + * @author sr on 2021-11-04 + */ + UserDTO find(UserQueryDTO userQueryDTO); + + /** + * 查询指定用户 + * + * @param userId + * @return + */ + UserDTO get(Long userId); + + /** + * 获取指定用户的扩展状态(实名认证、证件正反面照上传、手机绑定、微信绑定状态) + * + * @param userId + * @return + */ + UserExtendStatusDTO getUserExtendStatus(Long userId); + + /** + * 个人用户(证件)创建 + * + * @param personUserCardCreateDTO + * @return + * @author sr on 2021-06-21 + */ + UserDTO createPersonUser(PersonUserCardCreateDTO personUserCardCreateDTO); + + /** + * 批量-个人用户(证件)创建 + * + * @param personUserCardCreateDTOs + * @return + * @author sr on 2021-06-23 + */ + List batchCreatePersonUser( + List personUserCardCreateDTOs); + + /** + * 个人用户创建/修改 + * 查所有-修改/创建绑定态用户 + * @param personUserPhoneCreateDTO + * @return + * @author sr on 2022-08-02 + */ + UserDetailDTO modifyAndCreatePersonUser(PersonUserPhoneCreateDTO personUserPhoneCreateDTO); + + /** + * 个人用户创建 + * 查绑定态-创建绑定态用户 + * + * @param personUserPhoneCreateDTO + * @return + * @author sr on 2021-06-21 + */ + UserDetailDTO createPersonUser(PersonUserPhoneCreateDTO personUserPhoneCreateDTO); + + /** + * 初始账号密码-自己操作 + * + * @param initUserPasswordDTO + * @author sr on 2021-06-23 + */ + void initUserPassword(InitUserPasswordDTO initUserPasswordDTO); + + /** + * 修改账号 + * @param username + * @author sr on 2021-08-04 + */ + void modifyUsername(String username); + + /** + * 修改密码 + * @param modifyPasswordDTO + * @author sr on 2021-08-04 + */ + void modifyPassword(ModifyPasswordDTO modifyPasswordDTO); + + /** + * 创建企业用户 + * + * @param orgUserCreateDTO + * @return + * @author sr on 2021-06-23 + */ + Long createOrgUser(OrgUserCreateDTO orgUserCreateDTO); + + /** + * 批量创建企业用户 + * 单条失败仅回滚该条,不影响其他条目,返回逐条结果 + * + * @param orgUserCreateDTOs 创建dto列表 + * @return {@link List}<{@link OrgUserCreateResultDTO}> 与入参顺序一一对应 + */ + List batchCreateOrgUser(List orgUserCreateDTOs); + + /** + * 修改企业用户 + * + * @param orgUserModifyDTO + * @return + * @author gxm on 2023-01-03 + */ + void modifyOrgUser(OrgUserModifyDTO orgUserModifyDTO); + + /** + * 获取认证信息对应登录用户 + * + * @param authDetailDTO + * @return + * @author sr on 2021-06-28 + */ + UserDetailDTO loadUser(AuthDetailLoginDTO authDetailDTO); + + + /** + * 个人实名 + * + * @param authenticateUserDTO + * 账号合并抛 ChangeTokenException + * @author sr on 2021-07-06 + */ + void authenticatePersonUser(AuthenticateUserDTO authenticateUserDTO); + + /** + * 激活个人用户(创建用户+实名并激活用户) + * + * @author sr on 2021-06-28 + */ + Long createAndAuthenticatePersonUser(AuthenticateUserDTO authenticateUserDTO); + + /** + * 个人用户自己绑定手机号 + * + * @author sr on 2021-06-28 + */ + void bindPersonPhone(BindPhoneDTO bindPhoneDTO); + + /** + * 直接更新个人用户手机号绑定状态-前置校验在调用方已做过 + * 手机号登录(已校验过验证码)/绑定手机号(已校验过验证码和其他限制校验) + * + * @param userId + * @param phone + * @author sr on 2021-07-02 + */ + void updatePersonPhoneBinding(Long userId, String phone); + + /** + * 分页查询平台用户信息 + * + * @param reqDTO 点播dto + * @return {@link List} + */ + List pagePlatformUser(PlatformUserInfoReqDTO reqDTO); + + /** + * 查询平台用户列表 + * + * @param queryDTO 查询dto + * @return {@link List}<{@link PlatformUserInfoDTO}> + */ + List listPlatformUser(PlatformUserListQueryDTO queryDTO); + + /** + * 检查安全代码 + * + * @param reqDTO + * @return {@link Boolean} + */ + Boolean checkSecurityCode(@Valid CheckSecurityCodeReqDTO reqDTO); + + /** + * 重置密码 + * @param resetPwdDTO + * @author sr on 2021-08-10 + */ + void resetPwd(ResetPwdDTO resetPwdDTO); + + /** + * 查询用户信息 + * + * @param userId + * @param orgId + * @return + * @author sr on 2020-06-11 + */ + UserInfoDTO findUserInfo(@Param("userId") Long userId, @Param("orgId") Long orgId); + + /** + * 绑定用户授权信息 + * @param authDetailBindDTO + * @author sr on 2021-08-23 + */ + void bindUserAuth(AuthDetailBindDTO authDetailBindDTO); + + /** + * 查询单个用户信息(未注销) + * @param userQueryDTO + * @return + * @author sr on 2021-09-02 + */ + UserDTO findUserDTO(UserQueryDTO userQueryDTO); + + /** + * 重置安全码 + * @param resetSecurityCodeDTO + * @author sr on 2021-09-02 + */ + void resetSecurityCode(ResetSecurityCodeDTO resetSecurityCodeDTO); + + /** + * 换绑手机 + * @param changePhoneDTO + * @author sr on 2021-09-10 + */ + void changePhone(ChangePhoneDTO changePhoneDTO); + + /** + * 验证账号是否存在 + * @param userId + * @param username + */ + void checkExistUsername(Long userId, String username); + + /** + * 代管-换绑手机 + * @param superChangePhoneDTO + * @author sr on 2021-09-24 + */ + void changePhone(SuperChangePhoneDTO superChangePhoneDTO); + + /** + * 管理员修改用户信息 + * @param orgUserEditDTO + * @return {@link Boolean} + */ + Boolean modifyOrgUserInfo(OrgUserEditDTO orgUserEditDTO); + + /** + * 超级管理员重置密码 + * + * @param resetPasswordDTO + * @return + */ + String resetOrgUserPassword(SuperResetPasswordDTO resetPasswordDTO); + + /** + * 查询企业负责人信息 + * + * @param userIds + * @return + */ + List personInCharge(Set userIds); + /** + * 验证机构用户是否存在 + */ + boolean existOrgUser(OrgUserCreateDTO orgUserCreateDTO); + + /** + * 通过角色信息查询用户列表 + * @param userQueryByRoleDTO + * @author sr on 2022-05-25 + */ + List listByRole(UserQueryByRoleDTO userQueryByRoleDTO); + + /** + * @description: 通过姓名或手机号查询用户列表 + * @return: 用户信息 + * @author: guixinman + * @param: + */ + List listByRealNameOrPhone(Set realNames, Set phones); + + /** + * 启用用户(系统管理员) + * + * @param reqDTO 操作dto + * @return {@link Boolean} + */ + Boolean enableUser(UserStatusOperateDTO reqDTO); + + /** + * 禁用用户(系统管理员) + * + * @param reqDTO 操作dto + * @return {@link Boolean} + */ + Boolean disableUser(UserStatusOperateDTO reqDTO); + + /** + * 注销用户(系统管理员,直接注销不进入注销申请流程) + * + * @param reqDTO 操作dto + */ + void adminCancelUser(UserStatusOperateDTO reqDTO); + + /** + * 分页查询机构账号信息(系统管理员) + * 一行代表一个机构下的一个账号 + * + * @param queryDTO 查询dto + */ + void pageOrgAccount(OrgAccountQueryDTO queryDTO); + + /** + * 修改用户姓名(系统管理员) + * 平台超管可修改全部用户,机构管理员仅可修改本机构用户 + * + * @param reqDTO 操作dto + * @return {@link Boolean} + */ + Boolean modifyRealName(UserRealNameModifyDTO reqDTO); + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/service/impl/OrgUserServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/user/service/impl/OrgUserServiceImpl.java new file mode 100644 index 0000000..8be1732 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/service/impl/OrgUserServiceImpl.java @@ -0,0 +1,120 @@ +package com.senmesh.usercenter.user.service.impl; + +import java.util.List; + +import org.apache.commons.lang3.BooleanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.common.exception.util.Assert; +import com.senmesh.frame.redis.dto.LockDTO; +import com.senmesh.frame.redis.redisson.RedissonUtils; +import com.senmesh.usercenter.user.dao.OrgUserMapper; +import com.senmesh.usercenter.user.dto.OrgUserDTO; +import com.senmesh.usercenter.user.dto.OrgUserInfoDTO; +import com.senmesh.usercenter.user.dto.OrgUserInfoQueryDTO; +import com.senmesh.usercenter.user.dto.OrgUserOperateDTO; +import com.senmesh.usercenter.user.dto.OrgUserQueryDTO; +import com.senmesh.usercenter.user.entity.OrgUser; +import com.senmesh.usercenter.user.login.dto.OrgDetailDTO; +import com.senmesh.usercenter.user.service.OrgUserService; + +/** @author sr on 2021-05-24 */ +@Service +public class OrgUserServiceImpl implements OrgUserService { + + @Autowired + private OrgUserMapper orgUserMapper; + + + private static final String NORMAL_LOCK_NAME = "orgUser"; + private static final String ADMINISTRATOR_LOCK_NAME = "orgUserAdministrator"; + + private LockDTO getNormalLockDTO(Long orgId, Long userId) { + Assert.isTrue(orgId != null && userId != null, "操作机构用户参数缺失"); + return LockDTO.builder().methodName(NORMAL_LOCK_NAME).tryLockWaitTime(0L) + .arg(orgId.toString()).arg(userId.toString()) + .build(); + } + + private LockDTO getAdministratorLockDTO(Long orgId) { + Assert.notNull(orgId, "操作机构管理员用户参数缺失"); + return LockDTO.builder().methodName(ADMINISTRATOR_LOCK_NAME).tryLockWaitTime(0L) + .arg(orgId.toString()) + .build(); + } + + @Override + @Transactional + public Long create(OrgUserOperateDTO orgUserOperateDTO) { + Long orgId = orgUserOperateDTO.getOrgId(); + Long userId = orgUserOperateDTO.getUserId(); + // 只有true才是管理员 + if (BooleanUtils.isTrue(orgUserOperateDTO.getAdministrator())) { + return createAdministrator(orgId, userId); + } + return createNormal(orgId, userId); + } + + private Long createNormal(Long orgId, Long userId) { + OrgUserQueryDTO orgUserQueryDTO = OrgUserQueryDTO.builder().orgId(orgId).userId(userId).build(); + List orgUserList = orgUserMapper + .listOrgUserDTO(orgUserQueryDTO); + if (!orgUserList.isEmpty()) { + // 存在则直接返回 + return orgUserList.get(0).getId(); + } + // 上锁 + LockDTO lockDTO = getNormalLockDTO(orgId, userId); + try { + Assert.isTrue(RedissonUtils.tryLock(lockDTO), "请勿重复操作关联企业用户"); + // 绑定机构用户,控制绑一次 + orgUserList = orgUserMapper.listOrgUserDTO(orgUserQueryDTO); + if (!orgUserList.isEmpty()) { + // 存在则直接返回 + return orgUserList.get(0).getId(); + } + OrgUser orgUser = OrgUser.builder().orgId(orgId).userId(userId).administrator(Boolean.FALSE).build(); + orgUserMapper.saveEntity(orgUser); + return orgUser.getId(); + } finally { + RedissonUtils.unlock(lockDTO); + } + } + + @Override + public boolean existOrgUser(Long orgId, Long userId) { + // 绑定机构用户,控制绑一次 + List orgUserList = orgUserMapper + .listOrgUserDTO(OrgUserQueryDTO.builder().orgId(orgId).userId(userId).build()); + return !orgUserList.isEmpty(); + } + + private Long createAdministrator(Long orgId, Long userId) { + // 上锁 + LockDTO lockDTO = getAdministratorLockDTO(orgId); + try { + Assert.isTrue(RedissonUtils.tryLock(lockDTO), "请勿重复操作关联企业管理员用户"); + // 绑定机构管理员,控制机构下管理员唯一 + Boolean canCreate = orgUserMapper.checkCreateAdministratorUser(orgId, userId); + Assert.isTrue(canCreate, "无法创建机构管理员(机构管理员唯一),请刷新检查数据"); + OrgUser orgUser = OrgUser.builder().orgId(orgId).userId(userId).administrator(Boolean.TRUE).build(); + orgUserMapper.saveEntity(orgUser); + return orgUser.getId(); + } finally { + RedissonUtils.unlock(lockDTO); + } + } + + @Override + public List list(OrgUserInfoQueryDTO queryDTO) { + return orgUserMapper.list(queryDTO); + } + + @Override + public List listLoginOrgByUser(Long userId, Long orgId) { + return orgUserMapper.listLoginOrgByUser(userId, orgId); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserAuthServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserAuthServiceImpl.java new file mode 100644 index 0000000..4ad3bbd --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserAuthServiceImpl.java @@ -0,0 +1,57 @@ +package com.senmesh.usercenter.user.service.impl; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.usercenter.user.dao.UserAuthMapper; +import com.senmesh.usercenter.user.service.UserAuthService; +import com.senmesh.usercenter.user.dto.UserAuthQueryDTO; +import com.senmesh.usercenter.user.dto.UserAuthDTO; +import com.senmesh.usercenter.user.dto.UserAuthOperateDTO; +import com.senmesh.usercenter.user.entity.UserAuth; +import com.senmesh.usercenter.user.mapstruct.UserAuthMapMapper; +import com.senmesh.common.util.UserContextHolder; + +/** + * @author sr on 2021-05-24 + */ +@Service +public class UserAuthServiceImpl implements UserAuthService { + + @Autowired + private UserAuthMapper userAuthMapper; + + @Override + @Transactional + public Long create(UserAuthOperateDTO userAuthOperateDTO) { + UserAuth userAuth = UserAuthMapMapper.INSTANCE.toEntity(userAuthOperateDTO); + userAuthMapper.saveEntity(userAuth); + return userAuth.getId(); + } + + @Override + public void modify(UserAuthOperateDTO userAuthOperateDTO) { + // TODO Auto-generated method stub + + } + + @Override + public void remove(Long id) { + userAuthMapper.deleteEntity(UserAuth.builder().id(id).build(), + UserContextHolder.getLoginUserId()); + } + + @Override + public List list(UserAuthQueryDTO userAuthQueryDTO) { + userAuthQueryDTO.disablePage(); + return userAuthMapper.listUserAuthDTO(userAuthQueryDTO); + } + + @Override + public void page(UserAuthQueryDTO userAuthQueryDTO) { + userAuthMapper.listUserAuthDTO(userAuthQueryDTO); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserCancelServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserCancelServiceImpl.java new file mode 100644 index 0000000..2a0f468 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserCancelServiceImpl.java @@ -0,0 +1,162 @@ +package com.senmesh.usercenter.user.service.impl; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import javax.annotation.Resource; + +import org.springframework.aop.framework.AopContext; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.common.util.ListUtil; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.config.constant.ConfigConstants; +import com.senmesh.config.dto.ConfigDTO; +import com.senmesh.config.service.ConfigService; +import com.senmesh.frame.redis.aop.annotation.AutoUnLock; +import com.senmesh.frame.redis.dto.LockDTO; +import com.senmesh.frame.redis.redisson.RedissonUtils; +import com.senmesh.sdk.robot.util.RobotUtils; +import com.senmesh.usercenter.user.constant.UserCancelConstants; +import com.senmesh.usercenter.user.dao.UserCancelMapper; +import com.senmesh.usercenter.user.dao.UserMapper; +import com.senmesh.usercenter.user.dto.UserCancelApplyReqDTO; +import com.senmesh.usercenter.user.dto.UserCancelDTO; +import com.senmesh.usercenter.user.dto.UserCancelPageQueryDTO; +import com.senmesh.usercenter.user.entity.UserCancel; +import com.senmesh.usercenter.user.service.UserCancelService; + +import cn.hutool.core.collection.CollUtil; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class UserCancelServiceImpl implements UserCancelService { + + @Resource + private UserCancelMapper userCancelMapper; + + @Resource + private UserMapper userMapper; + + @Resource + private ConfigService configService; + + @Override + public void toNotify() { + List userCancels = userCancelMapper.toNotify(); + if (CollUtil.isEmpty(userCancels)) { + return; + } + RobotUtils.sendDevops("存在账号注销申请未处理,请查询表:uc_user_cancel确认!"); +// List successMsg = Lists.newArrayList(); +// for (UserCancelDTO dto : userCancels) { +// successMsg.add(String.format("【姓名:%s,手机号:%s,身份证:%s】申请账号注销,请前往中台“个人用户管理”页面处理。", +// dto.getRealName(), dto.getPhone(), dto.getCardNo())); +// } +// RobotUtils.sendDevops(String.join("\n", successMsg)); + } + + private List setExcludedOrgIds() { + List excludedOrgIds = new ArrayList<>(); + ConfigDTO configDTO = configService.queryConfigByCode(CommonConstants.PLATFORM_ORG_ID, ConfigConstants.CONFIG_IGNORE_ORG_INFO); + if (configDTO != null && configDTO.getConfigValue() != null) { + try { + excludedOrgIds = JsonUtils.toList(configDTO.getConfigValue(), Long.class); + } catch (Exception e) { + log.info("忽略的机构转换配置错误ignore_org_info:{}", configDTO); + } + } + return excludedOrgIds; + } + + @Override + @Transactional(rollbackFor = Exception.class) + @AutoUnLock + public UserCancelDTO apply(UserCancelApplyReqDTO applyDTO) { + Long existLoginUserId = UserContextHolder.getExistLoginUserId(); + Assert.isTrue( + RedissonUtils.tryLockAutomatically( + LockDTO.builder() + .tryLockWaitTime(0L) + .lockTimeout(60 * 5L) + .arg(existLoginUserId + "") + .methodName("user:cancel:apply") + .build() + ), + "申请注销正在处理, 请稍后再试"); + UserCancelDTO userCancel = find(UserCancelPageQueryDTO.builder().userId(existLoginUserId).build()); + + if (Objects.nonNull(userCancel)) { + return UserCancelDTO.builder().status(userCancel.getStatus()).build(); + } + + userCancelMapper.saveEntity(UserCancel.builder() + .userId(existLoginUserId) + .status(UserCancelConstants.USER_CANCEL_STATUS_APPLY) + .cancellationType(applyDTO.getCancellationType()) + .remark(applyDTO.getRemark()) + .build(), existLoginUserId); + // 发送钉钉消息 + /*UserCancelDTO notifyInfo = userCancelMapper.findNotifyInfo(existLoginUserId); + if (Objects.nonNull(notifyInfo)) { + String notifyMsg = String.format("【姓名:%s,手机号:%s,身份证:%s】申请账号注销,请前往中台“个人用户管理”页面处理。", + notifyInfo.getRealName(), notifyInfo.getPhone(), notifyInfo.getCardNo()); + RobotUtils.sendDevops(notifyMsg); + }*/ + ConfigDTO configDto = configService.getConfigDto("cancellation_audit_enable", CommonConstants.PLATFORM_ORG_ID, Boolean.TRUE); + if (Objects.nonNull(configDto)) { + ((UserCancelServiceImpl) AopContext.currentProxy()).agreeCancel(existLoginUserId); + } + return UserCancelDTO.builder().status(UserCancelConstants.USER_CANCEL_STATUS_APPLY).build(); + } + + @Override + public UserCancelDTO find(UserCancelPageQueryDTO queryDTO) { + queryDTO.disablePage(); + List userCancelDTOs = userCancelMapper.page(queryDTO); + return ListUtil.first(userCancelDTOs); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @AutoUnLock + public UserCancelDTO agreeCancel(Long userId) { + Assert.isTrue( + RedissonUtils.tryLockAutomatically( + LockDTO.builder() + .tryLockWaitTime(0L) + .lockTimeout(60 * 5L) + .arg(userId + "") + .methodName("user:cancel:agreeCancel") + .build() + ), + "用户注销正在处理, 请稍后再试"); + + UserCancelDTO userCancel = find(UserCancelPageQueryDTO.builder().status(UserCancelConstants.USER_CANCEL_STATUS_APPLY).userId(userId).build()); + + if (Objects.isNull(userCancel)) { + return null; + } + + //更新用户为已注销 + userMapper.cancel(userId, UserContextHolder.getExistLoginUserId()); + + UserCancel cancel = UserCancel.builder() + .status(UserCancelConstants.USER_CANCEL_STATUS_SUCCESS) + .build(); + cancel.setId(userCancel.getId()); + userCancelMapper.updateEntitySelective(cancel); + return UserCancelDTO.builder().status(UserCancelConstants.USER_CANCEL_STATUS_SUCCESS).build(); + } + + @Override + public List page(UserCancelPageQueryDTO queryDTO) { + return userCancelMapper.page(queryDTO); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserConfigServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserConfigServiceImpl.java new file mode 100644 index 0000000..c54069d --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserConfigServiceImpl.java @@ -0,0 +1,89 @@ +package com.senmesh.usercenter.user.service.impl; + +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.usercenter.user.dao.UserConfigMapper; +import com.senmesh.usercenter.user.service.UserConfigService; +import com.senmesh.usercenter.user.dto.UserConfigQueryDTO; +import com.senmesh.usercenter.user.dto.UserConfigDTO; +import com.senmesh.usercenter.user.dto.UserConfigOperateDTO; +import com.senmesh.usercenter.user.entity.UserConfig; +import com.senmesh.usercenter.user.mapstruct.UserConfigMapMapper; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.ListUtil; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.common.validation.Create; +import com.senmesh.common.validation.util.ValidateUtils; +import com.senmesh.frame.redis.dto.LockDTO; +import com.senmesh.frame.redis.redisson.RedissonUtils; + +/** + * @author sr on 2021-08-12 + */ +@Service +public class UserConfigServiceImpl implements UserConfigService { + + private static final String USER_CONFIG_LOCK_NAME = "user:config"; + + @Autowired + private UserConfigMapper userConfigMapper; + + private static LockDTO getLockDTO(Long userId, String configCode) { + Assert.isTrue(userId != null && StringUtils.isNotBlank(configCode), "配置参数缺失"); + return LockDTO.builder().methodName(USER_CONFIG_LOCK_NAME).tryLockWaitTime(0L) + .arg(userId.toString()).arg(configCode) + .build(); + } + + @Override + @Transactional + public Long create(UserConfigOperateDTO userConfigOperateDTO) { + ValidateUtils.validateBiz(userConfigOperateDTO, Create.class); + Long userId = userConfigOperateDTO.getUserId(); + String configCode = userConfigOperateDTO.getConfigCode(); + // 上锁 + LockDTO lockDTO = getLockDTO(userId, configCode); + try { + Assert.isTrue(RedissonUtils.tryLock(lockDTO), "该用户配置正在被操作"); + boolean exists = userConfigMapper + .existsEntity(UserConfig.builder().userId(userId).configCode(configCode).build()); + Assert.isTrue(!exists, "该用户配置已存在"); + UserConfig userConfig = UserConfigMapMapper.INSTANCE.toEntity(userConfigOperateDTO); + userConfigMapper.saveEntity(userConfig); + } finally { + RedissonUtils.unlock(lockDTO); + } + + + return null; + } + + @Override + public void modify(UserConfigOperateDTO userConfigOperateDTO) { + + } + + @Override + public void remove(Long id) { + userConfigMapper.deleteEntity(UserConfig.builder().id(id).build(), + UserContextHolder.getLoginUserId()); + } + + @Override + public List list(UserConfigQueryDTO userConfigQueryDTO) { + return userConfigMapper.listUserConfigDTO(userConfigQueryDTO); + } + + public UserConfigDTO find(UserConfigQueryDTO userConfigQueryDTO) { + List userConfigDTOs = + list((UserConfigQueryDTO) userConfigQueryDTO.disablePage()); + return userConfigDTOs.isEmpty() ? null : ListUtil.first(userConfigDTOs); + } + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserExtensionServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserExtensionServiceImpl.java new file mode 100644 index 0000000..c1bd558 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserExtensionServiceImpl.java @@ -0,0 +1,87 @@ +package com.senmesh.usercenter.user.service.impl; + +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.user.dao.UserExtensionMapper; +import com.senmesh.usercenter.user.dto.UserExtensionDTO; +import com.senmesh.usercenter.user.dto.UserExtensionOperateDTO; +import com.senmesh.usercenter.user.entity.UserExtension; +import com.senmesh.usercenter.user.mapstruct.UserExtensionMapMapper; +import com.senmesh.usercenter.user.service.UserExtensionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * @author czy + * @date 2021-06-15 + */ +@Service +public class UserExtensionServiceImpl implements UserExtensionService { + + @Autowired + private UserExtensionMapper userExtensionMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteUserFile() { + Long userId = UserContextHolder.getLoginUserId(); + UserExtensionDTO userExtensionDTO = userExtensionMapper.getByUserId(userId); + if(userExtensionDTO == null){ + return; + } + userExtensionDTO.setFileName(null); + userExtensionDTO.setFileCode(null); + UserExtension userExtension = UserExtensionMapMapper.INSTANCE.toEntity(userExtensionDTO); + int i = userExtensionMapper.updateEntity(userExtension, UserContextHolder.getLoginUserId()); + Assert.isTrue(i == 1, "修改扩展信息失败!"); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Long edit(UserExtensionOperateDTO userExtensionOperateDTO) { + Long userId = UserContextHolder.getLoginUserId(); + UserExtensionDTO userExtensionDTO = userExtensionMapper.getByUserId(userId); + Long userExtensionId = null; + if(userExtensionDTO == null){ + UserExtension userExtension = UserExtensionMapMapper.INSTANCE.toEntity(userExtensionOperateDTO); + userExtension.setUserId(UserContextHolder.getLoginUserId()); + userExtensionMapper.saveEntity(userExtension); + userExtensionId = userExtension.getId(); + }else{ + userExtensionId = userExtensionDTO.getId(); + UserExtension userExtension = UserExtensionMapMapper.INSTANCE.toEntity(userExtensionOperateDTO); + userExtension.setId(userExtensionId); + int i = userExtensionMapper + .updateEntitySelective(userExtension, UserContextHolder.getLoginUserId()); + Assert.isTrue(i == 1, "修改扩展信息失败!"); + } + return userExtensionId; + } + + @Override + public void createOrEditByUserId(UserExtensionOperateDTO userExtensionOperateDTO, Long userId) { + if (userId == null) { + throw new BusinessException("用户id缺失"); + } + UserExtensionDTO userExtensionDTO = userExtensionMapper.getByUserId(userId); + + if(userExtensionDTO == null){ + UserExtension userExtension = UserExtensionMapMapper.INSTANCE.toEntity(userExtensionOperateDTO); + userExtension.setUserId(userId); + userExtensionMapper.saveEntity(userExtension); + }else{ + UserExtension userExtension = UserExtensionMapMapper.INSTANCE.toEntity(userExtensionOperateDTO); + userExtension.setId(userExtensionDTO.getId()); + int i = userExtensionMapper + .updateEntitySelective(userExtension, UserContextHolder.getLoginUserId()); + Assert.isTrue(i == 1, "修改扩展信息失败!"); + } + } + + @Override + public UserExtensionDTO getByUserId(Long userId) { + return userExtensionMapper.getByUserId(userId); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserMergeImpl.java b/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserMergeImpl.java new file mode 100644 index 0000000..ef4b965 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserMergeImpl.java @@ -0,0 +1,127 @@ +package com.senmesh.usercenter.user.service.impl; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.google.common.collect.Sets; +import com.senmesh.common.exception.ChangeTokenException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.sensitive.SensitiveInfoUtils; +import com.senmesh.mq.util.MqSendUtils; +import com.senmesh.security.jwt.JwtTokenUtils; +import com.senmesh.usercenter.common.mq.constant.UcMqConstants; +import com.senmesh.usercenter.user.dao.UserAuthMapper; +import com.senmesh.usercenter.user.dao.UserMapper; +import com.senmesh.usercenter.user.dto.ChangePhoneMqDTO; +import com.senmesh.usercenter.user.dto.UserAuthDTO; +import com.senmesh.usercenter.user.dto.UserAuthQueryDTO; +import com.senmesh.usercenter.user.dto.UserDTO; +import com.senmesh.usercenter.user.dto.UserQueryDTO; +import com.senmesh.usercenter.user.entity.User; + +import lombok.extern.slf4j.Slf4j; + +@Service +@Slf4j +public class UserMergeImpl { + + @Autowired + private UserMapper userMapper; + + @Autowired + private UserAuthMapper userAuthMapper; + + @Transactional(noRollbackFor = ChangeTokenException.class) + public void mergePersonUser(Long existUserId, Long currentUserId) { + Long authenticatedUserId = checkAuthenticate(existUserId, currentUserId); + Long phoneUserId = checkPhone(existUserId, currentUserId); + checkAuth(existUserId, currentUserId); + // 身份证(实名) 》 绑定手机号 》当前用户 + Long retainUserId = authenticatedUserId != null ? authenticatedUserId + : phoneUserId != null ? phoneUserId : currentUserId; + if (phoneUserId != null && !retainUserId.equals(phoneUserId)) { + // 存在绑定手机用户,绑定用户不是保留用户,更新手机号到保留用户 + userMapper.mergeUser(retainUserId, phoneUserId); + } + + boolean deleteCurrent = retainUserId.equals(existUserId); + // 删除用户 + Long deletedUserId = deleteCurrent ? currentUserId : existUserId; + userMapper.deleteEntity(User.builder().id(deletedUserId).proxyBy(retainUserId).build()); + log.info("合并删除用户:{},保留用户:{}", deletedUserId, retainUserId); + // 授权信息迁移到保留用户 + userAuthMapper.mergeAuth(retainUserId, deletedUserId); + // 当原手机号绑定用户与保留用户不一致时 + if (!retainUserId.equals(phoneUserId)) { + User retainUser = userMapper.getById(retainUserId); + if (retainUser.getPhoneBinding()) { + // 发送异步消息关联简历 + MqSendUtils.send(UcMqConstants.CHANGE_PHONE_RESUME, + ChangePhoneMqDTO.builder().userId(retainUserId).phone(retainUser.getPhone()).build()); + } + } + // 替换token + JwtTokenUtils.changeToken(retainUserId); + } + + private Map getUserMap(Long existUserId, Long currentUserId) { + // 查询用户信息 + List userDTOs = userMapper + .listUserDTO((UserQueryDTO) UserQueryDTO.builder() + .ids(Sets.newHashSet(existUserId, currentUserId)).build().disablePage()); + return userDTOs.stream().collect(Collectors.toMap(UserDTO::getId, userDTO -> userDTO)); + } + + private Long checkAuthenticate(Long existUserId, Long currentUserId) { + Map userMap = this.getUserMap(existUserId, currentUserId); + UserDTO existUser = userMap.get(existUserId); + UserDTO currentUser = userMap.get(currentUserId); + // TODO 以身份证为准,还是以实名状态为准??? + boolean hasExistCardNo = StringUtils.isNotBlank(existUser.getCardNo()); + boolean hasCurrentCardNo = StringUtils.isNotBlank(currentUser.getCardNo()); + Assert.isTrue(!hasExistCardNo || !hasCurrentCardNo, "合并账号失败,存在不同实名信息用户"); + if (hasExistCardNo) { + return existUser.getId(); + } + if (hasCurrentCardNo) { + return currentUser.getId(); + } + return null; + } + + private Long checkPhone(Long existUserId, Long currentUserId) { + Map userMap = this.getUserMap(existUserId, currentUserId); + UserDTO existUser = userMap.get(existUserId); + UserDTO currentUser = userMap.get(currentUserId); + Assert.isTrue(!existUser.getPhoneBinding() || !currentUser.getPhoneBinding(), String.format("身份信息已被手机号%s绑定,请使用绑定手机号登录。", SensitiveInfoUtils.mobilePhone2(existUser.getPhone()))); + if (existUser.getPhoneBinding()) { + return existUser.getId(); + } + if (currentUser.getPhoneBinding()) { + return currentUser.getId(); + } + return null; + } + + private void checkAuth(Long existUserId, Long currentUserId) { + // 查询用户授权信息,相同maintype两用户都有,就不允许合并 + List userAuthDTOs = + userAuthMapper.listUserAuthDTO((UserAuthQueryDTO) UserAuthQueryDTO.builder() + .userIds(Sets.newHashSet(existUserId, currentUserId)).build().disablePage()); + + // authMainType:userId + Map> map = + userAuthDTOs.stream().collect(Collectors.groupingBy(UserAuthDTO::getAuthMainType, + Collectors.mapping(UserAuthDTO::getUserId, Collectors.toSet()))); + map.entrySet().forEach(entry -> Assert.isTrue(entry.getValue().size() <= 1, "合并账号失败,存在不同授权信息")); + + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserPostalInfoServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserPostalInfoServiceImpl.java new file mode 100644 index 0000000..d9eab97 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserPostalInfoServiceImpl.java @@ -0,0 +1,82 @@ +package com.senmesh.usercenter.user.service.impl; + +import java.util.List; + +import com.senmesh.usercenter.user.mapstruct.UserPostalInfoMapMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.usercenter.user.dao.UserPostalInfoMapper; +import com.senmesh.usercenter.user.service.UserPostalInfoService; +import com.senmesh.usercenter.user.dto.UserPostalInfoQueryDTO; +import com.senmesh.usercenter.user.dto.UserPostalInfoDTO; +import com.senmesh.usercenter.user.dto.UserPostalInfoOperateDTO; +import com.senmesh.usercenter.user.entity.UserPostalInfo; + +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.common.util.ListUtil; + +/** + * @author fzp on 2022-01-19 + */ +@Service +public class UserPostalInfoServiceImpl implements UserPostalInfoService { + + @Autowired + private UserPostalInfoMapper userPostalInfoMapper; + + @Override + @Transactional + public Long create(UserPostalInfoOperateDTO userPostalInfoOperateDTO) { + UserPostalInfo userPostalInfo = UserPostalInfoMapMapper.INSTANCE.toEntity(userPostalInfoOperateDTO); + userPostalInfoMapper.saveEntity(userPostalInfo); + + // 如果当前数据是默认,则该用户的其它数据取消默认 + if(userPostalInfo.getDefaulted()){ + Long userId = UserContextHolder.getLoginUserId(); + userPostalInfoMapper.cancelDefaultedById(userPostalInfo.getId(), userId); + } + return userPostalInfo.getId(); + } + + @Override + @Transactional + public void modify(UserPostalInfoOperateDTO userPostalInfoOperateDTO) { + UserPostalInfo userPostalInfo = UserPostalInfoMapMapper.INSTANCE.toEntity(userPostalInfoOperateDTO); + userPostalInfoMapper.updateEntitySelective(userPostalInfo); + + // 如果当前数据是默认,则该用户的其它数据取消默认 + if(userPostalInfo.getDefaulted()){ + Long userId = UserContextHolder.getLoginUserId(); + userPostalInfoMapper.cancelDefaultedById(userPostalInfo.getId(),userId); + } + } + + @Override + @Transactional + public void remove(Long id) { + userPostalInfoMapper.deleteEntity(UserPostalInfo.builder().id(id).build(), + UserContextHolder.getLoginUserId()); + } + + @Override + public List list(UserPostalInfoQueryDTO userPostalInfoQueryDTO) { + userPostalInfoQueryDTO.disablePage(); + userPostalInfoQueryDTO.setCreateBy(UserContextHolder.getLoginUserId()); + return userPostalInfoMapper.listUserPostalInfoDTO(userPostalInfoQueryDTO); + } + + @Override + public void page(UserPostalInfoQueryDTO userPostalInfoQueryDTO) { + userPostalInfoQueryDTO.setCreateBy(UserContextHolder.getLoginUserId()); + userPostalInfoMapper.listUserPostalInfoDTO(userPostalInfoQueryDTO); + } + + @Override + public UserPostalInfoDTO find(UserPostalInfoQueryDTO userPostalInfoQueryDTO) { + List userPostalInfoDTOs = this.list(userPostalInfoQueryDTO); + return userPostalInfoDTOs.isEmpty() ? null : ListUtil.first(userPostalInfoDTOs); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserRegisterServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserRegisterServiceImpl.java new file mode 100644 index 0000000..4de900b --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserRegisterServiceImpl.java @@ -0,0 +1,187 @@ +package com.senmesh.usercenter.user.service.impl; + +import java.util.List; +import java.util.Optional; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.senmesh.common.AlitaResult; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.ListUtil; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.frame.redis.aop.annotation.AutoUnLock; +import com.senmesh.frame.redis.dto.LockDTO; +import com.senmesh.frame.redis.redisson.RedissonUtils; +import com.senmesh.mq.util.MqSendUtils; +import com.senmesh.security.util.UserLoginUtils; +import com.senmesh.usercenter.common.dto.SlickParamCreateDTO; +import com.senmesh.usercenter.common.service.SlickParamService; +import com.senmesh.usercenter.dto.IUserDetail; +import com.senmesh.usercenter.sys.service.DomainService; +import com.senmesh.usercenter.user.dao.UserRegisterMapper; +import com.senmesh.usercenter.user.dto.UserRegisterCodeDTO; +import com.senmesh.usercenter.user.dto.UserRegisterCodeInfoDTO; +import com.senmesh.usercenter.user.dto.UserRegisterCreateDTO; +import com.senmesh.usercenter.user.dto.UserRegisterDTO; +import com.senmesh.usercenter.user.dto.UserRegisterInfoQueryDTO; +import com.senmesh.usercenter.user.dto.UserRegisterQueryDTO; +import com.senmesh.usercenter.user.entity.UserRegister; +import com.senmesh.usercenter.user.login.dto.UserDetailDTO; +import com.senmesh.usercenter.user.mapstruct.UserRegisterMapMapper; +import com.senmesh.usercenter.user.service.UserRegisterService; +import com.senmesh.usercenter.user.util.UserRegisterUtils; +import com.senmesh.usercenter.userprod.constant.UcMqSelfConstants; + +/** + * @author sr on 2021-11-16 + */ +@Service +public class UserRegisterServiceImpl implements UserRegisterService { + + @Autowired + private UserRegisterMapper userRegisterMapper; + + @Autowired + private DomainService domainService; + + @Autowired + private SlickParamService slickParamService; + + private static final String LOCK_NAME = "user:register"; + + public static LockDTO getLockDTO(Integer platformCode, Long userId) { + Assert.isTrue(platformCode != null && userId != null, "手机号不能为空"); + return LockDTO.builder().methodName(LOCK_NAME).tryLockWaitTime(0L) + .arg(platformCode.toString()) + .arg(userId.toString()) + .build(); + } + + @Override + public List list(UserRegisterQueryDTO userRegisterQueryDTO) { + userRegisterQueryDTO.disablePage(); + return userRegisterMapper.listUserRegisterDTO(userRegisterQueryDTO); + } + + @Override + public void page(UserRegisterQueryDTO userRegisterQueryDTO) { + userRegisterMapper.listUserRegisterDTO(userRegisterQueryDTO); + } + + @Override + public UserRegisterDTO find(UserRegisterQueryDTO userRegisterQueryDTO) { + List userRegisterDTOs = this.list(userRegisterQueryDTO); + return userRegisterDTOs.isEmpty() ? null : ListUtil.first(userRegisterDTOs); + } + + @Override + public String getCode(UserRegisterCodeDTO userRegisterCodeDTO) { + IUserDetail userDetail = UserContextHolder.getExistLoginUser(); + UserRegisterCodeInfoDTO codeDTO = UserRegisterMapMapper.INSTANCE.toDto(userRegisterCodeDTO); + codeDTO.setInviterId(userDetail.getId()); + codeDTO.setInviterType(userDetail.getType()); + codeDTO.setInviterOrgId(userDetail.getOrgId()); + codeDTO.setPlatformCode(dealPlatformCode(userRegisterCodeDTO.getPlatformCode())); + return slickParamService.create(SlickParamCreateDTO.builder().paramData(codeDTO).build()) + .getUniqueCode(); + } + + + + /** + * 不传应用编码时,取请求host所属应用编码 + * @param platformCode + * @return + * @author sr on 2021-11-16 + */ + private Integer dealPlatformCode(Integer platformCode) { + return Optional.ofNullable(platformCode).orElseGet(() -> domainService.findPlatformCode()); + } + + @Override + public String getCode(UserRegisterCodeInfoDTO codeDTO) { + // 验证邀请人用户信息是否正确 + AlitaResult userDetailDTO = UserLoginUtils.findUserDetailDTOResult( + UserRegisterMapMapper.INSTANCE.toDto(codeDTO)); + Assert.isTrue(userDetailDTO.getSuccess(), "邀请人信息异常", userDetailDTO.getMsg()); + // 生成邀请码 + codeDTO.setPlatformCode(dealPlatformCode(codeDTO.getPlatformCode())); + return slickParamService.create(SlickParamCreateDTO.builder().paramData(codeDTO).build()) + .getUniqueCode(); + } + + @Override + public UserRegisterCodeInfoDTO analyRegisterCode(String registerCode) { + if (StringUtils.isBlank(registerCode)) { + return null; + } + // 兼容老的注册邀请码,新的注册码是uuid + if (registerCode.length() > 32) { + return UserRegisterUtils.parseCode(registerCode); + } + return slickParamService.parseCode(registerCode, UserRegisterCodeInfoDTO.class); + } + + @Override + @Transactional + @AutoUnLock + public boolean create(UserRegisterCreateDTO userRegisterCreateDTO) { + // 注册码不为空,解析注册码 + UserRegisterCodeInfoDTO codeInfoDTO = analyRegisterCode(userRegisterCreateDTO.getRegisterCode()); + Integer platformCode = null; + if (codeInfoDTO != null) { + platformCode = codeInfoDTO.getPlatformCode(); + } else { + platformCode = domainService.findPlatformCode(); + } + Long userId = userRegisterCreateDTO.getUserId(); + UserRegisterQueryDTO userRegisterQueryDTO = + UserRegisterQueryDTO.builder().platformCode(platformCode).userId(userId).build(); + // 校验用户是否已注册 + UserRegisterDTO userRegisterDTO = find(userRegisterQueryDTO); + if (userRegisterDTO != null) { + return false; + } + // 上锁 + LockDTO lockDTO = getLockDTO(platformCode, userId); + Assert.isTrue(RedissonUtils.tryLockAutomatically(lockDTO), "用户正在被注册"); + // 二次校验 + userRegisterDTO = find(userRegisterQueryDTO); + if (userRegisterDTO != null) { + return false; + } + // 创建注册记录 + UserRegister userRegister = null; + if (codeInfoDTO != null) { + userRegister = UserRegisterMapMapper.INSTANCE.toEntity(codeInfoDTO); + } else { + userRegister = UserRegister.builder().platformCode(platformCode).build(); + } + userRegister.setUserId(userId); + userRegister.setEntrypoint(userRegisterCreateDTO.getEntrypoint()); + userRegisterMapper.saveEntity(userRegister); + // 注册后续处理 + MqSendUtils.send(UcMqSelfConstants.ROUTING_KEY_USER_REGISTER, + UserRegisterMapMapper.INSTANCE.toDto(userRegister)); + return true; + } + + @Override + public void page(UserRegisterInfoQueryDTO userRegisterInfoQueryDTO) { + userRegisterMapper.listUserRegisterInfoDTO(userRegisterInfoQueryDTO); + } + + @Override + public boolean existRegister(Long userId) { + Integer platformCode = domainService.findPlatformCode(); + UserRegisterQueryDTO userRegisterQueryDTO = + UserRegisterQueryDTO.builder().platformCode(platformCode).userId(userId).build(); + // 校验用户是否已注册 + UserRegisterDTO userRegisterDTO = find(userRegisterQueryDTO); + return userRegisterDTO != null; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserServiceImpl.java b/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..8745a40 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/service/impl/UserServiceImpl.java @@ -0,0 +1,1147 @@ +package com.senmesh.usercenter.user.service.impl; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; + +import javax.annotation.Resource; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.aop.framework.AopContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import com.google.common.collect.Lists; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.exception.ChangeTokenException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.exception.util.ExceptionUtils; +import com.senmesh.common.util.ListUtil; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.common.validation.util.ValidateUtils; +import com.senmesh.frame.redis.aop.annotation.AutoUnLock; +import com.senmesh.frame.redis.dto.LockDTO; +import com.senmesh.frame.redis.redisson.RedissonUtils; +import com.senmesh.mq.util.MqSendUtils; +import com.senmesh.security.dto.UserInfoDTO; +import com.senmesh.security.jwt.JwtTokenUtils; +import com.senmesh.security.util.PasswordUtils; +import com.senmesh.security.util.UserDisabledCache; +import com.senmesh.usercenter.auth.constant.AuthTypeEnum; +import com.senmesh.usercenter.auth.dto.AuthDetailBindDTO; +import com.senmesh.usercenter.auth.dto.AuthDetailLoginDTO; +import com.senmesh.usercenter.auth.service.AuthDetailService; +import com.senmesh.usercenter.common.mq.constant.UcMqConstants; +import com.senmesh.usercenter.dto.OrgUserEditDTO; +import com.senmesh.usercenter.dto.SuperResetPasswordDTO; +import com.senmesh.usercenter.user.constant.UserConfigConstants; +import com.senmesh.usercenter.user.constant.UserStatusEnum; +import com.senmesh.usercenter.user.constant.UserTypeEnum; +import com.senmesh.usercenter.user.dao.UserMapper; +import com.senmesh.usercenter.user.dto.AuthenticateUserDTO; +import com.senmesh.usercenter.user.dto.BindPhoneDTO; +import com.senmesh.usercenter.user.dto.ChangePhoneDTO; +import com.senmesh.usercenter.user.dto.ChangePhoneMqDTO; +import com.senmesh.usercenter.user.dto.CheckSecurityCodeReqDTO; +import com.senmesh.usercenter.user.dto.InitUserPasswordDTO; +import com.senmesh.usercenter.user.dto.ModifyPasswordDTO; +import com.senmesh.usercenter.user.dto.OrgAccountDTO; +import com.senmesh.usercenter.user.dto.OrgAccountQueryDTO; +import com.senmesh.usercenter.user.dto.OrgUserCreateDTO; +import com.senmesh.usercenter.user.dto.OrgUserCreateResultDTO; +import com.senmesh.usercenter.user.dto.OrgUserModifyDTO; +import com.senmesh.usercenter.user.dto.OrgUserOperateDTO; +import com.senmesh.usercenter.user.dto.PersonUserCardCreateDTO; +import com.senmesh.usercenter.user.dto.PersonUserCardCreateResultDTO; +import com.senmesh.usercenter.user.dto.PersonUserPhoneCreateDTO; +import com.senmesh.usercenter.user.dto.PlatformUserInfoDTO; +import com.senmesh.usercenter.user.dto.PlatformUserInfoReqDTO; +import com.senmesh.usercenter.user.dto.PlatformUserListQueryDTO; +import com.senmesh.usercenter.user.dto.ResetPwdDTO; +import com.senmesh.usercenter.user.dto.ResetSecurityCodeDTO; +import com.senmesh.usercenter.user.dto.SelectUserDTO; +import com.senmesh.usercenter.user.dto.SuperChangePhoneDTO; +import com.senmesh.usercenter.user.dto.UserAuthOperateDTO; +import com.senmesh.usercenter.user.dto.UserAuthQueryDTO; +import com.senmesh.usercenter.user.dto.UserCancelReqDTO; +import com.senmesh.usercenter.user.dto.UserConfigDTO; +import com.senmesh.usercenter.user.dto.UserConfigQueryDTO; +import com.senmesh.usercenter.user.dto.UserDTO; +import com.senmesh.usercenter.user.dto.UserDetailQueryDTO; +import com.senmesh.usercenter.user.dto.UserExtendStatusDTO; +import com.senmesh.usercenter.user.dto.UserExtensionOperateDTO; +import com.senmesh.usercenter.user.dto.UserOperateDTO; +import com.senmesh.usercenter.user.dto.UserQueryByRoleDTO; +import com.senmesh.usercenter.user.dto.UserQueryDTO; +import com.senmesh.usercenter.user.dto.UserRealNameModifyDTO; +import com.senmesh.usercenter.user.dto.UserStatusOperateDTO; +import com.senmesh.usercenter.user.entity.User; +import com.senmesh.usercenter.user.login.dto.UserDetailDTO; +import com.senmesh.usercenter.user.mapstruct.UserMapMapper; +import com.senmesh.usercenter.user.phone.util.PhoneCodeUtils; +import com.senmesh.usercenter.user.service.OrgUserService; +import com.senmesh.usercenter.user.service.UserAuthService; +import com.senmesh.usercenter.user.service.UserConfigService; +import com.senmesh.usercenter.user.service.UserExtensionService; +import com.senmesh.usercenter.user.service.UserService; +import com.senmesh.usercenter.user.util.UserUtils; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author sr on 2021-05-24 + */ +@Service +@Slf4j +@Lazy +public class UserServiceImpl implements UserService { + + private static final String PHONE_LOCK_NAME = "user:phone"; + private static final String CARD_NO_LOCK_NAME = "user:cardno"; + private static final String USERNAME_LOCK_NAME = "user:username"; + private static final String AUTH_LOCK_NAME = "user:auth"; + private static final int BATCH_CREATE_ORG_USER_LIMIT = 500; + + @Resource + private UserMapper userMapper; + + @Autowired + private OrgUserService orgUserService; + + @Autowired + private AuthDetailService authDetailService; + + @Autowired + private UserAuthService userAuthService; + + @Autowired + private UserMergeImpl userMergeImpl; + + @Autowired + private UserConfigService userConfigService; + + @Autowired + private UserExtensionService userExtensionService; + + + public static LockDTO getPhoneLockDTO(Integer userType, String phone) { + Assert.notBlank(phone, "手机号不能为空"); + return LockDTO.builder().methodName(PHONE_LOCK_NAME).tryLockWaitTime(0L) + .arg(userType.toString()) + .arg(phone) + .build(); + } + + public static LockDTO getCardNoLockDTO(String cardNo) { + Assert.notBlank(cardNo, "证件号码不能为空"); + return LockDTO.builder().methodName(CARD_NO_LOCK_NAME).tryLockWaitTime(0L).arg(cardNo) + .build(); + } + + public static LockDTO getUsernameLockDTO(String username) { + Assert.notBlank(username, "用户账号不能为空"); + return LockDTO.builder().methodName(USERNAME_LOCK_NAME).tryLockWaitTime(0L).arg(username) + .build(); + } + + private LockDTO getAuthLockDTO(String uniqueId) { + Assert.notBlank(uniqueId, "授权唯一标识不能为空"); + return LockDTO.builder().methodName(AUTH_LOCK_NAME).tryLockWaitTime(0L).arg(uniqueId) + .build(); + } + + + @Override + @AutoUnLock + @Transactional + public Long createOrgUser(OrgUserCreateDTO companyUserCreateDTO) { + ValidateUtils.validateBiz(companyUserCreateDTO); + if (StringUtils.isNotBlank(companyUserCreateDTO.getEmail())) { + if (!ValidateUtils.checkEmail(companyUserCreateDTO.getEmail())) { + throw new BusinessException("邮箱格式不正确"); + } + } + String phone = companyUserCreateDTO.getPhone(); + Long orgId = companyUserCreateDTO.getOrgId(); + Integer userType = UserTypeEnum.ORG.getType(); + // 判断用户是否存在 + UserQueryDTO userQueryDTO = (UserQueryDTO) UserQueryDTO.builder() + .type(userType).phone(phone).build().disablePage(); + UserDTO userDTO = this.findUserDTO(userQueryDTO); + Long userId = null; + if (userDTO != null) { + userId = userDTO.getId(); + } + if (userId == null) { + // 上锁 + LockDTO lockDTO = getPhoneLockDTO(userType, phone); + Assert.isTrue(RedissonUtils.tryLockAutomatically(lockDTO), "该手机号企业用户信息正在被操作"); + // 根据手机号获取企业用户 + userDTO = this.findUserDTO(userQueryDTO); + // 用户不存在 + if (userDTO == null) { + User companyUser = UserMapMapper.INSTANCE.toCreateCompanyUser(companyUserCreateDTO); + // 设置通用初始状态数据 + UserUtils.setInitToCreateUser(companyUser); + UserUtils.setInitUserNameAndPasswordToCreateUser(companyUser,companyUserCreateDTO.getAdministrator()); + userMapper.saveEntity(companyUser); + userId = companyUser.getId(); + } else { + userId = userDTO.getId(); + } + } + Assert.isTrue(!orgUserService.existOrgUser(orgId, userId), "手机号已存在,不能重复添加"); + + userExtensionService.createOrEditByUserId(UserExtensionOperateDTO.builder().wechatQrCode(companyUserCreateDTO.getWechatQrCode()).build(), userId); + // 创建机构用户关联 + orgUserService.create(OrgUserOperateDTO.builder() + .orgId(orgId) + .userId(userId) + .administrator(companyUserCreateDTO.getAdministrator()) + .build()); + return userId; + } + + @Override + public List batchCreateOrgUser(List orgUserCreateDTOs) { + Assert.isTrue(CollectionUtils.isNotEmpty(orgUserCreateDTOs), "创建列表不能为空"); + Assert.isTrue(orgUserCreateDTOs.size() <= BATCH_CREATE_ORG_USER_LIMIT, + "单次批量创建不能超过" + BATCH_CREATE_ORG_USER_LIMIT + "条"); + List resultDTOs = + Lists.newArrayListWithExpectedSize(orgUserCreateDTOs.size()); + // 不开外层事务,逐条走代理调用,单条独立事务+手机号锁,失败仅回滚该条 + UserService proxy = ((UserService) AopContext.currentProxy()); + for (OrgUserCreateDTO createDTO : orgUserCreateDTOs) { + OrgUserCreateResultDTO resultDTO = OrgUserCreateResultDTO.builder() + .phone(createDTO.getPhone()) + .realName(createDTO.getRealName()) + .build(); + try { + resultDTO.setUserId(proxy.createOrgUser(createDTO)); + resultDTO.setSuccess(Boolean.TRUE); + } catch (Exception e) { + resultDTO.setSuccess(Boolean.FALSE); + resultDTO.setMsg(e.getMessage()); + } + resultDTOs.add(resultDTO); + } + return resultDTOs; + } + + @Transactional + @Override + public void modifyOrgUser(OrgUserModifyDTO orgUserModifyDTO) { + if (StringUtils.isNotBlank(orgUserModifyDTO.getPhone())) { + if (!ValidateUtils.isPhone(orgUserModifyDTO.getPhone())) { + throw new BusinessException("手机号格式不正确"); + } + } + + if (StringUtils.isNotBlank(orgUserModifyDTO.getEmail())) { + if (!ValidateUtils.checkEmail(orgUserModifyDTO.getEmail())) { + throw new BusinessException("邮箱格式不正确"); + } + } + + Integer userType = UserTypeEnum.ORG.getType(); + // 判断用户是否存在 + UserQueryDTO userQueryDTO = (UserQueryDTO) UserQueryDTO.builder() + .type(userType).phone(orgUserModifyDTO.getPhone()).build().disablePage(); + UserDTO userDTO = this.findUserDTO(userQueryDTO); + + if (userDTO != null) { + if (orgUserModifyDTO.getId().longValue() != userDTO.getId().longValue()) { + throw new BusinessException("手机号已存在"); + } + } + ; + User user = userMapper.getById(orgUserModifyDTO.getId()); + Assert.notNull(user, "该用户记录不存在"); + + userMapper.updateEntitySelective(User.builder() + .id(orgUserModifyDTO.getId()) + .phone(orgUserModifyDTO.getPhone()) + .realName(orgUserModifyDTO.getRealName()) + .email(orgUserModifyDTO.getEmail()) + .nickname(orgUserModifyDTO.getNickname()) + .updateTime(new Date()) + .updateBy(UserContextHolder.getLoginUserId()) + .build()); + + userExtensionService.createOrEditByUserId(UserExtensionOperateDTO.builder().wechatQrCode(orgUserModifyDTO.getWechatQrCode()).build(), orgUserModifyDTO.getId()); + } + + @Override + @AutoUnLock + @Transactional(propagation = Propagation.REQUIRES_NEW) + public UserDTO createPersonUser(PersonUserCardCreateDTO personUserCardCreateDTO) { + ValidateUtils.validateBiz(personUserCardCreateDTO); + String cardNo = personUserCardCreateDTO.getCardNo(); + // 判断用户是否存在 + UserQueryDTO userQueryDTO = (UserQueryDTO) UserQueryDTO.builder() + .type(UserTypeEnum.PERSON.getType()).cardNo(cardNo).build().disablePage(); + UserDTO userDTO = this.findUserDTO(userQueryDTO); + Long bindOrgId = personUserCardCreateDTO.getBindOrgId(); + if (userDTO != null) { + + if (Boolean.TRUE.equals(userDTO.getAuthenticated())) { + //身份证号码查询实名认证数据后,要记得与用户提交的信息进行比对。姓名与身份证号都一致才算实名认证通过 + if (!StringUtils.equals(personUserCardCreateDTO.getRealName(), userDTO.getRealName())) { + throw new BusinessException("实名认证未通过"); + } + } + + if (bindOrgId != null) { + // 绑定机构 + orgUserService.create(OrgUserOperateDTO.builder().orgId(bindOrgId) + .userId(userDTO.getId()).build()); + } + return userDTO; + } + + // 上锁 + LockDTO lockDTO = getCardNoLockDTO(cardNo); + Assert.isTrue(RedissonUtils.tryLockAutomatically(lockDTO), cardNo + "-该身份证号正在操作"); + // 二次判断用户是否存在 + userDTO = this.findUserDTO(userQueryDTO); + if (userDTO != null) { + if (bindOrgId != null) { + // 绑定机构 + orgUserService.create(OrgUserOperateDTO.builder().orgId(bindOrgId) + .userId(userDTO.getId()).build()); + } + return userDTO; + } + + User personUser = UserMapMapper.INSTANCE.toCreatePersonUser(personUserCardCreateDTO); + this.savePersonUser(personUser); + Long userId = personUser.getId(); + if (bindOrgId != null) { + // 绑定机构 + orgUserService.create(OrgUserOperateDTO.builder().orgId(bindOrgId) + .userId(userId).build()); + } + return UserMapMapper.INSTANCE.toDto(personUser); + } + + @Override + @Transactional + public List batchCreatePersonUser( + List personUserCardCreateDTOs) { + List resultDTOs = + Lists.newArrayListWithExpectedSize(personUserCardCreateDTOs.size()); + for (PersonUserCardCreateDTO personUserCardCreateDTO : personUserCardCreateDTOs) { + PersonUserCardCreateResultDTO resultDTO = + UserMapMapper.INSTANCE.toResultDTO(personUserCardCreateDTO); + try { + UserDTO userDto = + ((UserService) AopContext.currentProxy()).createPersonUser(personUserCardCreateDTO); + resultDTO = UserMapMapper.INSTANCE.toResultDTO(userDto); + resultDTO.setSuccess(true); + resultDTO.setUserId(userDto.getId()); + } catch (Exception e) { + resultDTO.setSuccess(false); + resultDTO.setMsg(e.getMessage()); + } + resultDTOs.add(resultDTO); + } + return resultDTOs; + } + + @Override + public UserDetailDTO modifyAndCreatePersonUser(PersonUserPhoneCreateDTO personUserPhoneCreateDTO) { + String phone = personUserPhoneCreateDTO.getPhone(); + // 查询用户 + List userDetailDTOs = userMapper.listUserDetailDTO( + UserDetailQueryDTO.builder().phone(phone).userType(UserTypeEnum.PERSON.getType()).build()); + UserService userService = ((UserService) AopContext.currentProxy()); + if (userDetailDTOs.size() == 1) { + UserDetailDTO userDetailDTO = userDetailDTOs.get(0); + Long userId = userDetailDTO.getId(); + if (!userDetailDTO.getPhoneBinding()) { + userService.updatePersonPhoneBinding(userId, phone); + userDetailDTO.setPhoneBinding(Boolean.TRUE); + } + return userDetailDTO; + } else { + return userService.createPersonUser(personUserPhoneCreateDTO); + } + } + + @Override + @AutoUnLock + @Transactional(propagation = Propagation.REQUIRES_NEW) + public UserDetailDTO createPersonUser(PersonUserPhoneCreateDTO personUserPhoneCreateDTO) { + // 上锁 + String phone = personUserPhoneCreateDTO.getPhone(); + Integer userType = UserTypeEnum.PERSON.getType(); + LockDTO lockDTO = getPhoneLockDTO(userType, phone); + Assert.isTrue(RedissonUtils.tryLockAutomatically(lockDTO), "手机号正在被操作"); + UserDTO userDTO = this.findUserDTO((UserQueryDTO) UserQueryDTO.builder() + .type(userType).phone(phone).phoneBinding(Boolean.TRUE).build().disablePage()); + if (userDTO != null) { + return UserMapMapper.INSTANCE.toUserDetailDTO(userDTO); + } + User personUser = + User.builder().type(userType).phone(phone).phoneBinding(Boolean.TRUE).build(); + this.savePersonUser(personUser); + Long userId = personUser.getId(); + // 清理其他个人用户未绑定手机号 + userMapper.cleanOtherPersonUserPhone(userId, phone); + // 发送异步消息关联简历 + MqSendUtils.send(UcMqConstants.CHANGE_PHONE_RESUME, + ChangePhoneMqDTO.builder().userId(userId).phone(phone).build()); + return UserMapMapper.INSTANCE.toUserDetailDTO(personUser); + } + + /** + * (请勿随意使用该方法)当前类内部使用 + * + * @param personUser 必须是已通过各种校验的个人用户对象 + * @author sr on 2021-06-24 + */ + private void savePersonUser(User personUser) { + personUser.setType(UserTypeEnum.PERSON.getType()); + // 设置通用初始状态数据 + UserUtils.setInitToCreateUser(personUser); + userMapper.saveEntity(personUser); + } + + @Override + public void checkExistUsername(Long userId, String username) { + Assert.isTrue(!userMapper.existUsername(username, userId), "该账号已存在"); + } + + @Override + @AutoUnLock + @Transactional(propagation = Propagation.REQUIRES_NEW, noRollbackFor = ChangeTokenException.class) + public void initUserPassword(InitUserPasswordDTO initUserPasswordDTO) { + UserUtils.checkApiUser(); + // 用户密码没设置才能设置/账号唯一控制 + Long userId = initUserPasswordDTO.getOperateUserId(); + String password = initUserPasswordDTO.getPassword(); + String repassword = initUserPasswordDTO.getRePassword(); + String username = initUserPasswordDTO.getUsername(); + Assert.isTrue(StringUtils.isNotBlank(password) && password.equals(repassword), "两次密码输入不一致"); + // 上锁 + LockDTO lockDTO = getUsernameLockDTO(username); + Assert.isTrue(RedissonUtils.tryLockAutomatically(lockDTO), "(initUp)当前账号正在操作,请稍后重试"); + checkExistUsername(userId, username); + int num = userMapper.initUserPassword(username, PasswordUtils.encode(password), userId); + Assert.isTrue(num > 0, "账号密码设置失败,请刷新检查数据"); + // 替换token + JwtTokenUtils.changeToken(userId, UserContextHolder.getLoginOrgId()); + } + + @Override + @AutoUnLock + @Transactional(propagation = Propagation.REQUIRES_NEW, noRollbackFor = ChangeTokenException.class) + public void modifyUsername(String username) { + boolean matchUsername = ValidateUtils.matchUsername(username); + Assert.isTrue(matchUsername, "账号格式不正确"); + UserUtils.checkApiUser(); + // 上锁 + LockDTO lockDTO = getUsernameLockDTO(username); + Long userId = UserContextHolder.getExistLoginUserId(); + Assert.isTrue(RedissonUtils.tryLockAutomatically(lockDTO), "(rename)当前账号正在操作,请稍后重试"); + checkExistUsername(userId, username); + int num = userMapper + .updateEntitySelective(User.builder().id(userId).username(username).build(), userId); + Assert.isTrue(num > 0, "账号修改失败,请刷新检查数据"); + // 替换token + JwtTokenUtils.changeToken(userId, UserContextHolder.getLoginOrgId()); + } + + @Override + @Transactional + public void modifyPassword(ModifyPasswordDTO modifyPasswordDTO) { + UserUtils.checkApiUser(); + String oldPassword = modifyPasswordDTO.getOldPassword(); + String newPassword = modifyPasswordDTO.getNewPassword(); + String reNewPassword = modifyPasswordDTO.getReNewPassword(); + Long userId = modifyPasswordDTO.getOperateUserId(); + Assert.isTrue(StringUtils.isNotBlank(newPassword) && newPassword.equals(reNewPassword), + "两次密码输入不一致"); + UserDTO userDTO = + findUserDTO(UserQueryDTO.builder().id(modifyPasswordDTO.getOperateUserId()).build()); + Assert.notNull(userDTO, "未找到对应用户"); + Assert.isTrue(PasswordUtils.match(oldPassword, userDTO.getPassword()), "密码错误"); + int num = userMapper + .updateEntitySelective( + User.builder().id(userId).password(PasswordUtils.encode(newPassword)).build(), userId); + Assert.isTrue(num > 0, "用户密码修改失败,请刷新检查数据"); + } + + @Override + @Transactional + public void modify(UserOperateDTO userOperateDTO) { + Long userId = UserContextHolder.getLoginUserId(); + User existUser = userMapper.getById(userId); + Assert.notNull(existUser, "当前登录信息异常,请退出重新登录"); + User user = UserMapMapper.INSTANCE.toEntity(userOperateDTO); + user.setId(userId); + userMapper.updateEntitySelective(user, userId); + if (UserTypeEnum.PERSON.getType().equals(UserContextHolder.getExistUserType())) { + //查询个人信息是否完善 + try { + if (!StringUtils.isAnyEmpty(existUser.getAvatar(), existUser.getNickname(), existUser.getRealName(), + existUser.getCardNo(), existUser.getAddress(), existUser.getPhone(), existUser.getEmail(), + existUser.getEducation() + "")) { + // 个人信息完善后续处理 +// MqSendUtils.send(UcMqSelfConstants.ROUTING_KEY_USER_ACTIVITY_POINT, +// UserActivityRecordCreateDTO.builder() +// .activityCode(ProdActivityCodeEnum.GRXX.name()) +// .actionId(userId) +// .actionUserId(userId) +// .build()); + } + } catch (Exception e) { + log.info(e.getMessage()); + } + } + + } + + @Override + @AutoUnLock + @Transactional(rollbackFor = Exception.class) + public void userCancel(UserCancelReqDTO reqDTO) { + Assert.isTrue(RedissonUtils + .tryLockAutomatically( + LockDTO.builder().methodName("userCancel").arg(String.valueOf(reqDTO.getUserId())) + .build()), + "该用户正在注销,请勿重复操作"); + //查询用户信息 + Long existLoginOrgId = UserContextHolder.getExistLoginOrgId(); + UserDTO userDTO = userMapper.getUserInfoByOrg(reqDTO.getUserId(), existLoginOrgId); + Assert.notNull(userDTO, "获取用户信息异常,请联系管理员"); + if (Optional.ofNullable(userDTO.getStatus()).orElse(1) + .compareTo(UserStatusEnum.CLOSED.getStatus()) != 0) { + User updateInfo = new User(); + updateInfo.setId(userDTO.getId()); + updateInfo.setStatus(UserStatusEnum.CLOSED.getStatus()); + updateInfo.setEnabled(Boolean.FALSE); + userMapper.updateEntitySelective(updateInfo, UserContextHolder.getLoginUserId()); + // 使该用户已发放的token立即失效 + UserDisabledCache.mark(userDTO.getId(), JwtTokenUtils.getExpiration()); + } + } + + @Override + public void page(UserQueryDTO userQueryDTO) { + userMapper.listUserDTO(userQueryDTO); + } + + @Override + public List list(UserQueryDTO userQueryDTO) { + userQueryDTO.setNeedPage(false); + return userMapper.listUserDTO(userQueryDTO); + } + + @Override + public List listUncanceledByExactPhoneAndType(String phone, Integer type) { + Assert.notBlank(phone, "手机号不能为空"); + Assert.notNull(type, "用户类型不能为空"); + return userMapper.listUncanceledByExactPhoneAndType(phone.trim(), type); + } + + @Override + public UserDTO find(UserQueryDTO userQueryDTO) { + List userDTOs = list(userQueryDTO); + return userDTOs.isEmpty() ? null : ListUtil.first(userDTOs); + } + + @Override + public UserDTO get(Long userId) { + return this.find(UserQueryDTO.builder().id(userId).build()); + } + + @Override + public UserExtendStatusDTO getUserExtendStatus(Long userId) { + UserExtendStatusDTO userExtendStatus = userMapper.getUserExtendStatus(userId); + if (userExtendStatus == null) { + return null; + } + return userExtendStatus; + } + + @Override + @AutoUnLock + @Transactional(propagation = Propagation.REQUIRES_NEW) + public UserDetailDTO loadUser(AuthDetailLoginDTO authDetailLoginDTO) { + // 校验参数 + ValidateUtils.validateBiz(authDetailLoginDTO); + Integer userType = authDetailLoginDTO.getUserType(); + Integer authMainType = AuthTypeEnum.getAuthMainType(authDetailLoginDTO.getAuthTypeCode()); + UserAuthQueryDTO userAuthQueryDTO = (UserAuthQueryDTO) UserAuthQueryDTO.builder() + .authMainType(authMainType) + .uniqueId(authDetailLoginDTO.getUniqueId()) + .userType(userType) + .build() + .disablePage(); + List userDetailDTOs = + userMapper.listAuthUserDetailDTO(userAuthQueryDTO); + int userNum = userDetailDTOs.size(); + Assert.isTrue(userNum <= 1, "授权信息用户数据异常,请联系管理员"); + // 不支持用户授权信息创建 + Assert.isTrue(userNum == 1, "企业用户无对应授权信息"); + // 查到唯一匹配的(企业/个人)用户,直接返回 + return ListUtil.first(userDetailDTOs); + } + + @Override + public UserDTO findUserDTO(UserQueryDTO userQueryDTO) { + userQueryDTO.setUncanceled(Boolean.TRUE); + List userDTOs = userMapper.listUserDTO((UserQueryDTO) (userQueryDTO.disablePage())); + Assert.isTrue(userDTOs.size() <= 1, "用户数据异常,请联系管理员"); + return userDTOs.isEmpty() ? null : userDTOs.get(0); + } + + @Override + @AutoUnLock + @Transactional(noRollbackFor = ChangeTokenException.class, propagation = Propagation.REQUIRES_NEW) + public void authenticatePersonUser(AuthenticateUserDTO authenticateUserDTO) { + ValidateUtils.validateBiz(authenticateUserDTO); + String operateCardNo = authenticateUserDTO.getCardNo(); + Assert.isTrue(UserTypeEnum.PERSON.getType().equals(UserContextHolder.getUserType()), + "只有个人用户可操作"); + // 上锁 + LockDTO lockDTO = getCardNoLockDTO(operateCardNo); + Assert.isTrue(RedissonUtils.tryLockAutomatically(lockDTO), operateCardNo + "-该身份证号正在操作"); + Long currentUserId = UserContextHolder.getLoginUserId(); + User currentUser = userMapper.getById(currentUserId); + if (currentUser.getAuthenticated()) { + Assert.isTrue(currentUser.getCardNo().equals(operateCardNo), "用户已实名,身份证号不一致"); + return; + } + + String currentUserCardNo = currentUser.getCardNo(); + boolean hasCardNo = StringUtils.isNotBlank(currentUserCardNo); + Assert.isTrue(!hasCardNo || currentUserCardNo.equals(operateCardNo), "实名身份证号与用户已有身份证号不一致"); + if (hasCardNo) { + // 有身份证,更新当前用户实名状态 + authenticatePersonUserSelf(authenticateUserDTO, currentUserId); + return; + } + // 当前用户无身份证号 + // 查询身份证号是否有对应用户 + UserQueryDTO userQueryDTO = (UserQueryDTO) UserQueryDTO.builder() + .type(UserTypeEnum.PERSON.getType()).cardNo(operateCardNo).build() + .disablePage(); + UserDTO userDTO = this.findUserDTO(userQueryDTO); + if (userDTO == null) { + // 不存在,则当前用户实名 + authenticatePersonUserSelf(authenticateUserDTO, currentUserId); + return; + } + // 存在不是自己 + Long existUserId = userDTO.getId(); + if (!userDTO.getAuthenticated()) { + // 如果对应身份证号未实名,则更新该用户实名状态 + authenticateUserDTO.setUserId(existUserId); + userMapper.authenticatePersonUser(authenticateUserDTO); + } + //合并账号 + userMergeImpl.mergePersonUser(existUserId, currentUserId); + } + + /** + * 用户自己实名,激活;替换token + * + * @param authenticateUserDTO + * @param currentUserId + * @author sr on 2021-07-07 + */ + private void authenticatePersonUserSelf(AuthenticateUserDTO authenticateUserDTO, Long currentUserId) { + authenticateUserDTO.setUserId(currentUserId); + int num = userMapper.authenticatePersonUser(authenticateUserDTO); + Assert.isTrue(num == 1, "实名失败,请检查数据"); + // 实名后续处理 +// MqSendUtils.send(UcMqSelfConstants.ROUTING_KEY_USER_ACTIVITY_POINT, +// UserActivityRecordCreateDTO.builder() +// .activityCode(ProdActivityCodeEnum.SMRZ.name()) +// .actionId(authenticateUserDTO.getUserId()) +// .actionUserId(authenticateUserDTO.getUserId()) +// .build()); + // 替换token + JwtTokenUtils.changeToken(currentUserId); + } + + @Override + @Transactional + public Long createAndAuthenticatePersonUser(AuthenticateUserDTO authenticateUserDTO) { + ValidateUtils.validateBiz(authenticateUserDTO); + UserDTO userDTO = ((UserService) AopContext.currentProxy()).createPersonUser( + PersonUserCardCreateDTO.builder().realName(authenticateUserDTO.getRealName()) + .phone(authenticateUserDTO.getPhone()) + .cardNo(authenticateUserDTO.getCardNo()).build()); + Long userId = userDTO.getId(); + if (!userDTO.getAuthenticated()) { + int num = userMapper.authenticatePersonUser(authenticateUserDTO); + Assert.isTrue(num == 1, "实名失败,请检查数据"); + // 实名后续处理 +// MqSendUtils.send(UcMqSelfConstants.ROUTING_KEY_USER_ACTIVITY_POINT, +// UserActivityRecordCreateDTO.builder() +// .activityCode(ProdActivityCodeEnum.SMRZ.name()) +// .actionId(authenticateUserDTO.getUserId()) +// .actionUserId(authenticateUserDTO.getUserId()) +// .build()); + } + return userId; + } + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW, noRollbackFor = ChangeTokenException.class) + public void bindPersonPhone(BindPhoneDTO bindPhoneDTO) { + Assert.isTrue(UserTypeEnum.PERSON.getType().equals(UserContextHolder.getUserType()), + "只有个人用户可操作"); + String phone = bindPhoneDTO.getPhone(); + PhoneCodeUtils.matchBiz(bindPhoneDTO); + // 查询绑定手机号个人用户 + UserDTO userDTO = + findUserDTO(UserQueryDTO.builder().type(UserTypeEnum.PERSON.getType()).phone(phone) + .phoneBinding(Boolean.TRUE).build()); + Long userId = UserContextHolder.getLoginUserId(); + if (userDTO == null) { + // 不存在,上锁,二次校验,用户绑定手机号 + ((UserService) AopContext.currentProxy()).updatePersonPhoneBinding(userId, phone); + // 替换token + JwtTokenUtils.changeToken(userId); + } else if (!userDTO.getId().equals(userId)) { + // 不是当前用户,合并账号,比对实名,比对授权信息, + try { + userMergeImpl.mergePersonUser(userDTO.getId(), userId); + } catch (BusinessException e) { + log.info("合并失败:{}", e.getMessage()); + throw new BusinessException("手机号已被其他用户绑定"); + } + + } else { + // 是当前用户不处理,已经绑定成功 + } + } + + + @Override + @AutoUnLock + @Transactional(propagation = Propagation.REQUIRES_NEW, noRollbackFor = ChangeTokenException.class) + public void updatePersonPhoneBinding(Long userId, String phone) { + // 上锁 + Integer userType = UserTypeEnum.PERSON.getType(); + LockDTO lockDTO = getPhoneLockDTO(userType, phone); + Assert.isTrue(RedissonUtils.tryLockAutomatically(lockDTO), userId + "-手机号正在操作"); + UserDTO userDTO = + findUserDTO(UserQueryDTO.builder().type(UserTypeEnum.PERSON.getType()).phone(phone) + .phoneBinding(Boolean.TRUE).build()); + if (userDTO == null) { + // 更新用户手机号 + int num = userMapper.bindingPhone(userId, phone); + // 清理手机号其他未绑定用户 + userMapper.cleanOtherPersonUserPhone(userId, phone); + Assert.isTrue(num == 1, "用户绑定手机号失败,请检查数据"); + } else if (!userDTO.getId().equals(userId)) { + throw new BusinessException("该手机号已被其他用户绑定"); + } else { + // 自己绑定不处理,已经绑定成功 + } + // 发送异步消息关联简历 + MqSendUtils.send(UcMqConstants.CHANGE_PHONE_RESUME, + ChangePhoneMqDTO.builder().userId(userId).phone(phone).build()); + } + + @Override + public List pagePlatformUser(PlatformUserInfoReqDTO reqDTO) { + return userMapper.pagePlatformUser(reqDTO); + } + + @Override + public List listPlatformUser(PlatformUserListQueryDTO queryDTO) { + return userMapper.listPlatformUser(queryDTO); + } + + @Override + @Transactional + public void resetPwd(ResetPwdDTO resetPwdDTO) { + Integer userType = UserContextHolder.getUserType(); + if (userType == null) { + // 匿名访问 + userType = resetPwdDTO.getUserType(); + } + Assert.notNull(userType, "用户类型不能为空"); + PhoneCodeUtils.matchBiz(resetPwdDTO); + String password = resetPwdDTO.getPassword(); + String repassword = resetPwdDTO.getRePassword(); + Assert.isTrue(StringUtils.isNotBlank(password) && password.equals(repassword), "两次密码输入不一致"); + UserDTO userDto = this + .findUserDTO(UserQueryDTO.builder().phone(resetPwdDTO.getPhone()).type(userType).build()); + Assert.notNull(userDto, "未找到匹配用户"); + Long userId = userDto.getId(); + int num = userMapper + .updateEntitySelective( + User.builder().id(userId).password(PasswordUtils.encode(password)).build(), userId); + Assert.isTrue(num > 0, "重置密码失败,请刷新检查数据"); + } + + @Override + public UserInfoDTO findUserInfo(Long userId, Long orgId) { + if (userId == null || orgId == null) { + return null; + } + UserInfoDTO userInfoDTO = userMapper.findUserInfo(userId, orgId); + // 已经初始过密码,就忽略初始密码通知 + Boolean ignoreInitPwd = userInfoDTO.getInitialedPassword(); + if (!ignoreInitPwd) { + UserConfigDTO userConfigDTO = + userConfigService.find(UserConfigQueryDTO.builder().userId(userId) + .configCode(UserConfigConstants.IGNORE_INIT_PWD_CODE).build()); + ignoreInitPwd = userConfigDTO != null + && CommonConstants.CONFIG_TRUE.equals(userConfigDTO.getConfigValue()); + } + userInfoDTO.setIgnoreInitPwd(ignoreInitPwd); + return userInfoDTO; + } + + @Override + @AutoUnLock + @Transactional(propagation = Propagation.REQUIRES_NEW) + public void bindUserAuth(AuthDetailBindDTO authDetailBindDTO) { + ValidateUtils.validateBiz(authDetailBindDTO); + // 创建(或查询)授权明细信息 + authDetailService.create(authDetailBindDTO); + // 查询用户授权中间表是否存在相同用户类型已绑定过 + Integer userType = authDetailBindDTO.getUserType(); + Integer authMainType = AuthTypeEnum.getAuthMainType(authDetailBindDTO.getAuthTypeCode()); + UserAuthQueryDTO userAuthQueryDTO = (UserAuthQueryDTO) UserAuthQueryDTO.builder() + .authMainType(authMainType) + .uniqueId(authDetailBindDTO.getUniqueId()) + .userType(userType) + .build() + .disablePage(); + List userDetailDTOs = + userMapper.listAuthUserDetailDTO(userAuthQueryDTO); + // 有则异常 + int size = userDetailDTOs.size(); + Assert.isTrue(size <= 1, "用户授权信息异常,请联系管理员"); + Long userId = authDetailBindDTO.getUserId(); + userId = userId == null ? UserContextHolder.getExistLoginUserId() : userId; + if (size == 1) { + Assert.isTrue(ListUtil.first(userDetailDTOs).getId().equals(userId), "该授权信息已被其他用户绑定"); + return; + } + // 无则创建用户授权信息 + // 上锁 + String uniqueId = authDetailBindDTO.getUniqueId(); + LockDTO lockDTO = getAuthLockDTO(uniqueId); + Assert.isTrue(RedissonUtils.tryLockAutomatically(lockDTO), "该授权信息正在被操作"); + // 二次校验是否存在 + userDetailDTOs = + userMapper.listAuthUserDetailDTO(userAuthQueryDTO); + Assert.isTrue(userDetailDTOs.isEmpty(), "绑定授权信息失败,请稍后重试"); + userAuthService.create(UserAuthOperateDTO.builder().authMainType(authMainType) + .uniqueId(uniqueId).userId(userId).build()); + } + + + @Override + public Boolean checkSecurityCode(CheckSecurityCodeReqDTO reqDTO) { + Long userId = reqDTO.getUserId(); + User user = userMapper.getById(userId); + Assert.notNull(user, "用户不存在"); + return PasswordUtils.match(reqDTO.getSecurityCode(), user.getSecurityCode()); + } + + @Override + @Transactional + public void resetSecurityCode(ResetSecurityCodeDTO resetSecurityCodeDTO) { + PhoneCodeUtils.matchBiz(resetSecurityCodeDTO); + Assert.isTrue( + resetSecurityCodeDTO.getResecurityCode().equals(resetSecurityCodeDTO.getResecurityCode()), + "两次安全码输入不一致"); + Long userId = UserContextHolder.getExistLoginUserId(); + User existUser = userMapper.getById(userId); + Assert.notNull(existUser, "当前登录信息异常,请退出重新登录"); + userMapper.updateEntitySelective(User.builder().id(userId) + .securityCode(PasswordUtils.encode(resetSecurityCodeDTO.getSecurityCode())).build()); + } + + @Override + @AutoUnLock + @Transactional(propagation = Propagation.REQUIRES_NEW) + public void changePhone(ChangePhoneDTO changePhoneDTO) { + String phone = changePhoneDTO.getPhone(); + Integer userType = UserContextHolder.getExistUserType(); + Long userId = UserContextHolder.getExistLoginUserId(); + PhoneCodeUtils.matchBiz(changePhoneDTO); + this.lockAndCheck(userType, phone); + userMapper.bindingPhone(userId, phone); + if (UserTypeEnum.PERSON.getType().equals(userType)) { + // 发送异步消息 + MqSendUtils.send(UcMqConstants.CHANGE_PHONE, + ChangePhoneMqDTO.builder().userId(userId).phone(phone).build()); + // 发送异步消息关联简历 + MqSendUtils.send(UcMqConstants.CHANGE_PHONE_RESUME, + ChangePhoneMqDTO.builder().userId(userId).phone(phone).build()); + } + } + + private void lockAndCheck(Integer userType, String phone) { + LockDTO lockDTO = getPhoneLockDTO(userType, phone); + Assert.isTrue(RedissonUtils.tryLockAutomatically(lockDTO), "当前手机号正在操作"); + // 未被其它相同用户类型的用户绑定 + UserQueryDTO userQueryDTO = UserQueryDTO.builder() + .phone(phone).type(userType).build(); + if (UserTypeEnum.PERSON.getType().equals(userType)) { + // 个人可能存在未绑定的多条记录 + userQueryDTO.setPhoneBinding(Boolean.TRUE); + } + UserDTO userDTO = this.findUserDTO(userQueryDTO); + Assert.isNull(userDTO, "该手机号已被其他用户绑定"); + } + + @Override + @AutoUnLock + @Transactional + public void changePhone(SuperChangePhoneDTO superChangePhoneDTO) { + ValidateUtils.validateBiz(superChangePhoneDTO); + Long userId = superChangePhoneDTO.getUserId(); + String phone = superChangePhoneDTO.getPhone(); + User existUser = userMapper.getById(userId); + Assert.notNull(existUser, "当前登录信息异常,请退出重新登录"); + lockAndCheck(existUser.getType(), phone); + // 代管-换上去是未绑定状态 + userMapper.updateEntitySelective(User.builder().id(userId).phone(phone).phoneBinding(Boolean.FALSE).build()); + } + + @Override + @Transactional + @AutoUnLock + public Boolean modifyOrgUserInfo(OrgUserEditDTO orgUserEditDTO) { + // 平台超管可修改全部用户,机构管理员仅可修改本机构用户 + Assert.isTrue(UserContextHolder.isSuperior() || UserContextHolder.isAdministrator(), + "当前用户无操作权限"); + ValidateUtils.validateBiz(orgUserEditDTO); + Long userId = orgUserEditDTO.getId(); + this.checkOrgScopeOfOperateUser(userId); + UserDTO userDto = findUserDTO(UserQueryDTO.builder().id(userId).build()); + Assert.notNull(userDto, userId + "-用户不可用"); + Assert.isTrue(!Boolean.TRUE.equals(userDto.getSupeiror()), "不能修改超级管理员账号"); + User user = new User(); + user.setId(userId); + //校验 + String username = orgUserEditDTO.getUsername(); + boolean userFlag = ValidateUtils.matchUsername(username); + Assert.isTrue(userFlag, "账户名格式错误!(长度4-32位,只支持英文字母、数字)"); + //是否已经有重名 + Assert.isTrue(!userMapper.existUsername(username, orgUserEditDTO.getId()), + "账号已存在!"); + user.setUsername(username); + + if (StringUtils.isNotBlank(orgUserEditDTO.getEmail())) { + boolean emailFlag = ValidateUtils.checkEmail(orgUserEditDTO.getEmail()); + Assert.isTrue(emailFlag, "请输入正确格式的邮箱地址"); + } + user.setEmail(orgUserEditDTO.getEmail()); + + if (StringUtils.isNotBlank(orgUserEditDTO.getNickname())) { + boolean nicknameFlag = ValidateUtils.checkNickName(orgUserEditDTO.getNickname()); + Assert.isTrue(nicknameFlag, "中文名格式错误!(长度小于32位,不支持特殊字符)"); + user.setNickname(orgUserEditDTO.getNickname()); + } + user.setRealName(orgUserEditDTO.getRealName()); + + // 用户名上锁 + LockDTO lockDTO = UserServiceImpl.getUsernameLockDTO(username); + Assert.isTrue(RedissonUtils.tryLockAutomatically(lockDTO), "当前用户名正在操作"); + + //手机号码有变化则更新 +/* String phone = orgUserEditDTO.getPhone(); + if (!Objects.equals(phone, userDto.getPhone())) { + lockAndCheck(userDto.getType(), phone); + user.setPhone(orgUserEditDTO.getPhone()); + //代管操作,更新手机号码后,恢复到未绑定状态 + user.setPhoneBinding(Boolean.FALSE); + }*/ + user.setEnabled(orgUserEditDTO.getEnabled()); + return userMapper.updateEntitySelective(user) == 1; + } + + + @Override + public String resetOrgUserPassword(SuperResetPasswordDTO resetPasswordDTO) { + // 平台超管可重置全部用户,机构管理员仅可重置本机构用户 + Assert.isTrue(UserContextHolder.isSuperior() || UserContextHolder.isAdministrator(), + "当前用户无操作权限"); + Long userId = resetPasswordDTO.getUserId(); + this.checkOrgScopeOfOperateUser(userId); + Assert.isTrue(StringUtils + .equals(resetPasswordDTO.getNewPassword(), resetPasswordDTO.getConfirmPassword()) + , "密码输入不一致"); + //更新操作 + String encodedPassword = PasswordUtils.encode(resetPasswordDTO.getNewPassword()); + User user = userMapper.getById(userId); + Assert.notNull(user, "用户不存在"); + Assert.isTrue(!Boolean.TRUE.equals(user.getSupeiror()), "不能重置超级管理员密码"); + Assert.isTrue(!UserStatusEnum.CLOSED.getStatus().equals(user.getStatus()), "已注销账号无需重置密码"); + ExceptionUtils.throwBusinessException( + PasswordUtils.match(resetPasswordDTO.getNewPassword(), user.getPassword()), + "重置密码与原密码一致,无需重置!"); + // 上锁 + LockDTO lockDTO = UserServiceImpl.getUsernameLockDTO(user.getUsername()); + try { + Assert.isTrue(userMapper.updatePassword(userId, encodedPassword, + UserContextHolder.getLoginUserId()) > 0, "数据更新失败"); + } finally { + RedissonUtils.unlock(lockDTO); + } + return resetPasswordDTO.getNewPassword(); + } + + @Override + public List personInCharge(Set userIds) { + return userMapper.personInCharge(userIds); + } + + @Override + public boolean existOrgUser(OrgUserCreateDTO companyUserCreateDTO) { + ValidateUtils.validateBiz(companyUserCreateDTO); + String phone = companyUserCreateDTO.getPhone(); + Integer userType = UserTypeEnum.ORG.getType(); + // 判断用户是否存在 + UserQueryDTO userQueryDTO = (UserQueryDTO) UserQueryDTO.builder() + .type(userType).phone(phone).build().disablePage(); + UserDTO userDTO = this.findUserDTO(userQueryDTO); + if (userDTO == null) { + return false; + } + return orgUserService.existOrgUser(companyUserCreateDTO.getOrgId(), userDTO.getId()); + } + + @Override + public List listByRole(UserQueryByRoleDTO userQueryByRoleDTO) { + return userMapper.listByRole(userQueryByRoleDTO); + } + + @Override + public List listByRealNameOrPhone(Set realNames, Set phones) { + if (CollectionUtils.isEmpty(realNames) && CollectionUtils.isEmpty(phones)) { + return new ArrayList<>(); + } + return userMapper.listByRealNameOrPhone(UserContextHolder.getExistLoginOrgId(), realNames, phones); + } + + @Override + @Transactional + public Boolean enableUser(UserStatusOperateDTO reqDTO) { + // 平台超管可操作全部用户,机构管理员仅可启用本机构用户 + Assert.isTrue(UserContextHolder.isSuperior() || UserContextHolder.isAdministrator(), + "当前用户无操作权限"); + this.checkOrgScopeOfOperateUser(reqDTO.getUserId()); + User user = userMapper.getById(reqDTO.getUserId()); + Assert.notNull(user, "用户不存在"); + Assert.isTrue(!UserStatusEnum.CLOSED.getStatus().equals(user.getStatus()), "已注销账号不可启用"); + // 幂等:已启用直接返回 + if (Boolean.TRUE.equals(user.getEnabled())) { + return true; + } + User updateInfo = User.builder().id(user.getId()).enabled(Boolean.TRUE).build(); + boolean updated = userMapper.updateEntitySelective(updateInfo, UserContextHolder.getLoginUserId()) == 1; + if (updated) { + UserDisabledCache.unmark(user.getId()); + } + return updated; + } + + @Override + @Transactional + public Boolean disableUser(UserStatusOperateDTO reqDTO) { + // 平台超管可操作全部用户,机构管理员仅可禁用本机构用户 + Assert.isTrue(UserContextHolder.isSuperior() || UserContextHolder.isAdministrator(), + "当前用户无操作权限"); + Long operateUserId = UserContextHolder.getExistLoginUserId(); + Long userId = reqDTO.getUserId(); + Assert.isTrue(!userId.equals(operateUserId), "不能禁用当前登录账号"); + this.checkOrgScopeOfOperateUser(userId); + User user = userMapper.getById(userId); + Assert.notNull(user, "用户不存在"); + Assert.isTrue(!Boolean.TRUE.equals(user.getSupeiror()), "不能禁用超级管理员账号"); + Assert.isTrue(!UserStatusEnum.CLOSED.getStatus().equals(user.getStatus()), "已注销账号无需禁用"); + // 幂等:已禁用直接返回 + if (Boolean.FALSE.equals(user.getEnabled())) { + return true; + } + User updateInfo = User.builder().id(user.getId()).enabled(Boolean.FALSE).build(); + boolean updated = userMapper.updateEntitySelective(updateInfo, operateUserId) == 1; + if (updated) { + // 使该用户已发放的token立即失效 + UserDisabledCache.mark(user.getId(), JwtTokenUtils.getExpiration()); + } + return updated; + } + + /** + * 非平台超管(机构管理员)操作他人账号时,校验目标用户属于本机构 + */ + private void checkOrgScopeOfOperateUser(Long userId) { + if (!UserContextHolder.isSuperior()) { + Assert.isTrue( + orgUserService.existOrgUser(UserContextHolder.getExistLoginOrgId(), userId), + "只能操作本机构的用户"); + } + } + + @Override + @AutoUnLock + @Transactional(rollbackFor = Exception.class) + public void adminCancelUser(UserStatusOperateDTO reqDTO) { + Assert.isTrue(UserContextHolder.isSuperior(), "当前用户无操作权限"); + Long operateUserId = UserContextHolder.getExistLoginUserId(); + Long userId = reqDTO.getUserId(); + Assert.isTrue(!userId.equals(operateUserId), "不能注销当前登录账号"); + Assert.isTrue(RedissonUtils.tryLockAutomatically( + LockDTO.builder().methodName("adminCancelUser").arg(String.valueOf(userId)).build()), + "该用户正在注销,请勿重复操作"); + User user = userMapper.getById(userId); + Assert.notNull(user, "用户不存在"); + Assert.isTrue(!Boolean.TRUE.equals(user.getSupeiror()), "不能注销超级管理员账号"); + // 幂等:已注销直接返回 + if (UserStatusEnum.CLOSED.getStatus().equals(user.getStatus())) { + return; + } + Assert.isTrue(userMapper.adminCancel(userId, operateUserId) == 1, "注销失败,请刷新后重试"); + // 使该用户已发放的token立即失效 + UserDisabledCache.mark(userId, JwtTokenUtils.getExpiration()); + } + + @Override + public void pageOrgAccount(OrgAccountQueryDTO queryDTO) { + Assert.isTrue(UserContextHolder.isSuperior(), "当前用户无操作权限"); + userMapper.listOrgAccount(queryDTO); + } + + @Override + @Transactional + public Boolean modifyRealName(UserRealNameModifyDTO reqDTO) { + // 平台超管可修改全部用户姓名,机构管理员仅可修改本机构用户 + Assert.isTrue(UserContextHolder.isSuperior() || UserContextHolder.isAdministrator(), + "当前用户无操作权限"); + this.checkOrgScopeOfOperateUser(reqDTO.getUserId()); + User user = userMapper.getById(reqDTO.getUserId()); + Assert.notNull(user, "用户不存在"); + Assert.isTrue(!UserStatusEnum.CLOSED.getStatus().equals(user.getStatus()), "已注销账号不可修改姓名"); + Assert.isTrue(ValidateUtils.checkRealName(reqDTO.getRealName()), + "姓名格式错误!(长度2-30位,仅支持中文或英文姓名)"); + Assert.isTrue(!StringUtils.equals(reqDTO.getRealName(), user.getRealName()), + "姓名与原姓名一致,无需修改!"); + User updateInfo = User.builder().id(user.getId()).realName(reqDTO.getRealName()).build(); + return userMapper.updateEntitySelective(updateInfo, UserContextHolder.getLoginUserId()) == 1; + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/util/UserRegisterUtils.java b/backend/src/main/java/com/senmesh/usercenter/user/util/UserRegisterUtils.java new file mode 100644 index 0000000..4e55eeb --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/util/UserRegisterUtils.java @@ -0,0 +1,68 @@ +package com.senmesh.usercenter.user.util; + +import org.apache.commons.lang3.StringUtils; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.BusinessException; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.JasyptUtils; +import com.senmesh.security.util.SecurityUtils; +import com.senmesh.usercenter.user.dto.UserRegisterCodeInfoDTO; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author sr on 2021-11-15 + */ +@Slf4j +public class UserRegisterUtils { + + private static final int PLATFORM_CODE_INDEX = 0; + private static final int INVITER_TYPE_INDEX = 1; + private static final int INVITER_ID_INDEX = 2; + private static final int INVITER_ORG_ID_INDEX = 3; + + /** + * 兼容老注册码规则,等老规则生成的注册码没人用时可删除 + * @param registerCode + * @return + * @author sr on 2022-01-12 + */ + @Deprecated + public static UserRegisterCodeInfoDTO parseCode(String registerCode) { + if (StringUtils.isBlank(registerCode)) { + return null; + } + // 解一次码,小程序可能会encode一次 + registerCode = SecurityUtils.decodeURL(registerCode); + registerCode = JasyptUtils.decrypt(registerCode); + Assert.notBlank(registerCode, "非法邀请码"); + String[] codeArray = registerCode.split(CommonConstants.UNDERLINE); + UserRegisterCodeInfoDTO dto = new UserRegisterCodeInfoDTO(); + try { + for (int i = 0; i < codeArray.length; i++) { + switch (i) { + case PLATFORM_CODE_INDEX: + dto.setPlatformCode(Integer.valueOf(codeArray[i])); + break; + case INVITER_TYPE_INDEX: + dto.setInviterType(Integer.valueOf(codeArray[i])); + break; + case INVITER_ID_INDEX: + dto.setInviterId(Long.valueOf(codeArray[i])); + break; + case INVITER_ORG_ID_INDEX: + dto.setInviterOrgId(Long.valueOf(codeArray[i])); + break; + default: + break; + } + } + } catch (Exception e) { + log.error("无效邀请码:{}", registerCode); + throw new BusinessException("无效邀请码"); + } + return dto; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/user/util/UserUtils.java b/backend/src/main/java/com/senmesh/usercenter/user/util/UserUtils.java new file mode 100644 index 0000000..1536167 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/user/util/UserUtils.java @@ -0,0 +1,123 @@ +package com.senmesh.usercenter.user.util; + +import org.apache.commons.lang3.StringUtils; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.util.Assert; +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.common.util.RandomUtils; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.security.util.PasswordUtils; +import com.senmesh.usercenter.user.constant.UserStatusEnum; +import com.senmesh.usercenter.user.constant.UserTypeEnum; +import com.senmesh.usercenter.user.dto.IUserPhoneCodeSms; +import com.senmesh.usercenter.user.entity.User; + +/** + * @author sr on 2021-05-24 + */ +public class UserUtils { + + public static final int NICKNAME_LENGTH = 12; + + public static final String DEFAULT_AVATAR_KEY = "user.default.avatars"; + public static final String DEFAULT_ORG_USER_PASSWORD_KEY = "user.default.password"; + public static final String DEFAULT_ORG_USER_PASSWORD = "ou123567"; + + public static String getDefaultOrgUserPassword() { + String password = EnvironmentUtils.getProperty(DEFAULT_ORG_USER_PASSWORD_KEY); + return StringUtils.isNotBlank(password) ? password : DEFAULT_ORG_USER_PASSWORD; + } + + /** + * 设置创建用户初始状态数据 (账号随机生成/非超管/非实名/待激活/已启用-登录相关) + * + * @param user + * @author sr on 2021-06-10 + */ + public static void setInitToCreateUser(User user) { + user.setUsername(RandomUtils.generateUUID()); + String nickname = user.getNickname(); + user.setNickname(dealNickname(nickname, user.getPhone())); + user.setAvatar(dealAvatar(user.getAvatar())); + user.setSupeiror(Boolean.FALSE); + user.setAuthenticated(Boolean.FALSE); + user.setStatus(UserStatusEnum.INIT.getStatus()); + user.setEnabled(Boolean.TRUE); + user.setAccountNonExpired(Boolean.TRUE); + user.setAccountNonLocked(Boolean.TRUE); + user.setCredentialsNonExpired(Boolean.TRUE); + } + + /** + * @description: 初始化账号密码 + * @return: + * @author: guixinman + * @param: + */ + public static void setInitUserNameAndPasswordToCreateUser(User user, Boolean administrator) { + //创建用户的时候就给手机号绑定状态改为已绑定 + user.setPhoneBinding(true); + user.setUsername(user.getPhone()); + user.setPassword(PasswordUtils.encode(getDefaultOrgUserPassword())); + } + + public static String dealNickname(String nickname, String phone) { + if (StringUtils.isNotBlank(nickname)) { + return nickname; + } + if (StringUtils.isNotBlank(phone)) { + return "用户" + StringUtils.right(phone, 4); + } + return "用户" + RandomUtils.nextSixInt(); + } + + public static String dealAvatar(String avatar) { + if (StringUtils.isNotBlank(avatar)) { + return avatar; + } + String avatarStr = EnvironmentUtils.getProperty(DEFAULT_AVATAR_KEY); + if (StringUtils.isBlank(avatarStr)) { + return null; + } + String[] avatars = avatarStr.split(CommonConstants.COMMA); + return avatars[org.apache.commons.lang3.RandomUtils.nextInt(0, avatars.length)]; + } + + /** + * 校验是否api用户 + * + * @author sr on 2021-08-16 + */ + public static void checkApiUser() { + checkApiUser(UserContextHolder.getUserType()); + } + + /** + * 校验是否api用户 + * + * @param userType + * @author sr on 2021-08-16 + */ + public static void checkApiUser(Integer userType) { + Assert.isTrue(!UserTypeEnum.API_ORG.getType().equals(userType), + "用户类型异常"); + } + + /** + * 带有用户类型对象获取用户类型(优先取入参) + * + * @param iUserType + * @return + * @author sr on 2021-09-02 + */ + public static UserTypeEnum getUserType(IUserPhoneCodeSms iUserType) { + Integer userType = iUserType.getUserType(); + if (userType == null) { + userType = UserContextHolder.getUserType(); + } + Assert.notNull(userType, "无法获取验证码,用户类型不能为空"); + return UserTypeEnum.one(userType); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/userprod/constant/UcMqSelfConstants.java b/backend/src/main/java/com/senmesh/usercenter/userprod/constant/UcMqSelfConstants.java new file mode 100644 index 0000000..ffaa561 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/userprod/constant/UcMqSelfConstants.java @@ -0,0 +1,37 @@ +package com.senmesh.usercenter.userprod.constant; + +import com.senmesh.usercenter.common.mq.constant.UcMqConstants; + +/** + * 用户中心内部使用 + * + * @author sr on 2021-01-05 + */ +public interface UcMqSelfConstants { + + /** + * 手机短信验证码(用户中心内部) + **/ + String ROUTING_KEY_PHONE_CODE_SMS_PREFIX = UcMqConstants.MQ_PREFIX + "phone_code_sms"; + + /** + * 手机短信(用户中心内部) + */ + String ROUTING_KEY_SIMPLE_SMS_PREFIX = UcMqConstants.MQ_PREFIX + "simple_sms"; + + /** + * 通知消息通道处理 前缀 + **/ + String ROUTING_KEY_NOTICE_CHANNEL_DEAL_PREFIX = UcMqConstants.MQ_PREFIX + "notice_channel_deal"; + + /** + * 用户注册 + **/ + String ROUTING_KEY_USER_REGISTER = UcMqConstants.MQ_PREFIX + "user_register"; + + /** + * 活动送积分 + */ + String ROUTING_KEY_USER_ACTIVITY_POINT = UcMqConstants.MQ_PREFIX + "user:activity:point"; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/utils/CheckUtil.java b/backend/src/main/java/com/senmesh/usercenter/utils/CheckUtil.java new file mode 100644 index 0000000..d385021 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/utils/CheckUtil.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.utils; + +import cn.hutool.core.util.ReUtil; + +/** + * @description: 校验工具类 + * @author: chenyun.huang + * @create: 2020-05-07 16:07 + **/ +public class CheckUtil { + + /** + * 正则 数字或者是字母 最多10位 + */ + private static String NUMBER_ALPHABET_REG = "^[A-Za-z0-9]{2,26}$"; + + + /** + * 账号校验正则 + */ + private static String USERNAME_REG = "^[0-9]+admin$"; + + /** + * 正则 手机号 + */ + private static String PHONE_REG = "^1(3|4|5|7|8)\\d{9}$"; + + private CheckUtil() { + } + + /** + * 判断账号是否不为xxadmin规则的账号 + * @param username + * @return + */ + public static boolean checkUsernameRule(String username){ + return !ReUtil.isMatch(USERNAME_REG, username); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/utils/ComponentUtils.java b/backend/src/main/java/com/senmesh/usercenter/utils/ComponentUtils.java new file mode 100644 index 0000000..5583672 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/utils/ComponentUtils.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.utils; + +import com.senmesh.usercenter.resource.dto.ComponentDTO; +import com.senmesh.usercenter.resource.entity.Component; + +/** + * 组件工具类 + * + * @author sr on 2019-10-15 + */ +public class ComponentUtils { + + /** + * 新增,dto转entity + * @param componentDTO + * @return + * @author sr on 2019-10-15 + */ + public static Component toCreateComponent(ComponentDTO componentDTO) { + return Component.builder().urlId(componentDTO.getUrlId()).code(componentDTO.getCode()) + .name(componentDTO.getName()).build(); + } + + /** + * 修改,dto转entity + * @param componentDTO + * @return + * @author sr on 2019-10-15 + */ + public static Component toUpdateComponent(ComponentDTO componentDTO) { + return Component.builder().id(componentDTO.getId()).urlId(componentDTO.getUrlId()) + .code(componentDTO.getCode()).name(componentDTO.getName()).build(); + } + + public static ComponentDTO toDto(Component component) { + return ComponentDTO.builder().id(component.getId()).urlId(component.getUrlId()) + .code(component.getCode()).name(component.getName()).build(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/utils/FindPwdUtils.java b/backend/src/main/java/com/senmesh/usercenter/utils/FindPwdUtils.java new file mode 100644 index 0000000..d18af95 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/utils/FindPwdUtils.java @@ -0,0 +1,117 @@ +package com.senmesh.usercenter.utils; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.exception.util.ExceptionUtils; +import com.senmesh.frame.redis.util.RedisUtils; +import java.time.LocalDate; + +/** + * @author czy on 2020-08-20 + */ +public class FindPwdUtils { + + /** 找回密码短信验证码前缀 **/ + public static final String FIND_PWD_SMS_CODE_PREFIX = "find:pwd:sms:code"; + /** 短信最后发送前缀 **/ + public static final String FIND_PWD_SMS_LAST_PREFIX = "find:pwd:sms:last"; + /** 短信次数前缀 **/ + public static final String FIND_PWD_SMS_COUNT_PREFIX = "find:pwd:sms:count"; + /** 发送验证码时间间隔-秒 **/ + public static final long LAST_EXPIRE_TIME = 60; + /** 验证码过期时间-秒 **/ + public static final long CODE_EXPIRE_TIME = 300; + /** 验证码找回密码次数过期时间-秒 **/ + public static final long COUNT_EXPIRE_TIME = 60 * 60 * 24; + + /** + * 存储验证码的key + * + * @param phone + * @return + * @author czy on 2020-08-20 + */ + public static String getFindPwdSmsCodeKey(String phone) { + // 验证码 find:pwd:sms:code:phone + return String.join(CommonConstants.COLON, FIND_PWD_SMS_CODE_PREFIX, phone); + } + + /** + * 最后一次获取验证码的key + * + * @param phone + * @return + * @author czy on 2020-08-20 + */ + public static String getFindPwdSmsLastKey(String phone) { + // 验证码 find:pwd:sms:last:phone + return String.join(CommonConstants.COLON, FIND_PWD_SMS_LAST_PREFIX, phone); + } + + /** + * 一天内登录验证码次数的key + * + * @param phone + * @return + * @author czy on 2020-08-20 + */ + public static String getFindPwdSmsCountKey(String phone) { + // 登录次数 find:pwd:sms:count:dayOfYear:phone 有效期一天 + return String.join(CommonConstants.COLON, FIND_PWD_SMS_COUNT_PREFIX, + String.valueOf(LocalDate.now().getDayOfYear()), phone); + } + + /** + * 校验上一次找回密码时间间隔是否超过一分钟 + * + * @param phone + * @author czy on 2020-08-20 + */ + public static void checkFindPwdSmsLast(String phone) { + Long num = RedisUtils.increment(getFindPwdSmsLastKey(phone), LAST_EXPIRE_TIME); + ExceptionUtils.throwBusinessException(num > 1L, "操作过于频繁,请60秒后重试"); + } + + /** + * 设置验证码,过期时间5分钟 + * + * @param phone + * @param code + * @author czy on 2020-08-20 + */ + public static void setFindPwdSmsCode(String phone, String code) { + RedisUtils.add(getFindPwdSmsCodeKey(phone), code, CODE_EXPIRE_TIME); + } + + /** + * 获取验证码 + * + * @param phone + * @return + * @author czy on 2020-08-20 + */ + public static String getFindPwdSmsCode(String phone) { + return (String) RedisUtils.get(getFindPwdSmsCodeKey(phone)); + } + + /** + * 找回密码成功,移除验证码 + * + * @param phone + * @author czy on 2020-08-20 + */ + public static void removeFindPwdSmsCode(String phone) { + RedisUtils.remove(getFindPwdSmsCodeKey(phone)); + } + + /** + * 获取当前获取验证码次数 + * + * @param phone + * @return + * @author czy on 2020-08-20 + */ + public static long getFindPwdSmsCount(String phone) { + return RedisUtils.increment(getFindPwdSmsCountKey(phone), COUNT_EXPIRE_TIME); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/utils/PermissionPackageUtils.java b/backend/src/main/java/com/senmesh/usercenter/utils/PermissionPackageUtils.java new file mode 100644 index 0000000..7ac0462 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/utils/PermissionPackageUtils.java @@ -0,0 +1,23 @@ +package com.senmesh.usercenter.utils; + +import com.senmesh.usercenter.permissionpackage.dto.PermissionPackageDTO; +import com.senmesh.usercenter.permissionpackage.entity.PermissionPackage; + +/** + * 权限包工具类 + */ +public class PermissionPackageUtils { + + + public static PermissionPackage toCreatePermissionPackage( + PermissionPackageDTO permissionPackageDTO) { + return PermissionPackage.builder() + .permissionPackageName(permissionPackageDTO.getPermissionPackageName()) + .platformCode(permissionPackageDTO.getPlatformCode()) + .permissionPackageType(permissionPackageDTO.getPermissionPackageType()) + .status(permissionPackageDTO.getStatus()).build(); + } + + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/utils/PermissionUtils.java b/backend/src/main/java/com/senmesh/usercenter/utils/PermissionUtils.java new file mode 100644 index 0000000..19aa90f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/utils/PermissionUtils.java @@ -0,0 +1,32 @@ +package com.senmesh.usercenter.utils; + +import com.senmesh.common.util.EnvironmentUtils; +import com.senmesh.common.util.UserContextHolder; +import com.senmesh.usercenter.authority.entity.Permission; +import com.senmesh.usercenter.constants.SecurityConstants; +import org.apache.commons.lang3.StringUtils; + +/** + * 角色权限工具类 + * @author sr on 2019-10-17 + */ +public class PermissionUtils { + + /** + * 创建权限entity + * @param roleId + * @param resourceType + * @param resourceId + * @return + * @author sr on 2019-10-17 + */ + public static Permission createPermission(Long roleId, String resourceType, Long resourceId) { + return Permission.builder().roleId(roleId) + .resourceType(resourceType) + .resourceId(resourceId) + .orgId(UserContextHolder.getLoginOrgId()) + .platformCode(EnvironmentUtils.getSystemCode()) + .attribute(StringUtils.join(SecurityConstants.ROLE_PERMISSION_PREFIX, roleId)).build(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/utils/RoleAllocationUtils.java b/backend/src/main/java/com/senmesh/usercenter/utils/RoleAllocationUtils.java new file mode 100644 index 0000000..6d3f725 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/utils/RoleAllocationUtils.java @@ -0,0 +1,27 @@ +package com.senmesh.usercenter.utils; + +import com.senmesh.usercenter.authority.entity.RoleAllocation; + +/** + * 角色分配常量类 + * + * @author sr on 2019-10-19 + */ +public class RoleAllocationUtils { + + /** + * 创建角色分配 + * + * @param roleId + * @param allocationType + * @param allocationId + * @return + * @author sr on 2019-10-19 + */ + public static RoleAllocation toCreate(Long roleId, String allocationType, Long allocationId) { + return RoleAllocation.builder().allocationId(allocationId) + .allocationType(allocationType) + .roleId(roleId).build(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/utils/RoleUtils.java b/backend/src/main/java/com/senmesh/usercenter/utils/RoleUtils.java new file mode 100644 index 0000000..bfe02f9 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/utils/RoleUtils.java @@ -0,0 +1,79 @@ +package com.senmesh.usercenter.utils; + +import com.senmesh.usercenter.authority.entity.Role; +import com.senmesh.usercenter.constants.RoleConstants; +import com.senmesh.usercenter.dto.RoleDTO; + +/** + * 角色工具类 + * + * @author sr on 2019-10-12 + */ +public class RoleUtils { + + private RoleUtils() { + } + + /** + * 新增,dto转entity,id为空 + * + * @param orgId + * @param roleDTO + * @param roleType + * @return + * @author sr on 2019-10-14 + */ + public static Role toCreateRole(Long orgId, RoleDTO roleDTO, String roleType) { + return Role.builder() + .orgId(orgId) + .name(roleDTO.getName()) + .type(roleType) + .enabled(Boolean.TRUE.equals(roleDTO.getEnabled())) + .description(roleDTO.getDescription()) + .standardType(roleDTO.getStandardType()) + .platformCode(roleDTO.getPlatformCode()) + .build(); + } + + /** + * 修改,dto转entity,有id,类型不变(置null) + * + * @param roleDTO + * @return + * @author sr on 2019-10-14 + */ + public static Role toUpdateRole(RoleDTO roleDTO) { + return Role.builder() + .id(roleDTO.getId()) + .name(roleDTO.getName()) + .enabled(Boolean.TRUE.equals(roleDTO.getEnabled())) + .description(roleDTO.getDescription()) + .standardType(roleDTO.getStandardType()) + .platformCode(roleDTO.getPlatformCode()) + .build(); + } + + /** + * 获取启用业务角色dto + * + * @return + * @author sr on 2019-10-17 + */ + public static RoleDTO getBusinessRoleDTO() { + return RoleDTO.builder().type(RoleConstants.ROLE_TYPE_BUSINESS).enabled(true).build(); + } + + /** + * 获取校验对象(同机构下是否存在同名有效的角色) + * + * @param roleDTO + * @param orgId + * @return + * @author sr on 2019-10-22 + */ + public static Role toValidation(RoleDTO roleDTO, Long orgId) { + return Role.builder().id(roleDTO.getId()).name(roleDTO.getName()).orgId(orgId).deleted(false) + .build(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/utils/StringUtils.java b/backend/src/main/java/com/senmesh/usercenter/utils/StringUtils.java new file mode 100644 index 0000000..c9fc982 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/utils/StringUtils.java @@ -0,0 +1,23 @@ +package com.senmesh.usercenter.utils; + +import org.apache.commons.lang3.RandomStringUtils; + +/** + * @author Jerry.li + * @description 字符串工具类 + * @date 2020/3/24 + */ +public class StringUtils { + + private StringUtils() { + } + + /** + * 生成8-16位的随机字母+数字的字符串 + * + * @return + */ + public static String generateOrgActivationCode(int min, int max) { + return RandomStringUtils.randomAlphanumeric(min + (int) (Math.random() * (max - min + 1))); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/utils/UrlUtils.java b/backend/src/main/java/com/senmesh/usercenter/utils/UrlUtils.java new file mode 100644 index 0000000..1466420 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/utils/UrlUtils.java @@ -0,0 +1,90 @@ +package com.senmesh.usercenter.utils; + +import com.senmesh.usercenter.resource.dto.UrlDTO; +import com.senmesh.usercenter.resource.entity.Url; + +import java.util.Objects; + +/** + * 菜单工具类 + * + * @author sr on 2019-10-15 + */ +public class UrlUtils { + + private UrlUtils() { + } + + /** + * 新增,dto转entity + * + * @param urlDTO + * @return + * @author sr on 2019-10-15 + */ + public static Url toCreateUrl(UrlDTO urlDTO) { + return Url.builder() + .name(urlDTO.getName()) + .link(urlDTO.getLink()) + .icon(urlDTO.getIcon()) + .parentId(urlDTO.getParentId()) + .resourceOrder(urlDTO.getResourceOrder()) + .visible(Boolean.TRUE.equals(urlDTO.getVisible())) + .description(urlDTO.getDescription()) + .platformCode(urlDTO.getPlatformCode()) + .type(urlDTO.getType()) + .build(); + } + + /** + * 修改,dto转entity,有id + * + * @param urlDTO + * @return + * @author sr on 2019-10-15 + */ + public static Url toUpdateUrl(UrlDTO urlDTO) { + return Url.builder() + .id(urlDTO.getId()) + .name(urlDTO.getName()) + .link(urlDTO.getLink()) + .icon(urlDTO.getIcon()) + .type(urlDTO.getType()) + .parentId(urlDTO.getParentId()) + .resourceOrder(urlDTO.getResourceOrder()) + .visible(Boolean.TRUE.equals(urlDTO.getVisible())) + .description(urlDTO.getDescription()) + .platformCode(urlDTO.getPlatformCode()) + .deleted(Objects.equals(urlDTO.getDeleted(), 1)) + .build(); + } + + public static Url toUrl(UrlDTO url) { + return Url.builder() + .id(url.getId()) + .name(url.getName()) + .link(url.getLink()) + .icon(url.getIcon()) + .type(url.getType()) + .parentId(url.getParentId()) + .resourceOrder(url.getResourceOrder()) + .visible(Boolean.TRUE.equals(url.getVisible())) + .description(url.getDescription()) + .build(); + } + + public static UrlDTO toDTO(Url url) { + return UrlDTO.builder() + .id(url.getId()) + .name(url.getName()) + .link(url.getLink()) + .icon(url.getIcon()) + .type(url.getType()) + .parentId(url.getParentId()) + .resourceOrder(url.getResourceOrder()) + .visible(Boolean.TRUE.equals(url.getVisible())) + .description(url.getDescription()) + .build(); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/websocket/config/DefaultHttpSessionHandshakeInterceptor.java b/backend/src/main/java/com/senmesh/usercenter/websocket/config/DefaultHttpSessionHandshakeInterceptor.java new file mode 100644 index 0000000..b77b84f --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/websocket/config/DefaultHttpSessionHandshakeInterceptor.java @@ -0,0 +1,21 @@ +package com.senmesh.usercenter.websocket.config; + +import java.util.Collection; + +import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor; + +import com.google.common.collect.Lists; + +/** + * 拦截器,复制httpSession属性到websocketSession + * + * @author sr on 2021-01-04 + */ +public class DefaultHttpSessionHandshakeInterceptor extends HttpSessionHandshakeInterceptor { + + public DefaultHttpSessionHandshakeInterceptor(Collection attributeNames) { + // 指定从HttpSession复制属性到WebSocketSession: + super(Lists.newArrayList(attributeNames)); + + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/websocket/config/DefaultTextWebSocketHandler.java b/backend/src/main/java/com/senmesh/usercenter/websocket/config/DefaultTextWebSocketHandler.java new file mode 100644 index 0000000..358a0bd --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/websocket/config/DefaultTextWebSocketHandler.java @@ -0,0 +1,142 @@ +package com.senmesh.usercenter.websocket.config; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.apache.commons.collections.CollectionUtils; +import org.springframework.http.HttpHeaders; +import org.springframework.web.socket.CloseStatus; +import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.handler.TextWebSocketHandler; + +import com.senmesh.common.constant.CommonConstants; +import com.senmesh.common.util.CookieUtils; +import com.senmesh.common.util.JsonUtils; +import com.senmesh.security.jwt.JwtTokenUtils; +import com.senmesh.security.util.SecurityPropertyUtils; +import com.senmesh.usercenter.dto.IUserDetail; +import com.senmesh.usercenter.websocket.service.IWebSocketProvider; +import com.senmesh.usercenter.websocket.service.SocketMessage; + +import lombok.extern.slf4j.Slf4j; + +/** + * 文本消息处理器 + * + * @author sr on 2021-01-04 + */ +@Slf4j +public class DefaultTextWebSocketHandler extends TextWebSocketHandler { + + /** + * concurrent包的线程安全,用来存放每个客户端对应的MyWebSocket对象。 + */ + private static Map> clients = + new ConcurrentHashMap<>(500); + private IWebSocketProvider webSocketProvider; + + public DefaultTextWebSocketHandler(IWebSocketProvider webSocketProvider) { + this.webSocketProvider = webSocketProvider; + } + + private Long dealToken(WebSocketSession session) { + HttpHeaders headers = session.getHandshakeHeaders(); + List headerTokens = headers.get(SecurityPropertyUtils.getProperties().getJwt().getHeader()); + IUserDetail userDto = null; + if (CollectionUtils.isNotEmpty(headerTokens)) { + String headerToken = headerTokens.get(0); + userDto = JwtTokenUtils.getUserLoginDtoFromToken(headerToken); + } + if (userDto == null) { + List cookies = headers.get(HttpHeaders.COOKIE); + log.debug("cookies:{}", cookies); + if (CollectionUtils.isEmpty(cookies)) { + return null; + } + for(String cookie : cookies.get(0).split(CommonConstants.SEMICOLON)) { + String[] cookieArray = cookie.split(CommonConstants.EQUAL); + String key = cookieArray[0]; + if (CookieUtils.getLoginTokenCookieKey().equals(key.trim())) { + userDto = JwtTokenUtils.getUserLoginDtoFromToken(cookieArray[1]); + } + } + } + return userDto == null ? null : userDto.getId(); + } + + @Override + public void afterConnectionEstablished(WebSocketSession session) throws Exception { + Long userId = dealToken(session); + if (userId == null) { + log.info("用户未登录,不添加连接"); + return; + } + CopyOnWriteArrayList servers = clients.get(userId); + if (servers == null) { + servers = new CopyOnWriteArrayList(); + clients.put(userId, servers); + } + servers.add(session); + log.info("websocket open:userId-{}, sessionId-{}", userId, + session.getId()); + webSocketProvider.onOpenSend(userId, session); + } + + @Override + public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { + Long userId = dealToken(session); + if (userId != null) { + clients.get(userId).remove(session); + log.info("websocket close:userId-{}, sessionId-{}.", userId, + session.getId()); + } + } + + @Override + protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { + log.info("客户端发送消息:{}", message.getPayload()); + } + + + /** + * @param session + * @param message + */ + public static void sendMessage(WebSocketSession session, SocketMessage message) { + try { + TextMessage textMessage = new TextMessage(JsonUtils.toJsonString(message)); + session.sendMessage(textMessage); + } catch (Exception e) { + log.info("websocket sendMessage error:{}", e.getMessage()); + } + } + + /** + * @param userId + * @param message + */ + public static void sendMessageToUser(Long userId, SocketMessage message) { + CopyOnWriteArrayList sessions = clients.get(userId); + if (sessions == null) { + log.info("{}用户未建立ws..."); + return ; + } + log.info("websocket send msg to {}-{}", userId, message.getType()); + sessions.stream().forEach(session -> DefaultTextWebSocketHandler.sendMessage(session, message)); + } + + /** + * 群发自定义消息 + */ + public static void sendMessageToAll(SocketMessage message) { + clients.values().stream().flatMap(Collection::stream) + .forEach(session -> DefaultTextWebSocketHandler.sendMessage(session, message)); + } + + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/websocket/config/WebSocketConfiguration.java b/backend/src/main/java/com/senmesh/usercenter/websocket/config/WebSocketConfiguration.java new file mode 100644 index 0000000..a6c8851 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/websocket/config/WebSocketConfiguration.java @@ -0,0 +1,71 @@ +package com.senmesh.usercenter.websocket.config; + +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpHeaders; +import org.springframework.web.socket.config.annotation.EnableWebSocket; +import org.springframework.web.socket.config.annotation.WebSocketConfigurer; +import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; + +import com.google.common.collect.Lists; +import com.senmesh.security.util.SecurityPropertyUtils; +import com.senmesh.usercenter.websocket.service.IWebSocketProvider; +import com.senmesh.usercenter.websocket.service.impl.DefaultWebSocketProvider; +import com.senmesh.usercenter.websocket.util.WebSocketUtils; + +/** + * websocket配置类 + * + * @author sr on 2021-01-04 + */ +@Configuration +@ConditionalOnProperty(name = "websocket.enable", havingValue = "true") +@EnableWebSocket +@EnableConfigurationProperties({WebSocketProperties.class}) +public class WebSocketConfiguration { + + @Autowired + private WebSocketProperties webSocketProperties; + + @Bean + IWebSocketProvider webSocketProvider() { + return new DefaultWebSocketProvider(); + } + + @Bean + DefaultTextWebSocketHandler defaultTextWebSocketHandler() { + return new DefaultTextWebSocketHandler(webSocketProvider()); + } + + @Bean + DefaultHttpSessionHandshakeInterceptor defaultHttpSessionHandshakeInterceptor() { + List attributeNames = Lists.newArrayList(HttpHeaders.COOKIE, + SecurityPropertyUtils.getProperties().getJwt().getHeader()); + return new DefaultHttpSessionHandshakeInterceptor(attributeNames); + } + + + @Bean + WebSocketConfigurer createWebSocketConfigurer() { + + return new WebSocketConfigurer() { + public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { + String path = webSocketProperties.getPath(); + path = StringUtils.isNotBlank(path) ? path : "/ws"; + WebSocketUtils.setPath(path); + // 把URL与指定的WebSocketHandler关联,可关联多个: + registry + .addHandler(defaultTextWebSocketHandler(), path) + .addInterceptors(defaultHttpSessionHandshakeInterceptor()) + .setAllowedOrigins("*"); + } + }; + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/websocket/config/WebSocketProperties.java b/backend/src/main/java/com/senmesh/usercenter/websocket/config/WebSocketProperties.java new file mode 100644 index 0000000..521fff5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/websocket/config/WebSocketProperties.java @@ -0,0 +1,24 @@ +package com.senmesh.usercenter.websocket.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 配置属性 + * + * @author sr on 2021-01-04 + */ +@ConfigurationProperties(prefix = "websocket") +@Data +@NoArgsConstructor +public class WebSocketProperties { + + /** 是否启用 **/ + private Boolean enable; + + /** 路径 **/ + private String path; + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/websocket/service/ISocketMessageSender.java b/backend/src/main/java/com/senmesh/usercenter/websocket/service/ISocketMessageSender.java new file mode 100644 index 0000000..d79cfe0 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/websocket/service/ISocketMessageSender.java @@ -0,0 +1,80 @@ +package com.senmesh.usercenter.websocket.service; + +import org.springframework.web.socket.WebSocketSession; + +import com.senmesh.usercenter.websocket.util.WebSocketUtils; + +/** + * @param + * @author sr on 2020-06-29 + */ +public interface ISocketMessageSender { + + /** + * 类型,需唯一 + * + * @return + * @author sr on 2020-07-01 + */ + String getType(); + + /** + * 获取消息对象 + * + * @return + * @author sr on 2020-07-01 + */ + default T getData() { + return null; + }; + + /** + * 给指定人的客户端发消息 + * + * @param userId + * @author sr on 2020-07-01 + */ + default void send(Long userId) { + WebSocketUtils.send(userId, getType(), getData()); + } + + /** + * 给指定人发送消息 + * + * @param userId + * @param data + * @author sr on 2021-01-04 + */ + default void send(Long userId, T data) { + WebSocketUtils.send(userId, getType(), data); + } + + /** + * 给所有客户端发消息 + * + * @author sr on 2020-07-01 + */ + default void sendAll() { + WebSocketUtils.sendAll(getType(), getData()); + } + + /** + * 给所有客户端发消息 + * + * @param data + * @author sr on 2021-01-04 + */ + default void sendAll(T data) { + WebSocketUtils.sendAll(getType(), data); + } + + /** + * 建立连接时发送消息 + * + * @param userId + * @param session + * @author sr on 2020-07-01 + */ + default void onOpenSend(Long userId, WebSocketSession session) {} + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/websocket/service/IWebSocketProvider.java b/backend/src/main/java/com/senmesh/usercenter/websocket/service/IWebSocketProvider.java new file mode 100644 index 0000000..70f218a --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/websocket/service/IWebSocketProvider.java @@ -0,0 +1,18 @@ +package com.senmesh.usercenter.websocket.service; + +import org.springframework.web.socket.WebSocketSession; + +/** + * @author sr on 2021-01-04 + */ +public interface IWebSocketProvider { + + /** + * @param userId + * @param session + * @author sr on 2021-01-04 + */ + void onOpenSend(Long userId, WebSocketSession session); + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/websocket/service/SocketMessage.java b/backend/src/main/java/com/senmesh/usercenter/websocket/service/SocketMessage.java new file mode 100644 index 0000000..cb7b599 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/websocket/service/SocketMessage.java @@ -0,0 +1,25 @@ +package com.senmesh.usercenter.websocket.service; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sr on 2020-06-29 + * @param + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class SocketMessage { + + private String type; + private T data; + + + public static SocketMessage create(String type, T data) { + return new SocketMessage(type, data); + } +} diff --git a/backend/src/main/java/com/senmesh/usercenter/websocket/service/impl/DefaultWebSocketProvider.java b/backend/src/main/java/com/senmesh/usercenter/websocket/service/impl/DefaultWebSocketProvider.java new file mode 100644 index 0000000..617899e --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/websocket/service/impl/DefaultWebSocketProvider.java @@ -0,0 +1,29 @@ +package com.senmesh.usercenter.websocket.service.impl; + +import java.util.Collections; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.socket.WebSocketSession; + +import com.senmesh.usercenter.websocket.service.ISocketMessageSender; +import com.senmesh.usercenter.websocket.service.IWebSocketProvider; + +/** + * @author sr on 2021-01-04 + */ +public class DefaultWebSocketProvider implements IWebSocketProvider{ + + @SuppressWarnings({"rawtypes"}) + @Autowired(required = false) + private List socketMessageSenders = Collections.emptyList(); + + @Override + public void onOpenSend(Long userId, WebSocketSession session) { + if (socketMessageSenders.isEmpty()) { + return ; + } + socketMessageSenders.forEach(sender -> sender.onOpenSend(userId, session)); + } + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/websocket/service/impl/WebsocketNoticeSendProvider.java b/backend/src/main/java/com/senmesh/usercenter/websocket/service/impl/WebsocketNoticeSendProvider.java new file mode 100644 index 0000000..a99d13c --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/websocket/service/impl/WebsocketNoticeSendProvider.java @@ -0,0 +1,18 @@ +package com.senmesh.usercenter.websocket.service.impl; + +import com.senmesh.component.notice.dto.NoticeMsgDTO; +import org.springframework.stereotype.Service; + +import com.senmesh.component.notice.service.INoticeSendProvider; +import com.senmesh.usercenter.websocket.util.WebSocketUtils; + +@Service +public class WebsocketNoticeSendProvider implements INoticeSendProvider { + + @Override + public void send(NoticeMsgDTO msg) { + WebSocketUtils.send(msg.getReceiverId(), msg.getType(), msg); + } + + +} diff --git a/backend/src/main/java/com/senmesh/usercenter/websocket/util/WebSocketUtils.java b/backend/src/main/java/com/senmesh/usercenter/websocket/util/WebSocketUtils.java new file mode 100644 index 0000000..6dc7dc5 --- /dev/null +++ b/backend/src/main/java/com/senmesh/usercenter/websocket/util/WebSocketUtils.java @@ -0,0 +1,40 @@ +package com.senmesh.usercenter.websocket.util; + +import com.senmesh.usercenter.websocket.config.DefaultTextWebSocketHandler; +import com.senmesh.usercenter.websocket.service.SocketMessage; + +/** + * 工具类 + * + * @author sr on 2021-01-04 + */ +public class WebSocketUtils { + + private static String path; + + public static void setPath(String path) { + // 初始化websocket会设置 + WebSocketUtils.path = path; + } + + public static String getPath() { + return path; + } + + static SocketMessage createMsg(String type, T data) { + SocketMessage socketMessage = new SocketMessage(); + socketMessage.setData(data); + socketMessage.setType(type); + return socketMessage; + } + + public static void sendAll(String type, T data) { + DefaultTextWebSocketHandler.sendMessageToAll(createMsg(type, data)); + } + + public static void send(Long userId, String type, T data) { + DefaultTextWebSocketHandler.sendMessageToUser(userId, createMsg(type, data)); + } + + +} diff --git a/backend/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java b/backend/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java new file mode 100644 index 0000000..c9cbcd6 --- /dev/null +++ b/backend/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java @@ -0,0 +1,116 @@ +package org.springframework.boot.autoconfigure.security.oauth2.client; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties.Provider; +import org.springframework.boot.context.properties.PropertyMapper; +import org.springframework.boot.convert.ApplicationConversionService; +import org.springframework.core.convert.ConversionException; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.ClientRegistration.Builder; +import org.springframework.security.oauth2.client.registration.ClientRegistrations; +import org.springframework.security.oauth2.core.AuthenticationMethod; +import org.springframework.security.oauth2.core.AuthorizationGrantType; +import org.springframework.security.oauth2.core.ClientAuthenticationMethod; +import org.springframework.util.StringUtils; + +import com.senmesh.security.social.service.CommonOAuth2Provider; + +/** + * Adapter class to convert {@link OAuth2ClientProperties} to a + * {@link ClientRegistration}. + * + * @author Phillip Webb + * @author Thiago Hirata + * @author Madhura Bhave + * @author MyeongHyeon Lee + * @since 2.1.0 + */ +public final class OAuth2ClientPropertiesRegistrationAdapter { + + private OAuth2ClientPropertiesRegistrationAdapter() { + } + + public static Map getClientRegistrations(OAuth2ClientProperties properties) { + Map clientRegistrations = new HashMap<>(); + properties.getRegistration().forEach((key, value) -> clientRegistrations.put(key, + getClientRegistration(key, value, properties.getProvider()))); + return clientRegistrations; + } + + private static ClientRegistration getClientRegistration(String registrationId, + OAuth2ClientProperties.Registration properties, Map providers) { + Builder builder = getBuilderFromIssuerIfPossible(registrationId, properties.getProvider(), providers); + if (builder == null) { + builder = getBuilder(registrationId, properties.getProvider(), providers); + } + PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); + map.from(properties::getClientId).to(builder::clientId); + map.from(properties::getClientSecret).to(builder::clientSecret); + map.from(properties::getClientAuthenticationMethod).as(ClientAuthenticationMethod::new) + .to(builder::clientAuthenticationMethod); + map.from(properties::getAuthorizationGrantType).as(AuthorizationGrantType::new) + .to(builder::authorizationGrantType); + map.from(properties::getRedirectUri).to(builder::redirectUri); + map.from(properties::getScope).as(StringUtils::toStringArray).to(builder::scope); + map.from(properties::getClientName).to(builder::clientName); + return builder.build(); + } + + private static Builder getBuilderFromIssuerIfPossible(String registrationId, String configuredProviderId, + Map providers) { + String providerId = (configuredProviderId != null) ? configuredProviderId : registrationId; + if (providers.containsKey(providerId)) { + Provider provider = providers.get(providerId); + String issuer = provider.getIssuerUri(); + if (issuer != null) { + Builder builder = ClientRegistrations.fromIssuerLocation(issuer).registrationId(registrationId); + return getBuilder(builder, provider); + } + } + return null; + } + + private static Builder getBuilder(String registrationId, String configuredProviderId, + Map providers) { + String providerId = (configuredProviderId != null) ? configuredProviderId : registrationId; + CommonOAuth2Provider provider = getCommonProvider(providerId); + if (provider == null && !providers.containsKey(providerId)) { + throw new IllegalStateException(getErrorMessage(configuredProviderId, registrationId)); + } + Builder builder = (provider != null) ? provider.getBuilder(registrationId) + : ClientRegistration.withRegistrationId(registrationId); + if (providers.containsKey(providerId)) { + return getBuilder(builder, providers.get(providerId)); + } + return builder; + } + + private static String getErrorMessage(String configuredProviderId, String registrationId) { + return ((configuredProviderId != null) ? "Unknown provider ID '" + configuredProviderId + "'" + : "Provider ID must be specified for client registration '" + registrationId + "'"); + } + + private static Builder getBuilder(Builder builder, Provider provider) { + PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); + map.from(provider::getAuthorizationUri).to(builder::authorizationUri); + map.from(provider::getTokenUri).to(builder::tokenUri); + map.from(provider::getUserInfoUri).to(builder::userInfoUri); + map.from(provider::getUserInfoAuthenticationMethod).as(AuthenticationMethod::new) + .to(builder::userInfoAuthenticationMethod); + map.from(provider::getJwkSetUri).to(builder::jwkSetUri); + map.from(provider::getUserNameAttribute).to(builder::userNameAttributeName); + return builder; + } + + private static CommonOAuth2Provider getCommonProvider(String providerId) { + try { + return ApplicationConversionService.getSharedInstance().convert(providerId, CommonOAuth2Provider.class); + } + catch (ConversionException ex) { + return null; + } + } + +} diff --git a/backend/src/main/java/org/springframework/data/redis/cache/RedisCache.java b/backend/src/main/java/org/springframework/data/redis/cache/RedisCache.java new file mode 100644 index 0000000..a742ae7 --- /dev/null +++ b/backend/src/main/java/org/springframework/data/redis/cache/RedisCache.java @@ -0,0 +1,381 @@ +package org.springframework.data.redis.cache; + +import java.lang.reflect.Method; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Collection; +import java.util.Map; +import java.util.Map.Entry; +import java.util.StringJoiner; +import java.util.concurrent.Callable; + +import org.springframework.cache.support.AbstractValueAdaptingCache; +import org.springframework.cache.support.NullValue; +import org.springframework.cache.support.SimpleValueWrapper; +import org.springframework.core.convert.ConversionFailedException; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.util.ByteUtils; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; +import org.springframework.util.ReflectionUtils; + +/** + * {@link org.springframework.cache.Cache} implementation using for Redis as underlying store. + *

+ * Use {@link RedisCacheManager} to create {@link RedisCache} instances. + * + * @author Christoph Strobl + * @author Mark Paluch + * @see RedisCacheConfiguration + * @see RedisCacheWriter + * @since 2.0 + */ +public class RedisCache extends AbstractValueAdaptingCache { + + private static final byte[] BINARY_NULL_VALUE = RedisSerializer.java().serialize(NullValue.INSTANCE); + + private final String name; + private final RedisCacheWriter cacheWriter; + private final RedisCacheConfiguration cacheConfig; + private final ConversionService conversionService; + + /** + * Create new {@link RedisCache}. + * + * @param name must not be {@literal null}. + * @param cacheWriter must not be {@literal null}. + * @param cacheConfig must not be {@literal null}. + */ + protected RedisCache(String name, RedisCacheWriter cacheWriter, RedisCacheConfiguration cacheConfig) { + + super(cacheConfig.getAllowCacheNullValues()); + + Assert.notNull(name, "Name must not be null!"); + Assert.notNull(cacheWriter, "CacheWriter must not be null!"); + Assert.notNull(cacheConfig, "CacheConfig must not be null!"); + + this.name = name; + this.cacheWriter = cacheWriter; + this.cacheConfig = cacheConfig; + this.conversionService = cacheConfig.getConversionService(); + } + + /* + * (non-Javadoc) + * @see org.springframework.cache.support.AbstractValueAdaptingCache#lookup(java.lang.Object) + */ + @Override + protected Object lookup(Object key) { + + byte[] value = cacheWriter.get(name, createAndConvertCacheKey(key)); + + if (value == null) { + return null; + } + + return deserializeCacheValue(value); + } + + /* + * (non-Javadoc) + * @see org.springframework.cache.Cache#getName() + */ + @Override + public String getName() { + return name; + } + + /* + * (non-Javadoc) + * @see org.springframework.cache.Cache#getNativeCache() + */ + @Override + public RedisCacheWriter getNativeCache() { + return this.cacheWriter; + } + + /* + * (non-Javadoc) + * @see org.springframework.cache.Cache#get(java.lang.Object, java.util.concurrent.Callable) + */ + @Override + @SuppressWarnings("unchecked") + public synchronized T get(Object key, Callable valueLoader) { + + ValueWrapper result = get(key); + + if (result != null) { + return (T) result.get(); + } + + T value = valueFromLoader(key, valueLoader); + put(key, value); + return value; + } + + /* + * (non-Javadoc) + * @see org.springframework.cache.Cache#put(java.lang.Object, java.lang.Object) + */ + @Override + public void put(Object key, @Nullable Object value) { + + Object cacheValue = preProcessCacheValue(value); + + if (!isAllowNullValues() && cacheValue == null) { + + throw new IllegalArgumentException(String.format( + "Cache '%s' does not allow 'null' values. Avoid storing null via '@Cacheable(unless=\"#result == null\")' or configure RedisCache to allow 'null' via RedisCacheConfiguration.", + name)); + } + + cacheWriter.put(name, createAndConvertCacheKey(key), serializeCacheValue(cacheValue), cacheConfig.getTtl()); + } + + /* + * (non-Javadoc) + * @see org.springframework.cache.Cache#putIfAbsent(java.lang.Object, java.lang.Object) + */ + @Override + public ValueWrapper putIfAbsent(Object key, @Nullable Object value) { + + Object cacheValue = preProcessCacheValue(value); + + if (!isAllowNullValues() && cacheValue == null) { + return get(key); + } + + byte[] result = cacheWriter.putIfAbsent(name, createAndConvertCacheKey(key), serializeCacheValue(cacheValue), + cacheConfig.getTtl()); + + if (result == null) { + return null; + } + + return new SimpleValueWrapper(fromStoreValue(deserializeCacheValue(result))); + } + + /* + * (non-Javadoc) + * @see org.springframework.cache.Cache#evict(java.lang.Object) + */ + @Override + public void evict(Object key) { + // 通配符删除 + if (key instanceof String && ((String) key).endsWith("*")) { + byte[] pattern = conversionService.convert(createCacheKey(key), byte[].class); + this.cacheWriter.clean(this.name, pattern); + return ; + } + cacheWriter.remove(name, createAndConvertCacheKey(key)); + } + + /* + * (non-Javadoc) + * @see org.springframework.cache.Cache#clear() + */ + @Override + public void clear() { + + byte[] pattern = conversionService.convert(createCacheKey("*"), byte[].class); + cacheWriter.clean(name, pattern); + } + + /** + * Return the {@link CacheStatistics} snapshot for this cache instance. Statistics are accumulated per cache instance + * and not from the backing Redis data store. + * + * @return statistics object for this {@link RedisCache}. + * @since 2.4 + */ + public CacheStatistics getStatistics() { + return cacheWriter.getCacheStatistics(getName()); + } + + /** + * Reset all statistics counters and gauges for this cache. + * + * @since 2.4 + */ + public void clearStatistics() { + cacheWriter.clearStatistics(getName()); + } + + /** + * Get {@link RedisCacheConfiguration} used. + * + * @return immutable {@link RedisCacheConfiguration}. Never {@literal null}. + */ + public RedisCacheConfiguration getCacheConfiguration() { + return cacheConfig; + } + + /** + * Customization hook called before passing object to + * {@link org.springframework.data.redis.serializer.RedisSerializer}. + * + * @param value can be {@literal null}. + * @return preprocessed value. Can be {@literal null}. + */ + @Nullable + protected Object preProcessCacheValue(@Nullable Object value) { + + if (value != null) { + return value; + } + + return isAllowNullValues() ? NullValue.INSTANCE : null; + } + + /** + * Serialize the key. + * + * @param cacheKey must not be {@literal null}. + * @return never {@literal null}. + */ + protected byte[] serializeCacheKey(String cacheKey) { + return ByteUtils.getBytes(cacheConfig.getKeySerializationPair().write(cacheKey)); + } + + /** + * Serialize the value to cache. + * + * @param value must not be {@literal null}. + * @return never {@literal null}. + */ + protected byte[] serializeCacheValue(Object value) { + + if (isAllowNullValues() && value instanceof NullValue) { + return BINARY_NULL_VALUE; + } + + return ByteUtils.getBytes(cacheConfig.getValueSerializationPair().write(value)); + } + + /** + * Deserialize the given value to the actual cache value. + * + * @param value must not be {@literal null}. + * @return can be {@literal null}. + */ + @Nullable + protected Object deserializeCacheValue(byte[] value) { + + if (isAllowNullValues() && ObjectUtils.nullSafeEquals(value, BINARY_NULL_VALUE)) { + return NullValue.INSTANCE; + } + + return cacheConfig.getValueSerializationPair().read(ByteBuffer.wrap(value)); + } + + /** + * Customization hook for creating cache key before it gets serialized. + * + * @param key will never be {@literal null}. + * @return never {@literal null}. + */ + protected String createCacheKey(Object key) { + + String convertedKey = convertKey(key); + + if (!cacheConfig.usePrefix()) { + return convertedKey; + } + + return prefixCacheKey(convertedKey); + } + + /** + * Convert {@code key} to a {@link String} representation used for cache key creation. + * + * @param key will never be {@literal null}. + * @return never {@literal null}. + * @throws IllegalStateException if {@code key} cannot be converted to {@link String}. + */ + protected String convertKey(Object key) { + + if (key instanceof String) { + return (String) key; + } + + TypeDescriptor source = TypeDescriptor.forObject(key); + + if (conversionService.canConvert(source, TypeDescriptor.valueOf(String.class))) { + try { + return conversionService.convert(key, String.class); + } catch (ConversionFailedException e) { + + // may fail if the given key is a collection + if (isCollectionLikeOrMap(source)) { + return convertCollectionLikeOrMapKey(key, source); + } + + throw e; + } + } + + Method toString = ReflectionUtils.findMethod(key.getClass(), "toString"); + + if (toString != null && !Object.class.equals(toString.getDeclaringClass())) { + return key.toString(); + } + + throw new IllegalStateException(String.format( + "Cannot convert cache key %s to String. Please register a suitable Converter via 'RedisCacheConfiguration.configureKeyConverters(...)' or override '%s.toString()'.", + source, key.getClass().getSimpleName())); + } + + private String convertCollectionLikeOrMapKey(Object key, TypeDescriptor source) { + + if (source.isMap()) { + + StringBuilder target = new StringBuilder("{"); + + for (Entry entry : ((Map) key).entrySet()) { + target.append(convertKey(entry.getKey())).append("=").append(convertKey(entry.getValue())); + } + target.append("}"); + + return target.toString(); + } else if (source.isCollection() || source.isArray()) { + + StringJoiner sj = new StringJoiner(","); + + Collection collection = source.isCollection() ? (Collection) key + : Arrays.asList(ObjectUtils.toObjectArray(key)); + + for (Object val : collection) { + sj.add(convertKey(val)); + } + return "[" + sj.toString() + "]"; + } + + throw new IllegalArgumentException(String.format("Cannot convert cache key %s to String.", key)); + } + + private boolean isCollectionLikeOrMap(TypeDescriptor source) { + return source.isArray() || source.isCollection() || source.isMap(); + } + + private byte[] createAndConvertCacheKey(Object key) { + return serializeCacheKey(createCacheKey(key)); + } + + private String prefixCacheKey(String key) { + + // allow contextual cache names by computing the key prefix on every call. + return cacheConfig.getKeyPrefixFor(name) + key; + } + + private static T valueFromLoader(Object key, Callable valueLoader) { + + try { + return valueLoader.call(); + } catch (Exception e) { + throw new ValueRetrievalException(key, valueLoader, e); + } + } +} diff --git a/backend/src/main/resources/Dockerfile b/backend/src/main/resources/Dockerfile new file mode 100644 index 0000000..47074fb --- /dev/null +++ b/backend/src/main/resources/Dockerfile @@ -0,0 +1,4 @@ +FROM freshworks/oraclejdk8:latest +VOLUME /tmp +COPY s-file.jar s-file.jar +ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/s-file.jar"] \ No newline at end of file diff --git a/backend/src/main/resources/Dockerfile.arm64 b/backend/src/main/resources/Dockerfile.arm64 new file mode 100644 index 0000000..ebac40a --- /dev/null +++ b/backend/src/main/resources/Dockerfile.arm64 @@ -0,0 +1,4 @@ +FROM eclipse-temurin:8-jre +VOLUME /tmp +COPY s-file.jar s-file.jar +ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/s-file.jar"] diff --git a/backend/src/main/resources/META-INF/spring.factories b/backend/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..4d5667e --- /dev/null +++ b/backend/src/main/resources/META-INF/spring.factories @@ -0,0 +1,5 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.senmesh.common.CommonConfiguration,\ +com.senmesh.codegenerator.config.CodeConfiguration,\ +com.senmesh.frame.redis.config.RedisCacheConfig,\ +com.senmesh.frame.redis.redisson.RedissonConfig \ No newline at end of file diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties new file mode 100644 index 0000000..e69de29 diff --git a/backend/src/main/resources/static/index.html b/backend/src/main/resources/static/index.html new file mode 100644 index 0000000..f5a1032 --- /dev/null +++ b/backend/src/main/resources/static/index.html @@ -0,0 +1,10 @@ + + + + +Insert title here + + + hi,have a good time! + + \ No newline at end of file diff --git a/backend/src/main/resources/static/login.html b/backend/src/main/resources/static/login.html new file mode 100644 index 0000000..e74ae61 --- /dev/null +++ b/backend/src/main/resources/static/login.html @@ -0,0 +1,2573 @@ + + + + + + + + + + +

+

hello security!

+

up login

+
+ 用户名: + 密码: + 用户类型: + +
+ +

phone login

+
+ + + + +
+
+ + + + + + diff --git a/backend/src/test/java/com/senmesh/PwdTest.java b/backend/src/test/java/com/senmesh/PwdTest.java new file mode 100644 index 0000000..97553cb --- /dev/null +++ b/backend/src/test/java/com/senmesh/PwdTest.java @@ -0,0 +1,7 @@ +package com.senmesh; + +public class PwdTest { + + + +} diff --git a/deploy/config/application-iw.yml b/deploy/config/application-iw.yml new file mode 100644 index 0000000..a4a292e --- /dev/null +++ b/deploy/config/application-iw.yml @@ -0,0 +1,115 @@ +# s-file 内网侧(file.transfer.location=1)本地联调配置 +# 仅本机 docker 部署使用,密码与 JWT secret 不要带到生产 +server: + port: 8080 + +spring: + application: + name: s-file + datasource: + url: jdbc:postgresql://pg-iw:5432/s_file + driver-class-name: org.postgresql.Driver + username: sfile + password: sfile_iw_2026 + druid: + initial-size: 2 + min-idle: 2 + max-active: 10 + validation-query: SELECT 1 + redis: + host: redis-iw + port: 6379 + timeout: 5000 + lettuce: + pool: + max-active: 8 + max-idle: 4 + rabbitmq: + host: mq-iw + port: 5672 + username: sfile + password: sfile_mq_iw_2026 + servlet: + multipart: + max-file-size: 500MB + max-request-size: 500MB + main: + allow-bean-definition-overriding: true + +mybatis-plus: + mapper-locations: classpath*:com/senmesh/**/mapper/*.xml + +# 平台编码(init-data 中 uc_platform.platform_code=1) +system: + code: 1 + +# 发号器雪花 workerId:键为 compose 中固定的容器 IP +"[code.snowflake.workid.172.25.18.10]": 1 + +security: + jwt: + enable: true + secret: sfile-local-iw-secret-key-please-change-0123456789abcdef + expiration: 86400000 + header: Authorization + ignoring: /error,/favicon.ico + login-page: /login + superior-only: false + use-local: true + allow-if-all-abstain-decisions: true + oauth2: + enable: false + not-logs: "" + anonymous: "" + +# 新用户初始密码 +user: + default: + password: Qaz123567!@# + +file: + upload-dir: /data/upload + storage: + type: local + transfer: + # 内网侧 + location: "1" + # send-dir 与外网侧 receive-dir 指向同一摆渡目录,反之亦然 + send-dir: /data/transfer/send + receive-dir: /data/transfer/receive + unpack-risk-check: false + +dify: + risk: + rule: + api-key: test-rule-key + scan: + api-key: test-scan-key + +# MeshSafe 文件安全检测:复用本机已部署的 meshsafe-nginx(44380) +# 凭证需存在于 MeshSafe .env 的 MESHSAFE_API_CLIENTS 白名单中 +meshsafe: + enabled: true + base-url: http://host.docker.internal:44380 + client-id: test-client + secret: test-secret + channel: sfile-iw + timeout-seconds: 120 + fail-open: true + poll-timeout-minutes: 60 + review-sync-to-meshsafe: true + poll: + cron: "0/10 * * * * ?" + +rabbitmq: + custom: + topic-exchange-name: s-file-iw-topic + delayed-exchange-name: s-file-iw-delayed + broadcast-id: s-file-iw-broadcast + +swagger: + enable: false + +logging: + level: + com.senmesh: info diff --git a/deploy/config/application-ow.yml b/deploy/config/application-ow.yml new file mode 100644 index 0000000..82132f4 --- /dev/null +++ b/deploy/config/application-ow.yml @@ -0,0 +1,115 @@ +# s-file 外网侧(file.transfer.location=2)本地联调配置 +# 仅本机 docker 部署使用,密码与 JWT secret 不要带到生产 +server: + port: 8080 + +spring: + application: + name: s-file + datasource: + url: jdbc:postgresql://pg-ow:5432/s_file + driver-class-name: org.postgresql.Driver + username: sfile + password: sfile_ow_2026 + druid: + initial-size: 2 + min-idle: 2 + max-active: 10 + validation-query: SELECT 1 + redis: + host: redis-ow + port: 6379 + timeout: 5000 + lettuce: + pool: + max-active: 8 + max-idle: 4 + rabbitmq: + host: mq-ow + port: 5672 + username: sfile + password: sfile_mq_ow_2026 + servlet: + multipart: + max-file-size: 500MB + max-request-size: 500MB + main: + allow-bean-definition-overriding: true + +mybatis-plus: + mapper-locations: classpath*:com/senmesh/**/mapper/*.xml + +# 平台编码(init-data 中 uc_platform.platform_code=1) +system: + code: 1 + +# 发号器雪花 workerId:键为 compose 中固定的容器 IP;两侧 workerId 必须不同 +"[code.snowflake.workid.172.25.28.10]": 2 + +security: + jwt: + enable: true + secret: sfile-local-ow-secret-key-please-change-0123456789abcdef + expiration: 86400000 + header: Authorization + ignoring: /error,/favicon.ico + login-page: /login + superior-only: false + use-local: true + allow-if-all-abstain-decisions: true + oauth2: + enable: false + not-logs: "" + anonymous: "" + +# 新用户初始密码 +user: + default: + password: Qaz123567!@# + +file: + upload-dir: /data/upload + storage: + type: local + transfer: + # 外网侧:与内网侧相反 + location: "2" + # compose 里 send-dir 挂到 gate/ow2iw、receive-dir 挂到 gate/iw2ow + send-dir: /data/transfer/send + receive-dir: /data/transfer/receive + unpack-risk-check: false + +dify: + risk: + rule: + api-key: test-rule-key + scan: + api-key: test-scan-key + +# MeshSafe 文件安全检测:复用本机已部署的 meshsafe-nginx(44380) +# 凭证需存在于 MeshSafe .env 的 MESHSAFE_API_CLIENTS 白名单中 +meshsafe: + enabled: true + base-url: http://host.docker.internal:44380 + client-id: test-client + secret: test-secret + channel: sfile-ow + timeout-seconds: 120 + fail-open: true + poll-timeout-minutes: 60 + review-sync-to-meshsafe: true + poll: + cron: "0/10 * * * * ?" + +rabbitmq: + custom: + topic-exchange-name: s-file-ow-topic + delayed-exchange-name: s-file-ow-delayed + broadcast-id: s-file-ow-broadcast + +swagger: + enable: false + +logging: + level: + com.senmesh: info diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml new file mode 100644 index 0000000..b2f1524 --- /dev/null +++ b/deploy/docker-compose.yml @@ -0,0 +1,252 @@ +# ============================================================================= +# s-file 信创文件安全传输系统 —— 本机 docker 部署(内网侧 + 外网侧两套) +# +# 启动: +# docker build -f deploy/docker/Dockerfile.app -t sfile-app:local backend/target +# docker build -f deploy/docker/Dockerfile.web -t sfile-web:local frontend +# cd deploy && docker compose up -d +# +# 端口: +# 内网前端 http://<本机IP>:28180 外网前端 http://<本机IP>:28280 +# 其余(后端/postgres/redis/rabbitmq)只在容器网络内通信,不映射宿主机端口 +# MeshSafe 复用本机已运行的 meshsafe-nginx:44380(两套后端都经 host.docker.internal 调用) +# +# 摆渡目录(模拟光闸): +# gate/iw2ow = 内网 send + 外网 receive gate/ow2iw = 外网 send + 内网 receive +# ============================================================================= + +name: sfile + +services: + # ===================== 内网侧 ===================== + web-iw: + image: sfile-web:local + container_name: sfile-iw-web + restart: unless-stopped + networks: [iw_net] + ports: + - "0.0.0.0:28180:80" + volumes: + - ./nginx/web-iw.conf:/etc/nginx/conf.d/default.conf:ro + depends_on: + app-iw: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "curl -sf -o /dev/null http://127.0.0.1:80/ || exit 1"] + interval: 30s + timeout: 5s + retries: 3 + + app-iw: + image: sfile-app:local + container_name: sfile-iw-app + restart: unless-stopped + networks: + iw_net: + ipv4_address: 172.25.18.10 + environment: + TZ: Asia/Shanghai + SPRING_CONFIG_ADDITIONAL_LOCATION: file:/config/application.yml + CODE_SNOWFLAKE_WORKID_172_25_18_10: "1" + volumes: + - ./config/application-iw.yml:/config/application.yml:ro + - ${SFILE_DATA:-D:/zcodedata/sfile}/iw/upload:/data/upload + - ${SFILE_DATA:-D:/zcodedata/sfile}/iw/logs:/app/logs + - ${SFILE_DATA:-D:/zcodedata/sfile}/gate/iw2ow:/data/transfer/send + - ${SFILE_DATA:-D:/zcodedata/sfile}/gate/ow2iw:/data/transfer/receive + extra_hosts: + - "host.docker.internal:host-gateway" + depends_on: + pg-iw: + condition: service_healthy + redis-iw: + condition: service_healthy + mq-iw: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "curl -s --max-time 5 -o /dev/null http://127.0.0.1:8080/ || exit 1"] + interval: 30s + timeout: 8s + retries: 5 + start_period: 150s + + pg-iw: + image: postgres:latest + container_name: sfile-iw-pg + restart: unless-stopped + networks: [iw_net] + environment: + TZ: Asia/Shanghai + POSTGRES_DB: s_file + POSTGRES_USER: sfile + POSTGRES_PASSWORD: sfile_iw_2026 + volumes: + # postgres:latest 为 18.x,数据目录挂载点已改为 /var/lib/postgresql + - sfile-pgdata-iw:/var/lib/postgresql + - ../backend/db/init-table-postgres-full.sql:/docker-entrypoint-initdb.d/01-init-table.sql:ro + - ../backend/db/init-data.sql:/docker-entrypoint-initdb.d/02-init-data.sql:ro + healthcheck: + test: ["CMD-SHELL", "pg_isready -U sfile -d s_file"] + interval: 10s + timeout: 5s + retries: 10 + start_period: 40s + + redis-iw: + image: redis:latest + container_name: sfile-iw-redis + restart: unless-stopped + networks: [iw_net] + command: ["redis-server", "--appendonly", "yes", "--maxmemory", "256mb", "--maxmemory-policy", "allkeys-lru"] + volumes: + - sfile-redis-iw:/data + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 3s + retries: 5 + + mq-iw: + image: rabbitmq:3-management-alpine + container_name: sfile-iw-mq + restart: unless-stopped + networks: [iw_net] + environment: + TZ: Asia/Shanghai + RABBITMQ_DEFAULT_USER: sfile + RABBITMQ_DEFAULT_PASS: sfile_mq_iw_2026 + volumes: + - sfile-mq-iw:/var/lib/rabbitmq + healthcheck: + test: ["CMD-SHELL", "rabbitmq-diagnostics -q ping"] + interval: 20s + timeout: 10s + retries: 10 + start_period: 40s + + # ===================== 外网侧 ===================== + web-ow: + image: sfile-web:local + container_name: sfile-ow-web + restart: unless-stopped + networks: [ow_net] + ports: + - "0.0.0.0:28280:80" + volumes: + - ./nginx/web-ow.conf:/etc/nginx/conf.d/default.conf:ro + depends_on: + app-ow: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "curl -sf -o /dev/null http://127.0.0.1:80/ || exit 1"] + interval: 30s + timeout: 5s + retries: 3 + + app-ow: + image: sfile-app:local + container_name: sfile-ow-app + restart: unless-stopped + networks: + ow_net: + ipv4_address: 172.25.28.10 + environment: + TZ: Asia/Shanghai + SPRING_CONFIG_ADDITIONAL_LOCATION: file:/config/application.yml + CODE_SNOWFLAKE_WORKID_172_25_28_10: "2" + volumes: + - ./config/application-ow.yml:/config/application.yml:ro + - ${SFILE_DATA:-D:/zcodedata/sfile}/ow/upload:/data/upload + - ${SFILE_DATA:-D:/zcodedata/sfile}/ow/logs:/app/logs + - ${SFILE_DATA:-D:/zcodedata/sfile}/gate/ow2iw:/data/transfer/send + - ${SFILE_DATA:-D:/zcodedata/sfile}/gate/iw2ow:/data/transfer/receive + extra_hosts: + - "host.docker.internal:host-gateway" + depends_on: + pg-ow: + condition: service_healthy + redis-ow: + condition: service_healthy + mq-ow: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "curl -s --max-time 5 -o /dev/null http://127.0.0.1:8080/ || exit 1"] + interval: 30s + timeout: 8s + retries: 5 + start_period: 150s + + pg-ow: + image: postgres:latest + container_name: sfile-ow-pg + restart: unless-stopped + networks: [ow_net] + environment: + TZ: Asia/Shanghai + POSTGRES_DB: s_file + POSTGRES_USER: sfile + POSTGRES_PASSWORD: sfile_ow_2026 + volumes: + - sfile-pgdata-ow:/var/lib/postgresql + - ../backend/db/init-table-postgres-full.sql:/docker-entrypoint-initdb.d/01-init-table.sql:ro + - ../backend/db/init-data.sql:/docker-entrypoint-initdb.d/02-init-data.sql:ro + healthcheck: + test: ["CMD-SHELL", "pg_isready -U sfile -d s_file"] + interval: 10s + timeout: 5s + retries: 10 + start_period: 40s + + redis-ow: + image: redis:latest + container_name: sfile-ow-redis + restart: unless-stopped + networks: [ow_net] + command: ["redis-server", "--appendonly", "yes", "--maxmemory", "256mb", "--maxmemory-policy", "allkeys-lru"] + volumes: + - sfile-redis-ow:/data + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 3s + retries: 5 + + mq-ow: + image: rabbitmq:3-management-alpine + container_name: sfile-ow-mq + restart: unless-stopped + networks: [ow_net] + environment: + TZ: Asia/Shanghai + RABBITMQ_DEFAULT_USER: sfile + RABBITMQ_DEFAULT_PASS: sfile_mq_ow_2026 + volumes: + - sfile-mq-ow:/var/lib/rabbitmq + healthcheck: + test: ["CMD-SHELL", "rabbitmq-diagnostics -q ping"] + interval: 20s + timeout: 10s + retries: 10 + start_period: 40s + +networks: + iw_net: + driver: bridge + ipam: + config: + - subnet: 172.25.18.0/24 + gateway: 172.25.18.1 + ow_net: + driver: bridge + ipam: + config: + - subnet: 172.25.28.0/24 + gateway: 172.25.28.1 + +volumes: + sfile-pgdata-iw: + sfile-redis-iw: + sfile-mq-iw: + sfile-pgdata-ow: + sfile-redis-ow: + sfile-mq-ow: diff --git a/deploy/docker/Dockerfile.app b/deploy/docker/Dockerfile.app new file mode 100644 index 0000000..73e4156 --- /dev/null +++ b/deploy/docker/Dockerfile.app @@ -0,0 +1,15 @@ +# s-file 后端运行镜像(构建上下文 = backend/target,内含 s-file.jar) +# 用 JVM 参数 -Xmx 控制内存,配置文件由容器挂载 /config/application.yml +FROM eclipse-temurin:8-jre-jammy + +ENV TZ=Asia/Shanghai +ENV JAVA_OPTS="-Xms256m -Xmx1g -Dfile.encoding=UTF-8" + +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +WORKDIR /app +COPY s-file.jar /app/s-file.jar + +EXPOSE 8080 + +ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app/s-file.jar"] diff --git a/deploy/docker/Dockerfile.web b/deploy/docker/Dockerfile.web new file mode 100644 index 0000000..cb844fe --- /dev/null +++ b/deploy/docker/Dockerfile.web @@ -0,0 +1,28 @@ +# 前端镜像:一次构建同时产出内网包与外网包 +# 构建上下文 = frontend/ (见 frontend/.dockerignore) +# 站点根:/usr/share/nginx/inside(内网)、/usr/share/nginx/outside(外网) +# 由两套 nginx 容器各挂一份 conf 选择站点根,镜像只读共用 +FROM node:20 AS build + +WORKDIR /src +COPY package.json ./ +RUN npm config set registry https://registry.npmmirror.com \ + && npm install --no-audit --no-fund + +COPY . . + +# .env.production.local 优先级高于 .env.production,用它固化两套包的差异: +# VITE_API_URL=/api —— 走同域 /api,由 nginx 反代时去掉前缀 +# VITE_IS_INSIDE —— true 内网包 / false 外网包 +RUN set -eux; \ + printf 'VITE_API_URL=/api\nVITE_IS_INSIDE=true\n' > .env.production.local; \ + npx vite build --outDir dist/inside; \ + printf 'VITE_API_URL=/api\nVITE_IS_INSIDE=false\n' > .env.production.local; \ + npx vite build --outDir dist/outside + +FROM nginx:alpine + +COPY --from=build /src/dist/inside /usr/share/nginx/inside +COPY --from=build /src/dist/outside /usr/share/nginx/outside + +EXPOSE 80 diff --git a/deploy/nginx/web-iw.conf b/deploy/nginx/web-iw.conf new file mode 100644 index 0000000..78c7221 --- /dev/null +++ b/deploy/nginx/web-iw.conf @@ -0,0 +1,37 @@ +server { + listen 80; + server_name _; + charset utf-8; + + root /usr/share/nginx/inside; + index index.html; + + # 与后端 multipart 上限(500MB)保持一致 + client_max_body_size 500m; + + # /api/xxx -> 后端 /xxx(去掉 /api 前缀,与 vite dev 代理行为一致) + location /api/ { + proxy_pass http://app-iw:8080/; + proxy_http_version 1.1; + # 必须保留端口($http_host):后端 getRootDomain 对无端口的 localhost/IP 会抛 + # IllegalStateException 导致 /login 成功回调 500(带端口时按非法域名返回 null,Cookie 不带 domain) + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_read_timeout 600s; + proxy_send_timeout 600s; + proxy_request_buffering off; + } + + # SPA:hash 路由,静态资源找不到时回落 index.html + location / { + try_files $uri $uri/ /index.html; + } + + location ~* \.(js|mjs|css|woff2?|ttf|png|jpe?g|gif|svg|ico)$ { + expires 7d; + access_log off; + } +} diff --git a/deploy/nginx/web-ow.conf b/deploy/nginx/web-ow.conf new file mode 100644 index 0000000..392d595 --- /dev/null +++ b/deploy/nginx/web-ow.conf @@ -0,0 +1,37 @@ +server { + listen 80; + server_name _; + charset utf-8; + + root /usr/share/nginx/outside; + index index.html; + + # 与后端 multipart 上限(500MB)保持一致 + client_max_body_size 500m; + + # /api/xxx -> 后端 /xxx(去掉 /api 前缀,与 vite dev 代理行为一致) + location /api/ { + proxy_pass http://app-ow:8080/; + proxy_http_version 1.1; + # 必须保留端口($http_host):后端 getRootDomain 对无端口的 localhost/IP 会抛 + # IllegalStateException 导致 /login 成功回调 500(带端口时按非法域名返回 null,Cookie 不带 domain) + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_read_timeout 600s; + proxy_send_timeout 600s; + proxy_request_buffering off; + } + + # SPA:hash 路由,静态资源找不到时回落 index.html + location / { + try_files $uri $uri/ /index.html; + } + + location ~* \.(js|mjs|css|woff2?|ttf|png|jpe?g|gif|svg|ico)$ { + expires 7d; + access_log off; + } +} diff --git a/deploy/部署说明.md b/deploy/部署说明.md new file mode 100644 index 0000000..ffd09ce --- /dev/null +++ b/deploy/部署说明.md @@ -0,0 +1,93 @@ +# s-file 本机 docker 部署说明(内网侧 + 外网侧两套) + +> 环境:Windows + Docker Desktop 4.54,MeshSafe 复用本机已运行的 `meshsafe-nginx:44380` +> 编排文件:`deploy/docker-compose.yml` + +## 1. 访问入口 + +| 侧 | 地址 | 前端包 | 后端 `file.transfer.location` | +|---|---|---|---| +| 内网 | http://本机IP:28180 | `VITE_IS_INSIDE=true` | `1` | +| 外网 | http://本机IP:28280 | `VITE_IS_INSIDE=false` | `2` | + +只有这两个 80 端口映射到宿主机(`0.0.0.0`,便于局域网真机联调)。后端 8080、PostgreSQL、Redis、RabbitMQ 全部只在容器网络内通信,**不映射宿主机端口**;nginx 通过 `location /api/ → http://app-xx:8080/` 反代并去掉 `/api` 前缀。 + +## 2. 容器与网段 + +| 内网侧 | 外网侧 | 说明 | +|---|---|---| +| `sfile-iw-web` | `sfile-ow-web` | nginx:alpine(本机已有) | +| `sfile-iw-app` | `sfile-ow-app` | sfile-app:local(eclipse-temurin:8-jre-jammy + s-file.jar) | +| `sfile-iw-pg` | `sfile-ow-pg` | postgres:latest(本机已有,18.3) | +| `sfile-iw-redis` | `sfile-ow-redis` | redis:latest(本机已有) | +| `sfile-iw-mq` | `sfile-ow-mq` | rabbitmq:3-management-alpine(本机已有) | +| 网络 `sfile_iw_net` 172.25.18.0/24 | 网络 `sfile_ow_net` 172.25.28.0/24 | 两侧物理隔离,仅通过摆渡目录互通 | + +app 容器固定 IP(`172.25.18.10` / `172.25.28.10`),对应雪花 workerId `1` / `2`,两侧必须不同;改网段时同步改 `deploy/config/application-*.yml` 里的 `[code.snowflake.workid.]` 与 compose 的 `CODE_SNOWFLAKE_WORKID_*` 环境变量。 + +## 3. 摆渡目录(模拟光闸) + +宿主机根目录:`D:/zcodedata/sfile/`(可用 `.env` 的 `SFILE_DATA` 覆盖) + +| 目录 | 内网侧挂载 | 外网侧挂载 | +|---|---|---| +| `gate/iw2ow` | `/data/transfer/send` | `/data/transfer/receive` | +| `gate/ow2iw` | `/data/transfer/receive` | `/data/transfer/send` | +| `iw/upload`、`ow/upload` | 各自 `/data/upload` | 网盘物理文件,两侧独立 | + +内网「我的发送」写入 `gate/iw2ow`,外网侧 `TransferFileMonitorJob` 扫描自己的 receive 目录解包入库并触发 MeshSafe 送检,反方向同理。 + +## 4. MeshSafe 对接 + +`deploy/config/application-iw.yml` / `application-ow.yml`: + +```yaml +meshsafe: + enabled: true + base-url: http://host.docker.internal:44380 # 本机 meshsafe-nginx + client-id: test-client # 需在 MeshSafe .env 的 MESHSAFE_API_CLIENTS 白名单内 + secret: test-secret + fail-open: true # 本地联调优先可用性;安全优先部署改 false +``` + +compose 给 app 容器加了 `extra_hosts: host.docker.internal:host-gateway`。上线前把两侧 channel 区分(`sfile-iw` / `sfile-ow`)并保持 MeshSafe 策略 `engine_failure_mode: fail_closed`。 + +## 5. 构建与启动 + +```bash +# 1) 后端 jar(需 JDK8 + Maven,本机已装在 D:/dev/jdk8、D:/dev/maven-tmp) +cd backend +JAVA_HOME=D:/dev/jdk8/jdk8u504-b01 mvn -s D:/dev/maven-conf/settings.xml clean package -DskipTests + +# 2) 镜像 +docker build -f deploy/docker/Dockerfile.app -t sfile-app:local backend/target +docker build -f deploy/docker/Dockerfile.web -t sfile-web:local frontend # 一次产出内网+外网两个站点 + +# 3) 启动(首次会执行 backend/db 的 PG 初始化脚本建 62 张表) +cd deploy && docker compose up -d +``` + +常用运维: + +```bash +docker compose ps # 全部 10 个容器应为 healthy +docker compose restart app-iw app-ow # 改配置后重启后端 +docker compose logs -f app-iw +docker compose down # 停止(保留数据卷与摆渡目录) +``` + +## 6. 已知取舍 + +- **spire.pdf 3.7.4**:公共仓库无此版本,本机用按 `PdfUtils.java` 引用签名手写的桩 jar(`~/.m2/repository/e-iceblue/spire.pdf/3.7.4/`)保证编译打包通过;**PDF 盖章功能运行时不可用**,正式环境需替换公司私服的真实 jar。 +- **前端 `VITE_API_URL=/api`**:`.env.production` 原值为空,容器构建时用 `.env.production.local` 固化为 `/api`,与 nginx 反代规则和 vite dev 行为保持一致;改构建口径需同步改 `Dockerfile.web`。 +- **postgres:latest 为 18.x**:数据目录挂载点已从 `/var/lib/postgresql/data` 改为 `/var/lib/postgresql`,挂错路径容器会反复重启。 +- **配置与口令仅用于本地联调**:JWT secret、数据库/RabbitMQ 密码为占位值,勿带到生产。 +- 数据库卷为命名卷(`sfile_sfile-pgdata-iw` / `-ow`);重新初始化需删卷后 `docker compose up -d`。 + +## 7. 验收清单 + +1. 两套登录页可访问(28180 / 28280),登录后内网侧菜单为「我的接收 / 我的发送」、外网侧相反; +2. 上传文件后「安全检测」列出现「检测中」→ 数秒内变「检测通过/不通过」(`docker exec sfile-iw-pg psql -U sfile -d s_file -c 'select * from x_file_security order by id desc limit 5;'`); +3. 检测不通过的文件分享/跨网传输被拒;文件夹部分不通过时确认后可只传通过项; +4. 内网发送到外网接收全链路走通,接收端解包后自动送检; +5. 管理端人工复核改判后文件恢复可分享/可传输。 diff --git a/frontend/.dockerignore b/frontend/.dockerignore new file mode 100644 index 0000000..3ec1b5f --- /dev/null +++ b/frontend/.dockerignore @@ -0,0 +1,7 @@ +node_modules +dist +.swc-cache +release +.git +*.log +.DS_Store diff --git a/frontend/.env.development b/frontend/.env.development new file mode 100644 index 0000000..56db2c7 --- /dev/null +++ b/frontend/.env.development @@ -0,0 +1,7 @@ +VITE_API_URL=/api +VITE_STORE_PREFIX=senmeshzc +VITE_BASEPATH= +VITE_APP_TITLE="森睿智传" +VITE_IS_INSIDE=true +VITE_DOMAIN= +VITE_INIT_PASSWORD="Qaz123567!@#" \ No newline at end of file diff --git a/frontend/.env.production b/frontend/.env.production new file mode 100644 index 0000000..725241a --- /dev/null +++ b/frontend/.env.production @@ -0,0 +1,7 @@ +VITE_API_URL= +VITE_STORE_PREFIX=senmeshzc +VITE_BASEPATH= +VITE_APP_TITLE="森睿智传" +VITE_IS_INSIDE=true +VITE_DOMAIN= +VITE_INIT_PASSWORD="Qaz123567!@#" \ No newline at end of file diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000..acabbed --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,6 @@ +node_modules/ +dist/ +.tanstack/ +.DS_Store +*.local +release/ diff --git a/frontend/.windsurfrules b/frontend/.windsurfrules new file mode 100644 index 0000000..8605641 --- /dev/null +++ b/frontend/.windsurfrules @@ -0,0 +1,14825 @@ +<@tanstack/react-router_api> +Always Apply: false - This rule should only be applied when relevant files are open +Always apply this rule in these files: src/**/*.ts, src/**/*.tsx + +# ActiveLinkOptions type + +The `ActiveLinkOptions` type extends the [`LinkOptions`](./LinkOptionsType.md) type and contains additional options that can be used to describe how a link should be styled when it is active. + +```tsx +type ActiveLinkOptions = LinkOptions & { + activeProps?: + | React.AnchorHTMLAttributes + | (() => React.AnchorHTMLAttributes) + inactiveProps?: + | React.AnchorHTMLAttributes + | (() => React.AnchorHTMLAttributes) +} +``` + +## ActiveLinkOptions properties + +The `ActiveLinkOptions` object accepts/contains the following properties: + +### `activeProps` + +- `React.AnchorHTMLAttributes` +- Optional +- The props that will be applied to the anchor element when the link is active + +### `inactiveProps` + +- Type: `React.AnchorHTMLAttributes` +- Optional +- The props that will be applied to the anchor element when the link is inactive + +# AsyncRouteComponent type + +The `AsyncRouteComponent` type is used to describe a code-split route component that can be preloaded using a `component.preload()` method. + +```tsx +type AsyncRouteComponent = SyncRouteComponent & { + preload?: () => Promise +} +``` + +# FileRoute class + +> [!CAUTION] +> This class has been deprecated and will be removed in the next major version of TanStack Router. +> Please use the [`createFileRoute`](./createFileRouteFunction.md) function instead. + +The `FileRoute` class is a factory that can be used to create a file-based route instance. This route instance can then be used to automatically generate a route tree with the `tsr generate` and `tsr watch` commands. + +## `FileRoute` constructor + +The `FileRoute` constructor accepts a single argument: the `path` of the file that the route will be generated for. + +### Constructor options + +- Type: `string` literal +- Required, but **automatically inserted and updated by the `tsr generate` and `tsr watch` commands**. +- The full path of the file that the route will be generated from. + +### Constructor returns + +- An instance of the `FileRoute` class that can be used to create a route. + +## `FileRoute` methods + +The `FileRoute` class implements the following method(s): + +### `.createRoute` method + +The `createRoute` method is a method that can be used to configure the file route instance. It accepts a single argument: the `options` that will be used to configure the file route instance. + +#### .createRoute options + +- Type: `Omit` +- [`RouteOptions`](./RouteOptionsType.md) +- Optional +- The same options that are available to the `Route` class, but with the `getParentRoute`, `path`, and `id` options omitted since they are unnecessary for file-based routing. + +#### .createRoute returns + +A [`Route`](./RouteType.md) instance that can be used to configure the route to be inserted into the route-tree. + +> ⚠️ Note: For `tsr generate` and `tsr watch` to work properly, the file route instance must be exported from the file using the `Route` identifier. + +### Examples + +```tsx +import { FileRoute } from '@tanstack/react-router' + +export const Route = new FileRoute('/').createRoute({ + loader: () => { + return 'Hello World' + }, + component: IndexComponent, +}) + +function IndexComponent() { + const data = Route.useLoaderData() + return
{data}
+} +``` + +# LinkOptions type + +The `LinkOptions` type extends the [`NavigateOptions`](./NavigateOptionsType.md) type and contains additional options that can be used by TanStack Router when handling actual anchor element attributes. + +```tsx +type LinkOptions = NavigateOptions & { + target?: HTMLAnchorElement['target'] + activeOptions?: ActiveOptions + preload?: false | 'intent' + preloadDelay?: number + disabled?: boolean +} +``` + +## LinkOptions properties + +The `LinkOptions` object accepts/contains the following properties: + +### `target` + +- Type: `HTMLAnchorElement['target']` +- Optional +- The standard anchor tag target attribute + +### `activeOptions` + +- Type: `ActiveOptions` +- Optional +- The options that will be used to determine if the link is active + +### `preload` + +- Type: `false | 'intent' | 'viewport' | 'render'` +- Optional +- If set, the link's preloading strategy will be set to this value. +- See the [Preloading guide](../../guide/preloading.md) for more information. + +### `preloadDelay` + +- Type: `number` +- Optional +- Delay intent preloading by this many milliseconds. If the intent exits before this delay, the preload will be cancelled. + +### `disabled` + +- Type: `boolean` +- Optional +- If true, will render the link without the href attribute + +# LinkProps type + +The `LinkProps` type extends the [`ActiveLinkOptions`](./ActiveLinkOptionsType.md) and `React.AnchorHTMLAttributes` types and contains additional props specific to the `Link` component. + +```tsx +type LinkProps = ActiveLinkOptions & + Omit, 'children'> & { + children?: + | React.ReactNode + | ((state: { isActive: boolean }) => React.ReactNode) + } +``` + +## LinkProps properties + +- All of the props from [`ActiveLinkOptions`](./ActiveLinkOptionsType.md) +- All of the props from `React.AnchorHTMLAttributes` + +#### `children` + +- Type: `React.ReactNode | ((state: { isActive: boolean }) => React.ReactNode)` +- Optional +- The children that will be rendered inside of the anchor element. If a function is provided, it will be called with an object that contains the `isActive` boolean value that can be used to determine if the link is active. + +# MatchRouteOptions type + +The `MatchRouteOptions` type is used to describe the options that can be used when matching a route. + +```tsx +interface MatchRouteOptions { + pending?: boolean + caseSensitive?: boolean /* @deprecated */ + includeSearch?: boolean + fuzzy?: boolean +} +``` + +## MatchRouteOptions properties + +The `MatchRouteOptions` type has the following properties: + +### `pending` property + +- Type: `boolean` +- Optional +- If `true`, will match against pending location instead of the current location + +### ~~`caseSensitive`~~ property (deprecated) + +- Type: `boolean` +- Optional +- If `true`, will match against the current location with case sensitivity +- Declare case sensitivity in the route definition instead, or globally for all routes using the `caseSensitive` option on the router + +### `includeSearch` property + +- Type: `boolean` +- Optional +- If `true`, will match against the current location's search params using a deep inclusive check. e.g. `{ a: 1 }` will match for a current location of `{ a: 1, b: 2 }` + +### `fuzzy` property + +- Type: `boolean` +- Optional +- If `true`, will match against the current location using a fuzzy match. e.g. `/posts` will match for a current location of `/posts/123` + +# NavigateOptions type + +The `NavigateOptions` type is used to describe the options that can be used when describing a navigation action in TanStack Router. + +```tsx +type NavigateOptions = ToOptions & { + replace?: boolean + resetScroll?: boolean + hashScrollIntoView?: boolean | ScrollIntoViewOptions + viewTransition?: boolean | ViewTransitionOptions + ignoreBlocker?: boolean + reloadDocument?: boolean + href?: string +} +``` + +## NavigateOptions properties + +The `NavigateOptions` object accepts the following properties: + +### `replace` + +- Type: `boolean` +- Optional +- Defaults to `false`. +- If `true`, the location will be committed to the browser history using `history.replace` instead of `history.push`. + +### `resetScroll` + +- Type: `boolean` +- Optional +- Defaults to `true` so that the scroll position will be reset to 0,0 after the location is committed to the browser history. +- If `false`, the scroll position will not be reset to 0,0 after the location is committed to history. + +### `hashScrollIntoView` + +- Type: `boolean | ScrollIntoViewOptions` +- Optional +- Defaults to `true` so the element with an id matching the hash will be scrolled into view after the location is committed to history. +- If `false`, the element with an id matching the hash will not be scrolled into view after the location is committed to history. +- If an object is provided, it will be passed to the `scrollIntoView` method as options. +- See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView) for more information on `ScrollIntoViewOptions`. + +### `viewTransition` + +- Type: `boolean | ViewTransitionOptions` +- Optional +- Defaults to `false`. +- If `true`, navigation will be called using `document.startViewTransition()`. +- If [`ViewTransitionOptions`](./ViewTransitionOptionsType.md), route navigations will be called using `document.startViewTransition({update, types})` where `types` will determine the strings array passed with `ViewTransitionOptions["types"]`. If the browser does not support viewTransition types, the navigation will fall back to normal `document.startTransition()`, same as if `true` was passed. +- If the browser does not support this api, this option will be ignored. +- See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Document/startViewTransition) for more information on how this function works. +- See [Google](https://developer.chrome.com/docs/web-platform/view-transitions/same-document#view-transition-types) for more information on viewTransition types + +### `ignoreBlocker` + +- Type: `boolean` +- Optional +- Defaults to `false`. +- If `true`, navigation will ignore any blockers that might prevent it. + +### `reloadDocument` + +- Type: `boolean` +- Optional +- Defaults to `false`. +- If `true`, navigation to a route inside of router will trigger a full page load instead of the traditional SPA navigation. + +### `href` + +- Type: `string` +- Optional +- This can be used instead of `to` to navigate to a fully built href, e.g. pointing to an external target. + +- [`ToOptions`](./ToOptionsType.md) + +# NotFoundError + +The `NotFoundError` type is used to represent a not-found error in TanStack Router. + +```tsx +export type NotFoundError = { + global?: boolean + data?: any + throw?: boolean + routeId?: string + headers?: HeadersInit +} +``` + +## NotFoundError properties + +The `NotFoundError` object accepts/contains the following properties: + +### `global` property (⚠️ deprecated, use `routeId: rootRouteId` instead) + +- Type: `boolean` +- Optional - `default: false` +- If true, the not-found error will be handled by the `notFoundComponent` of the root route instead of bubbling up from the route that threw it. This has the same behavior as importing the root route and calling `RootRoute.notFound()`. + +### `data` property + +- Type: `any` +- Optional +- Custom data that is passed into to `notFoundComponent` when the not-found error is handled + +### `throw` property + +- Type: `boolean` +- Optional - `default: false` +- If provided, will throw the not-found object instead of returning it. This can be useful in places where `throwing` in a function might cause it to have a return type of `never`. In that case, you can use `notFound({ throw: true })` to throw the not-found object instead of returning it. + +### `route` property + +- Type: `string` +- Optional +- The ID of the route that will attempt to handle the not-found error. If the route does not have a `notFoundComponent`, the error will bubble up to the parent route (and be handled by the root route if necessary). By default, TanStack Router will attempt to handle the not-found error with the route that threw it. + +### `headers` property + +- Type: `HeadersInit` +- Optional +- HTTP headers to be included when the not-found error is handled on the server side. + +# NotFoundRoute class + +> [!CAUTION] +> This class has been deprecated and will be removed in the next major version of TanStack Router. +> Please use the `notFoundComponent` route option that is present during route configuration. +> See the [Not Found Errors guide](../../guide/not-found-errors.md) for more information. + +The `NotFoundRoute` class extends the `Route` class and can be used to create a not found route instance. A not found route instance can be passed to the `routerOptions.notFoundRoute` option to configure a default not-found/404 route for every branch of the route tree. + +## Constructor options + +The `NotFoundRoute` constructor accepts an object as its only argument. + +- Type: + +```tsx +Omit< + RouteOptions, + | 'path' + | 'id' + | 'getParentRoute' + | 'caseSensitive' + | 'parseParams' + | 'stringifyParams' +> +``` + +- [RouteOptions](./RouteOptionsType.md) +- Required +- The options that will be used to configure the not found route instance. + +## Examples + +```tsx +import { NotFoundRoute, createRouter } from '@tanstack/react-router' +import { Route as rootRoute } from './routes/__root' +import { routeTree } from './routeTree.gen' + +const notFoundRoute = new NotFoundRoute({ + getParentRoute: () => rootRoute, + component: () =>
Not found!!!
, +}) + +const router = createRouter({ + routeTree, + notFoundRoute, +}) + +// ... other code +``` + +# ParsedHistoryState type + +The `ParsedHistoryState` type represents a parsed state object. Additionally to `HistoryState`, it contains the index and the unique key of the route. + +```tsx +export type ParsedHistoryState = HistoryState & { + key?: string // TODO: Remove in v2 - use __TSR_key instead + __TSR_key?: string + __TSR_index: number +} +``` + +# ParsedLocation type + +The `ParsedLocation` type represents a parsed location in TanStack Router. It contains a lot of useful information about the current location, including the pathname, search params, hash, location state, and route masking information. + +```tsx +interface ParsedLocation { + href: string + pathname: string + search: TFullSearchSchema + searchStr: string + state: ParsedHistoryState + hash: string + maskedLocation?: ParsedLocation + unmaskOnReload?: boolean +} +``` + +# Redirect type + +The `Redirect` type is used to represent a redirect action in TanStack Router. + +```tsx +export type Redirect = { + statusCode?: number + throw?: any + headers?: HeadersInit +} & NavigateOptions +``` + +- [`NavigateOptions`](./NavigateOptionsType.md) + +## Redirect properties + +The `Redirect` object accepts/contains the following properties: + +### `statusCode` property + +- Type: `number` +- Optional +- The HTTP status code to use when redirecting + +### `throw` property + +- Type: `any` +- Optional +- If provided, will throw the redirect object instead of returning it. This can be useful in places where `throwing` in a function might cause it to have a return type of `never`. In that case, you can use `redirect({ throw: true })` to throw the redirect object instead of returning it. + +### `headers` property + +- Type: `HeadersInit` +- Optional +- The HTTP headers to use when redirecting. + +### Navigation Properties + +Since `Redirect` extends `NavigateOptions`, it also supports navigation properties: + +- **`to`**: Use for internal application routes (e.g., `/dashboard`, `../profile`) +- **`href`**: Use for external URLs (e.g., `https://example.com`, `https://authprovider.com`) + +> **Important**: For external URLs, always use the `href` property instead of `to`. The `to` property is designed for internal navigation within your application. + +# Register type + +This type is used to register a route tree with a router instance. Doing so unlocks the full type safety of TanStack Router, including top-level exports from the `@tanstack/react-router` package. + +```tsx +export type Register = { + // router: [Your router type here] +} +``` + +To register a route tree with a router instance, use declaration merging to add the type of your router instance to the Register interface under the `router` property: + +## Examples + +```tsx +const router = createRouter({ + // ... +}) + +declare module '@tanstack/react-router' { + interface Register { + router: typeof router + } +} +``` + +# RootRoute class + +> [!CAUTION] +> This class has been deprecated and will be removed in the next major version of TanStack Router. +> Please use the [`createRootRoute`](./createRootRouteFunction.md) function instead. + +The `RootRoute` class extends the `Route` class and can be used to create a root route instance. A root route instance can then be used to create a route tree. + +## `RootRoute` constructor + +The `RootRoute` constructor accepts an object as its only argument. + +### Constructor options + +The options that will be used to configure the root route instance. + +- Type: + +```tsx +Omit< + RouteOptions, + | 'path' + | 'id' + | 'getParentRoute' + | 'caseSensitive' + | 'parseParams' + | 'stringifyParams' +> +``` + +- [`RouteOptions`](./RouteOptionsType.md) +- Optional + +## Constructor returns + +A new [`Route`](./RouteType.md) instance. + +## Examples + +```tsx +import { RootRoute, createRouter, Outlet } from '@tanstack/react-router' + +const rootRoute = new RootRoute({ + component: () => , + // ... root route options +}) + +const routeTree = rootRoute.addChildren([ + // ... other routes +]) + +const router = createRouter({ + routeTree, +}) +``` + +# RouteApi class + +> [!CAUTION] +> This class has been deprecated and will be removed in the next major version of TanStack Router. +> Please use the [`getRouteApi`](./getRouteApiFunction.md) function instead. + +The `RouteApi` class provides type-safe version of common hooks like `useParams`, `useSearch`, `useRouteContext`, `useNavigate`, `useLoaderData`, and `useLoaderDeps` that are pre-bound to a specific route ID and corresponding registered route types. + +## Constructor options + +The `RouteApi` constructor accepts a single argument: the `options` that will be used to configure the `RouteApi` instance. + +### `opts.routeId` option + +- Type: `string` +- Required +- The route ID to which the `RouteApi` instance will be bound + +## Constructor returns + +- An instance of the [`RouteApi`](./RouteApiType.md) that is pre-bound to the route ID that it was called with. + +## Examples + +```tsx +import { RouteApi } from '@tanstack/react-router' + +const routeApi = new RouteApi({ id: '/posts' }) + +export function PostsPage() { + const posts = routeApi.useLoaderData() + // ... +} +``` + +# RouteApi Type + +The `RouteApi` describes an instance that provides type-safe versions of common hooks like `useParams`, `useSearch`, `useRouteContext`, `useNavigate`, `useLoaderData`, and `useLoaderDeps` that are pre-bound to a specific route ID and corresponding registered route types. + +## `RouteApi` properties and methods + +The `RouteApi` has the following properties and methods: + +### `useMatch` method + +```tsx + useMatch(opts?: { + select?: (match: TAllContext) => TSelected + }): TSelected +``` + +- A type-safe version of the [`useMatch`](./useMatchHook.md) hook that is pre-bound to the route ID that the `RouteApi` instance was created with. +- Options + - `opts.select` + - Optional + - `(match: RouteMatch) => TSelected` + - If supplied, this function will be called with the route match and the return value will be returned from `useMatch`. This value will also be used to determine if the hook should re-render its parent component using shallow equality checks. + - `opts.structuralSharing` + - Optional + - `boolean` + - Configures whether structural sharing is enabled for the value returned by `select`. + - See the [Render Optimizations guide](../../guide/render-optimizations.md) for more information. +- Returns + - If a `select` function is provided, the return value of the `select` function. + - If no `select` function is provided, the `RouteMatch` object or a loosened version of the `RouteMatch` object if `opts.strict` is `false`. + +### `useRouteContext` method + +```tsx + useRouteContext(opts?: { + select?: (search: TAllContext) => TSelected + }): TSelected +``` + +- A type-safe version of the [`useRouteContext`](./useRouteContextHook.md) hook that is pre-bound to the route ID that the `RouteApi` instance was created with. +- Options + - `opts.select` + - Optional + - `(match: RouteContext) => TSelected` + - If supplied, this function will be called with the route match and the return value will be returned from `useRouteContext`. This value will also be used to determine if the hook should re-render its parent component using shallow equality checks. +- Returns + - If a `select` function is provided, the return value of the `select` function. + - If no `select` function is provided, the `RouteContext` object or a loosened version of the `RouteContext` object if `opts.strict` is `false`. + +### `useSearch` method + +```tsx + useSearch(opts?: { + select?: (search: TFullSearchSchema) => TSelected + }): TSelected +``` + +- A type-safe version of the [`useSearch`](./useSearchHook.md) hook that is pre-bound to the route ID that the `RouteApi` instance was created with. +- Options + - `opts.select` + - Optional + - `(match: TFullSearchSchema) => TSelected` + - If supplied, this function will be called with the route match and the return value will be returned from `useSearch`. This value will also be used to determine if the hook should re-render its parent component using shallow equality checks. + - `opts.structuralSharing` + - Optional + - `boolean` + - Configures whether structural sharing is enabled for the value returned by `select`. + - See the [Render Optimizations guide](../../guide/render-optimizations.md) for more information. +- Returns + - If a `select` function is provided, the return value of the `select` function. + - If no `select` function is provided, the `TFullSearchSchema` object or a loosened version of the `TFullSearchSchema` object if `opts.strict` is `false`. + +### `useParams` method + +```tsx + useParams(opts?: { + select?: (params: TAllParams) => TSelected + }): TSelected +``` + +- A type-safe version of the [`useParams`](./useParamsHook.md) hook that is pre-bound to the route ID that the `RouteApi` instance was created with. +- Options + - `opts.select` + - Optional + - `(match: TAllParams) => TSelected` + - If supplied, this function will be called with the route match and the return value will be returned from `useParams`. This value will also be used to determine if the hook should re-render its parent component using shallow equality checks. + - `opts.structuralSharing` + - Optional + - `boolean` + - Configures whether structural sharing is enabled for the value returned by `select`. + - See the [Render Optimizations guide](../../guide/render-optimizations.md) for more information. +- Returns + - If a `select` function is provided, the return value of the `select` function. + - If no `select` function is provided, the `TAllParams` object or a loosened version of the `TAllParams` object if `opts.strict` is `false`. + +### `useLoaderData` method + +```tsx + useLoaderData(opts?: { + select?: (search: TLoaderData) => TSelected + }): TSelected +``` + +- A type-safe version of the [`useLoaderData`](./useLoaderDataHook.md) hook that is pre-bound to the route ID that the `RouteApi` instance was created with. +- Options + - `opts.select` + - Optional + - `(match: TLoaderData) => TSelected` + - If supplied, this function will be called with the route match and the return value will be returned from `useLoaderData`. This value will also be used to determine if the hook should re-render its parent component using shallow equality checks. + - `opts.structuralSharing` + - Optional + - `boolean` + - Configures whether structural sharing is enabled for the value returned by `select`. + - See the [Render Optimizations guide](../../guide/render-optimizations.md) for more information. +- Returns + - If a `select` function is provided, the return value of the `select` function. + - If no `select` function is provided, the `TLoaderData` object or a loosened version of the `TLoaderData` object if `opts.strict` is `false`. + +### `useLoaderDeps` method + +```tsx + useLoaderDeps(opts?: { + select?: (search: TLoaderDeps) => TSelected + }): TSelected +``` + +- A type-safe version of the [`useLoaderDeps`](./useLoaderDepsHook.md) hook that is pre-bound to the route ID that the `RouteApi` instance was created with. +- Options + - `opts.select` + - Optional + - `(match: TLoaderDeps) => TSelected` + - If supplied, this function will be called with the route match and the return value will be returned from `useLoaderDeps`. + - `opts.structuralSharing` + - Optional + - `boolean` + - Configures whether structural sharing is enabled for the value returned by `select`. + - See the [Render Optimizations guide](../../guide/render-optimizations.md) for more information. +- Returns + - If a `select` function is provided, the return value of the `select` function. + - If no `select` function is provided, the `TLoaderDeps` object. + +### `useNavigate` method + +```tsx + useNavigate(): // navigate function +``` + +- A type-safe version of [`useNavigate`](./useNavigateHook.md) that is pre-bound to the route ID that the `RouteApi` instance was created with. + +# Route class + +> [!CAUTION] +> This class has been deprecated and will be removed in the next major version of TanStack Router. +> Please use the [`createRoute`](./createRouteFunction.md) function instead. + +The `Route` class implements the `RouteApi` class and can be used to create route instances. A route instance can then be used to create a route tree. + +## `Route` constructor + +The `Route` constructor accepts an object as its only argument. + +### Constructor options + +- Type: [`RouteOptions`](./RouteOptionsType.md) +- Required +- The options that will be used to configure the route instance + +### Constructor returns + +A new [`Route`](./RouteType.md) instance. + +## Examples + +```tsx +import { Route } from '@tanstack/react-router' +import { rootRoute } from './__root' + +const indexRoute = new Route({ + getParentRoute: () => rootRoute, + path: '/', + loader: () => { + return 'Hello World' + }, + component: IndexComponent, +}) + +function IndexComponent() { + const data = indexRoute.useLoaderData() + return
{data}
+} +``` + +# RouteMask type + +The `RouteMask` type extends the [`ToOptions`](./ToOptionsType.md) type and has other the necessary properties to create a route mask. + +## RouteMask properties + +The `RouteMask` type accepts an object with the following properties: + +### `...ToOptions` + +- Type: [`ToOptions`](./ToOptionsType.md) +- Required +- The options that will be used to configure the route mask + +### `options.routeTree` + +- Type: `TRouteTree` +- Required +- The route tree that this route mask will support + +### `options.unmaskOnReload` + +- Type: `boolean` +- Optional +- If `true`, the route mask will be removed when the page is reloaded + +# RouteMatch type + +The `RouteMatch` type represents a route match in TanStack Router. + +```tsx +interface RouteMatch { + id: string + routeId: string + pathname: string + params: Route['allParams'] + status: 'pending' | 'success' | 'error' | 'redirected' | 'notFound' + isFetching: false | 'beforeLoad' | 'loader' + showPending: boolean + error: unknown + paramsError: unknown + searchError: unknown + updatedAt: number + loaderData?: Route['loaderData'] + context: Route['allContext'] + search: Route['fullSearchSchema'] + fetchedAt: number + abortController: AbortController + cause: 'enter' | 'stay' + ssr?: boolean | 'data-only' +} +``` + +# RouteOptions type + +The `RouteOptions` type is used to describe the options that can be used when creating a route. + +## RouteOptions properties + +The `RouteOptions` type accepts an object with the following properties: + +### `getParentRoute` method + +- Type: `() => TParentRoute` +- Required +- A function that returns the parent route of the route being created. This is required to provide full type safety to child route configurations and to ensure that the route tree is built correctly. + +### `path` property + +- Type: `string` +- Required, unless an `id` is provided to configure the route as a pathless layout route +- The path segment that will be used to match the route. + +### `id` property + +- Type: `string` +- Optional, but required if a `path` is not provided +- The unique identifier for the route if it is to be configured as a pathless layout route. If provided, the route will not match against the location pathname and its routes will be flattened into its parent route for matching. + +### `component` property + +- Type: `RouteComponent` or `LazyRouteComponent` +- Optional - Defaults to `` +- The content to be rendered when the route is matched. + +### `errorComponent` property + +- Type: `RouteComponent` or `LazyRouteComponent` +- Optional - Defaults to `routerOptions.defaultErrorComponent` +- The content to be rendered when the route encounters an error. + +### `pendingComponent` property + +- Type: `RouteComponent` or `LazyRouteComponent` +- Optional - Defaults to `routerOptions.defaultPendingComponent` +- The content to be rendered if and when the route is pending and has reached its pendingMs threshold. + +### `notFoundComponent` property + +- Type: `NotFoundRouteComponent` or `LazyRouteComponent` +- Optional - Defaults to `routerOptions.defaultNotFoundComponent` +- The content to be rendered when the route is not found. + +### `validateSearch` method + +- Type: `(rawSearchParams: unknown) => TSearchSchema` +- Optional +- A function that will be called when this route is matched and passed the raw search params from the current location and return valid parsed search params. If this function throws, the route will be put into an error state and the error will be thrown during render. If this function does not throw, its return value will be used as the route's search params and the return type will be inferred into the rest of the router. +- Optionally, the parameter type can be tagged with the `SearchSchemaInput` type like this: `(searchParams: TSearchSchemaInput & SearchSchemaInput) => TSearchSchema`. If this tag is present, `TSearchSchemaInput` will be used to type the `search` property of `` and `navigate()` **instead of** `TSearchSchema`. The difference between `TSearchSchemaInput` and `TSearchSchema` can be useful, for example, to express optional search parameters. + +### `search.middlewares` property + +- Type: `(({search: TSearchSchema, next: (newSearch: TSearchSchema) => TSearchSchema}) => TSearchSchema)[]` +- Optional +- Search middlewares are functions that transform the search parameters when generating new links for a route or its descendants. +- A search middleware is passed in the current search (if it is the first middleware to run) or is invoked by the previous middleware calling `next`. + +### `parseParams` method (⚠️ deprecated, use `params.parse` instead) + +- Type: `(rawParams: Record) => TParams` +- Optional +- A function that will be called when this route is matched and passed the raw params from the current location and return valid parsed params. If this function throws, the route will be put into an error state and the error will be thrown during render. If this function does not throw, its return value will be used as the route's params and the return type will be inferred into the rest of the router. + +### `stringifyParams` method (⚠️ deprecated, use `params.stringify` instead) + +- Type: `(params: TParams) => Record` +- Required if `parseParams` is provided +- A function that will be called when this route's parsed params are being used to build a location. This function should return a valid object of `Record` mapping. + +### `params.parse` method + +- Type: `(rawParams: Record) => TParams` +- Optional +- A function that will be called when this route is matched and passed the raw params from the current location and return valid parsed params. If this function throws, the route will be put into an error state and the error will be thrown during render. If this function does not throw, its return value will be used as the route's params and the return type will be inferred into the rest of the router. + +### `params.stringify` method + +- Type: `(params: TParams) => Record` +- A function that will be called when this route's parsed params are being used to build a location. This function should return a valid object of `Record` mapping. + +### `beforeLoad` method + +- Type: + +```tsx +type beforeLoad = ( + opts: RouteMatch & { + search: TFullSearchSchema + abortController: AbortController + preload: boolean + params: TAllParams + context: TParentContext + location: ParsedLocation + navigate: NavigateFn // @deprecated + buildLocation: BuildLocationFn + cause: 'enter' | 'stay' + }, +) => Promise | TRouteContext | void +``` + +- Optional +- [`ParsedLocation`](./ParsedLocationType.md) +- This async function is called before a route is loaded. If an error is thrown here, the route's loader will not be called and the route will not render. If thrown during a navigation, the navigation will be canceled and the error will be passed to the `onError` function. If thrown during a preload event, the error will be logged to the console and the preload will fail. +- If this function returns a promise, the route will be put into a pending state and cause rendering to suspend until the promise resolves. If this route's pendingMs threshold is reached, the `pendingComponent` will be shown until it resolves. If the promise rejects, the route will be put into an error state and the error will be thrown during render. +- If this function returns a `TRouteContext` object, that object will be merged into the route's context and be made available in the `loader` and other related route components/methods. +- It's common to use this function to check if a user is authenticated and redirect them to a login page if they are not. To do this, you can either return or throw a `redirect` object from this function. + +> 🚧 `opts.navigate` has been deprecated and will be removed in the next major release. Use `throw redirect({ to: '/somewhere' })` instead. Read more about the `redirect` function [here](./redirectFunction.md). + +### `loader` method + +- Type: + +```tsx +type loader = ( + opts: RouteMatch & { + abortController: AbortController + cause: 'preload' | 'enter' | 'stay' + context: TAllContext + deps: TLoaderDeps + location: ParsedLocation + params: TAllParams + preload: boolean + parentMatchPromise: Promise> + navigate: NavigateFn // @deprecated + route: AnyRoute + }, +) => Promise | TLoaderData | void +``` + +- Optional +- [`ParsedLocation`](./ParsedLocationType.md) +- This async function is called when a route is matched and passed the route's match object. If an error is thrown here, the route will be put into an error state and the error will be thrown during render. If thrown during a navigation, the navigation will be canceled and the error will be passed to the `onError` function. If thrown during a preload event, the error will be logged to the console and the preload will fail. +- If this function returns a promise, the route will be put into a pending state and cause rendering to suspend until the promise resolves. If this route's pendingMs threshold is reached, the `pendingComponent` will be shown until it resolves. If the promise rejects, the route will be put into an error state and the error will be thrown during render. +- If this function returns a `TLoaderData` object, that object will be stored on the route match until the route match is no longer active. It can be accessed using the `useLoaderData` hook in any component that is a child of the route match before another `` is rendered. +- Deps must be returned by your `loaderDeps` function in order to appear. + +> 🚧 `opts.navigate` has been deprecated and will be removed in the next major release. Use `throw redirect({ to: '/somewhere' })` instead. Read more about the `redirect` function [here](./redirectFunction.md). + +### `loaderDeps` method + +- Type: + +```tsx +type loaderDeps = (opts: { search: TFullSearchSchema }) => Record +``` + +- Optional +- A function that will be called before this route is matched to provide additional unique identification to the route match and serve as a dependency tracker for when the match should be reloaded. It should return any serializable value that can uniquely identify the route match from navigation to navigation. +- By default, path params are already used to uniquely identify a route match, so it's unnecessary to return these here. +- If your route match relies on search params for unique identification, it's required that you return them here so they can be made available in the `loader`'s `deps` argument. + +### `staleTime` property + +- Type: `number` +- Optional +- Defaults to `routerOptions.defaultStaleTime`, which defaults to `0` +- The amount of time in milliseconds that a route match's loader data will be considered fresh. If a route match is matched again within this time frame, its loader data will not be reloaded. + +### `preloadStaleTime` property + +- Type: `number` +- Optional +- Defaults to `routerOptions.defaultPreloadStaleTime`, which defaults to `30_000` ms (30 seconds) +- The amount of time in milliseconds that a route match's loader data will be considered fresh when preloading. If a route match is preloaded again within this time frame, its loader data will not be reloaded. If a route match is loaded (for navigation) within this time frame, the normal `staleTime` is used instead. + +### `gcTime` property + +- Type: `number` +- Optional +- Defaults to `routerOptions.defaultGcTime`, which defaults to 30 minutes. +- The amount of time in milliseconds that a route match's loader data will be kept in memory after a preload or it is no longer in use. + +### `shouldReload` property + +- Type: `boolean | ((args: LoaderArgs) => boolean)` +- Optional +- If `false` or returns `false`, the route match's loader data will not be reloaded on subsequent matches. +- If `true` or returns `true`, the route match's loader data will be reloaded on subsequent matches. +- If `undefined` or returns `undefined`, the route match's loader data will adhere to the default stale-while-revalidate behavior. + +### `caseSensitive` property + +- Type: `boolean` +- Optional +- If `true`, this route will be matched as case-sensitive. + +### `wrapInSuspense` property + +- Type: `boolean` +- Optional +- If `true`, this route will be forcefully wrapped in a suspense boundary, regardless if a reason is found to do so from inspecting its provided components. + +### `pendingMs` property + +- Type: `number` +- Optional +- Defaults to `routerOptions.defaultPendingMs`, which defaults to `1000` +- The threshold in milliseconds that a route must be pending before its `pendingComponent` is shown. + +### `pendingMinMs` property + +- Type: `number` +- Optional +- Defaults to `routerOptions.defaultPendingMinMs` which defaults to `500` +- The minimum amount of time in milliseconds that the pending component will be shown for if it is shown. This is useful to prevent the pending component from flashing on the screen for a split second. + +### `preloadMaxAge` property + +- Type: `number` +- Optional +- Defaults to `30_000` ms (30 seconds) +- The maximum amount of time in milliseconds that a route's preloaded route data will be cached for. If a route is not matched within this time frame, its loader data will be discarded. + +### `preSearchFilters` property (⚠️ deprecated, use `search.middlewares` instead) + +- Type: `((search: TFullSearchSchema) => TFullSearchSchema)[]` +- Optional +- An array of functions that will be called when generating any new links to this route or its grandchildren. +- Each function will be called with the current search params and should return a new search params object that will be used to generate the link. +- It has a `pre` prefix because it is called before the user-provided function that is passed to `navigate`/`Link` etc has a chance to modify the search params. + +### `postSearchFilters` property (⚠️ deprecated, use `search.middlewares` instead) + +- Type: `((search: TFullSearchSchema) => TFullSearchSchema)[]` +- Optional +- An array of functions that will be called when generating any new links to this route or its grandchildren. +- Each function will be called with the current search params and should return a new search params object that will be used to generate the link. +- It has a `post` prefix because it is called after the user-provided function that is passed to `navigate`/`Link` etc has modified the search params. + +### `onError` property + +- Type: `(error: any) => void` +- Optional +- A function that will be called when an error is thrown during a navigation or preload event. +- If this function throws a [`redirect`](./redirectFunction.md), then the router will process and apply the redirect immediately. + +### `onEnter` property + +- Type: `(match: RouteMatch) => void` +- Optional +- A function that will be called when a route is matched and loaded after not being matched in the previous location. + +### `onStay` property + +- Type: `(match: RouteMatch) => void` +- Optional +- A function that will be called when a route is matched and loaded after being matched in the previous location. + +### `onLeave` property + +- Type: `(match: RouteMatch) => void` +- Optional +- A function that will be called when a route is no longer matched after being matched in the previous location. + +### `onCatch` property + +- Type: `(error: Error, errorInfo: ErrorInfo) => void` +- Optional - Defaults to `routerOptions.defaultOnCatch` +- A function that will be called when errors are caught when the route encounters an error. + +### `remountDeps` method + +- Type: + +```tsx +type remountDeps = (opts: RemountDepsOptions) => any + +interface RemountDepsOptions< + in out TRouteId, + in out TFullSearchSchema, + in out TAllParams, + in out TLoaderDeps, +> { + routeId: TRouteId + search: TFullSearchSchema + params: TAllParams + loaderDeps: TLoaderDeps +} +``` + +- Optional +- A function that will be called to determine whether a route component shall be remounted after navigation. If this function returns a different value than previously, it will remount. +- The return value needs to be JSON serializable. +- By default, a route component will not be remounted if it stays active after a navigation. + +Example: +If you want to configure to remount a route component upon `params` change, use: + +```tsx +remountDeps: ({ params }) => params +``` + +### `headers` method + +- Type: + +```tsx +type headers = (opts: { + matches: Array + match: RouteMatch + params: TAllParams + loaderData?: TLoaderData +}) => Promise> | Record +``` + +- Optional +- Allows you to specify custom HTTP headers to be sent when this route is rendered during SSR. The function receives the current match context and should return a plain object of header name/value pairs. + +### `head` method + +- Type: + +```tsx +type head = (ctx: { + matches: Array + match: RouteMatch + params: TAllParams + loaderData?: TLoaderData +}) => + | Promise<{ + links?: RouteMatch['links'] + scripts?: RouteMatch['headScripts'] + meta?: RouteMatch['meta'] + styles?: RouteMatch['styles'] + }> + | { + links?: RouteMatch['links'] + scripts?: RouteMatch['headScripts'] + meta?: RouteMatch['meta'] + styles?: RouteMatch['styles'] + } +``` + +- Optional +- Returns additional elements to inject into the document `` for this route. Use it to add route-level SEO metadata, preload links, inline styles, or custom scripts. + +### `scripts` method + +- Type: + +```tsx +type scripts = (ctx: { + matches: Array + match: RouteMatch + params: TAllParams + loaderData?: TLoaderData +}) => Promise | RouteMatch['scripts'] +``` + +- Optional +- A shorthand helper to return only ` + + diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 0000000..e4f3617 --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,9394 @@ +{ + "name": "senmesh-zc-legacy", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "senmesh-zc-legacy", + "version": "0.0.0", + "dependencies": { + "@hookform/resolvers": "^5.2.2", + "@radix-ui/react-alert-dialog": "^1.1.15", + "@radix-ui/react-avatar": "^1.1.11", + "@radix-ui/react-checkbox": "^1.3.3", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-label": "^2.1.8", + "@radix-ui/react-popover": "^1.1.15", + "@radix-ui/react-progress": "^1.1.8", + "@radix-ui/react-radio-group": "^1.3.8", + "@radix-ui/react-select": "^2.2.6", + "@radix-ui/react-separator": "^1.1.8", + "@radix-ui/react-slot": "^1.2.4", + "@radix-ui/react-switch": "^1.2.6", + "@radix-ui/react-tabs": "^1.1.13", + "@radix-ui/react-toggle": "^1.1.10", + "@radix-ui/react-toggle-group": "^1.1.11", + "@radix-ui/react-tooltip": "^1.2.8", + "@tanstack/react-pacer": "^0.19.0", + "@tanstack/react-query": "^5.90.12", + "@tanstack/react-query-devtools": "^5.91.2", + "@tanstack/react-router": "^1.143.11", + "@tanstack/react-table": "^8.21.3", + "axios": "^1.15.1", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "copy-to-clipboard": "^3.3.3", + "date-fns": "^4.1.0", + "derive-zustand": "^0.2.0", + "highlight.js": "^11.11.1", + "immer": "^11.1.0", + "lucide-react": "^0.562.0", + "mammoth": "^1.11.0", + "nanoid": "^5.1.6", + "next-themes": "^0.4.6", + "react": "^19.2.3", + "react-day-picker": "^9.13.0", + "react-dom": "^19.2.3", + "react-dropzone": "^14.3.8", + "react-hook-form": "^7.69.0", + "react-markdown": "^10.1.0", + "recharts": "2.15.4", + "rehype-highlight": "^7.0.2", + "rehype-raw": "^7.0.0", + "remark-gfm": "^4.0.1", + "sonner": "^2.0.7", + "tailwind-merge": "^3.4.0", + "tailwindcss": "^3.4.17", + "vaul": "^1.1.2", + "xlsx": "^0.18.5", + "zod": "^4.2.1", + "zustand": "^5.0.9" + }, + "devDependencies": { + "@eslint/js": "^9.39.1", + "@tanstack/react-router-devtools": "^1.158.1", + "@tanstack/router-plugin": "^1.158.1", + "@types/node": "^25.2.0", + "@types/react": "^19.2.5", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react-swc": "^4.2.2", + "autoprefixer": "^10.4.24", + "eslint": "^9.39.1", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.4.24", + "globals": "^16.5.0", + "postcss": "^8.5.6", + "tailwindcss-animate": "^1.0.7", + "typescript": "~5.9.3", + "typescript-eslint": "^8.46.4", + "vite": "npm:rolldown-vite@latest" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/@alloc/quick-lru/-/quick-lru-5.3.0.tgz", + "integrity": "sha512-U4+70Pc5ZS9osnCBCE5Jha/ciHM+Yp+CNMNC/7HvYbNRk1Ldd+f7qO65W5qfhu/TCv+/ozljlXXe9Nj8419DMA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.12", + "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.29.12.tgz", + "integrity": "sha512-2W76mhjrpQFO1lK5e8IvGYB2D0YZ7S2R1Z2BjO2ZUYuW+amcpK/z60U6ZZmzskwoa7sJ6XohP/Wg8H5KxXI/IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.12", + "@babel/types": "^7.29.11", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.11", + "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.29.11.tgz", + "integrity": "sha512-snZbO7MEDOof+hvNa97EjEY7qD7h2kwvQr5AJC3ZhQudKW5dnej6k3kP9NQV88hJwaS8vDqRLFo9rivLEhle2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.10", + "resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.29.10.tgz", + "integrity": "sha512-EMCx3AGZ3WfAl6ht7AyQoPm2Lh+BGYEMdc4Q6Hf7uSCDOZFuLq44qNwL+iaim8VlyYhRAo4X43+weadK8ZB4Yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.12", + "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.29.12.tgz", + "integrity": "sha512-WJ7JBp/Q4+z/ImydtI7jS6NVco5++632ExBemSX+Ysb+G1lCwQ5BVo3SY+jGGOcZXI4ZccbZSUSJLNBW6eEpJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.11" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.10", + "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.29.10.tgz", + "integrity": "sha512-NpugTzbKgGrNe45Ui32cN8vCFFMxVtP/9rtfwv0nP5FRDAjvYBxJcLVpYA9mr1jxP6cnIT7x9LUzuDTbWYYNRA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.12", + "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.29.12.tgz", + "integrity": "sha512-MscXe/NAZcOkYEsRajHZFt3ynsb22PUi6CTrp5U7+RYycR9By84mn9mFN54YgfITiqK4hFx3Ju3tZSyzfpS5ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.12", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.12", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.11", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.11", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.29.11.tgz", + "integrity": "sha512-WCsemW40Cpc6gouC1SrY6PBaZ+oLRlEVY9XBvZBI7il/HyUrb2nJ505wE1MHEFyDZNnrWDEuy4jL50WVHfTTSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.11", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@corvu/utils": { + "version": "0.4.2", + "resolved": "https://registry.npmmirror.com/@corvu/utils/-/utils-0.4.2.tgz", + "integrity": "sha512-Ox2kYyxy7NoXdKWdHeDEjZxClwzO4SKM8plAaVwmAJPxHMqA0rLOoAsa+hBDwRLpctf+ZRnAd/ykguuJidnaTA==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.6.11" + }, + "peerDependencies": { + "solid-js": "^1.8" + } + }, + "node_modules/@date-fns/tz": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/@date-fns/tz/-/tz-1.5.0.tgz", + "integrity": "sha512-lwYN/vDPeNRULcepoE/LO2Pgx+7/RV+S9ARfbc9lr2DtGkOD7pAiruHvbR1RX3Qyf6ja47EWJDMsNK5vK08DJg==", + "license": "MIT" + }, + "node_modules/@emnapi/core": { + "version": "1.11.3", + "resolved": "https://registry.npmmirror.com/@emnapi/core/-/core-1.11.3.tgz", + "integrity": "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.3", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.3", + "resolved": "https://registry.npmmirror.com/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/@emnapi/wasi-threads/-/wasi-threads-1.2.3.tgz", + "integrity": "sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.10.1", + "resolved": "https://registry.npmmirror.com/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", + "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmmirror.com/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmmirror.com/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmmirror.com/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmmirror.com/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.7", + "resolved": "https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-3.3.7.tgz", + "integrity": "sha512-F42g89Qd5oAWtp0k0nnSrjziAKza7w8SVT4mStc18LZMaRb4J1HQAHLCalEtDCxrTuksx7NU9qsmeLwpOfPqWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.3.2", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmmirror.com/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.5", + "resolved": "https://registry.npmmirror.com/@eslint/js/-/js-9.39.5.tgz", + "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmmirror.com/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.8.0", + "resolved": "https://registry.npmmirror.com/@floating-ui/core/-/core-1.8.0.tgz", + "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.8.0", + "resolved": "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.8.0.tgz", + "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.8.0", + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.9", + "resolved": "https://registry.npmmirror.com/@floating-ui/react-dom/-/react-dom-2.1.9.tgz", + "integrity": "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.8.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.12", + "resolved": "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.12.tgz", + "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", + "license": "MIT" + }, + "node_modules/@hookform/resolvers": { + "version": "5.9.2", + "resolved": "https://registry.npmmirror.com/@hookform/resolvers/-/resolvers-5.9.2.tgz", + "integrity": "sha512-RtjTnZqsC38s4NKp2XO3fD8IA5uyN4tB7McQ5C6uiMPcV+WWO8F+wVa3e+BXUpH2ScgxghAlwFRMVqjT9WChAQ==", + "license": "MIT", + "dependencies": { + "@standard-schema/utils": "^0.3.0" + }, + "peerDependencies": { + "@sinclair/typebox": ">=0.25.24", + "@standard-schema/spec": "^1.0.0", + "@typeschema/main": ">=0.13.7", + "@vinejs/vine": "^2.0.0 || ^3.0.0 || ^4.0.0", + "ajv": "^8.12.0", + "ajv-errors": "^3.0.0", + "ajv-formats": "^2.1.1", + "arktype": "^2.0.0", + "ata-validator": "^1.23.0", + "class-transformer": ">=0.4.0", + "class-validator": ">=0.12.0", + "computed-types": "^1.0.0", + "effect": "^3.10.3", + "fluentvalidation-ts": "^3.0.0", + "fp-ts": "^2.7.0", + "io-ts": "^2.0.0", + "joi": "^17.0.0 || ^18.0.0", + "nope-validator": ">=0.12.0", + "react-hook-form": "^7.55.0", + "superstruct": ">=0.12.0", + "typanion": "^3.3.2", + "valibot": ">=0.31.0 || ^1.0.0-beta.4 || ^1.0.0-rc", + "vest": ">=6.0.0", + "yup": "^1.0.0", + "zod": "^3.25.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "@sinclair/typebox": { + "optional": true + }, + "@standard-schema/spec": { + "optional": true + }, + "@typeschema/main": { + "optional": true + }, + "@vinejs/vine": { + "optional": true + }, + "ajv": { + "optional": true + }, + "ajv-errors": { + "optional": true + }, + "ajv-formats": { + "optional": true + }, + "arktype": { + "optional": true + }, + "ata-validator": { + "optional": true + }, + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + }, + "computed-types": { + "optional": true + }, + "effect": { + "optional": true + }, + "fluentvalidation-ts": { + "optional": true + }, + "fp-ts": { + "optional": true + }, + "io-ts": { + "optional": true + }, + "joi": { + "optional": true + }, + "nope-validator": { + "optional": true + }, + "superstruct": { + "optional": true + }, + "typanion": { + "optional": true + }, + "valibot": { + "optional": true + }, + "vest": { + "optional": true + }, + "yup": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmmirror.com/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmmirror.com/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmmirror.com/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmmirror.com/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@internationalized/number": { + "version": "3.6.9", + "resolved": "https://registry.npmmirror.com/@internationalized/number/-/number-3.6.9.tgz", + "integrity": "sha512-GgWy2caO/+hV9sT/oCTWGHvbjmJMPT9kkXzoKRLnkEq7adghhR7UprhvY9sXrKfrp3NcDfhF6QQHXR1KfQbB8g==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmmirror.com/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@kobalte/core": { + "version": "0.13.14", + "resolved": "https://registry.npmmirror.com/@kobalte/core/-/core-0.13.14.tgz", + "integrity": "sha512-SBVB1lnvYbYt2x3t7fG0lo5fGLEbHQ6PII3NDPva8vD5e2v53On84ZVQiuIk0XI/55R4GQhden7Yem+R/XR8uQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.5.1", + "@internationalized/number": "^3.2.1", + "@kobalte/utils": "^0.9.2", + "@solid-primitives/props": "^3.1.8", + "@solid-primitives/resize-observer": "^2.0.26", + "solid-presence": "^0.2.0", + "solid-prevent-scroll": "^0.1.11" + }, + "peerDependencies": { + "solid-js": "^1.9.8" + } + }, + "node_modules/@kobalte/utils": { + "version": "0.9.2", + "resolved": "https://registry.npmmirror.com/@kobalte/utils/-/utils-0.9.2.tgz", + "integrity": "sha512-jRVXr+zsVHxzDXRoh+CDeXzvCsFJ6uiHhqqNQ26Cw9ZsZ3D6nqPUBt1gGVtj2ZPmRL3a9Uk1v8D1aJ8/I12Dow==", + "license": "MIT", + "dependencies": { + "@solid-primitives/event-listener": "^2.2.14", + "@solid-primitives/keyed": "^1.2.0", + "@solid-primitives/map": "^0.4.7", + "@solid-primitives/media": "^2.2.4", + "@solid-primitives/props": "^3.1.8", + "@solid-primitives/refs": "^1.0.5", + "@solid-primitives/utils": "^6.2.1" + }, + "peerDependencies": { + "solid-js": "^1.8.8" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.2.6", + "resolved": "https://registry.npmmirror.com/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.6.tgz", + "integrity": "sha512-mRyDmEw9/fCDXCGfL1sbgIw/GUK0PVxRW4YwgPN61F3LQ+fSyoBFarJVzgGyhF6kRzEQZ0FejDqm4WLXSeqQmw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1 || 2.0.0-beta.2", + "@emnapi/runtime": "^1.7.1 || 2.0.0-beta.2" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@oxc-project/runtime": { + "version": "0.101.0", + "resolved": "https://registry.npmmirror.com/@oxc-project/runtime/-/runtime-0.101.0.tgz", + "integrity": "sha512-t3qpfVZIqSiLQ5Kqt/MC4Ge/WCOGrrcagAdzTcDaggupjiGxUx4nJF2v6wUCXWSzWHn5Ns7XLv13fCJEwCOERQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.101.0", + "resolved": "https://registry.npmmirror.com/@oxc-project/types/-/types-0.101.0.tgz", + "integrity": "sha512-nuFhqlUzJX+gVIPPfuE6xurd4lST3mdcWOhyK/rZO0B9XWMKm79SuszIQEnSMmmDhq1DC8WWVYGVd+6F93o1gQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@radix-ui/number": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/@radix-ui/number/-/number-1.1.3.tgz", + "integrity": "sha512-Road2bidD0uu/1BGDOWNdPI06g0lIRy6IF9GZcIrDK2KGItfor8IQwQa+yM2ERgHM1MmHxaxpTzk0/Jp42lNfA==", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/@radix-ui/primitive/-/primitive-1.2.0.tgz", + "integrity": "sha512-KABY+VMIRPJL+Vyzv/335FEhXXD/xDv8BMb1kl48/aXJZMH0LtHCTx5ga5RnxaEP3nZHtmTLf1P9vanmFX46bw==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-alert-dialog": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.2.1.tgz", + "integrity": "sha512-MWC4N7RY+qsbNrFNo7yQ9ZbdoZEW+B5DtpWxJfUnVCqcQxxqqg3qis3RMPTDbCNaTIdHJSn5XDkl9ZdVWXknLg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.2.0", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.3.0", + "@radix-ui/react-dialog": "1.3.1", + "@radix-ui/react-primitive": "2.2.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.17", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-arrow/-/react-arrow-1.1.17.tgz", + "integrity": "sha512-67jjcVvxjXCCStnTW3Z+M7jmaFMuMR7M2JgpDzH4w7JSRrikmzhjfYgP/09ECb8n7whnsgh1ifJ+Ie96qEj+pQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.2.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-avatar/-/react-avatar-1.3.1.tgz", + "integrity": "sha512-ssZOkfQNkFpYVmCPQlr978xSaU7moSrGXdwg4j2Xs2WlGl/1KsSZtfpK+WnLnx0Rwll1BAh6oUrAy/uR31SBvQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.2.0", + "@radix-ui/react-context": "1.3.0", + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-use-callback-ref": "1.1.5", + "@radix-ui/react-use-is-hydrated": "0.1.3", + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-checkbox/-/react-checkbox-1.4.1.tgz", + "integrity": "sha512-KWtwhh+98ML3seZ9vO9yRY2OwaQG90dCiDAxjpSNY2AaZ3Hik3B0dsk6m0ILywo/no3A9/SozadyPMNweVT8yw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.2.0", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.3.0", + "@radix-ui/react-presence": "1.1.11", + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-use-controllable-state": "1.3.0", + "@radix-ui/react-use-size": "1.1.5" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-collection/-/react-collection-1.2.0.tgz", + "integrity": "sha512-+yiQzqcc7Sy7/5s0jrMCjpPRFB3538VNrXPWdTLZhE/SCfgEws4aI6lHWN/vvcnyhHndROWBzqmqB4QBrITZ9Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.3.0", + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-slot": "1.5.0", + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.5.tgz", + "integrity": "sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-context/-/react-context-1.3.0.tgz", + "integrity": "sha512-v5AYEocMISkbJ+1fTXzZpiFv7NRr3D2WiYbLIKf+FkmJ8VkP6d503eV2n34MFussHXY1pcoq3yfJiQH77dc4Mg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-dialog/-/react-dialog-1.3.1.tgz", + "integrity": "sha512-+0E4qvVTwjAWra9sEhJ+9BTsvHE00zkUuNw1VGh7S+Gc13dfYk+S1PVQdchWDj+XYHhAai7Z7IpzXVDCGsDplg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.2.0", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.3.0", + "@radix-ui/react-dismissable-layer": "1.2.1", + "@radix-ui/react-focus-guards": "1.2.0", + "@radix-ui/react-focus-scope": "1.3.1", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-portal": "1.2.0", + "@radix-ui/react-presence": "1.1.11", + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-slot": "1.5.0", + "@radix-ui/react-use-controllable-state": "1.3.0", + "@radix-ui/react-use-layout-effect": "1.1.4", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.7.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-direction/-/react-direction-1.2.0.tgz", + "integrity": "sha512-FtRA52a/r+LKStFT+neLUm+8vSe7wbzkbQGGeU8ixFiwC8NU14Evoq9ATECqL3eGbcUzJR4fyfA4KkK/q6dfqg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.2.1.tgz", + "integrity": "sha512-KIfDcAsx+oVylFZ4xryVKusJUrLLhTQmfnJW4kwk4Km5myvhHCrj04hnWWUC166+xD4DHdH8tQGylwYX1h6+Pg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.2.0", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-use-callback-ref": "1.1.5", + "@radix-ui/react-use-effect-event": "0.0.5" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.2.1.tgz", + "integrity": "sha512-XsHcmYG2AcqnvTqrOXXWcMrhquEIlqucizuDH1MV/qMRW+DndpBCMvNeTRXOxqmG1H5j89M/+I0/34Zdd+zDcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.2.0", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.3.0", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-menu": "2.2.1", + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-use-controllable-state": "1.3.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.2.0.tgz", + "integrity": "sha512-MPm5R0iRGUDrDnPNxmLBkv+X7pN4XKzt+MbWJEuJQsH3NFH4omrbpXpucyYCCKTSt+na/ZxGhEWQrWTZ0285cA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.3.1.tgz", + "integrity": "sha512-ugeMhbXt4y5S2T1GnIqbWDKEN962PDwnX1fN0eKOOgf5f63Dh2mn8F1FUySlgW0iF6GiVsRF32DzuDIWTUyQJg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-use-callback-ref": "1.1.5" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-id/-/react-id-1.1.4.tgz", + "integrity": "sha512-TMQp2llA+RYn7JcjnrMnz7wN4pcVttPZnRZo52PLQsoLVKzNlVwUeHmfePgTgRluXFvlD3GD5g5MOVVTJCO0qA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.17", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-label/-/react-label-2.1.17.tgz", + "integrity": "sha512-xmj7MN/drx1oUAXkfiFIvyDmGNUIN/omGobvA5oAoNqu9zO2MkISYGZOkBcqSzs/UZXXwV+/3ACRE7q7mGcmkA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.2.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-menu/-/react-menu-2.2.1.tgz", + "integrity": "sha512-G34BsU90SBj5foYpz8pQqq/Q0Dlfyyl6KitWEfRwXC0QvfwhWNAwS49DWP2+rRJ0iwv20Z2Qx7Sk+T03bGo5JA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.2.0", + "@radix-ui/react-collection": "1.2.0", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.3.0", + "@radix-ui/react-direction": "1.2.0", + "@radix-ui/react-dismissable-layer": "1.2.1", + "@radix-ui/react-focus-guards": "1.2.0", + "@radix-ui/react-focus-scope": "1.3.1", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-popper": "1.4.0", + "@radix-ui/react-portal": "1.2.0", + "@radix-ui/react-presence": "1.1.11", + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-roving-focus": "1.2.1", + "@radix-ui/react-slot": "1.5.0", + "@radix-ui/react-use-callback-ref": "1.1.5", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.7.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-popover/-/react-popover-1.3.1.tgz", + "integrity": "sha512-ZNxvXRx5W2Wos4fXCXb5lpdqN0Z5chf+mStOUOTr4ik7d+62MRvoe9rzCA/eGNg36lxXqSrKEKmwuZEcUrIstw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.2.0", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.3.0", + "@radix-ui/react-dismissable-layer": "1.2.1", + "@radix-ui/react-focus-guards": "1.2.0", + "@radix-ui/react-focus-scope": "1.3.1", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-popper": "1.4.0", + "@radix-ui/react-portal": "1.2.0", + "@radix-ui/react-presence": "1.1.11", + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-slot": "1.5.0", + "@radix-ui/react-use-controllable-state": "1.3.0", + "@radix-ui/react-use-layout-effect": "1.1.4", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.7.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-popper/-/react-popper-1.4.0.tgz", + "integrity": "sha512-yCWRvLeGv9Pz3+efwHqGPp70mZ56r3kfIgQVF56Oj2aAa4uP/Tb+IE59wNcc+758rctqbCKx4LbK8II/r7Bn0Q==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.17", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.3.0", + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-use-callback-ref": "1.1.5", + "@radix-ui/react-use-layout-effect": "1.1.4", + "@radix-ui/react-use-rect": "1.1.4", + "@radix-ui/react-use-size": "1.1.5", + "@radix-ui/rect": "1.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-portal/-/react-portal-1.2.0.tgz", + "integrity": "sha512-StX7xXnaRU41VvFtMm9zlhVGz8XF6GmWWTXftkQaY+tqVkbs/R9UmAp5mLzHHapk5hM9RMZQvO/3usyIP/g42g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.11", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-presence/-/react-presence-1.1.11.tgz", + "integrity": "sha512-Z7/atlkab36Z8hm+V8zYc79r0W+tiOB1o0tun1By94JyadkekLQmtEAnBSP9XKXBNQsStoStS4+gX10JpS5akA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-primitive/-/react-primitive-2.2.0.tgz", + "integrity": "sha512-HCTSPMNqv55Qk0IX4geJbpyXazmqulcimwuyjxTkKi29v+QZbG2Zho9BnbBq4YS2PF+KlNb2CXoLz66uUmblkg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.5.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-progress/-/react-progress-1.2.1.tgz", + "integrity": "sha512-yQBiM6J3YM8Ums1orkEFpbznK47geKxa0igikzcaS1xHgdba3DdAQBsGbCTt5BVfR8zhEvgxQ0poGcINaD3lvw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.3.0", + "@radix-ui/react-primitive": "2.2.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group": { + "version": "1.5.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-radio-group/-/react-radio-group-1.5.1.tgz", + "integrity": "sha512-QbyVT1ddnjqB9H+CUYKkNWdU9fIK3QHCYtjf7mS6ekSqiuXkWtWn5UZW9mhA8qtl3vrVyIsmR9gePstAtKrqkw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.2.0", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.3.0", + "@radix-ui/react-direction": "1.2.0", + "@radix-ui/react-presence": "1.1.11", + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-roving-focus": "1.2.1", + "@radix-ui/react-use-controllable-state": "1.3.0", + "@radix-ui/react-use-size": "1.1.5" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.2.1.tgz", + "integrity": "sha512-UwraORzVUeEPMclhO1p0vz0qI+TbdDLO9i+FiOqhJyHKwdpCRCck9yVEscUnAMIzCiuNoQa8D4A9bIpOPXGt6Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.2.0", + "@radix-ui/react-collection": "1.2.0", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.3.0", + "@radix-ui/react-direction": "1.2.0", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-use-callback-ref": "1.1.5", + "@radix-ui/react-use-controllable-state": "1.3.0", + "@radix-ui/react-use-is-hydrated": "0.1.3", + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select": { + "version": "2.4.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-select/-/react-select-2.4.1.tgz", + "integrity": "sha512-888ZwW0Md6GyptuqYABRX9nLKgoYfcooCyBBvVaX5Jp3e+8Jp2i4Zo/Uy50Hm+Ysn2JfloQXstW4U36w8teVtg==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.3", + "@radix-ui/primitive": "1.2.0", + "@radix-ui/react-collection": "1.2.0", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.3.0", + "@radix-ui/react-direction": "1.2.0", + "@radix-ui/react-dismissable-layer": "1.2.1", + "@radix-ui/react-focus-guards": "1.2.0", + "@radix-ui/react-focus-scope": "1.3.1", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-popper": "1.4.0", + "@radix-ui/react-portal": "1.2.0", + "@radix-ui/react-presence": "1.1.11", + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-slot": "1.5.0", + "@radix-ui/react-use-callback-ref": "1.1.5", + "@radix-ui/react-use-controllable-state": "1.3.0", + "@radix-ui/react-use-layout-effect": "1.1.4", + "@radix-ui/react-visually-hidden": "1.2.13", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.7.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-separator/-/react-separator-1.2.0.tgz", + "integrity": "sha512-1jUAap0wZEqVP05Ou7kJgRxe/W+Qftng+rUNWGa0qkKbv9r5pWTG3E7a3ELKo2eJoHKMECnzuYrZpSyO1YgcYQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.2.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-slot/-/react-slot-1.5.0.tgz", + "integrity": "sha512-tyYd9ddPXAysAbdbD9eYxgwpCSv6f3PncqVSNKQFSR5lcJVLz3cb/pANDoYrLiHBpXv7skortyUgGUWsYuPPFQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.5" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-switch/-/react-switch-1.4.1.tgz", + "integrity": "sha512-NpBGwc40rY02ZmSvuyeKk0Bvc8ZsNeTMi4qHvJ+ZH4EiYCv0zIXEgdCW4bVdzgIUeP9xxbLJSxKOUfqITYNmkA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.2.0", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.3.0", + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-use-controllable-state": "1.3.0", + "@radix-ui/react-use-size": "1.1.5" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-tabs/-/react-tabs-1.2.1.tgz", + "integrity": "sha512-hRoJlode+hg5ZNlR+3tkfkUliIybdTpD5lkAvHQ9yaXseGf7XVO9Ib2GPEIOuaJJbo7YWYbNpDDRfo8Dhf6/xA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.2.0", + "@radix-ui/react-context": "1.3.0", + "@radix-ui/react-direction": "1.2.0", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-presence": "1.1.11", + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-roving-focus": "1.2.1", + "@radix-ui/react-use-controllable-state": "1.3.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-toggle/-/react-toggle-1.2.1.tgz", + "integrity": "sha512-+3MUq+WyiBplXYqQ0EIYlq8R4sLQ0T5NbOK7DMdDLCKO93pe2uE0DUJTWWfTBprpJJXxfoF3eMW0xpakVZrYsg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.2.0", + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-use-controllable-state": "1.3.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-toggle-group/-/react-toggle-group-1.2.1.tgz", + "integrity": "sha512-O8Ldx5ao4p4KoW+DO8/PmkOe5mdKNi3F2SseqjVj88wvDGDHe60cUmO0Zm/uHsKrvNgQGV8Efpuh95Tht/h4vw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.2.0", + "@radix-ui/react-context": "1.3.0", + "@radix-ui/react-direction": "1.2.0", + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-roving-focus": "1.2.1", + "@radix-ui/react-toggle": "1.2.1", + "@radix-ui/react-use-controllable-state": "1.3.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-tooltip/-/react-tooltip-1.4.1.tgz", + "integrity": "sha512-NxLFGSFtZ78zVfcoOhTwR1xwqo5qx1Jh8Pw6FMZ9McCaqfRzz7/gIRahs2Oy5XlPgQ+8QkUcKbN5B0U44J/kCg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.2.0", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.3.0", + "@radix-ui/react-dismissable-layer": "1.2.1", + "@radix-ui/react-focus-scope": "1.3.1", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-popper": "1.4.0", + "@radix-ui/react-portal": "1.2.0", + "@radix-ui/react-presence": "1.1.11", + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-slot": "1.5.0", + "@radix-ui/react-use-controllable-state": "1.3.0", + "@radix-ui/react-use-layout-effect": "1.1.4", + "@radix-ui/react-visually-hidden": "1.2.13" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.5.tgz", + "integrity": "sha512-Y5GBf4NKeADoXI1geiMlMuMoURT3k9MizzzKhGb/m55H94aGigZ01PIpkvsO6lML13BA6XYAXSJ6gza7vTn5nw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.3.0.tgz", + "integrity": "sha512-TAcBI7bw2ljYCbv4+zuTSd6zICu8pRt6SDN2vJ/Z06K2MXh6I9WYFe/A9ovlFDtR5HVHGm5iDxDoABm/++dbKg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.2.0", + "@radix-ui/react-use-effect-event": "0.0.5", + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.5", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.5.tgz", + "integrity": "sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.3", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.3.tgz", + "integrity": "sha512-umO/aJ+82CpOnhDZUTbILCQf7kU/g0iv+oGs/Q8jw7IkhWBzaEP4sA268PhFAJTFetbwp3ICc6ktpI4TqtxcIw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.4.tgz", + "integrity": "sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-rect/-/react-use-rect-1.1.4.tgz", + "integrity": "sha512-cSOCh6JlkmfjLyNcLiu2nB4v+nm+dkZ+Q5KHWk/soo4U7ZLiEQFKHK9/YmtBHjfCEaU43IBKQOc4/uJmCaiCTQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-use-size/-/react-use-size-1.1.5.tgz", + "integrity": "sha512-V1McDQkMGzgivwqdu7u96APs7oi0Jvj9LTzgq3WWrDZqxWdAqU9yZnZQqk5OizGFR8badUQwZsrlao7MOlWYOA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.13", + "resolved": "https://registry.npmmirror.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.13.tgz", + "integrity": "sha512-feijiN1oPk4rck4u9Dm9tsU4mT6Wp9oeEEhaz1WUEs1VuqLf8xzsFG+Qk+uWq6TnMH9O+WRECRg0NftyP9E4Fw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.2.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/@radix-ui/rect/-/rect-1.1.3.tgz", + "integrity": "sha512-JtyZR+mqgBibTo8xea3B6ZRmzZiM/YeVBtUkas6zMuXjAlfIFIW2FgqeM9eLyvEaYX66vr6DJMK+4U6LV0KhNw==", + "license": "MIT" + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-beta.53", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-beta.53.tgz", + "integrity": "sha512-Ok9V8o7o6YfSdTTYA/uHH30r3YtOxLD6G3wih/U9DO0ucBBFq8WPt/DslU53OgfteLRHITZny9N/qCUxMf9kjQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-beta.53", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.53.tgz", + "integrity": "sha512-yIsKqMz0CtRnVa6x3Pa+mzTihr4Ty+Z6HfPbZ7RVbk1Uxnco4+CUn7Qbm/5SBol1JD/7nvY8rphAgyAi7Lj6Vg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-beta.53", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.53.tgz", + "integrity": "sha512-GTXe+mxsCGUnJOFMhfGWmefP7Q9TpYUseHvhAhr21nCTgdS8jPsvirb0tJwM3lN0/u/cg7bpFNa16fQrjKrCjQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-beta.53", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.53.tgz", + "integrity": "sha512-9Tmp7bBvKqyDkMcL4e089pH3RsjD3SUungjmqWtyhNOxoQMh0fSmINTyYV8KXtE+JkxYMPWvnEt+/mfpVCkk8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-beta.53", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.53.tgz", + "integrity": "sha512-a1y5fiB0iovuzdbjUxa7+Zcvgv+mTmlGGC4XydVIsyl48eoxgaYkA3l9079hyTyhECsPq+mbr0gVQsFU11OJAQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-beta.53", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.53.tgz", + "integrity": "sha512-bpIGX+ov9PhJYV+wHNXl9rzq4F0QvILiURn0y0oepbQx+7stmQsKA0DhPGwmhfvF856wq+gbM8L92SAa/CBcLg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-beta.53", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.53.tgz", + "integrity": "sha512-bGe5EBB8FVjHBR1mOLOPEFg1Lp3//7geqWkU5NIhxe+yH0W8FVrQ6WRYOap4SUTKdklD/dC4qPLREkMMQ855FA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-beta.53", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.53.tgz", + "integrity": "sha512-qL+63WKVQs1CMvFedlPt0U9PiEKJOAL/bsHMKUDS6Vp2Q+YAv/QLPu8rcvkfIMvQ0FPU2WL0aX4eWwF6e/GAnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-beta.53", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.53.tgz", + "integrity": "sha512-VGl9JIGjoJh3H8Mb+7xnVqODajBmrdOOb9lxWXdcmxyI+zjB2sux69br0hZJDTyLJfvBoYm439zPACYbCjGRmw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-beta.53", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-beta.53.tgz", + "integrity": "sha512-B4iIserJXuSnNzA5xBLFUIjTfhNy7d9sq4FUMQY3GhQWGVhS2RWWzzDnkSU6MUt7/aHUrep0CdQfXUJI9D3W7A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-beta.53", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.53.tgz", + "integrity": "sha512-BUjAEgpABEJXilGq/BPh7jeU3WAJ5o15c1ZEgHaDWSz3LB881LQZnbNJHmUiM4d1JQWMYYyR1Y490IBHi2FPJg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.1.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-beta.53", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.53.tgz", + "integrity": "sha512-s27uU7tpCWSjHBnxyVXHt3rMrQdJq5MHNv3BzsewCIroIw3DJFjMH1dzCPPMUFxnh1r52Nf9IJ/eWp6LDoyGcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-beta.53", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.53.tgz", + "integrity": "sha512-cjWL/USPJ1g0en2htb4ssMjIycc36RvdQAx1WlXnS6DpULswiUTVXPDesTifSKYSyvx24E0YqQkEm0K/M2Z/AA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@solid-primitives/event-listener": { + "version": "2.4.6", + "resolved": "https://registry.npmmirror.com/@solid-primitives/event-listener/-/event-listener-2.4.6.tgz", + "integrity": "sha512-5I0YJcTVYIWoMmgBSROBZGcz+ymhew/pGTg2dHW74BUjFKsV8Li4bOZYl0YAGP4mHw5o4UBd9/BEesqBci3wxw==", + "license": "MIT", + "dependencies": { + "@solid-primitives/utils": "^6.4.1" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/keyed": { + "version": "1.5.3", + "resolved": "https://registry.npmmirror.com/@solid-primitives/keyed/-/keyed-1.5.3.tgz", + "integrity": "sha512-zNadtyYBhJSOjXtogkGHmRxjGdz9KHc8sGGVAGlUABkE8BED2tbIZoxkwSqzOwde8OcUEH0bb5DLZUWIMvyBSA==", + "license": "MIT", + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/map": { + "version": "0.4.13", + "resolved": "https://registry.npmmirror.com/@solid-primitives/map/-/map-0.4.13.tgz", + "integrity": "sha512-B1zyFbsiTQvqPr+cuPCXO72sRuczG9Swncqk5P74NCGw1VE8qa/Ry9GlfI1e/VdeQYHjan+XkbE3rO2GW/qKew==", + "license": "MIT", + "dependencies": { + "@solid-primitives/trigger": "^1.1.0" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/media": { + "version": "2.3.6", + "resolved": "https://registry.npmmirror.com/@solid-primitives/media/-/media-2.3.6.tgz", + "integrity": "sha512-pk49gPOq/UMRUJ+pTSrOfBiR8xJjRYHXIf1iR/jSnyQ/KroU+ZXhkZzavC7hvfp2vJeOTW5k2/HN0r3Q1VJ7Pw==", + "license": "MIT", + "dependencies": { + "@solid-primitives/event-listener": "^2.4.6", + "@solid-primitives/rootless": "^1.5.4", + "@solid-primitives/static-store": "^0.1.4", + "@solid-primitives/utils": "^6.4.1" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/props": { + "version": "3.2.4", + "resolved": "https://registry.npmmirror.com/@solid-primitives/props/-/props-3.2.4.tgz", + "integrity": "sha512-MXXdvi2TSB6d+0N6ueA/HP1j/Kh9SEc4WdF1ZDMLwPagxW6pIHHSS9xbRO0RjqSVpNP4j0nxCWT1hx3CkJNhNA==", + "license": "MIT", + "dependencies": { + "@solid-primitives/utils": "^6.4.1" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/refs": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/@solid-primitives/refs/-/refs-1.1.4.tgz", + "integrity": "sha512-bLjwIs6ZPu8NQnuw04sU3Zc8qKSpbc0umUU/O4SHf6oWOdO4+dHY8vb1T7C4b/Tg103+9WGr6sEE0+NFlbaB/A==", + "license": "MIT", + "dependencies": { + "@solid-primitives/utils": "^6.4.1" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/resize-observer": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/@solid-primitives/resize-observer/-/resize-observer-2.2.0.tgz", + "integrity": "sha512-9Fuu/EWBeGj+atGHRJp70HKhdfalmpjwxY8a32NZixdLNmfCJ45AfhLQNr6uOzETbbiMx4iCKlTrJ8KZCHC2Ww==", + "license": "MIT", + "dependencies": { + "@solid-primitives/event-listener": "^2.4.6", + "@solid-primitives/rootless": "^1.5.4", + "@solid-primitives/static-store": "^0.1.4", + "@solid-primitives/utils": "^6.4.1" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/rootless": { + "version": "1.5.4", + "resolved": "https://registry.npmmirror.com/@solid-primitives/rootless/-/rootless-1.5.4.tgz", + "integrity": "sha512-TOIZa1VUfVJ+9nkCcRajw3U4t9vBOP1HxX1WHNTbXq32mXwlqTvUnC4CRIilohcryBkT9u2ZkhUDSHRTaGp55g==", + "license": "MIT", + "dependencies": { + "@solid-primitives/utils": "^6.4.1" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/static-store": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/@solid-primitives/static-store/-/static-store-0.1.4.tgz", + "integrity": "sha512-LgtVaVBtB7EbmS4+M0b8xY5Iq6pUWXBsIC4VgtrFKDGDdyCaDt88sHk0fUlx1Enxm/XZnZyLXJABRoa39RjJqA==", + "license": "MIT", + "dependencies": { + "@solid-primitives/utils": "^6.4.1" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/storage": { + "version": "1.3.11", + "resolved": "https://registry.npmmirror.com/@solid-primitives/storage/-/storage-1.3.11.tgz", + "integrity": "sha512-PpQWR3TaTxHIJFbI9ZssYTM4Aa67g1vJIgps4TPhcXzHqqomrPAIveFC2FG7SDQoi9YQia8FVBjigELziJpfIg==", + "license": "MIT", + "dependencies": { + "@solid-primitives/utils": "^6.2.0" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/transition-group": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/@solid-primitives/transition-group/-/transition-group-1.1.2.tgz", + "integrity": "sha512-gnHS0OmcdjeoHN9n7Khu8KNrOlRc8a2weETDt2YT6o1zeW/XtUC6Db3Q9pkMU/9cCKdEmN4b0a/41MKAHRhzWA==", + "license": "MIT", + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/trigger": { + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/@solid-primitives/trigger/-/trigger-1.2.4.tgz", + "integrity": "sha512-Ju0e+ZOD7hpOp7nptJimvDSZHWFvIvF9iBWMvuwt30smX7c5wmB8Kmc0AdDuv0wOTi06PQ1J5IrP1WJbH2yUBQ==", + "license": "MIT", + "dependencies": { + "@solid-primitives/utils": "^6.4.1" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/utils": { + "version": "6.4.1", + "resolved": "https://registry.npmmirror.com/@solid-primitives/utils/-/utils-6.4.1.tgz", + "integrity": "sha512-ISSB5QX1qP2ynrheIpYwc4oKR5Ny4siNuUyf1qZniy+Il+p/PtDB0QK1Dnle8noiHpwRD3gpPdubOC3qI/Zamg==", + "license": "MIT", + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "resolved": "https://registry.npmmirror.com/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", + "license": "MIT" + }, + "node_modules/@swc/core": { + "version": "1.16.21", + "resolved": "https://registry.npmmirror.com/@swc/core/-/core-1.16.21.tgz", + "integrity": "sha512-sE2asan0US6gcp11oBDFJb5+s+ltaAPBcagVQGub1+qo+8TsQET2TmXfJCw/Oy0w1eEPp1rV1wsR/Umx2KXGcw==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.28" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.16.21", + "@swc/core-darwin-x64": "1.16.21", + "@swc/core-linux-arm-gnueabihf": "1.16.21", + "@swc/core-linux-arm64-gnu": "1.16.21", + "@swc/core-linux-arm64-musl": "1.16.21", + "@swc/core-linux-ppc64-gnu": "1.16.21", + "@swc/core-linux-s390x-gnu": "1.16.21", + "@swc/core-linux-x64-gnu": "1.16.21", + "@swc/core-linux-x64-musl": "1.16.21", + "@swc/core-win32-arm64-msvc": "1.16.21", + "@swc/core-win32-ia32-msvc": "1.16.21", + "@swc/core-win32-x64-msvc": "1.16.21" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.16.21", + "resolved": "https://registry.npmmirror.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.16.21.tgz", + "integrity": "sha512-VRreJpbRygpSD1hj3HBEOIA1xjXYnhB+IfcKsxZRhCIBGRP4UkqxZH4/ipFh/heIRp7EKQ56E8ygwEftLNCWXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.16.21", + "resolved": "https://registry.npmmirror.com/@swc/core-darwin-x64/-/core-darwin-x64-1.16.21.tgz", + "integrity": "sha512-KqCJ04pMYDBUYpAOFGUFR8TEjqo4h0Vtwe/za9xNRDKsxSDnjgM7HVhfO0uNNpMMlM2ao2E6d0iLpApIRvNGnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.16.21", + "resolved": "https://registry.npmmirror.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.16.21.tgz", + "integrity": "sha512-tLkw3uWxQj69qBRX5Xm8vbq+5iX5e/ktoPXhrDeFFa2jNMc+AWcxa0bqwatvVGK40v5mcmz6Ulu5Nk9jF8ciMA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.16.21", + "resolved": "https://registry.npmmirror.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.16.21.tgz", + "integrity": "sha512-lFHVlHB0B5C7FwyprWJQp7b2iF/ohj2RqnMiv8uCnFJc+rYP0Py2I7ftZ+rOX4Zu7Ra9eMk7GnmuxAywCZYUJQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.16.21", + "resolved": "https://registry.npmmirror.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.16.21.tgz", + "integrity": "sha512-gXDgrMMDsWT7r5gZsml10snBS9yaoVYwU9vGffa+DAts4ctEMrMHv+G8AH+ZxCV9gr5MfdgtGGQKjXjLay4mXQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-ppc64-gnu": { + "version": "1.16.21", + "resolved": "https://registry.npmmirror.com/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.16.21.tgz", + "integrity": "sha512-hZF7J2YzXiADZ4eQxTFOWJcSSy3fbUR8/DcCXqiBHh0bVyLl2Y+O5pVWxk/r/XV5tA9n7DnnLlvkPPsHoajE9w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-s390x-gnu": { + "version": "1.16.21", + "resolved": "https://registry.npmmirror.com/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.16.21.tgz", + "integrity": "sha512-rmtGwkAlbl+fQMGrGUMklUmByueOmt1ju9sKsE5YWVA0KfFYM0W87WVx4lFYQXt+E4P3zkLjeqo/AUa5mFbF1A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.16.21", + "resolved": "https://registry.npmmirror.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.16.21.tgz", + "integrity": "sha512-EUJsyrFw3aNE64iQzk3bDqjADgl4l0vpxfwVMjMuZIooNg35yKqvkw3bYNEhQyrBDY0+5kKoiirGLpth3Wf3lA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.16.21", + "resolved": "https://registry.npmmirror.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.16.21.tgz", + "integrity": "sha512-ZXUnLjxTHxvNhVmQmYlb8XNKArfi/MiGoW5DmfuME8ttCLH9OJTqJVFy7g1yYxUCgw3tU6dF1uU59N8P/Yr5Pw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.16.21", + "resolved": "https://registry.npmmirror.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.16.21.tgz", + "integrity": "sha512-jnnQpAHiWZgEobVfOPvJJzm1Jh4ZEIKh2IqcDqHv6zJcjvaEkHdkt+qdRsJ9AqvK7g18WBRHTnvKm5IxdbkagA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.16.21", + "resolved": "https://registry.npmmirror.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.16.21.tgz", + "integrity": "sha512-TaVTnNm9c1I+VG3hJUt11uspwbTrTQ9+fUPzODlvx4tj/ChYqUm4cKTIHw3O97hILxpmhBR0hbvLEs9seOV59A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.16.21", + "resolved": "https://registry.npmmirror.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.16.21.tgz", + "integrity": "sha512-aPv58Clf6SdAQtouzDYKbEtcCETY2hOXlrHgSFnFIJQOlMWINHSGazaM1Iv63/9wOUDPq6+0ZFytMqnPtER9OQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmmirror.com/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@swc/helpers": { + "version": "0.5.23", + "resolved": "https://registry.npmmirror.com/@swc/helpers/-/helpers-0.5.23.tgz", + "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@swc/types": { + "version": "0.1.28", + "resolved": "https://registry.npmmirror.com/@swc/types/-/types-0.1.28.tgz", + "integrity": "sha512-V6Mnml8v09QALx6K0elJ7o9K/MkVDtW3t6L+7Ou/JcWtb3xwId2AH4FeOceySd2JaO87IMw4+6vSZxLm34LPbw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@tabby_ai/hijri-converter": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/@tabby_ai/hijri-converter/-/hijri-converter-1.0.5.tgz", + "integrity": "sha512-r5bClKrcIusDoo049dSL8CawnHR6mRdDwhlQuIgZRNty68q0x8k3Lf1BtPAMxRf/GgnHBnIO4ujd3+GQdLWzxQ==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@tanstack/devtools-event-client": { + "version": "0.4.4", + "resolved": "https://registry.npmmirror.com/@tanstack/devtools-event-client/-/devtools-event-client-0.4.4.tgz", + "integrity": "sha512-6T5Yop/793YI+H+5J8Hsyj4kCih9sl4t3ElLgKioW5hk3ocn+ZdSJ94tT7vL7uabxSugWYBZlOTMPzEw2puvQw==", + "license": "MIT", + "bin": { + "intent": "bin/intent.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/history": { + "version": "1.162.5", + "resolved": "https://registry.npmmirror.com/@tanstack/history/-/history-1.162.5.tgz", + "integrity": "sha512-w1+YvwmTkwt5n8yUqEH3IWZ9DsmorCZW/EQ3KYHnqEgIkOZpH54NvW6/Epq3Dzb8H0ifIeYX8PExvrNLIH5FIA==", + "license": "MIT", + "engines": { + "node": ">=20.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/match-sorter-utils": { + "version": "9.2.6", + "resolved": "https://registry.npmmirror.com/@tanstack/match-sorter-utils/-/match-sorter-utils-9.2.6.tgz", + "integrity": "sha512-DIpUSOhPfQ7u/qfUi/Wgm0wBO56MyBYXGvnlI0NcauDRPqdBUlAZZjW2Dxm92m+k1UWVhKw8YJ4f47+75Aujyw==", + "license": "MIT", + "dependencies": { + "remove-accents": "0.5.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/pacer": { + "version": "0.18.0", + "resolved": "https://registry.npmmirror.com/@tanstack/pacer/-/pacer-0.18.0.tgz", + "integrity": "sha512-qhCRSFei0hokQr3xYcQXqxsRD/LKlgHCxHXtKHrQoImp4x2Zu6tUOpUGVH4y2qexIrzSu3aibQBNNfC3Eay6Mg==", + "license": "MIT", + "dependencies": { + "@tanstack/devtools-event-client": "^0.4.0", + "@tanstack/store": "^0.8.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/query-core": { + "version": "5.105.1", + "resolved": "https://registry.npmmirror.com/@tanstack/query-core/-/query-core-5.105.1.tgz", + "integrity": "sha512-B/rNlZoZ54w1dlddiUt9oEe1SLM+37c00SKLJEg9YH+7as3Y54P81o9Fh+2ujZ36tXPnQJ5oVe7AcyEWkyFhPg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/query-devtools": { + "version": "5.105.1", + "resolved": "https://registry.npmmirror.com/@tanstack/query-devtools/-/query-devtools-5.105.1.tgz", + "integrity": "sha512-3iHdlC/S1e1W+7bemP5WN/feZapc0WW6XHXtmfY3AmWVlA20tEK4WxVXcKhh7IngjPGHlY6eXi1MVkrHuaxDzQ==", + "license": "MIT", + "dependencies": { + "@kobalte/core": "^0.13.14", + "@solid-primitives/keyed": "^1.5.3", + "@solid-primitives/resize-observer": "^2.2.0", + "@solid-primitives/storage": "^1.3.11", + "@tanstack/match-sorter-utils": "^9.1.2", + "@tanstack/query-core": "5.105.1", + "clsx": "^2.1.1", + "goober": "^2.1.19", + "solid-js": "^1.9.15", + "solid-transition-group": "^0.2.3", + "superjson": "^2.2.6" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-pacer": { + "version": "0.19.4", + "resolved": "https://registry.npmmirror.com/@tanstack/react-pacer/-/react-pacer-0.19.4.tgz", + "integrity": "sha512-coj8ULAuR0qFpjAKD44gTgRuZyjxU6Xu+IX5MwwYvr4e61OtZcJshaExoOBKpCGde0Edb12jDnzzj2Im13Qm9Q==", + "license": "MIT", + "dependencies": { + "@tanstack/pacer": "0.18.0", + "@tanstack/react-store": "^0.8.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.105.1", + "resolved": "https://registry.npmmirror.com/@tanstack/react-query/-/react-query-5.105.1.tgz", + "integrity": "sha512-qcu+/+PtBOjW8qU4/0l47QVmNG7hPOWsCLzP0bTRhE1X7HYa757C4732wXTUH0QhCjTV1yedX8onsCiEwlNYrA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@tanstack/query-core": "5.105.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@types/react": "^18 || ^19", + "react": "^18 || ^19" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@tanstack/react-query-devtools": { + "version": "5.105.1", + "resolved": "https://registry.npmmirror.com/@tanstack/react-query-devtools/-/react-query-devtools-5.105.1.tgz", + "integrity": "sha512-VJwunCp9fPbGGkbXlKn4T8w20sNdlFZoMqTjOdzqdhfk0Ujthln4LSN7xkVLCTAq0OGaV/0srQ/5esNpaktRvw==", + "license": "MIT", + "dependencies": { + "@tanstack/query-devtools": "5.105.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/react-query": "^5.105.1", + "@types/react": "^18 || ^19", + "react": "^18 || ^19" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@tanstack/react-router": { + "version": "1.170.46", + "resolved": "https://registry.npmmirror.com/@tanstack/react-router/-/react-router-1.170.46.tgz", + "integrity": "sha512-ez1iNIhsPjGlaDHg3BXWs67EWVIYzB2tbopEHYDESdkO7owgkGb5de52+5Kv2v1fxdkggcNzo35bdk4arTVGQw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@tanstack/history": "1.162.5", + "@tanstack/react-store": "^0.11.2", + "@tanstack/router-core": "1.171.39", + "isbot": "^5.1.22" + }, + "engines": { + "node": ">=20.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=18.0.0 || >=19.0.0", + "react-dom": ">=18.0.0 || >=19.0.0" + } + }, + "node_modules/@tanstack/react-router-devtools": { + "version": "1.167.2", + "resolved": "https://registry.npmmirror.com/@tanstack/react-router-devtools/-/react-router-devtools-1.167.2.tgz", + "integrity": "sha512-VuoqB7OhDUrBa4WOFSKiAQ8xI8sJpeZdo9sYE1hQa89iMuVFUQu1iWE4iCiQhB+6TYOZDZ9e+iHKxYjop4ZVYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tanstack/router-devtools-core": "1.168.2" + }, + "engines": { + "node": ">=20.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/react-router": "^1.170.36", + "@tanstack/router-core": "^1.171.30", + "react": ">=18.0.0 || >=19.0.0", + "react-dom": ">=18.0.0 || >=19.0.0" + }, + "peerDependenciesMeta": { + "@tanstack/router-core": { + "optional": true + } + } + }, + "node_modules/@tanstack/react-router/node_modules/@tanstack/react-store": { + "version": "0.11.2", + "resolved": "https://registry.npmmirror.com/@tanstack/react-store/-/react-store-0.11.2.tgz", + "integrity": "sha512-oj5O5DmiMWE+ih+SioX2ayC1kbK7d3fpLx0B75fPJr9nY3zU+hoW010yr64qXsY/9fyiLVE2bn5mGNV3owm8RQ==", + "license": "MIT", + "dependencies": { + "@tanstack/store": "0.11.2", + "use-sync-external-store": "^1.6.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tanstack/react-router/node_modules/@tanstack/store": { + "version": "0.11.2", + "resolved": "https://registry.npmmirror.com/@tanstack/store/-/store-0.11.2.tgz", + "integrity": "sha512-sJ4mjol8uQsHV0gOJzzjwXfh2Fwm+Sz0+8deqiTm4jGbMdjzNSW+xZCFm0kUa870uhd8yi+DpKnZb5Kc4apa0Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-store": { + "version": "0.8.1", + "resolved": "https://registry.npmmirror.com/@tanstack/react-store/-/react-store-0.8.1.tgz", + "integrity": "sha512-XItJt+rG8c5Wn/2L/bnxys85rBpm0BfMbhb4zmPVLXAKY9POrp1xd6IbU4PKoOI+jSEGc3vntPRfLGSgXfE2Ig==", + "license": "MIT", + "dependencies": { + "@tanstack/store": "0.8.1", + "use-sync-external-store": "^1.6.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tanstack/react-table": { + "version": "8.21.3", + "resolved": "https://registry.npmmirror.com/@tanstack/react-table/-/react-table-8.21.3.tgz", + "integrity": "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==", + "license": "MIT", + "dependencies": { + "@tanstack/table-core": "8.21.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/@tanstack/router-core": { + "version": "1.171.39", + "resolved": "https://registry.npmmirror.com/@tanstack/router-core/-/router-core-1.171.39.tgz", + "integrity": "sha512-qUhoJ0meuSUqGYQbHbcJYdASr06YtK+bulbj6vtrhKYFkLgkSsZ6tXmMyym7sFxiSJSPYgasgozrL01LyyR/6A==", + "license": "MIT", + "peer": true, + "dependencies": { + "@tanstack/history": "1.162.5", + "cookie-es": "^3.0.0", + "seroval": "^1.6.7", + "seroval-plugins": "^1.6.7" + }, + "engines": { + "node": ">=20.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/router-devtools-core": { + "version": "1.168.2", + "resolved": "https://registry.npmmirror.com/@tanstack/router-devtools-core/-/router-devtools-core-1.168.2.tgz", + "integrity": "sha512-pCCdQ5M/NUeWdiAbPmjyfcNdls6G4vaVlIQbPf1IqZk1FLYFr00aQvi578yUuWFBNM2KNS2QcwM1uPucbtGf5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.1.1", + "goober": "^2.1.16" + }, + "engines": { + "node": ">=20.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/router-core": "^1.171.30", + "csstype": "^3.0.10" + }, + "peerDependenciesMeta": { + "csstype": { + "optional": true + } + } + }, + "node_modules/@tanstack/router-generator": { + "version": "1.167.46", + "resolved": "https://registry.npmmirror.com/@tanstack/router-generator/-/router-generator-1.167.46.tgz", + "integrity": "sha512-JSailAThcqPvqBzE3+MhNh6zQyZM2IdmIsHOxZgAc061Lh++SZqamNm/Whe7QNXWK5sLP4E0J1F8AI0hP8wTSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8", + "@tanstack/router-core": "1.171.39", + "@tanstack/router-utils": "1.162.4", + "@tanstack/virtual-file-routes": "1.162.0", + "jiti": "^2.7.0", + "magic-string": "^0.30.21", + "prettier": "^3.9.6", + "zod": "^4.5.4" + }, + "engines": { + "node": ">=20.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/router-plugin": { + "version": "1.168.48", + "resolved": "https://registry.npmmirror.com/@tanstack/router-plugin/-/router-plugin-1.168.48.tgz", + "integrity": "sha512-oLDEZO/vhvF5JLrQ6qMNYcCjMMhlHA0Byx6ZXl9AHJ6qVLRxUeCU41vlZQ4buisONY2p0Zl9O09/qwLiVrIBCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "@tanstack/router-core": "1.171.39", + "@tanstack/router-generator": "1.167.46", + "@tanstack/router-utils": "1.162.4", + "chokidar": "^5.0.0", + "unplugin": "^3.3.0", + "zod": "^4.5.4" + }, + "engines": { + "node": ">=20.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@rsbuild/core": ">=1.0.2 || ^2.0.0", + "@tanstack/react-router": "^1.170.46", + "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0", + "vite-plugin-solid": "^2.11.10 || ^3.0.0-0", + "webpack": ">=5.92.0" + }, + "peerDependenciesMeta": { + "@rsbuild/core": { + "optional": true + }, + "@tanstack/react-router": { + "optional": true + }, + "vite": { + "optional": true + }, + "vite-plugin-solid": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/@tanstack/router-utils": { + "version": "1.162.4", + "resolved": "https://registry.npmmirror.com/@tanstack/router-utils/-/router-utils-1.162.4.tgz", + "integrity": "sha512-3TSH3rwAQTqQOtTBF8IXMFXmGNJWnjwIm+l87uguyC/of0pSRKcU9GJrozaf0fY9it8dLQvUZJA2MOlfqbW1sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/generator": "^7.29.8", + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "ansis": "^4.3.1", + "babel-dead-code-elimination": "^1.0.12", + "diff": "^9.0.0", + "pathe": "^2.0.3", + "tinyglobby": "^0.2.17" + }, + "engines": { + "node": ">=20.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/store": { + "version": "0.8.1", + "resolved": "https://registry.npmmirror.com/@tanstack/store/-/store-0.8.1.tgz", + "integrity": "sha512-PtOisLjUZPz5VyPRSCGjNOlwTvabdTBQ2K80DpVL1chGVr35WRxfeavAPdNq6pm/t7F8GhoR2qtmkkqtCEtHYw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/table-core": { + "version": "8.21.3", + "resolved": "https://registry.npmmirror.com/@tanstack/table-core/-/table-core-8.21.3.tgz", + "integrity": "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/virtual-file-routes": { + "version": "1.162.0", + "resolved": "https://registry.npmmirror.com/@tanstack/virtual-file-routes/-/virtual-file-routes-1.162.0.tgz", + "integrity": "sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.4", + "resolved": "https://registry.npmmirror.com/@tybys/wasm-util/-/wasm-util-0.10.4.tgz", + "integrity": "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmmirror.com/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmmirror.com/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/@types/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-kVd74ta9eof3eJOvbNd1vGKS/XERRyQbT26Og63hIsvDO84cjD5gEOhsXf26w3FSoNlPVz84DOFcKv/oou+fMw==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmmirror.com/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.10", + "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.10.tgz", + "integrity": "sha512-lTyOMnOcmRBzdCv6/4zUZCrEhV0xrqQiUZBZtVcbmLHBXKLnN8q89v/wKRF/Q0HbwVsqbIG3o5HDoFl9sduM+g==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.5", + "resolved": "https://registry.npmmirror.com/@types/hast/-/hast-3.0.5.tgz", + "integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmmirror.com/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.9.9", + "resolved": "https://registry.npmmirror.com/@types/node/-/node-25.9.9.tgz", + "integrity": "sha512-b4e2xxj/yMeT2hNlD6x7zNFiQK2Dlmkb9CQ6v3/1G2RezKN4YS2lcEv8lzGm1mhs4f2lM4yNAMI/zUDBZBBt7w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/@types/react": { + "version": "19.3.0", + "resolved": "https://registry.npmmirror.com/@types/react/-/react-19.3.0.tgz", + "integrity": "sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==", + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.3.0", + "resolved": "https://registry.npmmirror.com/@types/react-dom/-/react-dom-19.3.0.tgz", + "integrity": "sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==", + "devOptional": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@types/react": "^19.3.0" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.72.1", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.72.1.tgz", + "integrity": "sha512-5CokTWXpmbylfFabsbvHC0CAw3XLaGnoa+nFJX5FR592h/LoZsENUE6p/rg5xvkKrFEXz6pYmgI29AgXc2N3BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.72.1", + "@typescript-eslint/type-utils": "8.72.1", + "@typescript-eslint/utils": "8.72.1", + "@typescript-eslint/visitor-keys": "8.72.1", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.72.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.14", + "resolved": "https://registry.npmmirror.com/ignore/-/ignore-7.0.14.tgz", + "integrity": "sha512-wCBiZ77u1tuWde6G/nfOtLaCTYcFDU5yCzARzK10y+rLhzYoL7a7yEemcopcc2Mzow7gZOIjnV2ym1NYmdiJOQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.72.1", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-8.72.1.tgz", + "integrity": "sha512-ZGwZP4OCfyA0AQTpEAMWz+rtX01DRhQWW5hB0ucKDEIX5U7jdmPSaMx94rQfaPAQzIYz2BimOgKOJtjfpRFQ9g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@typescript-eslint/scope-manager": "8.72.1", + "@typescript-eslint/types": "8.72.1", + "@typescript-eslint/typescript-estree": "8.72.1", + "@typescript-eslint/visitor-keys": "8.72.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.72.1", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/project-service/-/project-service-8.72.1.tgz", + "integrity": "sha512-fAuVMkwdO/huI8nyo/WKnNKf6Gag93S56Rh3Ts5mGcavwSdaN8tRg1gCeIGX8PF+nzp1BjGfO4gHhGzW1J6jTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.72.1", + "@typescript-eslint/types": "^8.72.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.72.1", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-8.72.1.tgz", + "integrity": "sha512-lC/t6eMCZZQAAKZEYGL6RDVSuFehpdmMT6h+nJIjIa6oylN/PwDgDVtEIbB7O9xFfZYtZAYLoLlDNWKJhtF+uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.72.1", + "@typescript-eslint/visitor-keys": "8.72.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.72.1", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.72.1.tgz", + "integrity": "sha512-e4D5R5vpeAEPBxT2BAzsFQL3sbwyeeeo5+aczgNSRK1V734jE7pTqaGFU+fXapWEQwnZbpFaTn32+Z8DwS6OTg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.72.1", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-8.72.1.tgz", + "integrity": "sha512-iY2wlmyrXJmx4yxUGP3aYCFF3cA/6ShddOKmLU2dx7LnEykbAM8WThlxZEfd1NddqceF6eJmZUayxx9oKIYNlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.72.1", + "@typescript-eslint/typescript-estree": "8.72.1", + "@typescript-eslint/utils": "8.72.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.72.1", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-8.72.1.tgz", + "integrity": "sha512-LmE5IhQet1BWOWEXqBrVtBPsMAOQ6Nzk35d+WLh3mk4EUF33sqlfxjio1MdYeSvKSG5skactKKuixBIKXhL4Rw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.72.1", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.72.1.tgz", + "integrity": "sha512-DAlUoUV93hIvrtIQLwCbmZQYVZwOMhiHJrOVUUIWicFZaIYjTRqlY3I/NZevfkLmSqkNHRu2qYDcq9lrn16oOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.72.1", + "@typescript-eslint/tsconfig-utils": "8.72.1", + "@typescript-eslint/types": "8.72.1", + "@typescript-eslint/visitor-keys": "8.72.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.72.1", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-8.72.1.tgz", + "integrity": "sha512-5v5liypurJBFHCBNqh/RjsymAD+VWcE0djuGY/BUqp5fC3Qn+luWDEksjuTtWjPn6i5zQlUtkZCRG/CYG0yCkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.72.1", + "@typescript-eslint/types": "8.72.1", + "@typescript-eslint/typescript-estree": "8.72.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.72.1", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.72.1.tgz", + "integrity": "sha512-SB8xqipSzZHUePCCLNeYxqnxq83X61/qzNhjQGbTfjxGZIeOEP7tBgWYX05Tcd6CgE02WdTJnh5b8kMZJ/+bnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.72.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/@ungap/structured-clone/-/structured-clone-1.4.0.tgz", + "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==", + "license": "ISC" + }, + "node_modules/@vitejs/plugin-react-swc": { + "version": "4.3.3", + "resolved": "https://registry.npmmirror.com/@vitejs/plugin-react-swc/-/plugin-react-swc-4.3.3.tgz", + "integrity": "sha512-bti8ZAcvz4Lh6/e4Uk2k3aa1TiUXbbMsahuqOHvd3MveFTkKDZOA6wQVkpj7J/+tepX/wGfe+lsGh/t24HTXMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "^1.0.1", + "@swc/core": "^1.15.46" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.15", + "resolved": "https://registry.npmmirror.com/@xmldom/xmldom/-/xmldom-0.8.15.tgz", + "integrity": "sha512-/5NV/vDALVFDXgLmfsy9TRCBlKwO2LNBFzpzvb9iIj+jR+eSc6DLYYvVOdivT/jm7MtU6TebYuRmzEOI7w40UA==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/acorn": { + "version": "8.19.0", + "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.19.0.tgz", + "integrity": "sha512-oJlA3XiRm7Cyk6qFD2Jn8ak9B7jSy0qy00ADO3+8dpT0LSjFihQYv4C02LFCSYJV3Q37xYwwRy5m+IpIiUzqWw==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "devOptional": true, + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansis": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/ansis/-/ansis-4.5.0.tgz", + "integrity": "sha512-KwIVkfFfJSSzBmZhDGuTmkhWqTdyB5oNVzzznBJbBZ5bZtHiqSrcugRF0RKJKT4Ss3d7ZrcjnlFVDlQNmtWfWw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmmirror.com/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmmirror.com/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/attr-accept": { + "version": "2.2.5", + "resolved": "https://registry.npmmirror.com/attr-accept/-/attr-accept-2.2.5.tgz", + "integrity": "sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/autoprefixer": { + "version": "10.6.2", + "resolved": "https://registry.npmmirror.com/autoprefixer/-/autoprefixer-10.6.2.tgz", + "integrity": "sha512-VOw9/yGTGwPPgzFcODtcv6zhEPIeIWkRSe10L2ri2f5vZ7ID7lCt6jZzRF5/ubgOZ+szYydmEF5AYsA5jxX1tA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.9", + "caniuse-lite": "^1.0.30001810", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/axios": { + "version": "1.21.0", + "resolved": "https://registry.npmmirror.com/axios/-/axios-1.21.0.tgz", + "integrity": "sha512-YCzXMB53Q9PZBsh7yN7wtapit4WepwcHS2fP8QhGsBxSz5YtgYobV7GGlWlAJi+RxfU77GQTQi2DSLUma42EYA==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.6", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/babel-dead-code-elimination": { + "version": "1.0.12", + "resolved": "https://registry.npmmirror.com/babel-dead-code-elimination/-/babel-dead-code-elimination-1.0.12.tgz", + "integrity": "sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.23.7", + "@babel/parser": "^7.23.6", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.34", + "resolved": "https://registry.npmmirror.com/baseline-browser-mapping/-/baseline-browser-mapping-2.11.34.tgz", + "integrity": "sha512-Aqr8mA1kIvyJ3UY5YAY7ib8LSo1DmDMbMnVqGPtsKW1LxaFQFwn9Eb3yvq2fUKJsRvaXjnAV7R5osqETapzNiA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.21", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.29.5", + "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.29.5.tgz", + "integrity": "sha512-khTmKu5NGYTotqcYo8Bew2k4RAE9PuXRSFRXG2lQBrCEQHyeQ/vX6gKMxfokwywBsLiXZMnHsmWMG1pnO8J7uQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.11.33", + "caniuse-lite": "^1.0.30001819", + "electron-to-chromium": "^1.5.464", + "node-releases": "^2.0.60", + "update-browserslist-db": "^1.3.4" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001820", + "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001820.tgz", + "integrity": "sha512-gfWD6MxqVCqAOwmODfZf7DchWvlrA+SRdNX7ceLfg3xRqe5ssjjpF7EgslC/0tiLiNTajdaNN/q8c/5u/7Gz8w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/cfb": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmmirror.com/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmmirror.com/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie-es": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/cookie-es/-/cookie-es-3.1.1.tgz", + "integrity": "sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==", + "license": "MIT" + }, + "node_modules/copy-anything": { + "version": "4.1.5", + "resolved": "https://registry.npmmirror.com/copy-anything/-/copy-anything-4.1.5.tgz", + "integrity": "sha512-vePst2VLTSqPglW7Q98VwFpGiGpOHTyXIo81MO5VyLecA5zMbZw/P/V1vmwD1jksa2iJpn/YkDrJ3XhTfzUyhQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/copy-to-clipboard": { + "version": "3.3.3", + "resolved": "https://registry.npmmirror.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", + "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", + "license": "MIT", + "dependencies": { + "toggle-selection": "^1.0.6" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT", + "peer": true + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmmirror.com/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/date-fns": { + "version": "4.4.0", + "resolved": "https://registry.npmmirror.com/date-fns/-/date-fns-4.4.0.tgz", + "integrity": "sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/date-fns-jalali": { + "version": "4.1.0-0", + "resolved": "https://registry.npmmirror.com/date-fns-jalali/-/date-fns-jalali-4.1.0-0.tgz", + "integrity": "sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmmirror.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/derive-zustand": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/derive-zustand/-/derive-zustand-0.2.0.tgz", + "integrity": "sha512-ZCC9MuSOHVMglG7UgClRq7/BXsNjhvGSAly3XSBwGSaJbwt0WGEBZ8vn1ZD4MMXczq276dLU5HetqisQp5fFzw==", + "license": "MIT", + "peerDependencies": { + "zustand": ">=4.1.0" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "license": "Apache-2.0" + }, + "node_modules/diff": { + "version": "9.0.0", + "resolved": "https://registry.npmmirror.com/diff/-/diff-9.0.0.tgz", + "integrity": "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dingbat-to-unicode": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/dingbat-to-unicode/-/dingbat-to-unicode-1.0.2.tgz", + "integrity": "sha512-R0bRerYzy/EZP6QzD3Hkl6JjUDA1Mnn+pd928w0nWjPzihnbAR6dcjGJGiRyznj5E4S1duEKzWrTqw02DPcdzg==", + "license": "BSD-2-Clause" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmmirror.com/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/duck": { + "version": "0.1.12", + "resolved": "https://registry.npmmirror.com/duck/-/duck-0.1.12.tgz", + "integrity": "sha512-wkctla1O6VfP89gQ+J/yDesM0S7B7XLXjKGzXxMDVFg7uEn706niAtyYovKbyq1oT9YwDcly721/iUWoc8MVRg==", + "license": "BSD", + "dependencies": { + "underscore": "^1.13.1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.472", + "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.472.tgz", + "integrity": "sha512-s4+nfT29b0FKpVKoaIxl2pWsoNcn7A/nMPSrxayw4T3BsmPeV2lF9Y06BsAQeMGhCTQ4nYJ5XST7jkqe4ZEqFw==", + "dev": true, + "license": "ISC" + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.4", + "resolved": "https://registry.npmmirror.com/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.1.1", + "resolved": "https://registry.npmmirror.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", + "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.26", + "resolved": "https://registry.npmmirror.com/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.26.tgz", + "integrity": "sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmmirror.com/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmmirror.com/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmmirror.com/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/fast-equals": { + "version": "5.4.5", + "resolved": "https://registry.npmmirror.com/fast-equals/-/fast-equals-5.4.5.tgz", + "integrity": "sha512-yKEpcFuRPu/pTQL2VB8YKE2yFldrLlIsoWtJeBnAdqEhvu21OgkFT0C8njf/xYc2LSZGEr3K9JGjthHJxnVLvQ==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmmirror.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.20.3", + "resolved": "https://registry.npmmirror.com/fastq/-/fastq-1.20.3.tgz", + "integrity": "sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/file-selector": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/file-selector/-/file-selector-2.1.2.tgz", + "integrity": "sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==", + "license": "MIT", + "dependencies": { + "tslib": "^2.7.0" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.4", + "resolved": "https://registry.npmmirror.com/flatted/-/flatted-3.4.4.tgz", + "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.16.2", + "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.16.2.tgz", + "integrity": "sha512-/kVP2U8z596Ia0gwFrwyIeo74ta5aVmSeU1FfAUMAmcEP5EP7zydmag3SLiN64NaRKef3lxsq7i/g7ltJQDGow==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.6", + "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/frac": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmmirror.com/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.5.0", + "resolved": "https://registry.npmmirror.com/globals/-/globals-16.5.0.tgz", + "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/goober": { + "version": "2.1.19", + "resolved": "https://registry.npmmirror.com/goober/-/goober-2.1.19.tgz", + "integrity": "sha512-U7veizMqxyKlM58+Z5j2ngJBH/r9siDmxpvNxSw0PylF6WQvrASJEZrxh1hidRBJc2jqoBVSyOban5u8m+6Rxg==", + "license": "MIT", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.4", + "resolved": "https://registry.npmmirror.com/hast-util-from-parse5/-/hast-util-from-parse5-8.0.4.tgz", + "integrity": "sha512-Yq7XlXor0Cpb71sI2E0zpv8QxQ5a6rfhDEETk4bcgrFX2SvJAY2PHocWwFtL6U9qyfiyByW3wZ6sZEfP2kW81g==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^9.0.0", + "property-information": "^7.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw": { + "version": "9.1.0", + "resolved": "https://registry.npmmirror.com/hast-util-raw/-/hast-util-raw-9.1.0.tgz", + "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.7", + "resolved": "https://registry.npmmirror.com/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.7.tgz", + "integrity": "sha512-F7DNV2NMcTxA4GqPVHnXzX+mpoPHAIY9rJAVH3CZ1FdBZOcBUEjUuvMkMpHVs/sicEtznh9tMGj5WUR9S4E2rg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^2.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmmirror.com/hast-util-to-parse5/-/hast-util-to-parse5-8.0.1.tgz", + "integrity": "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-text": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/hast-util-to-text/-/hast-util-to-text-4.0.3.tgz", + "integrity": "sha512-5yrlWOvGFs6CqHriUpSsNrjzT/Tdo+IOQudbznxOn8K5qblp18MJyzOg8IgDOKQ8MYgQcJA7SusuCjSpDr8mSA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "9.0.3", + "resolved": "https://registry.npmmirror.com/hastscript/-/hastscript-9.0.3.tgz", + "integrity": "sha512-1ALZXSmCGmW3h8AMz4R4+QKSKFi7sNgXLVwmwB8FYVtl1CwQ3WDkSAEY/d5tp1g/vbQgq2s1WlHgfO3jbw1TsA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmmirror.com/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmmirror.com/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/highlight.js": { + "version": "11.12.0", + "resolved": "https://registry.npmmirror.com/highlight.js/-/highlight.js-11.12.0.tgz", + "integrity": "sha512-nbfWpyRMcMrPMmDwJB+dhX/eiaPKtc2RB+0QZskqJ3WjRA/FDS0e9hZrx8EC/lbEv8gXy98FcDbNa/dspAaJMg==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/html-url-attributes": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/html-url-attributes/-/html-url-attributes-3.0.1.tgz", + "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmmirror.com/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, + "node_modules/immer": { + "version": "11.2.9", + "resolved": "https://registry.npmmirror.com/immer/-/immer-11.2.9.tgz", + "integrity": "sha512-IQ4UEtXjZjyefyWjtLEDXUSrF6T2hwjKPi6BIJl3bY/2XXW24d6cNGdXJSBOA/+KNnuiXkZY6DR0C3efolhitA==", + "license": "MIT", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/inline-style-parser": { + "version": "0.2.9", + "resolved": "https://registry.npmmirror.com/inline-style-parser/-/inline-style-parser-0.2.9.tgz", + "integrity": "sha512-IttN8BqKLxzUrnTqHI+/hwAJQItBAUjdoHERCDv+oOuX48VP6bzW8+QjOXSfoevzq3YrYAwX1uLHp8TqO9yIeg==", + "license": "MIT" + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.17.0", + "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.17.0.tgz", + "integrity": "sha512-J/vG0zBCbIKOQFfufSwyXdMrsohyJIUNkrnmo6WZGzoM7tr/lsbfW5b2BvisL6zsyMzK9UxV9L6c7AoFbyXHOA==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/isbot": { + "version": "5.2.2", + "resolved": "https://registry.npmmirror.com/isbot/-/isbot-5.2.2.tgz", + "integrity": "sha512-iQcBXcd+Rv/pkubRyGh2utW2j1oPG5hZY6TUhVPpqK4G+o3IbxpJNx04hgksjc/N7GK5pEorUxDeg31cFgEk/w==", + "license": "Unlicense", + "engines": { + "node": ">=18" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmmirror.com/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "devOptional": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.2", + "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jszip": { + "version": "3.10.2", + "resolved": "https://registry.npmmirror.com/jszip/-/jszip-3.10.2.tgz", + "integrity": "sha512-3l+rb15IOWtUhU0H5MFqES/T6Kh7abYwjosBey/vD6hDt8zoEffkSC5Ws5SGtgVw3gBx2NEbhTeSW1+kWkpyTQ==", + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lilconfig": { + "version": "3.1.4", + "resolved": "https://registry.npmmirror.com/lilconfig/-/lilconfig-3.1.4.tgz", + "integrity": "sha512-zJZyBmQhArDRefuWTypZxwDpFDIYmrj8ypSBvwGD5P13Y95s6DjzKgu4DVdGbeQa5PDEsAOCAPNk4X+QOR006w==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lop": { + "version": "0.4.2", + "resolved": "https://registry.npmmirror.com/lop/-/lop-0.4.2.tgz", + "integrity": "sha512-RefILVDQ4DKoRZsJ4Pj22TxE3omDO47yFpkIBoDKzkqPRISs5U1cnAdg/5583YPkWPaLIYHOKRMQSvjFsO26cw==", + "license": "BSD-2-Clause", + "dependencies": { + "duck": "^0.1.12", + "option": "~0.2.1", + "underscore": "^1.13.1" + } + }, + "node_modules/lowlight": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/lowlight/-/lowlight-3.3.0.tgz", + "integrity": "sha512-0JNhgFoPvP6U6lE/UdVsSq99tn6DhjjpAj5MxG49ewd2mOBVtwWYIT8ClyABhq198aXXODMU6Ox8DrGy/CpTZQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.0.0", + "highlight.js": "~11.11.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/lowlight/node_modules/highlight.js": { + "version": "11.11.2", + "resolved": "https://registry.npmmirror.com/highlight.js/-/highlight.js-11.11.2.tgz", + "integrity": "sha512-oaXMACAU0kzOMXBjWpNcX+vlwSBCIAiZ9BHa7gA15NOTtT2L/l8OSZDuqS2XppOhZBPJ7hm4o8ep2kyuip2uEQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.562.0", + "resolved": "https://registry.npmmirror.com/lucide-react/-/lucide-react-0.562.0.tgz", + "integrity": "sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/mammoth": { + "version": "1.13.0", + "resolved": "https://registry.npmmirror.com/mammoth/-/mammoth-1.13.0.tgz", + "integrity": "sha512-2cawcYFcP7ISfXbBcL9lmVgTNWo88v/52ND1gnywHtVT/pX0//puPnf0iMPV9ZgmuvNOE+zkIhDgZ9M2c2dDDg==", + "license": "BSD-2-Clause", + "dependencies": { + "@xmldom/xmldom": "^0.8.6", + "argparse": "~1.0.3", + "base64-js": "^1.5.1", + "dingbat-to-unicode": "^1.0.1", + "jszip": "^3.7.1", + "lop": "^0.4.2", + "underscore": "^1.13.1", + "xmlbuilder": "^10.0.0" + }, + "bin": { + "mammoth": "bin/mammoth" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/mammoth/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmmirror.com/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.4.tgz", + "integrity": "sha512-z4B5c6jrnJ1ltOQemhWYPBSAo6y42Z8Gt2yEgfgNTMcLSU59B8bfj8Z8AnAlJrBGLnqkdAUZ7jdDEqQw3KuipQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/mdast-util-from-markdown/-/mdast-util-from-markdown-2.1.0.tgz", + "integrity": "sha512-KRLgmPaP2H1ul2bpoJkOS+9pAcDAAj9Nu1mqLnh8NLeJG5tlvj42TH80PIGBpROWlRXLk0lDrWNuZCFy/tsB4A==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.1.tgz", + "integrity": "sha512-OuJHqvr455pwu2OaOrir7dbzqs4jlWKOtlu9L6GjcIjjQwNyw02VntQsr/Ek6/A13vgnXfUhBekWRUP1OkNivw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmmirror.com/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/mdast-util-to-markdown/-/mdast-util-to-markdown-2.2.1.tgz", + "integrity": "sha512-ThatlCBxG2GE+mljhNSfZPv56d3QrGiRh97jjYgIk80IzS4uU6d7cHAaexCYSAmUCCcOs3grJ07kX3oTGsFUOw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromark": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/micromark/-/micromark-4.0.3.tgz", + "integrity": "sha512-oGYfQzHSG5dOMovQcJ3fyTmZlWAWpi0XA0sJwJs+i6OT88o1+Jtw/8z0CmdowSLxGhhFK89rQ/oXph/wN02PNw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-edit-map": "^1.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/micromark-core-commonmark/-/micromark-core-commonmark-2.0.4.tgz", + "integrity": "sha512-wxEeE8v8XVvOrxn1TZj74qYhAtTQsSqufHVS3uNVyT1MupXxhyaHk8/9xDNPh9BmL77QNDgWTkZ3RsYHB2ry7w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.1.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-edit-map": "^1.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.3" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.2.tgz", + "integrity": "sha512-pRzm4kDTu0MjlmBkxmS9yYhw60nncfcEwu9NNdPFSQEFXS95ZKyIIyTSHu/o3ReBUrLKYEq+7YaXCRn/bPB4MA==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/micromark-factory-space/-/micromark-factory-space-2.1.0.tgz", + "integrity": "sha512-fS8hnLIjnjvdQIj39Geug8wWsR0HrYZ43KShKxNfwT7t2LOHo/LbWZEzEaSOjwtjdCsjoE6syHhonEzW0zv0+Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-edit-map": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/micromark-util-edit-map/-/micromark-util-edit-map-1.0.0.tgz", + "integrity": "sha512-Pa2ljlsEL6sVwFaYeyrOLSYbQt73JvGbPOYFq+9AElXiSnfI5Q4465RRZ1sHv7lDjDOnGRDDaqPXqClqWK/q1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/micromark-util-types/-/micromark-util-types-2.0.3.tgz", + "integrity": "sha512-oxB2Ik03hI0gv+VNn9tnh1t1YEe9MDPptViAEgfdf3YQHsn0pzGTgCdlSCJXcwhqm8phaEuM7zeEu3QQzVBrPg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmmirror.com/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "5.1.16", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-5.1.16.tgz", + "integrity": "sha512-kVrnsrJqMR8+oLJnGEmSWw9BivK5mt7H3FZatVRjrc5wGqFYuBxX1yG7+A7Gi5AefkX6t/oCkizcQgpu0cY1dQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/next-themes": { + "version": "0.4.6", + "resolved": "https://registry.npmmirror.com/next-themes/-/next-themes-0.4.6.tgz", + "integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/node-releases": { + "version": "2.0.63", + "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.63.tgz", + "integrity": "sha512-6li2QanLsAXpIH2R6j77MzRyvOyrvdTqlKtO4CgBdHGNvN99ZZfyxszHc5o5+IZBWD5u6Hzwg83JoGXmqZNG9Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/option": { + "version": "0.2.4", + "resolved": "https://registry.npmmirror.com/option/-/option-0.2.4.tgz", + "integrity": "sha512-pkEqbDyl8ou5cpq+VsnQbe/WlEy5qS7xPzMS1U55OCG9KPvwFD46zDbxQIj3egJSFc3D+XhYOPUzz49zQAVy7A==", + "license": "BSD-2-Clause" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmmirror.com/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmmirror.com/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmmirror.com/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmmirror.com/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmmirror.com/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.5.32", + "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.32.tgz", + "integrity": "sha512-LJlKCCAUFKOuZxipUdYw1NzIITEsPcgyOG9LkvRJvuKj/bRzbuRY0ARXvL0pWGpsZvn8jku+LMep2eU0seHp8g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "nanoid": "^3.3.20", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmmirror.com/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmmirror.com/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.5", + "resolved": "https://registry.npmmirror.com/postcss-selector-parser/-/postcss-selector-parser-6.1.5.tgz", + "integrity": "sha512-TEHFzb5KRDKaOgJ4TYE+0jyJtFbjLvkdVOu0fZ2b6MTWzoqZd4Le+61aEppWkvTlYePgOX4ATL1wsAIPMLTw6Q==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.20", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.20.tgz", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.9.10", + "resolved": "https://registry.npmmirror.com/prettier/-/prettier-3.9.10.tgz", + "integrity": "sha512-skGHTH1Yb9QvaTC4hWnRTzEYtCpApF0UMBPz+t/0ZPzP8ihefo/btKd+QA7pUE0fEwA1SbS/NmhyEcstdXOIdA==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmmirror.com/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/property-information": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/property-information/-/property-information-7.2.0.tgz", + "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "19.3.1", + "resolved": "https://registry.npmmirror.com/react/-/react-19.3.1.tgz", + "integrity": "sha512-QNhWdt7nrgVWWQG58QuGsAR3jv3Hbe4mb4vz7w2csnHavciZJgda1CPNaldF6eVxv90ud3jUXpKlHL69gO38yw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-day-picker": { + "version": "9.14.0", + "resolved": "https://registry.npmmirror.com/react-day-picker/-/react-day-picker-9.14.0.tgz", + "integrity": "sha512-tBaoDWjPwe0M5pGrum4H0SR6Lyk+BO9oHnp9JbKpGKW2mlraNPgP9BMfsg5pWpwrssARmeqk7YBl2oXutZTaHA==", + "license": "MIT", + "dependencies": { + "@date-fns/tz": "^1.4.1", + "@tabby_ai/hijri-converter": "1.0.5", + "date-fns": "^4.1.0", + "date-fns-jalali": "4.1.0-0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/gpbl" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/react-dom": { + "version": "19.3.1", + "resolved": "https://registry.npmmirror.com/react-dom/-/react-dom-19.3.1.tgz", + "integrity": "sha512-Y0bARz53lhEC1NMCASs0/j+faB/zqt3R8hpvg1e8+61ZVJ4UL0UdC4cBbXfZMcIuhrfgeILTLe+ZeBCavQPtKQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "scheduler": "^0.28.0" + }, + "peerDependencies": { + "react": "^19.3.1" + } + }, + "node_modules/react-dropzone": { + "version": "14.4.1", + "resolved": "https://registry.npmmirror.com/react-dropzone/-/react-dropzone-14.4.1.tgz", + "integrity": "sha512-QDuV76v3uKbHiH34SpwifZ+gOLi1+RdsCO1kl5vxMT4wW8R82+sthjvBw4th3NHF/XX6FBsqDYZVNN+pnhaw0g==", + "license": "MIT", + "dependencies": { + "attr-accept": "^2.2.4", + "file-selector": "^2.1.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "react": ">= 16.8 || 18.0.0" + } + }, + "node_modules/react-hook-form": { + "version": "7.91.0", + "resolved": "https://registry.npmmirror.com/react-hook-form/-/react-hook-form-7.91.0.tgz", + "integrity": "sha512-5BEBUnCBwa28AFXYTYmOaB/+CSpJ/+CWVASHEvIGUzFdHyUiPHeRhG7r5hOZ8nZi0yP7pbHdFNXO/p31EKTJFQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmmirror.com/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-markdown": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/react-markdown/-/react-markdown-10.1.0.tgz", + "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "html-url-attributes": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=18", + "react": ">=18" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.7.2", + "resolved": "https://registry.npmmirror.com/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmmirror.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-smooth": { + "version": "4.0.4", + "resolved": "https://registry.npmmirror.com/react-smooth/-/react-smooth-4.0.4.tgz", + "integrity": "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==", + "license": "MIT", + "dependencies": { + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmmirror.com/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmmirror.com/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/read-cache": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/read-cache/-/read-cache-1.0.2.tgz", + "integrity": "sha512-/peqiBB/n07gQGLsWaHho3WfvUyRscw0gYTsEFMhrIe/nWLkYaf5SbKYjGYqtRV3aPwykJgF2VEMo1ac4bnsGA==", + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readdirp": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-5.1.1.tgz", + "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/recharts": { + "version": "2.15.4", + "resolved": "https://registry.npmmirror.com/recharts/-/recharts-2.15.4.tgz", + "integrity": "sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==", + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.21", + "react-is": "^18.3.1", + "react-smooth": "^4.0.4", + "recharts-scale": "^0.4.4", + "tiny-invariant": "^1.3.1", + "victory-vendor": "^36.6.8" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmmirror.com/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "license": "MIT", + "dependencies": { + "decimal.js-light": "^2.4.1" + } + }, + "node_modules/recharts/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmmirror.com/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/rehype-highlight": { + "version": "7.0.2", + "resolved": "https://registry.npmmirror.com/rehype-highlight/-/rehype-highlight-7.0.2.tgz", + "integrity": "sha512-k158pK7wdC2qL3M5NcZROZ2tR/l7zOzjxXd5VGdcfIyoijjQqpHd3JKtYSBDpDZ38UI2WJWuFAtkMDxmx5kstA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-to-text": "^4.0.0", + "lowlight": "^3.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmmirror.com/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmmirror.com/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmmirror.com/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remove-accents": { + "version": "0.5.0", + "resolved": "https://registry.npmmirror.com/remove-accents/-/remove-accents-0.5.0.tgz", + "integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.13", + "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.13.tgz", + "integrity": "sha512-Dj/cW9zBV2aRj6XzCxuGIs3ESZKv02jixne3q6jFZYZ3/Tg09gHHviSMDL4kObh9pqSahdRHEnDoaP2gn8YLhA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.17.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rolldown": { + "version": "1.0.0-beta.53", + "resolved": "https://registry.npmmirror.com/rolldown/-/rolldown-1.0.0-beta.53.tgz", + "integrity": "sha512-Qd9c2p0XKZdgT5AYd+KgAMggJ8ZmCs3JnS9PTMWkyUfteKlfmKtxJbWTHkVakxwXs1Ub7jrRYVeFeF7N0sQxyw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@oxc-project/types": "=0.101.0", + "@rolldown/pluginutils": "1.0.0-beta.53" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-beta.53", + "@rolldown/binding-darwin-arm64": "1.0.0-beta.53", + "@rolldown/binding-darwin-x64": "1.0.0-beta.53", + "@rolldown/binding-freebsd-x64": "1.0.0-beta.53", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.53", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.53", + "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.53", + "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.53", + "@rolldown/binding-linux-x64-musl": "1.0.0-beta.53", + "@rolldown/binding-openharmony-arm64": "1.0.0-beta.53", + "@rolldown/binding-wasm32-wasi": "1.0.0-beta.53", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.53", + "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.53" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.53", + "resolved": "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.53.tgz", + "integrity": "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.28.0", + "resolved": "https://registry.npmmirror.com/scheduler/-/scheduler-0.28.0.tgz", + "integrity": "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/seroval": { + "version": "1.7.6", + "resolved": "https://registry.npmmirror.com/seroval/-/seroval-1.7.6.tgz", + "integrity": "sha512-oKNe6A8I3lSA5J0xg9xsrWCWDpET6CFhCMVuIsCmqrjNpBXzQXDAAQI5UfuC4Ner4DIR+VAtSw7TC0AmRMqFFQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=20" + } + }, + "node_modules/seroval-plugins": { + "version": "1.7.6", + "resolved": "https://registry.npmmirror.com/seroval-plugins/-/seroval-plugins-1.7.6.tgz", + "integrity": "sha512-/TPCAd6q5stAZnugD2fsvNKtM2UpgwrS8/fO1cXTgPC0EqCsGB+UfkEEsToFCfg35CDTMlWkppfr/zWnLJGpBA==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "seroval": "^1.0" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/solid-js": { + "version": "1.9.18", + "resolved": "https://registry.npmmirror.com/solid-js/-/solid-js-1.9.18.tgz", + "integrity": "sha512-CHGO5YFk6Y9m/1YSxVtKnXfrW7JD3Tmof8HmR4z6TmCPsS8efo8LnzIR8CQh3cUvffqYm6DWyBFfk8dQw1CNQQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.1.0", + "seroval": "~1.6.11", + "seroval-plugins": "~1.6.8" + } + }, + "node_modules/solid-js/node_modules/seroval": { + "version": "1.6.12", + "resolved": "https://registry.npmmirror.com/seroval/-/seroval-1.6.12.tgz", + "integrity": "sha512-CqbIVfk/7GL3ITwZI55lcPbpQbjHZ2DD5cUj4iH7E9YsCfHNJV1mx7yNp86Z84w5IpmkZZS/2s5vPOWmVWSdQg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/solid-js/node_modules/seroval-plugins": { + "version": "1.6.12", + "resolved": "https://registry.npmmirror.com/seroval-plugins/-/seroval-plugins-1.6.12.tgz", + "integrity": "sha512-+reiwp/lYxiyctSrdvX7OQ1YLrcbWYgBiZrhSFL+V43b0/DGRLNVSDyZINbQe+tWplPOI2fw2dPrdv6hcc09kQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "seroval": "^1.0" + } + }, + "node_modules/solid-presence": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/solid-presence/-/solid-presence-0.2.0.tgz", + "integrity": "sha512-YM92o+jvpzX3XGaD4rLYmq/Kc2ZVh47GSCLEufHBFQQIurvZTs8SoGJxO8BJGNDxBKdcS8F3dYhW1SDXp4BNjA==", + "license": "MIT", + "dependencies": { + "@corvu/utils": "~0.4.2" + }, + "peerDependencies": { + "solid-js": "^1.8" + } + }, + "node_modules/solid-prevent-scroll": { + "version": "0.1.11", + "resolved": "https://registry.npmmirror.com/solid-prevent-scroll/-/solid-prevent-scroll-0.1.11.tgz", + "integrity": "sha512-2PComVCDHaQN/5t7ogEqUYeHasritZKXZ8Sb/VLkl0Web8o9YhEwOo8LSujJEahvMlYCNyKt0zRJeHldOAeWZg==", + "license": "MIT", + "dependencies": { + "@corvu/utils": "~0.4.2" + }, + "peerDependencies": { + "solid-js": "^1.8" + } + }, + "node_modules/solid-transition-group": { + "version": "0.2.3", + "resolved": "https://registry.npmmirror.com/solid-transition-group/-/solid-transition-group-0.2.3.tgz", + "integrity": "sha512-iB72c9N5Kz9ykRqIXl0lQohOau4t0dhel9kjwFvx81UZJbVwaChMuBuyhiZmK24b8aKEK0w3uFM96ZxzcyZGdg==", + "license": "MIT", + "dependencies": { + "@solid-primitives/refs": "^1.0.5", + "@solid-primitives/transition-group": "^1.0.2" + }, + "engines": { + "node": ">=18.0.0", + "pnpm": ">=8.6.0" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/sonner": { + "version": "2.0.8", + "resolved": "https://registry.npmmirror.com/sonner/-/sonner-2.0.8.tgz", + "integrity": "sha512-UM/ByIoFra8yzV75n1o0Puu0bw5U/9UNnDacrJNspekBewIfsQ3D6ez1nvlWpt7aTsO6rujQtifBpycwIivqlg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/source-map-js": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/ssf": { + "version": "0.11.2", + "resolved": "https://registry.npmmirror.com/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "license": "Apache-2.0", + "dependencies": { + "frac": "~1.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmmirror.com/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-to-object": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/style-to-object/-/style-to-object-2.0.2.tgz", + "integrity": "sha512-QmbXPUylqU80HAgTOJeEOdbA40W9KtxmjMhQy+tq+b8F2aoh3aQLuy82hh2jm2qsC9hR9eI0+eQidTMydKcqRA==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.9" + } + }, + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmmirror.com/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/superjson": { + "version": "2.2.6", + "resolved": "https://registry.npmmirror.com/superjson/-/superjson-2.2.6.tgz", + "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", + "license": "MIT", + "dependencies": { + "copy-anything": "^4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwind-merge": { + "version": "3.7.0", + "resolved": "https://registry.npmmirror.com/tailwind-merge/-/tailwind-merge-3.7.0.tgz", + "integrity": "sha512-XPPUyAc+cvspz3lHTcR/QgPfW2A0lv/xQNIjX3HGhLR+Nq2lHaLq5MtTesHn8GUr3W3DguT2KT5x3NVgRtYwmA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.19", + "resolved": "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss-animate": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", + "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, + "node_modules/tailwindcss/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/tailwindcss/node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/tailwindcss/node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmmirror.com/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/tailwindcss/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmmirror.com/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmmirror.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==", + "license": "MIT" + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmmirror.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "license": "Apache-2.0" + }, + "node_modules/tslib": { + "version": "2.9.1", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.9.1.tgz", + "integrity": "sha512-a4Ux9VKuIMHsOS7ENbEq6hK2ZGYIT27Rtl0E4eD9KqwxhKiQeMZE/9xb3IdYwWaSOyIBQLExhQgXDTYoiCxnWA==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.72.1", + "resolved": "https://registry.npmmirror.com/typescript-eslint/-/typescript-eslint-8.72.1.tgz", + "integrity": "sha512-3Li9FfPmQp45nxEtFD1ZCrYFI3cYK5kpyNtmm1H7lMagm8u9sy6PTjy3ytwQZs7KNukOyKFHAZ6z6GjYFeaeXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.72.1", + "@typescript-eslint/parser": "8.72.1", + "@typescript-eslint/typescript-estree": "8.72.1", + "@typescript-eslint/utils": "8.72.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/underscore": { + "version": "1.13.8", + "resolved": "https://registry.npmmirror.com/underscore/-/underscore-1.13.8.tgz", + "integrity": "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "dev": true, + "license": "MIT" + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmmirror.com/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/unist-util-visit/-/unist-util-visit-5.2.0.tgz", + "integrity": "sha512-fpsYs/VVoZxfGY9/j3FQpZmN8wdLJaV1Pt38AaJNZu9uKIHcFU3halCdBveEq1HGKO1OEfJY65w1zvoFV1b3qQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/unist-util-visit-parents/-/unist-util-visit-parents-6.1.0.tgz", + "integrity": "sha512-vKXxz6O38sKDj1mtx/k2cWvkkFBuYGx6uGrlzBkVeWCRF/F8sdI0j3Wbkz/5rVNRRuVc8UrgRdbCxNhmYXgP3w==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unplugin": { + "version": "3.7.0", + "resolved": "https://registry.npmmirror.com/unplugin/-/unplugin-3.7.0.tgz", + "integrity": "sha512-GrM2uq3DQo3hvLU2FjeYhooJ8BY9N6j1Fbzgx7Pta3VVJevsD3VP4dPjZkZOS0mLvN8w9zzr9OlP+31bSMyuLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "@rolldown/pluginutils": "^1.0.1", + "picomatch": "^4.0.7", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@farmfe/core": "*", + "@rsbuild/core": "*", + "@rspack/core": "*", + "bun-types-no-globals": "*", + "esbuild": "*", + "rolldown": "*", + "rollup": "*", + "unloader": "*", + "vite": "*", + "webpack": "*" + }, + "peerDependenciesMeta": { + "@farmfe/core": { + "optional": true + }, + "@rsbuild/core": { + "optional": true + }, + "@rspack/core": { + "optional": true + }, + "bun-types-no-globals": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "rolldown": { + "optional": true + }, + "rollup": { + "optional": true + }, + "unloader": { + "optional": true + }, + "vite": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/unplugin/node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.3.4", + "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.3.4.tgz", + "integrity": "sha512-t8wonIOdQyOjtPd2VktlBu6QjTVTks6v8bSi7kd0r2Vll8TK1JYDZtRRdbmCHOAMphkZgrzK+L+vXK4pyZ8t4A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "devOptional": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmmirror.com/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.7.0", + "resolved": "https://registry.npmmirror.com/use-sync-external-store/-/use-sync-external-store-1.7.0.tgz", + "integrity": "sha512-6L+EeigHMQhdaIPNIFUKwfWJSwWFQ8gJbJ2DLOs5sDIegTwR9fRxvnM3uciHKjIZhFz+KAv2emhWMRvDmMcY8A==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/vaul": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/vaul/-/vaul-1.1.2.tgz", + "integrity": "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-dialog": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmmirror.com/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/victory-vendor": { + "version": "36.9.2", + "resolved": "https://registry.npmmirror.com/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, + "node_modules/vite": { + "name": "rolldown-vite", + "version": "7.3.1", + "resolved": "https://registry.npmmirror.com/rolldown-vite/-/rolldown-vite-7.3.1.tgz", + "integrity": "sha512-LYzdNAjRHhF2yA4JUQm/QyARyi216N2rpJ0lJZb8E9FU2y5v6Vk+xq/U4XBOxMefpWixT5H3TslmAHm1rqIq2w==", + "deprecated": "Use this package to migrate from Vite 7 to Vite 8. For the most recent updates, migrate to Vite 8 once you're ready.", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@oxc-project/runtime": "0.101.0", + "fdir": "^6.5.0", + "lightningcss": "^1.30.2", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rolldown": "1.0.0-beta.53", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "esbuild": "^0.27.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word": { + "version": "0.3.0", + "resolved": "https://registry.npmmirror.com/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/xlsx": { + "version": "0.18.5", + "resolved": "https://registry.npmmirror.com/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + }, + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/xmlbuilder": { + "version": "10.1.1", + "resolved": "https://registry.npmmirror.com/xmlbuilder/-/xmlbuilder-10.1.1.tgz", + "integrity": "sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg==", + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.6.7", + "resolved": "https://registry.npmmirror.com/zod/-/zod-4.6.7.tgz", + "integrity": "sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + }, + "node_modules/zustand": { + "version": "5.0.16", + "resolved": "https://registry.npmmirror.com/zustand/-/zustand-5.0.16.tgz", + "integrity": "sha512-Uv7e327ihlCfayfja3hDc0M64Upev1LWBKpRobdK4NyovDDPeeX4imWXc/wzC1yc6fkYPoAY/ncKVPAs2jrtQw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..da0a3f0 --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,90 @@ +{ + "name": "senmesh-zc-legacy", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "build:inside": "VITE_IS_INSIDE=true vite build --outDir dist/inside", + "build:outside": "VITE_IS_INSIDE=false vite build --outDir dist/outside", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@hookform/resolvers": "^5.2.2", + "@radix-ui/react-alert-dialog": "^1.1.15", + "@radix-ui/react-avatar": "^1.1.11", + "@radix-ui/react-checkbox": "^1.3.3", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-label": "^2.1.8", + "@radix-ui/react-popover": "^1.1.15", + "@radix-ui/react-progress": "^1.1.8", + "@radix-ui/react-radio-group": "^1.3.8", + "@radix-ui/react-select": "^2.2.6", + "@radix-ui/react-separator": "^1.1.8", + "@radix-ui/react-slot": "^1.2.4", + "@radix-ui/react-switch": "^1.2.6", + "@radix-ui/react-tabs": "^1.1.13", + "@radix-ui/react-toggle": "^1.1.10", + "@radix-ui/react-toggle-group": "^1.1.11", + "@radix-ui/react-tooltip": "^1.2.8", + "@tanstack/react-pacer": "^0.19.0", + "@tanstack/react-query": "^5.90.12", + "@tanstack/react-query-devtools": "^5.91.2", + "@tanstack/react-router": "^1.143.11", + "@tanstack/react-table": "^8.21.3", + "axios": "^1.15.1", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "copy-to-clipboard": "^3.3.3", + "date-fns": "^4.1.0", + "derive-zustand": "^0.2.0", + "highlight.js": "^11.11.1", + "immer": "^11.1.0", + "lucide-react": "^0.562.0", + "mammoth": "^1.11.0", + "nanoid": "^5.1.6", + "next-themes": "^0.4.6", + "react": "^19.2.3", + "react-day-picker": "^9.13.0", + "react-dom": "^19.2.3", + "react-dropzone": "^14.3.8", + "react-hook-form": "^7.69.0", + "react-markdown": "^10.1.0", + "recharts": "2.15.4", + "rehype-highlight": "^7.0.2", + "rehype-raw": "^7.0.0", + "remark-gfm": "^4.0.1", + "sonner": "^2.0.7", + "tailwind-merge": "^3.4.0", + "tailwindcss": "^3.4.17", + "vaul": "^1.1.2", + "xlsx": "^0.18.5", + "zod": "^4.2.1", + "zustand": "^5.0.9" + }, + "devDependencies": { + "@eslint/js": "^9.39.1", + "@tanstack/react-router-devtools": "^1.158.1", + "@tanstack/router-plugin": "^1.158.1", + "@types/node": "^25.2.0", + "@types/react": "^19.2.5", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react-swc": "^4.2.2", + "autoprefixer": "^10.4.24", + "eslint": "^9.39.1", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.4.24", + "globals": "^16.5.0", + "postcss": "^8.5.6", + "tailwindcss-animate": "^1.0.7", + "typescript": "~5.9.3", + "typescript-eslint": "^8.46.4", + "vite": "npm:rolldown-vite@latest" + }, + "overrides": { + "vite": "npm:rolldown-vite@latest" + } +} diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml new file mode 100644 index 0000000..ce4c774 --- /dev/null +++ b/frontend/pnpm-lock.yaml @@ -0,0 +1,6516 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@hookform/resolvers': + specifier: ^5.2.2 + version: 5.2.2(react-hook-form@7.72.0(react@19.2.4)) + '@radix-ui/react-alert-dialog': + specifier: ^1.1.15 + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-avatar': + specifier: ^1.1.11 + version: 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-checkbox': + specifier: ^1.3.3 + version: 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-dialog': + specifier: ^1.1.15 + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-dropdown-menu': + specifier: ^2.1.16 + version: 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-label': + specifier: ^2.1.8 + version: 2.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-popover': + specifier: ^1.1.15 + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-progress': + specifier: ^1.1.8 + version: 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-radio-group': + specifier: ^1.3.8 + version: 1.3.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-select': + specifier: ^2.2.6 + version: 2.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-separator': + specifier: ^1.1.8 + version: 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': + specifier: ^1.2.4 + version: 1.2.4(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-switch': + specifier: ^1.2.6 + version: 1.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-tabs': + specifier: ^1.1.13 + version: 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-toggle': + specifier: ^1.1.10 + version: 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-toggle-group': + specifier: ^1.1.11 + version: 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-tooltip': + specifier: ^1.2.8 + version: 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-pacer': + specifier: ^0.19.0 + version: 0.19.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-query': + specifier: ^5.90.12 + version: 5.96.1(react@19.2.4) + '@tanstack/react-query-devtools': + specifier: ^5.91.2 + version: 5.96.1(@tanstack/react-query@5.96.1(react@19.2.4))(react@19.2.4) + '@tanstack/react-router': + specifier: ^1.143.11 + version: 1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-table': + specifier: ^8.21.3 + version: 8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + axios: + specifier: ^1.15.1 + version: 1.15.1 + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + copy-to-clipboard: + specifier: ^3.3.3 + version: 3.3.3 + date-fns: + specifier: ^4.1.0 + version: 4.1.0 + derive-zustand: + specifier: ^0.2.0 + version: 0.2.0(zustand@5.0.12(@types/react@19.2.14)(immer@11.1.4)(react@19.2.4)(use-sync-external-store@1.6.0(react@19.2.4))) + highlight.js: + specifier: ^11.11.1 + version: 11.11.1 + immer: + specifier: ^11.1.0 + version: 11.1.4 + lucide-react: + specifier: ^0.562.0 + version: 0.562.0(react@19.2.4) + mammoth: + specifier: ^1.11.0 + version: 1.12.0 + nanoid: + specifier: ^5.1.6 + version: 5.1.7 + next-themes: + specifier: ^0.4.6 + version: 0.4.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: + specifier: ^19.2.3 + version: 19.2.4 + react-day-picker: + specifier: ^9.13.0 + version: 9.14.0(react@19.2.4) + react-dom: + specifier: ^19.2.3 + version: 19.2.4(react@19.2.4) + react-dropzone: + specifier: ^14.3.8 + version: 14.4.1(react@19.2.4) + react-hook-form: + specifier: ^7.69.0 + version: 7.72.0(react@19.2.4) + react-markdown: + specifier: ^10.1.0 + version: 10.1.0(@types/react@19.2.14)(react@19.2.4) + recharts: + specifier: 2.15.4 + version: 2.15.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + rehype-highlight: + specifier: ^7.0.2 + version: 7.0.2 + rehype-raw: + specifier: ^7.0.0 + version: 7.0.0 + remark-gfm: + specifier: ^4.0.1 + version: 4.0.1 + sonner: + specifier: ^2.0.7 + version: 2.0.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + tailwind-merge: + specifier: ^3.4.0 + version: 3.5.0 + tailwindcss: + specifier: ^3.4.17 + version: 3.4.19(tsx@4.21.0) + vaul: + specifier: ^1.1.2 + version: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + xlsx: + specifier: ^0.18.5 + version: 0.18.5 + zod: + specifier: ^4.2.1 + version: 4.3.6 + zustand: + specifier: ^5.0.9 + version: 5.0.12(@types/react@19.2.14)(immer@11.1.4)(react@19.2.4)(use-sync-external-store@1.6.0(react@19.2.4)) + devDependencies: + '@eslint/js': + specifier: ^9.39.1 + version: 9.39.4 + '@tanstack/react-router-devtools': + specifier: ^1.158.1 + version: 1.166.11(@tanstack/react-router@1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.168.9)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-plugin': + specifier: ^1.158.1 + version: 1.167.12(@tanstack/react-router@1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(rolldown-vite@7.3.1(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@25.5.0)(esbuild@0.27.7)(jiti@1.21.7)(tsx@4.21.0)) + '@types/node': + specifier: ^25.2.0 + version: 25.5.0 + '@types/react': + specifier: ^19.2.5 + version: 19.2.14 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.14) + '@vitejs/plugin-react-swc': + specifier: ^4.2.2 + version: 4.3.0(rolldown-vite@7.3.1(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@25.5.0)(esbuild@0.27.7)(jiti@1.21.7)(tsx@4.21.0)) + autoprefixer: + specifier: ^10.4.24 + version: 10.4.27(postcss@8.5.8) + eslint: + specifier: ^9.39.1 + version: 9.39.4(jiti@1.21.7) + eslint-plugin-react-hooks: + specifier: ^7.0.1 + version: 7.0.1(eslint@9.39.4(jiti@1.21.7)) + eslint-plugin-react-refresh: + specifier: ^0.4.24 + version: 0.4.26(eslint@9.39.4(jiti@1.21.7)) + globals: + specifier: ^16.5.0 + version: 16.5.0 + postcss: + specifier: ^8.5.6 + version: 8.5.8 + tailwindcss-animate: + specifier: ^1.0.7 + version: 1.0.7(tailwindcss@3.4.19(tsx@4.21.0)) + typescript: + specifier: ~5.9.3 + version: 5.9.3 + typescript-eslint: + specifier: ^8.46.4 + version: 8.58.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) + vite: + specifier: npm:rolldown-vite@latest + version: rolldown-vite@7.3.1(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@25.5.0)(esbuild@0.27.7)(jiti@1.21.7)(tsx@4.21.0) + +packages: + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.2': + resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.2': + resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-jsx@7.28.6': + resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.28.6': + resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.29.2': + resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + + '@date-fns/tz@1.4.1': + resolution: {integrity: sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==} + + '@emnapi/core@1.9.2': + resolution: {integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==} + + '@emnapi/runtime@1.9.2': + resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==} + + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.21.2': + resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.5': + resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.39.4': + resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@floating-ui/core@1.7.5': + resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} + + '@floating-ui/dom@1.7.6': + resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} + + '@floating-ui/react-dom@2.1.8': + resolution: {integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.11': + resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} + + '@hookform/resolvers@5.2.2': + resolution: {integrity: sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==} + peerDependencies: + react-hook-form: ^7.55.0 + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@napi-rs/wasm-runtime@1.1.2': + resolution: {integrity: sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@oxc-project/runtime@0.101.0': + resolution: {integrity: sha512-t3qpfVZIqSiLQ5Kqt/MC4Ge/WCOGrrcagAdzTcDaggupjiGxUx4nJF2v6wUCXWSzWHn5Ns7XLv13fCJEwCOERQ==} + engines: {node: ^20.19.0 || >=22.12.0} + + '@oxc-project/types@0.101.0': + resolution: {integrity: sha512-nuFhqlUzJX+gVIPPfuE6xurd4lST3mdcWOhyK/rZO0B9XWMKm79SuszIQEnSMmmDhq1DC8WWVYGVd+6F93o1gQ==} + + '@radix-ui/number@1.1.1': + resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} + + '@radix-ui/primitive@1.1.3': + resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + + '@radix-ui/react-alert-dialog@1.1.15': + resolution: {integrity: sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-arrow@1.1.7': + resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-avatar@1.1.11': + resolution: {integrity: sha512-0Qk603AHGV28BOBO34p7IgD5m+V5Sg/YovfayABkoDDBM5d3NCx0Mp4gGrjzLGes1jV5eNOE1r3itqOR33VC6Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-checkbox@1.3.3': + resolution: {integrity: sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collection@1.1.7': + resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context@1.1.2': + resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context@1.1.3': + resolution: {integrity: sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dialog@1.1.15': + resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-direction@1.1.1': + resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dismissable-layer@1.1.11': + resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-dropdown-menu@2.1.16': + resolution: {integrity: sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.1.3': + resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.1.7': + resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-id@1.1.1': + resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-label@2.1.8': + resolution: {integrity: sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-menu@2.1.16': + resolution: {integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popover@1.1.15': + resolution: {integrity: sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popper@1.2.8': + resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.1.9': + resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.5': + resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.4': + resolution: {integrity: sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-progress@1.1.8': + resolution: {integrity: sha512-+gISHcSPUJ7ktBy9RnTqbdKW78bcGke3t6taawyZ71pio1JewwGSJizycs7rLhGTvMJYCQB1DBK4KQsxs7U8dA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-radio-group@1.3.8': + resolution: {integrity: sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-roving-focus@1.1.11': + resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-select@2.2.6': + resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-separator@1.1.8': + resolution: {integrity: sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.2.3': + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-slot@1.2.4': + resolution: {integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-switch@1.2.6': + resolution: {integrity: sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-tabs@1.1.13': + resolution: {integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-toggle-group@1.1.11': + resolution: {integrity: sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-toggle@1.1.10': + resolution: {integrity: sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-tooltip@1.2.8': + resolution: {integrity: sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.1': + resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.1.1': + resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-is-hydrated@0.1.0': + resolution: {integrity: sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-previous@1.1.1': + resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-rect@1.1.1': + resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.1.1': + resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-visually-hidden@1.2.3': + resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/rect@1.1.1': + resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + + '@rolldown/binding-android-arm64@1.0.0-beta.53': + resolution: {integrity: sha512-Ok9V8o7o6YfSdTTYA/uHH30r3YtOxLD6G3wih/U9DO0ucBBFq8WPt/DslU53OgfteLRHITZny9N/qCUxMf9kjQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.0-beta.53': + resolution: {integrity: sha512-yIsKqMz0CtRnVa6x3Pa+mzTihr4Ty+Z6HfPbZ7RVbk1Uxnco4+CUn7Qbm/5SBol1JD/7nvY8rphAgyAi7Lj6Vg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.0-beta.53': + resolution: {integrity: sha512-GTXe+mxsCGUnJOFMhfGWmefP7Q9TpYUseHvhAhr21nCTgdS8jPsvirb0tJwM3lN0/u/cg7bpFNa16fQrjKrCjQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.0-beta.53': + resolution: {integrity: sha512-9Tmp7bBvKqyDkMcL4e089pH3RsjD3SUungjmqWtyhNOxoQMh0fSmINTyYV8KXtE+JkxYMPWvnEt+/mfpVCkk8w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.53': + resolution: {integrity: sha512-a1y5fiB0iovuzdbjUxa7+Zcvgv+mTmlGGC4XydVIsyl48eoxgaYkA3l9079hyTyhECsPq+mbr0gVQsFU11OJAQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.53': + resolution: {integrity: sha512-bpIGX+ov9PhJYV+wHNXl9rzq4F0QvILiURn0y0oepbQx+7stmQsKA0DhPGwmhfvF856wq+gbM8L92SAa/CBcLg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.53': + resolution: {integrity: sha512-bGe5EBB8FVjHBR1mOLOPEFg1Lp3//7geqWkU5NIhxe+yH0W8FVrQ6WRYOap4SUTKdklD/dC4qPLREkMMQ855FA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.53': + resolution: {integrity: sha512-qL+63WKVQs1CMvFedlPt0U9PiEKJOAL/bsHMKUDS6Vp2Q+YAv/QLPu8rcvkfIMvQ0FPU2WL0aX4eWwF6e/GAnA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.0.0-beta.53': + resolution: {integrity: sha512-VGl9JIGjoJh3H8Mb+7xnVqODajBmrdOOb9lxWXdcmxyI+zjB2sux69br0hZJDTyLJfvBoYm439zPACYbCjGRmw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.0.0-beta.53': + resolution: {integrity: sha512-B4iIserJXuSnNzA5xBLFUIjTfhNy7d9sq4FUMQY3GhQWGVhS2RWWzzDnkSU6MUt7/aHUrep0CdQfXUJI9D3W7A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.0-beta.53': + resolution: {integrity: sha512-BUjAEgpABEJXilGq/BPh7jeU3WAJ5o15c1ZEgHaDWSz3LB881LQZnbNJHmUiM4d1JQWMYYyR1Y490IBHi2FPJg==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.53': + resolution: {integrity: sha512-s27uU7tpCWSjHBnxyVXHt3rMrQdJq5MHNv3BzsewCIroIw3DJFjMH1dzCPPMUFxnh1r52Nf9IJ/eWp6LDoyGcw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.53': + resolution: {integrity: sha512-cjWL/USPJ1g0en2htb4ssMjIycc36RvdQAx1WlXnS6DpULswiUTVXPDesTifSKYSyvx24E0YqQkEm0K/M2Z/AA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.0-beta.53': + resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} + + '@rolldown/pluginutils@1.0.0-rc.7': + resolution: {integrity: sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==} + + '@standard-schema/utils@0.3.0': + resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} + + '@swc/core-darwin-arm64@1.15.21': + resolution: {integrity: sha512-SA8SFg9dp0qKRH8goWsax6bptFE2EdmPf2YRAQW9WoHGf3XKM1bX0nd5UdwxmC5hXsBUZAYf7xSciCler6/oyA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + + '@swc/core-darwin-x64@1.15.21': + resolution: {integrity: sha512-//fOVntgowz9+V90lVsNCtyyrtbHp3jWH6Rch7MXHXbcvbLmbCTmssl5DeedUWLLGiAAW1wksBdqdGYOTjaNLw==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + + '@swc/core-linux-arm-gnueabihf@1.15.21': + resolution: {integrity: sha512-meNI4Sh6h9h8DvIfEc0l5URabYMSuNvyisLmG6vnoYAS43s8ON3NJR8sDHvdP7NJTrLe0q/x2XCn6yL/BeHcZg==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + + '@swc/core-linux-arm64-gnu@1.15.21': + resolution: {integrity: sha512-QrXlNQnHeXqU2EzLlnsPoWEh8/GtNJLvfMiPsDhk+ht6Xv8+vhvZ5YZ/BokNWSIZiWPKLAqR0M7T92YF5tmD3g==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@swc/core-linux-arm64-musl@1.15.21': + resolution: {integrity: sha512-8/yGCMO333ultDaMQivE5CjO6oXDPeeg1IV4sphojPkb0Pv0i6zvcRIkgp60xDB+UxLr6VgHgt+BBgqS959E9g==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@swc/core-linux-ppc64-gnu@1.15.21': + resolution: {integrity: sha512-ucW0HzPx0s1dgRvcvuLSPSA/2Kk/VYTv9st8qe1Kc22Gu0Q0rH9+6TcBTmMuNIp0Xs4BPr1uBttmbO1wEGI49Q==} + engines: {node: '>=10'} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@swc/core-linux-s390x-gnu@1.15.21': + resolution: {integrity: sha512-ulTnOGc5I7YRObE/9NreAhQg94QkiR5qNhhcUZ1iFAYjzg/JGAi1ch+s/Ixe61pMIr8bfVrF0NOaB0f8wjaAfA==} + engines: {node: '>=10'} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@swc/core-linux-x64-gnu@1.15.21': + resolution: {integrity: sha512-D0RokxtM+cPvSqJIKR6uja4hbD+scI9ezo95mBhfSyLUs9wnPPl26sLp1ZPR/EXRdYm3F3S6RUtVi+8QXhT24Q==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@swc/core-linux-x64-musl@1.15.21': + resolution: {integrity: sha512-nER8u7VeRfmU6fMDzl1NQAbbB/G7O2avmvCOwIul1uGkZ2/acbPH+DCL9h5+0yd/coNcxMBTL6NGepIew+7C2w==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@swc/core-win32-arm64-msvc@1.15.21': + resolution: {integrity: sha512-+/AgNBnjYugUA8C0Do4YzymgvnGbztv7j8HKSQLvR/DQgZPoXQ2B3PqB2mTtGh/X5DhlJWiqnunN35JUgWcAeQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + + '@swc/core-win32-ia32-msvc@1.15.21': + resolution: {integrity: sha512-IkSZj8PX/N4HcaFhMQtzmkV8YSnuNoJ0E6OvMwFiOfejPhiKXvl7CdDsn1f4/emYEIDO3fpgZW9DTaCRMDxaDA==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + + '@swc/core-win32-x64-msvc@1.15.21': + resolution: {integrity: sha512-zUyWso7OOENB6e1N1hNuNn8vbvLsTdKQ5WKLgt/JcBNfJhKy/6jmBmqI3GXk/MyvQKd5SLvP7A0F36p7TeDqvw==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + + '@swc/core@1.15.21': + resolution: {integrity: sha512-fkk7NJcBscrR3/F8jiqlMptRHP650NxqDnspBMrRe5d8xOoCy9MLL5kOBLFXjFLfMo3KQQHhk+/jUULOMlR1uQ==} + engines: {node: '>=10'} + peerDependencies: + '@swc/helpers': '>=0.5.17' + peerDependenciesMeta: + '@swc/helpers': + optional: true + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + + '@swc/types@0.1.26': + resolution: {integrity: sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw==} + + '@tabby_ai/hijri-converter@1.0.5': + resolution: {integrity: sha512-r5bClKrcIusDoo049dSL8CawnHR6mRdDwhlQuIgZRNty68q0x8k3Lf1BtPAMxRf/GgnHBnIO4ujd3+GQdLWzxQ==} + engines: {node: '>=16.0.0'} + + '@tanstack/devtools-event-client@0.4.3': + resolution: {integrity: sha512-OZI6QyULw0FI0wjgmeYzCIfbgPsOEzwJtCpa69XrfLMtNXLGnz3d/dIabk7frg0TmHo+Ah49w5I4KC7Tufwsvw==} + engines: {node: '>=18'} + hasBin: true + + '@tanstack/history@1.161.6': + resolution: {integrity: sha512-NaOGLRrddszbQj9upGat6HG/4TKvXLvu+osAIgfxPYA+eIvYKv8GKDJOrY2D3/U9MRnKfMWD7bU4jeD4xmqyIg==} + engines: {node: '>=20.19'} + + '@tanstack/pacer@0.18.0': + resolution: {integrity: sha512-qhCRSFei0hokQr3xYcQXqxsRD/LKlgHCxHXtKHrQoImp4x2Zu6tUOpUGVH4y2qexIrzSu3aibQBNNfC3Eay6Mg==} + engines: {node: '>=18'} + + '@tanstack/query-core@5.96.1': + resolution: {integrity: sha512-u1yBgtavSy+N8wgtW3PiER6UpxcplMje65yXnnVgiHTqiMwLlxiw4WvQDrXyn+UD6lnn8kHaxmerJUzQcV/MMg==} + + '@tanstack/query-devtools@5.96.1': + resolution: {integrity: sha512-A4+uQTWbiqZDgrLeyjpFYLfMaWaKWpkwTkR1cUfocVj6vPYgym7QTG2se9A01WSxceDdmgxOqvn1ivcTvgWD8w==} + + '@tanstack/react-pacer@0.19.4': + resolution: {integrity: sha512-coj8ULAuR0qFpjAKD44gTgRuZyjxU6Xu+IX5MwwYvr4e61OtZcJshaExoOBKpCGde0Edb12jDnzzj2Im13Qm9Q==} + engines: {node: '>=18'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + + '@tanstack/react-query-devtools@5.96.1': + resolution: {integrity: sha512-3ZZ58fupIXtJFM0evj8YvWrauaZPUrQEqRYaq9e4ER/WPqTKeWEucqWCXn+KJLgWlcot5JIIUtQNynbovGjTTA==} + peerDependencies: + '@tanstack/react-query': ^5.96.1 + react: ^18 || ^19 + + '@tanstack/react-query@5.96.1': + resolution: {integrity: sha512-2X7KYK5KKWUKGeWCVcqxXAkYefJtrKB7tSKWgeG++b0H6BRHxQaLSSi8AxcgjmUnnosHuh9WsFZqvE16P1WCzA==} + peerDependencies: + react: ^18 || ^19 + + '@tanstack/react-router-devtools@1.166.11': + resolution: {integrity: sha512-WYR3q4Xui5yPT/5PXtQh8i03iUA7q8dONBjWpV3nsGdM8Cs1FxpfhLstW0wZO1dOvSyElscwTRCJ6nO5N8r3Lg==} + engines: {node: '>=20.19'} + peerDependencies: + '@tanstack/react-router': ^1.168.2 + '@tanstack/router-core': ^1.168.2 + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + peerDependenciesMeta: + '@tanstack/router-core': + optional: true + + '@tanstack/react-router@1.168.10': + resolution: {integrity: sha512-/RmDlOwDkCug609KdPB3U+U1zmrtadJpvsmRg2zEn8TRCKRNri7dYZIjQZbNg8PgUiRL4T6njrZBV1ChzblNaA==} + engines: {node: '>=20.19'} + peerDependencies: + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + + '@tanstack/react-store@0.8.1': + resolution: {integrity: sha512-XItJt+rG8c5Wn/2L/bnxys85rBpm0BfMbhb4zmPVLXAKY9POrp1xd6IbU4PKoOI+jSEGc3vntPRfLGSgXfE2Ig==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@tanstack/react-store@0.9.3': + resolution: {integrity: sha512-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@tanstack/react-table@8.21.3': + resolution: {integrity: sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==} + engines: {node: '>=12'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + + '@tanstack/router-core@1.168.9': + resolution: {integrity: sha512-18oeEwEDyXOIuO1VBP9ACaK7tYHZUjynGDCoUh/5c/BNhia9vCJCp9O0LfhZXOorDc/PmLSgvmweFhVmIxF10g==} + engines: {node: '>=20.19'} + hasBin: true + + '@tanstack/router-devtools-core@1.167.1': + resolution: {integrity: sha512-ECMM47J4KmifUvJguGituSiBpfN8SyCUEoxQks5RY09hpIBfR2eswCv2e6cJimjkKwBQXOVTPkTUk/yRvER+9w==} + engines: {node: '>=20.19'} + peerDependencies: + '@tanstack/router-core': ^1.168.2 + csstype: ^3.0.10 + peerDependenciesMeta: + csstype: + optional: true + + '@tanstack/router-generator@1.166.24': + resolution: {integrity: sha512-vdaGKwuH+r+DPe6R1mjk+TDDmDH6NTG7QqwxHqGEvOH4aGf9sPjhmRKNJZqQr8cPIbfp6u5lXyZ1TeDcSNMVEA==} + engines: {node: '>=20.19'} + + '@tanstack/router-plugin@1.167.12': + resolution: {integrity: sha512-StEHcctCuFI5taSjO+lhR/yQ+EK63BdyYa+ne6FoNQPB3MMrOUrz2ZVnbqILRLkh2b+p2EfBKt65sgAKdKygPQ==} + engines: {node: '>=20.19'} + hasBin: true + peerDependencies: + '@rsbuild/core': '>=1.0.2' + '@tanstack/react-router': ^1.168.10 + vite: '>=5.0.0 || >=6.0.0 || >=7.0.0' + vite-plugin-solid: ^2.11.10 + webpack: '>=5.92.0' + peerDependenciesMeta: + '@rsbuild/core': + optional: true + '@tanstack/react-router': + optional: true + vite: + optional: true + vite-plugin-solid: + optional: true + webpack: + optional: true + + '@tanstack/router-utils@1.161.6': + resolution: {integrity: sha512-nRcYw+w2OEgK6VfjirYvGyPLOK+tZQz1jkYcmH5AjMamQ9PycnlxZF2aEZtPpNoUsaceX2bHptn6Ub5hGXqNvw==} + engines: {node: '>=20.19'} + + '@tanstack/store@0.8.1': + resolution: {integrity: sha512-PtOisLjUZPz5VyPRSCGjNOlwTvabdTBQ2K80DpVL1chGVr35WRxfeavAPdNq6pm/t7F8GhoR2qtmkkqtCEtHYw==} + + '@tanstack/store@0.9.3': + resolution: {integrity: sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==} + + '@tanstack/table-core@8.21.3': + resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==} + engines: {node: '>=12'} + + '@tanstack/virtual-file-routes@1.161.7': + resolution: {integrity: sha512-olW33+Cn+bsCsZKPwEGhlkqS6w3M2slFv11JIobdnCFKMLG97oAI2kWKdx5/zsywTL8flpnoIgaZZPlQTFYhdQ==} + engines: {node: '>=20.19'} + hasBin: true + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + + '@types/d3-array@3.2.2': + resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-shape@3.1.8': + resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} + + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/node@25.5.0': + resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.14': + resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} + + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@typescript-eslint/eslint-plugin@8.58.0': + resolution: {integrity: sha512-RLkVSiNuUP1C2ROIWfqX+YcUfLaSnxGE/8M+Y57lopVwg9VTYYfhuz15Yf1IzCKgZj6/rIbYTmJCUSqr76r0Wg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.58.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/parser@8.58.0': + resolution: {integrity: sha512-rLoGZIf9afaRBYsPUMtvkDWykwXwUPL60HebR4JgTI8mxfFe2cQTu3AGitANp4b9B2QlVru6WzjgB2IzJKiCSA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/project-service@8.58.0': + resolution: {integrity: sha512-8Q/wBPWLQP1j16NxoPNIKpDZFMaxl7yWIoqXWYeWO+Bbd2mjgvoF0dxP2jKZg5+x49rgKdf7Ck473M8PC3V9lg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/scope-manager@8.58.0': + resolution: {integrity: sha512-W1Lur1oF50FxSnNdGp3Vs6P+yBRSmZiw4IIjEeYxd8UQJwhUF0gDgDD/W/Tgmh73mxgEU3qX0Bzdl/NGuSPEpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.58.0': + resolution: {integrity: sha512-doNSZEVJsWEu4htiVC+PR6NpM+pa+a4ClH9INRWOWCUzMst/VA9c4gXq92F8GUD1rwhNvRLkgjfYtFXegXQF7A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/type-utils@8.58.0': + resolution: {integrity: sha512-aGsCQImkDIqMyx1u4PrVlbi/krmDsQUs4zAcCV6M7yPcPev+RqVlndsJy9kJ8TLihW9TZ0kbDAzctpLn5o+lOg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/types@8.58.0': + resolution: {integrity: sha512-O9CjxypDT89fbHxRfETNoAnHj/i6IpRK0CvbVN3qibxlLdo5p5hcLmUuCCrHMpxiWSwKyI8mCP7qRNYuOJ0Uww==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.58.0': + resolution: {integrity: sha512-7vv5UWbHqew/dvs+D3e1RvLv1v2eeZ9txRHPnEEBUgSNLx5ghdzjHa0sgLWYVKssH+lYmV0JaWdoubo0ncGYLA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/utils@8.58.0': + resolution: {integrity: sha512-RfeSqcFeHMHlAWzt4TBjWOAtoW9lnsAGiP3GbaX9uVgTYYrMbVnGONEfUCiSss+xMHFl+eHZiipmA8WkQ7FuNA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/visitor-keys@8.58.0': + resolution: {integrity: sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + + '@vitejs/plugin-react-swc@4.3.0': + resolution: {integrity: sha512-mOkXCII839dHyAt/gpoSlm28JIVDwhZ6tnG6wJxUy2bmOx7UaPjvOyIDf3SFv5s7Eo7HVaq6kRcu6YMEzt5Z7w==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^4 || ^5 || ^6 || ^7 || ^8 + + '@xmldom/xmldom@0.8.12': + resolution: {integrity: sha512-9k/gHF6n/pAi/9tqr3m3aqkuiNosYTurLLUtc7xQ9sxB/wm7WPygCv8GYa6mS0fLJEHhqMC1ATYhz++U/lRHqg==} + engines: {node: '>=10.0.0'} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + + adler-32@1.3.1: + resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==} + engines: {node: '>=0.8'} + + ajv@6.14.0: + resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansis@4.2.0: + resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} + engines: {node: '>=14'} + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + + ast-types@0.16.1: + resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} + engines: {node: '>=4'} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + attr-accept@2.2.5: + resolution: {integrity: sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==} + engines: {node: '>=4'} + + autoprefixer@10.4.27: + resolution: {integrity: sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + axios@1.15.1: + resolution: {integrity: sha512-WOG+Jj8ZOvR0a3rAn+Tuf1UQJRxw5venr6DgdbJzngJE3qG7X0kL83CZGpdHMxEm+ZK3seAbvFsw4FfOfP9vxg==} + + babel-dead-code-elimination@1.0.12: + resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==} + + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + baseline-browser-mapping@2.10.13: + resolution: {integrity: sha512-BL2sTuHOdy0YT1lYieUxTw/QMtPBC3pmlJC6xk8BBYVv6vcw3SGdKemQ+Xsx9ik2F/lYDO9tqsFQH1r9PFuHKw==} + engines: {node: '>=6.0.0'} + hasBin: true + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + bluebird@3.4.7: + resolution: {integrity: sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==} + + brace-expansion@1.1.13: + resolution: {integrity: sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==} + + brace-expansion@5.0.5: + resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} + engines: {node: 18 || 20 || >=22} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + + caniuse-lite@1.0.30001784: + resolution: {integrity: sha512-WU346nBTklUV9YfUl60fqRbU5ZqyXlqvo1SgigE1OAXK5bFL8LL9q1K7aap3N739l4BvNqnkm3YrGHiY9sfUQw==} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + cfb@1.2.2: + resolution: {integrity: sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==} + engines: {node: '>=0.8'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + codepage@1.15.0: + resolution: {integrity: sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==} + engines: {node: '>=0.8'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie-es@2.0.1: + resolution: {integrity: sha512-aVf4A4hI2w70LnF7GG+7xDQUkliwiXWXFvTjkip4+b64ygDQ2sJPRSKFDHbxn8o0xu9QzPkMuuiWIXyFSE2slA==} + + copy-to-clipboard@3.3.3: + resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-format@3.1.2: + resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + date-fns-jalali@4.1.0-0: + resolution: {integrity: sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==} + + date-fns@4.1.0: + resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decimal.js-light@2.5.1: + resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} + + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + derive-zustand@0.2.0: + resolution: {integrity: sha512-ZCC9MuSOHVMglG7UgClRq7/BXsNjhvGSAly3XSBwGSaJbwt0WGEBZ8vn1ZD4MMXczq276dLU5HetqisQp5fFzw==} + peerDependencies: + zustand: '>=4.1.0' + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} + engines: {node: '>=0.3.1'} + + dingbat-to-unicode@1.0.1: + resolution: {integrity: sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w==} + + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + + dom-helpers@5.2.1: + resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + + duck@0.1.12: + resolution: {integrity: sha512-wkctla1O6VfP89gQ+J/yDesM0S7B7XLXjKGzXxMDVFg7uEn706niAtyYovKbyq1oT9YwDcly721/iUWoc8MVRg==} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + electron-to-chromium@1.5.331: + resolution: {integrity: sha512-IbxXrsTlD3hRodkLnbxAPP4OuJYdWCeM3IOdT+CpcMoIwIoDfCmRpEtSPfwBXxVkg9xmBeY7Lz2Eo2TDn/HC3Q==} + + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + eslint-plugin-react-hooks@7.0.1: + resolution: {integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + + eslint-plugin-react-refresh@0.4.26: + resolution: {integrity: sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==} + peerDependencies: + eslint: '>=8.40' + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@9.39.4: + resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-equals@5.4.0: + resolution: {integrity: sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==} + engines: {node: '>=6.0.0'} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + file-selector@2.1.2: + resolution: {integrity: sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==} + engines: {node: '>= 12'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} + + follow-redirects@1.15.11: + resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + + frac@1.1.2: + resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==} + engines: {node: '>=0.8'} + + fraction.js@5.3.4: + resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.13.7: + resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@16.5.0: + resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} + engines: {node: '>=18'} + + goober@2.1.18: + resolution: {integrity: sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw==} + peerDependencies: + csstype: ^3.0.10 + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hast-util-from-parse5@8.0.3: + resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} + + hast-util-is-element@3.0.0: + resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} + + hast-util-parse-selector@4.0.0: + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + + hast-util-raw@9.1.0: + resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} + + hast-util-to-jsx-runtime@2.3.6: + resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} + + hast-util-to-parse5@8.0.1: + resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} + + hast-util-to-text@4.0.2: + resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hastscript@9.0.1: + resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} + + hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + + hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + + highlight.js@11.11.1: + resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==} + engines: {node: '>=12.0.0'} + + html-url-attributes@3.0.1: + resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + + immer@11.1.4: + resolution: {integrity: sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw==} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + inline-style-parser@0.2.7: + resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} + + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isbot@5.1.37: + resolution: {integrity: sha512-5bcicX81xf6NlTEV8rWdg7Pk01LFizDetuYGHx6d/f6y3lR2/oo8IfxjzJqn1UdDEyCcwT9e7NRloj8DwCYujQ==} + engines: {node: '>=18'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jiti@1.21.7: + resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jszip@3.10.1: + resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lie@3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash@4.18.1: + resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lop@0.4.2: + resolution: {integrity: sha512-RefILVDQ4DKoRZsJ4Pj22TxE3omDO47yFpkIBoDKzkqPRISs5U1cnAdg/5583YPkWPaLIYHOKRMQSvjFsO26cw==} + + lowlight@3.3.0: + resolution: {integrity: sha512-0JNhgFoPvP6U6lE/UdVsSq99tn6DhjjpAj5MxG49ewd2mOBVtwWYIT8ClyABhq198aXXODMU6Ox8DrGy/CpTZQ==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lucide-react@0.562.0: + resolution: {integrity: sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + mammoth@1.12.0: + resolution: {integrity: sha512-cwnK1RIcRdDMi2HRx2EXGYlxqIEh0Oo3bLhorgnsVJi2UkbX1+jKxuBNR9PC5+JaX7EkmJxFPmo6mjLpqShI2w==} + engines: {node: '>=12.0.0'} + hasBin: true + + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.3: + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-mdx-expression@2.0.1: + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + + mdast-util-mdx-jsx@3.2.0: + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} + + mdast-util-mdxjs-esm@2.0.1: + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} + + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + nanoid@5.1.7: + resolution: {integrity: sha512-ua3NDgISf6jdwezAheMOk4mbE1LXjm1DfMUDMuJf4AqxLFK3ccGpgWizwa5YV7Yz9EpXwEaWoRXSb/BnV0t5dQ==} + engines: {node: ^18 || >=20} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + next-themes@0.4.6: + resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==} + peerDependencies: + react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + + node-releases@2.0.37: + resolution: {integrity: sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + + option@0.2.4: + resolution: {integrity: sha512-pkEqbDyl8ou5cpq+VsnQbe/WlEy5qS7xPzMS1U55OCG9KPvwFD46zDbxQIj3egJSFc3D+XhYOPUzz49zQAVy7A==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + postcss-import@15.1.0: + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + + postcss-js@4.1.0: + resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + + postcss-nested@6.2.0: + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.5.8: + resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier@3.8.1: + resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + engines: {node: '>=14'} + hasBin: true + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + property-information@7.1.0: + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + react-day-picker@9.14.0: + resolution: {integrity: sha512-tBaoDWjPwe0M5pGrum4H0SR6Lyk+BO9oHnp9JbKpGKW2mlraNPgP9BMfsg5pWpwrssARmeqk7YBl2oXutZTaHA==} + engines: {node: '>=18'} + peerDependencies: + react: '>=16.8.0' + + react-dom@19.2.4: + resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} + peerDependencies: + react: ^19.2.4 + + react-dropzone@14.4.1: + resolution: {integrity: sha512-QDuV76v3uKbHiH34SpwifZ+gOLi1+RdsCO1kl5vxMT4wW8R82+sthjvBw4th3NHF/XX6FBsqDYZVNN+pnhaw0g==} + engines: {node: '>= 10.13'} + peerDependencies: + react: '>= 16.8 || 18.0.0' + + react-hook-form@7.72.0: + resolution: {integrity: sha512-V4v6jubaf6JAurEaVnT9aUPKFbNtDgohj5CIgVGyPHvT9wRx5OZHVjz31GsxnPNI278XMu+ruFz+wGOscHaLKw==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 || ^19 + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + react-markdown@10.1.0: + resolution: {integrity: sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==} + peerDependencies: + '@types/react': '>=18' + react: '>=18' + + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.2: + resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-smooth@4.0.4: + resolution: {integrity: sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-transition-group@4.4.5: + resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} + peerDependencies: + react: '>=16.6.0' + react-dom: '>=16.6.0' + + react@19.2.4: + resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} + engines: {node: '>=0.10.0'} + + read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + recast@0.23.11: + resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} + engines: {node: '>= 4'} + + recharts-scale@0.4.5: + resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==} + + recharts@2.15.4: + resolution: {integrity: sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==} + engines: {node: '>=14'} + peerDependencies: + react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + rehype-highlight@7.0.2: + resolution: {integrity: sha512-k158pK7wdC2qL3M5NcZROZ2tR/l7zOzjxXd5VGdcfIyoijjQqpHd3JKtYSBDpDZ38UI2WJWuFAtkMDxmx5kstA==} + + rehype-raw@7.0.0: + resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rolldown-vite@7.3.1: + resolution: {integrity: sha512-LYzdNAjRHhF2yA4JUQm/QyARyi216N2rpJ0lJZb8E9FU2y5v6Vk+xq/U4XBOxMefpWixT5H3TslmAHm1rqIq2w==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + esbuild: ^0.27.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + rolldown@1.0.0-beta.53: + resolution: {integrity: sha512-Qd9c2p0XKZdgT5AYd+KgAMggJ8ZmCs3JnS9PTMWkyUfteKlfmKtxJbWTHkVakxwXs1Ub7jrRYVeFeF7N0sQxyw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + + seroval-plugins@1.5.1: + resolution: {integrity: sha512-4FbuZ/TMl02sqv0RTFexu0SP6V+ywaIe5bAWCCEik0fk17BhALgwvUDVF7e3Uvf9pxmwCEJsRPmlkUE6HdzLAw==} + engines: {node: '>=10'} + peerDependencies: + seroval: ^1.0 + + seroval@1.5.1: + resolution: {integrity: sha512-OwrZRZAfhHww0WEnKHDY8OM0U/Qs8OTfIDWhUD4BLpNJUfXK4cGmjiagGze086m+mhI+V2nD0gfbHEnJjb9STA==} + engines: {node: '>=10'} + + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + sonner@2.0.7: + resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + ssf@0.11.2: + resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==} + engines: {node: '>=0.8'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + style-to-js@1.1.21: + resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} + + style-to-object@1.0.14: + resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + tailwind-merge@3.5.0: + resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==} + + tailwindcss-animate@1.0.7: + resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + + tailwindcss@3.4.19: + resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==} + engines: {node: '>=14.0.0'} + hasBin: true + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toggle-selection@1.0.6: + resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} + + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tsx@4.21.0: + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} + engines: {node: '>=18.0.0'} + hasBin: true + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + typescript-eslint@8.58.0: + resolution: {integrity: sha512-e2TQzKfaI85fO+F3QywtX+tCTsu/D3WW5LVU6nz8hTFKFZ8yBJ6mSYRpXqdR3mFjPWmO0eWsTa5f+UpAOe/FMA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + underscore@1.13.8: + resolution: {integrity: sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==} + + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unist-util-find-after@5.0.0: + resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + + unplugin@2.3.11: + resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} + engines: {node: '>=18.12.0'} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + vaul@1.1.2: + resolution: {integrity: sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + + vfile-location@5.0.3: + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + victory-vendor@36.9.2: + resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==} + + web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wmf@1.0.2: + resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==} + engines: {node: '>=0.8'} + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + word@0.3.0: + resolution: {integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==} + engines: {node: '>=0.8'} + + xlsx@0.18.5: + resolution: {integrity: sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==} + engines: {node: '>=0.8'} + hasBin: true + + xmlbuilder@10.1.1: + resolution: {integrity: sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg==} + engines: {node: '>=4.0'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zod-validation-error@4.0.2: + resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + + zod@4.3.6: + resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + + zustand@5.0.12: + resolution: {integrity: sha512-i77ae3aZq4dhMlRhJVCYgMLKuSiZAaUPAct2AksxQ+gOtimhGMdXljRT21P5BNpeT4kXlLIckvkPM029OljD7g==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@alloc/quick-lru@5.2.0': {} + + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.0': {} + + '@babel/core@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.29.2 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.28.6': + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.28.6': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.28.6': {} + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.29.2': + dependencies: + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + + '@babel/parser@7.29.2': + dependencies: + '@babel/types': 7.29.0 + + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/runtime@7.29.2': {} + + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@date-fns/tz@1.4.1': {} + + '@emnapi/core@1.9.2': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.9.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.27.7': + optional: true + + '@esbuild/android-arm64@0.27.7': + optional: true + + '@esbuild/android-arm@0.27.7': + optional: true + + '@esbuild/android-x64@0.27.7': + optional: true + + '@esbuild/darwin-arm64@0.27.7': + optional: true + + '@esbuild/darwin-x64@0.27.7': + optional: true + + '@esbuild/freebsd-arm64@0.27.7': + optional: true + + '@esbuild/freebsd-x64@0.27.7': + optional: true + + '@esbuild/linux-arm64@0.27.7': + optional: true + + '@esbuild/linux-arm@0.27.7': + optional: true + + '@esbuild/linux-ia32@0.27.7': + optional: true + + '@esbuild/linux-loong64@0.27.7': + optional: true + + '@esbuild/linux-mips64el@0.27.7': + optional: true + + '@esbuild/linux-ppc64@0.27.7': + optional: true + + '@esbuild/linux-riscv64@0.27.7': + optional: true + + '@esbuild/linux-s390x@0.27.7': + optional: true + + '@esbuild/linux-x64@0.27.7': + optional: true + + '@esbuild/netbsd-arm64@0.27.7': + optional: true + + '@esbuild/netbsd-x64@0.27.7': + optional: true + + '@esbuild/openbsd-arm64@0.27.7': + optional: true + + '@esbuild/openbsd-x64@0.27.7': + optional: true + + '@esbuild/openharmony-arm64@0.27.7': + optional: true + + '@esbuild/sunos-x64@0.27.7': + optional: true + + '@esbuild/win32-arm64@0.27.7': + optional: true + + '@esbuild/win32-ia32@0.27.7': + optional: true + + '@esbuild/win32-x64@0.27.7': + optional: true + + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@1.21.7))': + dependencies: + eslint: 9.39.4(jiti@1.21.7) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.21.2': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.5 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.5': + dependencies: + ajv: 6.14.0 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.5 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.4': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + + '@floating-ui/core@1.7.5': + dependencies: + '@floating-ui/utils': 0.2.11 + + '@floating-ui/dom@1.7.6': + dependencies: + '@floating-ui/core': 1.7.5 + '@floating-ui/utils': 0.2.11 + + '@floating-ui/react-dom@2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@floating-ui/dom': 1.7.6 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@floating-ui/utils@0.2.11': {} + + '@hookform/resolvers@5.2.2(react-hook-form@7.72.0(react@19.2.4))': + dependencies: + '@standard-schema/utils': 0.3.0 + react-hook-form: 7.72.0(react@19.2.4) + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@napi-rs/wasm-runtime@1.1.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': + dependencies: + '@emnapi/core': 1.9.2 + '@emnapi/runtime': 1.9.2 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + + '@oxc-project/runtime@0.101.0': {} + + '@oxc-project/types@0.101.0': {} + + '@radix-ui/number@1.1.1': {} + + '@radix-ui/primitive@1.1.3': {} + + '@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-avatar@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-context': 1.1.3(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-context@1.1.2(@types/react@19.2.14)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-context@1.1.3(@types/react@19.2.14)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) + aria-hidden: 1.2.6 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-direction@1.1.1(@types/react@19.2.14)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.14)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-id@1.1.1(@types/react@19.2.14)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-label@2.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) + aria-hidden: 1.2.6 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) + aria-hidden: 1.2.6 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/rect': 1.1.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-slot': 1.2.4(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-progress@1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-context': 1.1.3(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-radio-group@1.3.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-select@2.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + aria-hidden: 1.2.6 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-separator@1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-slot@1.2.3(@types/react@19.2.14)(react@19.2.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-slot@1.2.4(@types/react@19.2.14)(react@19.2.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-switch@1.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-toggle-group@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-toggle': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-toggle@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.14)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.14)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.14)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.14)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@19.2.14)(react@19.2.4)': + dependencies: + react: 19.2.4 + use-sync-external-store: 1.6.0(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.14)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.14)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.14)(react@19.2.4)': + dependencies: + '@radix-ui/rect': 1.1.1 + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-use-size@1.1.1(@types/react@19.2.14)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/rect@1.1.1': {} + + '@rolldown/binding-android-arm64@1.0.0-beta.53': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.0-beta.53': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-beta.53': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.0-beta.53': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.53': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.53': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.53': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.53': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-beta.53': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-beta.53': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-beta.53(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': + dependencies: + '@napi-rs/wasm-runtime': 1.1.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.53': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.53': + optional: true + + '@rolldown/pluginutils@1.0.0-beta.53': {} + + '@rolldown/pluginutils@1.0.0-rc.7': {} + + '@standard-schema/utils@0.3.0': {} + + '@swc/core-darwin-arm64@1.15.21': + optional: true + + '@swc/core-darwin-x64@1.15.21': + optional: true + + '@swc/core-linux-arm-gnueabihf@1.15.21': + optional: true + + '@swc/core-linux-arm64-gnu@1.15.21': + optional: true + + '@swc/core-linux-arm64-musl@1.15.21': + optional: true + + '@swc/core-linux-ppc64-gnu@1.15.21': + optional: true + + '@swc/core-linux-s390x-gnu@1.15.21': + optional: true + + '@swc/core-linux-x64-gnu@1.15.21': + optional: true + + '@swc/core-linux-x64-musl@1.15.21': + optional: true + + '@swc/core-win32-arm64-msvc@1.15.21': + optional: true + + '@swc/core-win32-ia32-msvc@1.15.21': + optional: true + + '@swc/core-win32-x64-msvc@1.15.21': + optional: true + + '@swc/core@1.15.21': + dependencies: + '@swc/counter': 0.1.3 + '@swc/types': 0.1.26 + optionalDependencies: + '@swc/core-darwin-arm64': 1.15.21 + '@swc/core-darwin-x64': 1.15.21 + '@swc/core-linux-arm-gnueabihf': 1.15.21 + '@swc/core-linux-arm64-gnu': 1.15.21 + '@swc/core-linux-arm64-musl': 1.15.21 + '@swc/core-linux-ppc64-gnu': 1.15.21 + '@swc/core-linux-s390x-gnu': 1.15.21 + '@swc/core-linux-x64-gnu': 1.15.21 + '@swc/core-linux-x64-musl': 1.15.21 + '@swc/core-win32-arm64-msvc': 1.15.21 + '@swc/core-win32-ia32-msvc': 1.15.21 + '@swc/core-win32-x64-msvc': 1.15.21 + + '@swc/counter@0.1.3': {} + + '@swc/types@0.1.26': + dependencies: + '@swc/counter': 0.1.3 + + '@tabby_ai/hijri-converter@1.0.5': {} + + '@tanstack/devtools-event-client@0.4.3': {} + + '@tanstack/history@1.161.6': {} + + '@tanstack/pacer@0.18.0': + dependencies: + '@tanstack/devtools-event-client': 0.4.3 + '@tanstack/store': 0.8.1 + + '@tanstack/query-core@5.96.1': {} + + '@tanstack/query-devtools@5.96.1': {} + + '@tanstack/react-pacer@0.19.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/pacer': 0.18.0 + '@tanstack/react-store': 0.8.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@tanstack/react-query-devtools@5.96.1(@tanstack/react-query@5.96.1(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/query-devtools': 5.96.1 + '@tanstack/react-query': 5.96.1(react@19.2.4) + react: 19.2.4 + + '@tanstack/react-query@5.96.1(react@19.2.4)': + dependencies: + '@tanstack/query-core': 5.96.1 + react: 19.2.4 + + '@tanstack/react-router-devtools@1.166.11(@tanstack/react-router@1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.168.9)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/react-router': 1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-devtools-core': 1.167.1(@tanstack/router-core@1.168.9)(csstype@3.2.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@tanstack/router-core': 1.168.9 + transitivePeerDependencies: + - csstype + + '@tanstack/react-router@1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/history': 1.161.6 + '@tanstack/react-store': 0.9.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-core': 1.168.9 + isbot: 5.1.37 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@tanstack/react-store@0.8.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/store': 0.8.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + use-sync-external-store: 1.6.0(react@19.2.4) + + '@tanstack/react-store@0.9.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/store': 0.9.3 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + use-sync-external-store: 1.6.0(react@19.2.4) + + '@tanstack/react-table@8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/table-core': 8.21.3 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@tanstack/router-core@1.168.9': + dependencies: + '@tanstack/history': 1.161.6 + cookie-es: 2.0.1 + seroval: 1.5.1 + seroval-plugins: 1.5.1(seroval@1.5.1) + + '@tanstack/router-devtools-core@1.167.1(@tanstack/router-core@1.168.9)(csstype@3.2.3)': + dependencies: + '@tanstack/router-core': 1.168.9 + clsx: 2.1.1 + goober: 2.1.18(csstype@3.2.3) + optionalDependencies: + csstype: 3.2.3 + + '@tanstack/router-generator@1.166.24': + dependencies: + '@tanstack/router-core': 1.168.9 + '@tanstack/router-utils': 1.161.6 + '@tanstack/virtual-file-routes': 1.161.7 + prettier: 3.8.1 + recast: 0.23.11 + source-map: 0.7.6 + tsx: 4.21.0 + zod: 3.25.76 + transitivePeerDependencies: + - supports-color + + '@tanstack/router-plugin@1.167.12(@tanstack/react-router@1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(rolldown-vite@7.3.1(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@25.5.0)(esbuild@0.27.7)(jiti@1.21.7)(tsx@4.21.0))': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@tanstack/router-core': 1.168.9 + '@tanstack/router-generator': 1.166.24 + '@tanstack/router-utils': 1.161.6 + '@tanstack/virtual-file-routes': 1.161.7 + chokidar: 3.6.0 + unplugin: 2.3.11 + zod: 3.25.76 + optionalDependencies: + '@tanstack/react-router': 1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + vite: rolldown-vite@7.3.1(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@25.5.0)(esbuild@0.27.7)(jiti@1.21.7)(tsx@4.21.0) + transitivePeerDependencies: + - supports-color + + '@tanstack/router-utils@1.161.6': + dependencies: + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + ansis: 4.2.0 + babel-dead-code-elimination: 1.0.12 + diff: 8.0.4 + pathe: 2.0.3 + tinyglobby: 0.2.15 + transitivePeerDependencies: + - supports-color + + '@tanstack/store@0.8.1': {} + + '@tanstack/store@0.9.3': {} + + '@tanstack/table-core@8.21.3': {} + + '@tanstack/virtual-file-routes@1.161.7': {} + + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/d3-array@3.2.2': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-shape@3.1.8': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + + '@types/debug@4.1.13': + dependencies: + '@types/ms': 2.1.0 + + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.8 + + '@types/estree@1.0.8': {} + + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/json-schema@7.0.15': {} + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/ms@2.1.0': {} + + '@types/node@25.5.0': + dependencies: + undici-types: 7.18.2 + + '@types/react-dom@19.2.3(@types/react@19.2.14)': + dependencies: + '@types/react': 19.2.14 + + '@types/react@19.2.14': + dependencies: + csstype: 3.2.3 + + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + + '@typescript-eslint/eslint-plugin@8.58.0(@typescript-eslint/parser@8.58.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.58.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.58.0 + '@typescript-eslint/type-utils': 8.58.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/utils': 8.58.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.58.0 + eslint: 9.39.4(jiti@1.21.7) + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.58.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.58.0 + '@typescript-eslint/types': 8.58.0 + '@typescript-eslint/typescript-estree': 8.58.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.58.0 + debug: 4.4.3 + eslint: 9.39.4(jiti@1.21.7) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.58.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.58.0(typescript@5.9.3) + '@typescript-eslint/types': 8.58.0 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.58.0': + dependencies: + '@typescript-eslint/types': 8.58.0 + '@typescript-eslint/visitor-keys': 8.58.0 + + '@typescript-eslint/tsconfig-utils@8.58.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/type-utils@8.58.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.58.0 + '@typescript-eslint/typescript-estree': 8.58.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.58.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) + debug: 4.4.3 + eslint: 9.39.4(jiti@1.21.7) + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.58.0': {} + + '@typescript-eslint/typescript-estree@8.58.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.58.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.58.0(typescript@5.9.3) + '@typescript-eslint/types': 8.58.0 + '@typescript-eslint/visitor-keys': 8.58.0 + debug: 4.4.3 + minimatch: 10.2.5 + semver: 7.7.4 + tinyglobby: 0.2.15 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.58.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@1.21.7)) + '@typescript-eslint/scope-manager': 8.58.0 + '@typescript-eslint/types': 8.58.0 + '@typescript-eslint/typescript-estree': 8.58.0(typescript@5.9.3) + eslint: 9.39.4(jiti@1.21.7) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.58.0': + dependencies: + '@typescript-eslint/types': 8.58.0 + eslint-visitor-keys: 5.0.1 + + '@ungap/structured-clone@1.3.0': {} + + '@vitejs/plugin-react-swc@4.3.0(rolldown-vite@7.3.1(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@25.5.0)(esbuild@0.27.7)(jiti@1.21.7)(tsx@4.21.0))': + dependencies: + '@rolldown/pluginutils': 1.0.0-rc.7 + '@swc/core': 1.15.21 + vite: rolldown-vite@7.3.1(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@25.5.0)(esbuild@0.27.7)(jiti@1.21.7)(tsx@4.21.0) + transitivePeerDependencies: + - '@swc/helpers' + + '@xmldom/xmldom@0.8.12': {} + + acorn-jsx@5.3.2(acorn@8.16.0): + dependencies: + acorn: 8.16.0 + + acorn@8.16.0: {} + + adler-32@1.3.1: {} + + ajv@6.14.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansis@4.2.0: {} + + any-promise@1.3.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.2 + + arg@5.0.2: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + + ast-types@0.16.1: + dependencies: + tslib: 2.8.1 + + asynckit@0.4.0: {} + + attr-accept@2.2.5: {} + + autoprefixer@10.4.27(postcss@8.5.8): + dependencies: + browserslist: 4.28.2 + caniuse-lite: 1.0.30001784 + fraction.js: 5.3.4 + picocolors: 1.1.1 + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + axios@1.15.1: + dependencies: + follow-redirects: 1.15.11 + form-data: 4.0.5 + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + + babel-dead-code-elimination@1.0.12: + dependencies: + '@babel/core': 7.29.0 + '@babel/parser': 7.29.2 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + bail@2.0.2: {} + + balanced-match@1.0.2: {} + + balanced-match@4.0.4: {} + + base64-js@1.5.1: {} + + baseline-browser-mapping@2.10.13: {} + + binary-extensions@2.3.0: {} + + bluebird@3.4.7: {} + + brace-expansion@1.1.13: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@5.0.5: + dependencies: + balanced-match: 4.0.4 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.28.2: + dependencies: + baseline-browser-mapping: 2.10.13 + caniuse-lite: 1.0.30001784 + electron-to-chromium: 1.5.331 + node-releases: 2.0.37 + update-browserslist-db: 1.2.3(browserslist@4.28.2) + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + callsites@3.1.0: {} + + camelcase-css@2.0.1: {} + + caniuse-lite@1.0.30001784: {} + + ccount@2.0.1: {} + + cfb@1.2.2: + dependencies: + adler-32: 1.3.1 + crc-32: 1.2.2 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + + clsx@2.1.1: {} + + codepage@1.15.0: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + comma-separated-tokens@2.0.3: {} + + commander@4.1.1: {} + + concat-map@0.0.1: {} + + convert-source-map@2.0.0: {} + + cookie-es@2.0.1: {} + + copy-to-clipboard@3.3.3: + dependencies: + toggle-selection: 1.0.6 + + core-util-is@1.0.3: {} + + crc-32@1.2.2: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + cssesc@3.0.0: {} + + csstype@3.2.3: {} + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-color@3.1.0: {} + + d3-ease@3.0.1: {} + + d3-format@3.1.2: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@3.1.0: {} + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.2 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + date-fns-jalali@4.1.0-0: {} + + date-fns@4.1.0: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decimal.js-light@2.5.1: {} + + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + + deep-is@0.1.4: {} + + delayed-stream@1.0.0: {} + + dequal@2.0.3: {} + + derive-zustand@0.2.0(zustand@5.0.12(@types/react@19.2.14)(immer@11.1.4)(react@19.2.4)(use-sync-external-store@1.6.0(react@19.2.4))): + dependencies: + zustand: 5.0.12(@types/react@19.2.14)(immer@11.1.4)(react@19.2.4)(use-sync-external-store@1.6.0(react@19.2.4)) + + detect-libc@2.1.2: {} + + detect-node-es@1.1.0: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + didyoumean@1.2.2: {} + + diff@8.0.4: {} + + dingbat-to-unicode@1.0.1: {} + + dlv@1.1.3: {} + + dom-helpers@5.2.1: + dependencies: + '@babel/runtime': 7.29.2 + csstype: 3.2.3 + + duck@0.1.12: + dependencies: + underscore: 1.13.8 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + electron-to-chromium@1.5.331: {} + + entities@6.0.1: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + esbuild@0.27.7: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + + escalade@3.2.0: {} + + escape-string-regexp@4.0.0: {} + + escape-string-regexp@5.0.0: {} + + eslint-plugin-react-hooks@7.0.1(eslint@9.39.4(jiti@1.21.7)): + dependencies: + '@babel/core': 7.29.0 + '@babel/parser': 7.29.2 + eslint: 9.39.4(jiti@1.21.7) + hermes-parser: 0.25.1 + zod: 4.3.6 + zod-validation-error: 4.0.2(zod@4.3.6) + transitivePeerDependencies: + - supports-color + + eslint-plugin-react-refresh@0.4.26(eslint@9.39.4(jiti@1.21.7)): + dependencies: + eslint: 9.39.4(jiti@1.21.7) + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint-visitor-keys@5.0.1: {} + + eslint@9.39.4(jiti@1.21.7): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@1.21.7)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.2 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.5 + '@eslint/js': 9.39.4 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.14.0 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 1.21.7 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) + eslint-visitor-keys: 4.2.1 + + esprima@4.0.1: {} + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-util-is-identifier-name@3.0.0: {} + + esutils@2.0.3: {} + + eventemitter3@4.0.7: {} + + extend@3.0.2: {} + + fast-deep-equal@3.1.3: {} + + fast-equals@5.4.0: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + file-selector@2.1.2: + dependencies: + tslib: 2.8.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.4.2 + keyv: 4.5.4 + + flatted@3.4.2: {} + + follow-redirects@1.15.11: {} + + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + frac@1.1.2: {} + + fraction.js@5.3.4: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gensync@1.0.0-beta.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-nonce@1.0.1: {} + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-tsconfig@4.13.7: + dependencies: + resolve-pkg-maps: 1.0.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@14.0.0: {} + + globals@16.5.0: {} + + goober@2.1.18(csstype@3.2.3): + dependencies: + csstype: 3.2.3 + + gopd@1.2.0: {} + + has-flag@4.0.0: {} + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hast-util-from-parse5@8.0.3: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + devlop: 1.1.0 + hastscript: 9.0.1 + property-information: 7.1.0 + vfile: 6.0.3 + vfile-location: 5.0.3 + web-namespaces: 2.0.1 + + hast-util-is-element@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-parse-selector@4.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-raw@9.1.0: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + '@ungap/structured-clone': 1.3.0 + hast-util-from-parse5: 8.0.3 + hast-util-to-parse5: 8.0.1 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + parse5: 7.3.0 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-to-jsx-runtime@2.3.6: + dependencies: + '@types/estree': 1.0.8 + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + hast-util-to-parse5@8.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-to-text@4.0.2: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + hast-util-is-element: 3.0.0 + unist-util-find-after: 5.0.0 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hastscript@9.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + + hermes-estree@0.25.1: {} + + hermes-parser@0.25.1: + dependencies: + hermes-estree: 0.25.1 + + highlight.js@11.11.1: {} + + html-url-attributes@3.0.1: {} + + html-void-elements@3.0.0: {} + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + immediate@3.0.6: {} + + immer@11.1.4: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + inherits@2.0.4: {} + + inline-style-parser@0.2.7: {} + + internmap@2.0.3: {} + + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-decimal@2.0.1: {} + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-hexadecimal@2.0.1: {} + + is-number@7.0.0: {} + + is-plain-obj@4.1.0: {} + + isarray@1.0.0: {} + + isbot@5.1.37: {} + + isexe@2.0.0: {} + + jiti@1.21.7: {} + + js-tokens@4.0.0: {} + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@2.2.3: {} + + jszip@3.10.1: + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lie@3.3.0: + dependencies: + immediate: 3.0.6 + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + lilconfig@3.1.3: {} + + lines-and-columns@1.2.4: {} + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + lodash@4.18.1: {} + + longest-streak@3.1.0: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lop@0.4.2: + dependencies: + duck: 0.1.12 + option: 0.2.4 + underscore: 1.13.8 + + lowlight@3.3.0: + dependencies: + '@types/hast': 3.0.4 + devlop: 1.1.0 + highlight.js: 11.11.1 + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lucide-react@0.562.0(react@19.2.4): + dependencies: + react: 19.2.4 + + mammoth@1.12.0: + dependencies: + '@xmldom/xmldom': 0.8.12 + argparse: 1.0.10 + base64-js: 1.5.1 + bluebird: 3.4.7 + dingbat-to-unicode: 1.0.1 + jszip: 3.10.1 + lop: 0.4.2 + path-is-absolute: 1.0.1 + underscore: 1.13.8 + xmlbuilder: 10.1.1 + + markdown-table@3.0.4: {} + + math-intrinsics@1.1.0: {} + + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + mdast-util-from-markdown@2.0.3: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.3 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-expression@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.2.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + mdast-util-mdxjs-esm@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + merge2@1.4.1: {} + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.3.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.13 + debug: 4.4.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.2 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.5 + + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.13 + + ms@2.1.3: {} + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + nanoid@3.3.11: {} + + nanoid@5.1.7: {} + + natural-compare@1.4.0: {} + + next-themes@0.4.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + node-releases@2.0.37: {} + + normalize-path@3.0.0: {} + + object-assign@4.1.1: {} + + object-hash@3.0.0: {} + + option@0.2.4: {} + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + pako@1.0.11: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.3.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + + parse5@7.3.0: + dependencies: + entities: 6.0.1 + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + pathe@2.0.3: {} + + picocolors@1.1.1: {} + + picomatch@2.3.2: {} + + picomatch@4.0.4: {} + + pify@2.3.0: {} + + pirates@4.0.7: {} + + postcss-import@15.1.0(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.11 + + postcss-js@4.1.0(postcss@8.5.8): + dependencies: + camelcase-css: 2.0.1 + postcss: 8.5.8 + + postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.8)(tsx@4.21.0): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + jiti: 1.21.7 + postcss: 8.5.8 + tsx: 4.21.0 + + postcss-nested@6.2.0(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-selector-parser: 6.1.2 + + postcss-selector-parser@6.1.2: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-value-parser@4.2.0: {} + + postcss@8.5.8: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prettier@3.8.1: {} + + process-nextick-args@2.0.1: {} + + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + property-information@7.1.0: {} + + proxy-from-env@2.1.0: {} + + punycode@2.3.1: {} + + queue-microtask@1.2.3: {} + + react-day-picker@9.14.0(react@19.2.4): + dependencies: + '@date-fns/tz': 1.4.1 + '@tabby_ai/hijri-converter': 1.0.5 + date-fns: 4.1.0 + date-fns-jalali: 4.1.0-0 + react: 19.2.4 + + react-dom@19.2.4(react@19.2.4): + dependencies: + react: 19.2.4 + scheduler: 0.27.0 + + react-dropzone@14.4.1(react@19.2.4): + dependencies: + attr-accept: 2.2.5 + file-selector: 2.1.2 + prop-types: 15.8.1 + react: 19.2.4 + + react-hook-form@7.72.0(react@19.2.4): + dependencies: + react: 19.2.4 + + react-is@16.13.1: {} + + react-is@18.3.1: {} + + react-markdown@10.1.0(@types/react@19.2.14)(react@19.2.4): + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/react': 19.2.14 + devlop: 1.1.0 + hast-util-to-jsx-runtime: 2.3.6 + html-url-attributes: 3.0.1 + mdast-util-to-hast: 13.2.1 + react: 19.2.4 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + unified: 11.0.5 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + react-remove-scroll-bar@2.3.8(@types/react@19.2.14)(react@19.2.4): + dependencies: + react: 19.2.4 + react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.4) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.14 + + react-remove-scroll@2.7.2(@types/react@19.2.14)(react@19.2.4): + dependencies: + react: 19.2.4 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.14)(react@19.2.4) + react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.4) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.2.14)(react@19.2.4) + use-sidecar: 1.1.3(@types/react@19.2.14)(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + + react-smooth@4.0.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + fast-equals: 5.4.0 + prop-types: 15.8.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-transition-group: 4.4.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + + react-style-singleton@2.2.3(@types/react@19.2.14)(react@19.2.4): + dependencies: + get-nonce: 1.0.1 + react: 19.2.4 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.14 + + react-transition-group@4.4.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + '@babel/runtime': 7.29.2 + dom-helpers: 5.2.1 + loose-envify: 1.4.0 + prop-types: 15.8.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + react@19.2.4: {} + + read-cache@1.0.0: + dependencies: + pify: 2.3.0 + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.2 + + recast@0.23.11: + dependencies: + ast-types: 0.16.1 + esprima: 4.0.1 + source-map: 0.6.1 + tiny-invariant: 1.3.3 + tslib: 2.8.1 + + recharts-scale@0.4.5: + dependencies: + decimal.js-light: 2.5.1 + + recharts@2.15.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + clsx: 2.1.1 + eventemitter3: 4.0.7 + lodash: 4.18.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-is: 18.3.1 + react-smooth: 4.0.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + recharts-scale: 0.4.5 + tiny-invariant: 1.3.3 + victory-vendor: 36.9.2 + + rehype-highlight@7.0.2: + dependencies: + '@types/hast': 3.0.4 + hast-util-to-text: 4.0.2 + lowlight: 3.3.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + + rehype-raw@7.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-raw: 9.1.0 + vfile: 6.0.3 + + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.1 + unified: 11.0.5 + vfile: 6.0.3 + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + + resolve-from@4.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.1.0: {} + + rolldown-vite@7.3.1(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@25.5.0)(esbuild@0.27.7)(jiti@1.21.7)(tsx@4.21.0): + dependencies: + '@oxc-project/runtime': 0.101.0 + fdir: 6.5.0(picomatch@4.0.4) + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.8 + rolldown: 1.0.0-beta.53(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 25.5.0 + esbuild: 0.27.7 + fsevents: 2.3.3 + jiti: 1.21.7 + tsx: 4.21.0 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + + rolldown@1.0.0-beta.53(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2): + dependencies: + '@oxc-project/types': 0.101.0 + '@rolldown/pluginutils': 1.0.0-beta.53 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-beta.53 + '@rolldown/binding-darwin-arm64': 1.0.0-beta.53 + '@rolldown/binding-darwin-x64': 1.0.0-beta.53 + '@rolldown/binding-freebsd-x64': 1.0.0-beta.53 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.53 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.53 + '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.53 + '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.53 + '@rolldown/binding-linux-x64-musl': 1.0.0-beta.53 + '@rolldown/binding-openharmony-arm64': 1.0.0-beta.53 + '@rolldown/binding-wasm32-wasi': 1.0.0-beta.53(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.53 + '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.53 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-buffer@5.1.2: {} + + scheduler@0.27.0: {} + + semver@6.3.1: {} + + semver@7.7.4: {} + + seroval-plugins@1.5.1(seroval@1.5.1): + dependencies: + seroval: 1.5.1 + + seroval@1.5.1: {} + + setimmediate@1.0.5: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + sonner@2.0.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + source-map-js@1.2.1: {} + + source-map@0.6.1: {} + + source-map@0.7.6: {} + + space-separated-tokens@2.0.2: {} + + sprintf-js@1.0.3: {} + + ssf@0.11.2: + dependencies: + frac: 1.1.2 + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + strip-json-comments@3.1.1: {} + + style-to-js@1.1.21: + dependencies: + style-to-object: 1.0.14 + + style-to-object@1.0.14: + dependencies: + inline-style-parser: 0.2.7 + + sucrase@3.35.1: + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + commander: 4.1.1 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.7 + tinyglobby: 0.2.15 + ts-interface-checker: 0.1.13 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + tailwind-merge@3.5.0: {} + + tailwindcss-animate@1.0.7(tailwindcss@3.4.19(tsx@4.21.0)): + dependencies: + tailwindcss: 3.4.19(tsx@4.21.0) + + tailwindcss@3.4.19(tsx@4.21.0): + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.3 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.7 + lilconfig: 3.1.3 + micromatch: 4.0.8 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.1.1 + postcss: 8.5.8 + postcss-import: 15.1.0(postcss@8.5.8) + postcss-js: 4.1.0(postcss@8.5.8) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.8)(tsx@4.21.0) + postcss-nested: 6.2.0(postcss@8.5.8) + postcss-selector-parser: 6.1.2 + resolve: 1.22.11 + sucrase: 3.35.1 + transitivePeerDependencies: + - tsx + - yaml + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + tiny-invariant@1.3.3: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + toggle-selection@1.0.6: {} + + trim-lines@3.0.1: {} + + trough@2.2.0: {} + + ts-api-utils@2.5.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + ts-interface-checker@0.1.13: {} + + tslib@2.8.1: {} + + tsx@4.21.0: + dependencies: + esbuild: 0.27.7 + get-tsconfig: 4.13.7 + optionalDependencies: + fsevents: 2.3.3 + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typescript-eslint@8.58.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.58.0(@typescript-eslint/parser@8.58.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/parser': 8.58.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.58.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.58.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) + eslint: 9.39.4(jiti@1.21.7) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + typescript@5.9.3: {} + + underscore@1.13.8: {} + + undici-types@7.18.2: {} + + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unist-util-find-after@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + unplugin@2.3.11: + dependencies: + '@jridgewell/remapping': 2.3.5 + acorn: 8.16.0 + picomatch: 4.0.4 + webpack-virtual-modules: 0.6.2 + + update-browserslist-db@1.2.3(browserslist@4.28.2): + dependencies: + browserslist: 4.28.2 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + use-callback-ref@1.3.3(@types/react@19.2.14)(react@19.2.4): + dependencies: + react: 19.2.4 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.14 + + use-sidecar@1.1.3(@types/react@19.2.14)(react@19.2.4): + dependencies: + detect-node-es: 1.1.0 + react: 19.2.4 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.14 + + use-sync-external-store@1.6.0(react@19.2.4): + dependencies: + react: 19.2.4 + + util-deprecate@1.0.2: {} + + vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + + vfile-location@5.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile: 6.0.3 + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + + victory-vendor@36.9.2: + dependencies: + '@types/d3-array': 3.2.2 + '@types/d3-ease': 3.0.2 + '@types/d3-interpolate': 3.0.4 + '@types/d3-scale': 4.0.9 + '@types/d3-shape': 3.1.8 + '@types/d3-time': 3.0.4 + '@types/d3-timer': 3.0.2 + d3-array: 3.2.4 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-scale: 4.0.2 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-timer: 3.0.1 + + web-namespaces@2.0.1: {} + + webpack-virtual-modules@0.6.2: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wmf@1.0.2: {} + + word-wrap@1.2.5: {} + + word@0.3.0: {} + + xlsx@0.18.5: + dependencies: + adler-32: 1.3.1 + cfb: 1.2.2 + codepage: 1.15.0 + crc-32: 1.2.2 + ssf: 0.11.2 + wmf: 1.0.2 + word: 0.3.0 + + xmlbuilder@10.1.1: {} + + yallist@3.1.1: {} + + yocto-queue@0.1.0: {} + + zod-validation-error@4.0.2(zod@4.3.6): + dependencies: + zod: 4.3.6 + + zod@3.25.76: {} + + zod@4.3.6: {} + + zustand@5.0.12(@types/react@19.2.14)(immer@11.1.4)(react@19.2.4)(use-sync-external-store@1.6.0(react@19.2.4)): + optionalDependencies: + '@types/react': 19.2.14 + immer: 11.1.4 + react: 19.2.4 + use-sync-external-store: 1.6.0(react@19.2.4) + + zwitch@2.0.4: {} diff --git a/frontend/postcss.config.js b/frontend/postcss.config.js new file mode 100644 index 0000000..2e7af2b --- /dev/null +++ b/frontend/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/frontend/public/favicon.png b/frontend/public/favicon.png new file mode 100644 index 0000000..6da05ca Binary files /dev/null and b/frontend/public/favicon.png differ diff --git a/frontend/public/pdfjs/LICENSE b/frontend/public/pdfjs/LICENSE new file mode 100644 index 0000000..f433b1a --- /dev/null +++ b/frontend/public/pdfjs/LICENSE @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/frontend/public/pdfjs/build/pdf.js b/frontend/public/pdfjs/build/pdf.js new file mode 100644 index 0000000..2b0c521 --- /dev/null +++ b/frontend/public/pdfjs/build/pdf.js @@ -0,0 +1,24450 @@ +/** + * @licstart The following is the entire license notice for the + * JavaScript code in this page + * + * Copyright 2022 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @licend The above is the entire license notice for the + * JavaScript code in this page + */ + +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define("pdfjs-dist/build/pdf", [], factory); + else if(typeof exports === 'object') + exports["pdfjs-dist/build/pdf"] = factory(); + else + root["pdfjs-dist/build/pdf"] = root.pdfjsLib = factory(); +})(globalThis, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ([ +/* 0 */, +/* 1 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.VerbosityLevel = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.UNSUPPORTED_FEATURES = exports.TextRenderingMode = exports.StreamType = exports.RenderingIntentFlag = exports.PermissionFlag = exports.PasswordResponses = exports.PasswordException = exports.PageActionEventType = exports.OPS = exports.MissingPDFException = exports.LINE_FACTOR = exports.LINE_DESCENT_FACTOR = exports.InvalidPDFException = exports.ImageKind = exports.IDENTITY_MATRIX = exports.FormatError = exports.FontType = exports.FeatureTest = exports.FONT_IDENTITY_MATRIX = exports.DocumentActionEventType = exports.CMapCompressionType = exports.BaseException = exports.AnnotationType = exports.AnnotationStateModelType = exports.AnnotationReviewState = exports.AnnotationReplyType = exports.AnnotationMode = exports.AnnotationMarkedState = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationEditorType = exports.AnnotationEditorPrefix = exports.AnnotationEditorParamsType = exports.AnnotationBorderStyleType = exports.AnnotationActionEventType = exports.AbortException = void 0; +exports.arrayByteLength = arrayByteLength; +exports.arraysToBytes = arraysToBytes; +exports.assert = assert; +exports.bytesToString = bytesToString; +exports.createPromiseCapability = createPromiseCapability; +exports.createValidAbsoluteUrl = createValidAbsoluteUrl; +exports.escapeString = escapeString; +exports.getModificationDate = getModificationDate; +exports.getVerbosityLevel = getVerbosityLevel; +exports.info = info; +exports.isArrayBuffer = isArrayBuffer; +exports.isArrayEqual = isArrayEqual; +exports.isAscii = isAscii; +exports.objectFromMap = objectFromMap; +exports.objectSize = objectSize; +exports.setVerbosityLevel = setVerbosityLevel; +exports.shadow = shadow; +exports.string32 = string32; +exports.stringToBytes = stringToBytes; +exports.stringToPDFString = stringToPDFString; +exports.stringToUTF16BEString = stringToUTF16BEString; +exports.stringToUTF8String = stringToUTF8String; +exports.unreachable = unreachable; +exports.utf8StringToString = utf8StringToString; +exports.warn = warn; + +__w_pdfjs_require__(2); + +const IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0]; +exports.IDENTITY_MATRIX = IDENTITY_MATRIX; +const FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0]; +exports.FONT_IDENTITY_MATRIX = FONT_IDENTITY_MATRIX; +const LINE_FACTOR = 1.35; +exports.LINE_FACTOR = LINE_FACTOR; +const LINE_DESCENT_FACTOR = 0.35; +exports.LINE_DESCENT_FACTOR = LINE_DESCENT_FACTOR; +const RenderingIntentFlag = { + ANY: 0x01, + DISPLAY: 0x02, + PRINT: 0x04, + ANNOTATIONS_FORMS: 0x10, + ANNOTATIONS_STORAGE: 0x20, + ANNOTATIONS_DISABLE: 0x40, + OPLIST: 0x100 +}; +exports.RenderingIntentFlag = RenderingIntentFlag; +const AnnotationMode = { + DISABLE: 0, + ENABLE: 1, + ENABLE_FORMS: 2, + ENABLE_STORAGE: 3 +}; +exports.AnnotationMode = AnnotationMode; +const AnnotationEditorPrefix = "pdfjs_internal_editor_"; +exports.AnnotationEditorPrefix = AnnotationEditorPrefix; +const AnnotationEditorType = { + DISABLE: -1, + NONE: 0, + FREETEXT: 3, + INK: 15 +}; +exports.AnnotationEditorType = AnnotationEditorType; +const AnnotationEditorParamsType = { + FREETEXT_SIZE: 1, + FREETEXT_COLOR: 2, + FREETEXT_OPACITY: 3, + INK_COLOR: 11, + INK_THICKNESS: 12, + INK_OPACITY: 13 +}; +exports.AnnotationEditorParamsType = AnnotationEditorParamsType; +const PermissionFlag = { + PRINT: 0x04, + MODIFY_CONTENTS: 0x08, + COPY: 0x10, + MODIFY_ANNOTATIONS: 0x20, + FILL_INTERACTIVE_FORMS: 0x100, + COPY_FOR_ACCESSIBILITY: 0x200, + ASSEMBLE: 0x400, + PRINT_HIGH_QUALITY: 0x800 +}; +exports.PermissionFlag = PermissionFlag; +const TextRenderingMode = { + FILL: 0, + STROKE: 1, + FILL_STROKE: 2, + INVISIBLE: 3, + FILL_ADD_TO_PATH: 4, + STROKE_ADD_TO_PATH: 5, + FILL_STROKE_ADD_TO_PATH: 6, + ADD_TO_PATH: 7, + FILL_STROKE_MASK: 3, + ADD_TO_PATH_FLAG: 4 +}; +exports.TextRenderingMode = TextRenderingMode; +const ImageKind = { + GRAYSCALE_1BPP: 1, + RGB_24BPP: 2, + RGBA_32BPP: 3 +}; +exports.ImageKind = ImageKind; +const AnnotationType = { + TEXT: 1, + LINK: 2, + FREETEXT: 3, + LINE: 4, + SQUARE: 5, + CIRCLE: 6, + POLYGON: 7, + POLYLINE: 8, + HIGHLIGHT: 9, + UNDERLINE: 10, + SQUIGGLY: 11, + STRIKEOUT: 12, + STAMP: 13, + CARET: 14, + INK: 15, + POPUP: 16, + FILEATTACHMENT: 17, + SOUND: 18, + MOVIE: 19, + WIDGET: 20, + SCREEN: 21, + PRINTERMARK: 22, + TRAPNET: 23, + WATERMARK: 24, + THREED: 25, + REDACT: 26 +}; +exports.AnnotationType = AnnotationType; +const AnnotationStateModelType = { + MARKED: "Marked", + REVIEW: "Review" +}; +exports.AnnotationStateModelType = AnnotationStateModelType; +const AnnotationMarkedState = { + MARKED: "Marked", + UNMARKED: "Unmarked" +}; +exports.AnnotationMarkedState = AnnotationMarkedState; +const AnnotationReviewState = { + ACCEPTED: "Accepted", + REJECTED: "Rejected", + CANCELLED: "Cancelled", + COMPLETED: "Completed", + NONE: "None" +}; +exports.AnnotationReviewState = AnnotationReviewState; +const AnnotationReplyType = { + GROUP: "Group", + REPLY: "R" +}; +exports.AnnotationReplyType = AnnotationReplyType; +const AnnotationFlag = { + INVISIBLE: 0x01, + HIDDEN: 0x02, + PRINT: 0x04, + NOZOOM: 0x08, + NOROTATE: 0x10, + NOVIEW: 0x20, + READONLY: 0x40, + LOCKED: 0x80, + TOGGLENOVIEW: 0x100, + LOCKEDCONTENTS: 0x200 +}; +exports.AnnotationFlag = AnnotationFlag; +const AnnotationFieldFlag = { + READONLY: 0x0000001, + REQUIRED: 0x0000002, + NOEXPORT: 0x0000004, + MULTILINE: 0x0001000, + PASSWORD: 0x0002000, + NOTOGGLETOOFF: 0x0004000, + RADIO: 0x0008000, + PUSHBUTTON: 0x0010000, + COMBO: 0x0020000, + EDIT: 0x0040000, + SORT: 0x0080000, + FILESELECT: 0x0100000, + MULTISELECT: 0x0200000, + DONOTSPELLCHECK: 0x0400000, + DONOTSCROLL: 0x0800000, + COMB: 0x1000000, + RICHTEXT: 0x2000000, + RADIOSINUNISON: 0x2000000, + COMMITONSELCHANGE: 0x4000000 +}; +exports.AnnotationFieldFlag = AnnotationFieldFlag; +const AnnotationBorderStyleType = { + SOLID: 1, + DASHED: 2, + BEVELED: 3, + INSET: 4, + UNDERLINE: 5 +}; +exports.AnnotationBorderStyleType = AnnotationBorderStyleType; +const AnnotationActionEventType = { + E: "Mouse Enter", + X: "Mouse Exit", + D: "Mouse Down", + U: "Mouse Up", + Fo: "Focus", + Bl: "Blur", + PO: "PageOpen", + PC: "PageClose", + PV: "PageVisible", + PI: "PageInvisible", + K: "Keystroke", + F: "Format", + V: "Validate", + C: "Calculate" +}; +exports.AnnotationActionEventType = AnnotationActionEventType; +const DocumentActionEventType = { + WC: "WillClose", + WS: "WillSave", + DS: "DidSave", + WP: "WillPrint", + DP: "DidPrint" +}; +exports.DocumentActionEventType = DocumentActionEventType; +const PageActionEventType = { + O: "PageOpen", + C: "PageClose" +}; +exports.PageActionEventType = PageActionEventType; +const StreamType = { + UNKNOWN: "UNKNOWN", + FLATE: "FLATE", + LZW: "LZW", + DCT: "DCT", + JPX: "JPX", + JBIG: "JBIG", + A85: "A85", + AHX: "AHX", + CCF: "CCF", + RLX: "RLX" +}; +exports.StreamType = StreamType; +const FontType = { + UNKNOWN: "UNKNOWN", + TYPE1: "TYPE1", + TYPE1STANDARD: "TYPE1STANDARD", + TYPE1C: "TYPE1C", + CIDFONTTYPE0: "CIDFONTTYPE0", + CIDFONTTYPE0C: "CIDFONTTYPE0C", + TRUETYPE: "TRUETYPE", + CIDFONTTYPE2: "CIDFONTTYPE2", + TYPE3: "TYPE3", + OPENTYPE: "OPENTYPE", + TYPE0: "TYPE0", + MMTYPE1: "MMTYPE1" +}; +exports.FontType = FontType; +const VerbosityLevel = { + ERRORS: 0, + WARNINGS: 1, + INFOS: 5 +}; +exports.VerbosityLevel = VerbosityLevel; +const CMapCompressionType = { + NONE: 0, + BINARY: 1, + STREAM: 2 +}; +exports.CMapCompressionType = CMapCompressionType; +const OPS = { + dependency: 1, + setLineWidth: 2, + setLineCap: 3, + setLineJoin: 4, + setMiterLimit: 5, + setDash: 6, + setRenderingIntent: 7, + setFlatness: 8, + setGState: 9, + save: 10, + restore: 11, + transform: 12, + moveTo: 13, + lineTo: 14, + curveTo: 15, + curveTo2: 16, + curveTo3: 17, + closePath: 18, + rectangle: 19, + stroke: 20, + closeStroke: 21, + fill: 22, + eoFill: 23, + fillStroke: 24, + eoFillStroke: 25, + closeFillStroke: 26, + closeEOFillStroke: 27, + endPath: 28, + clip: 29, + eoClip: 30, + beginText: 31, + endText: 32, + setCharSpacing: 33, + setWordSpacing: 34, + setHScale: 35, + setLeading: 36, + setFont: 37, + setTextRenderingMode: 38, + setTextRise: 39, + moveText: 40, + setLeadingMoveText: 41, + setTextMatrix: 42, + nextLine: 43, + showText: 44, + showSpacedText: 45, + nextLineShowText: 46, + nextLineSetSpacingShowText: 47, + setCharWidth: 48, + setCharWidthAndBounds: 49, + setStrokeColorSpace: 50, + setFillColorSpace: 51, + setStrokeColor: 52, + setStrokeColorN: 53, + setFillColor: 54, + setFillColorN: 55, + setStrokeGray: 56, + setFillGray: 57, + setStrokeRGBColor: 58, + setFillRGBColor: 59, + setStrokeCMYKColor: 60, + setFillCMYKColor: 61, + shadingFill: 62, + beginInlineImage: 63, + beginImageData: 64, + endInlineImage: 65, + paintXObject: 66, + markPoint: 67, + markPointProps: 68, + beginMarkedContent: 69, + beginMarkedContentProps: 70, + endMarkedContent: 71, + beginCompat: 72, + endCompat: 73, + paintFormXObjectBegin: 74, + paintFormXObjectEnd: 75, + beginGroup: 76, + endGroup: 77, + beginAnnotations: 78, + endAnnotations: 79, + beginAnnotation: 80, + endAnnotation: 81, + paintJpegXObject: 82, + paintImageMaskXObject: 83, + paintImageMaskXObjectGroup: 84, + paintImageXObject: 85, + paintInlineImageXObject: 86, + paintInlineImageXObjectGroup: 87, + paintImageXObjectRepeat: 88, + paintImageMaskXObjectRepeat: 89, + paintSolidColorImageMask: 90, + constructPath: 91 +}; +exports.OPS = OPS; +const UNSUPPORTED_FEATURES = { + unknown: "unknown", + forms: "forms", + javaScript: "javaScript", + signatures: "signatures", + smask: "smask", + shadingPattern: "shadingPattern", + font: "font", + errorTilingPattern: "errorTilingPattern", + errorExtGState: "errorExtGState", + errorXObject: "errorXObject", + errorFontLoadType3: "errorFontLoadType3", + errorFontState: "errorFontState", + errorFontMissing: "errorFontMissing", + errorFontTranslate: "errorFontTranslate", + errorColorSpace: "errorColorSpace", + errorOperatorList: "errorOperatorList", + errorFontToUnicode: "errorFontToUnicode", + errorFontLoadNative: "errorFontLoadNative", + errorFontBuildPath: "errorFontBuildPath", + errorFontGetPath: "errorFontGetPath", + errorMarkedContent: "errorMarkedContent", + errorContentSubStream: "errorContentSubStream" +}; +exports.UNSUPPORTED_FEATURES = UNSUPPORTED_FEATURES; +const PasswordResponses = { + NEED_PASSWORD: 1, + INCORRECT_PASSWORD: 2 +}; +exports.PasswordResponses = PasswordResponses; +let verbosity = VerbosityLevel.WARNINGS; + +function setVerbosityLevel(level) { + if (Number.isInteger(level)) { + verbosity = level; + } +} + +function getVerbosityLevel() { + return verbosity; +} + +function info(msg) { + if (verbosity >= VerbosityLevel.INFOS) { + console.log(`Info: ${msg}`); + } +} + +function warn(msg) { + if (verbosity >= VerbosityLevel.WARNINGS) { + console.log(`Warning: ${msg}`); + } +} + +function unreachable(msg) { + throw new Error(msg); +} + +function assert(cond, msg) { + if (!cond) { + unreachable(msg); + } +} + +function _isValidProtocol(url) { + if (!url) { + return false; + } + + switch (url.protocol) { + case "http:": + case "https:": + case "ftp:": + case "mailto:": + case "tel:": + return true; + + default: + return false; + } +} + +function createValidAbsoluteUrl(url) { + let baseUrl = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + + if (!url) { + return null; + } + + try { + if (options && typeof url === "string") { + if (options.addDefaultProtocol && url.startsWith("www.")) { + const dots = url.match(/\./g); + + if (dots && dots.length >= 2) { + url = `http://${url}`; + } + } + + if (options.tryConvertEncoding) { + try { + url = stringToUTF8String(url); + } catch (ex) {} + } + } + + const absoluteUrl = baseUrl ? new URL(url, baseUrl) : new URL(url); + + if (_isValidProtocol(absoluteUrl)) { + return absoluteUrl; + } + } catch (ex) {} + + return null; +} + +function shadow(obj, prop, value) { + Object.defineProperty(obj, prop, { + value, + enumerable: true, + configurable: true, + writable: false + }); + return value; +} + +const BaseException = function BaseExceptionClosure() { + function BaseException(message, name) { + if (this.constructor === BaseException) { + unreachable("Cannot initialize BaseException."); + } + + this.message = message; + this.name = name; + } + + BaseException.prototype = new Error(); + BaseException.constructor = BaseException; + return BaseException; +}(); + +exports.BaseException = BaseException; + +class PasswordException extends BaseException { + constructor(msg, code) { + super(msg, "PasswordException"); + this.code = code; + } + +} + +exports.PasswordException = PasswordException; + +class UnknownErrorException extends BaseException { + constructor(msg, details) { + super(msg, "UnknownErrorException"); + this.details = details; + } + +} + +exports.UnknownErrorException = UnknownErrorException; + +class InvalidPDFException extends BaseException { + constructor(msg) { + super(msg, "InvalidPDFException"); + } + +} + +exports.InvalidPDFException = InvalidPDFException; + +class MissingPDFException extends BaseException { + constructor(msg) { + super(msg, "MissingPDFException"); + } + +} + +exports.MissingPDFException = MissingPDFException; + +class UnexpectedResponseException extends BaseException { + constructor(msg, status) { + super(msg, "UnexpectedResponseException"); + this.status = status; + } + +} + +exports.UnexpectedResponseException = UnexpectedResponseException; + +class FormatError extends BaseException { + constructor(msg) { + super(msg, "FormatError"); + } + +} + +exports.FormatError = FormatError; + +class AbortException extends BaseException { + constructor(msg) { + super(msg, "AbortException"); + } + +} + +exports.AbortException = AbortException; + +function bytesToString(bytes) { + if (typeof bytes !== "object" || bytes === null || bytes.length === undefined) { + unreachable("Invalid argument for bytesToString"); + } + + const length = bytes.length; + const MAX_ARGUMENT_COUNT = 8192; + + if (length < MAX_ARGUMENT_COUNT) { + return String.fromCharCode.apply(null, bytes); + } + + const strBuf = []; + + for (let i = 0; i < length; i += MAX_ARGUMENT_COUNT) { + const chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length); + const chunk = bytes.subarray(i, chunkEnd); + strBuf.push(String.fromCharCode.apply(null, chunk)); + } + + return strBuf.join(""); +} + +function stringToBytes(str) { + if (typeof str !== "string") { + unreachable("Invalid argument for stringToBytes"); + } + + const length = str.length; + const bytes = new Uint8Array(length); + + for (let i = 0; i < length; ++i) { + bytes[i] = str.charCodeAt(i) & 0xff; + } + + return bytes; +} + +function arrayByteLength(arr) { + if (arr.length !== undefined) { + return arr.length; + } + + if (arr.byteLength !== undefined) { + return arr.byteLength; + } + + unreachable("Invalid argument for arrayByteLength"); +} + +function arraysToBytes(arr) { + const length = arr.length; + + if (length === 1 && arr[0] instanceof Uint8Array) { + return arr[0]; + } + + let resultLength = 0; + + for (let i = 0; i < length; i++) { + resultLength += arrayByteLength(arr[i]); + } + + let pos = 0; + const data = new Uint8Array(resultLength); + + for (let i = 0; i < length; i++) { + let item = arr[i]; + + if (!(item instanceof Uint8Array)) { + if (typeof item === "string") { + item = stringToBytes(item); + } else { + item = new Uint8Array(item); + } + } + + const itemLength = item.byteLength; + data.set(item, pos); + pos += itemLength; + } + + return data; +} + +function string32(value) { + return String.fromCharCode(value >> 24 & 0xff, value >> 16 & 0xff, value >> 8 & 0xff, value & 0xff); +} + +function objectSize(obj) { + return Object.keys(obj).length; +} + +function objectFromMap(map) { + const obj = Object.create(null); + + for (const [key, value] of map) { + obj[key] = value; + } + + return obj; +} + +function isLittleEndian() { + const buffer8 = new Uint8Array(4); + buffer8[0] = 1; + const view32 = new Uint32Array(buffer8.buffer, 0, 1); + return view32[0] === 1; +} + +function isEvalSupported() { + try { + new Function(""); + return true; + } catch (e) { + return false; + } +} + +class FeatureTest { + static get isLittleEndian() { + return shadow(this, "isLittleEndian", isLittleEndian()); + } + + static get isEvalSupported() { + return shadow(this, "isEvalSupported", isEvalSupported()); + } + + static get isOffscreenCanvasSupported() { + return shadow(this, "isOffscreenCanvasSupported", typeof OffscreenCanvas !== "undefined"); + } + +} + +exports.FeatureTest = FeatureTest; +const hexNumbers = [...Array(256).keys()].map(n => n.toString(16).padStart(2, "0")); + +class Util { + static makeHexColor(r, g, b) { + return `#${hexNumbers[r]}${hexNumbers[g]}${hexNumbers[b]}`; + } + + static scaleMinMax(transform, minMax) { + let temp; + + if (transform[0]) { + if (transform[0] < 0) { + temp = minMax[0]; + minMax[0] = minMax[1]; + minMax[1] = temp; + } + + minMax[0] *= transform[0]; + minMax[1] *= transform[0]; + + if (transform[3] < 0) { + temp = minMax[2]; + minMax[2] = minMax[3]; + minMax[3] = temp; + } + + minMax[2] *= transform[3]; + minMax[3] *= transform[3]; + } else { + temp = minMax[0]; + minMax[0] = minMax[2]; + minMax[2] = temp; + temp = minMax[1]; + minMax[1] = minMax[3]; + minMax[3] = temp; + + if (transform[1] < 0) { + temp = minMax[2]; + minMax[2] = minMax[3]; + minMax[3] = temp; + } + + minMax[2] *= transform[1]; + minMax[3] *= transform[1]; + + if (transform[2] < 0) { + temp = minMax[0]; + minMax[0] = minMax[1]; + minMax[1] = temp; + } + + minMax[0] *= transform[2]; + minMax[1] *= transform[2]; + } + + minMax[0] += transform[4]; + minMax[1] += transform[4]; + minMax[2] += transform[5]; + minMax[3] += transform[5]; + } + + static transform(m1, m2) { + return [m1[0] * m2[0] + m1[2] * m2[1], m1[1] * m2[0] + m1[3] * m2[1], m1[0] * m2[2] + m1[2] * m2[3], m1[1] * m2[2] + m1[3] * m2[3], m1[0] * m2[4] + m1[2] * m2[5] + m1[4], m1[1] * m2[4] + m1[3] * m2[5] + m1[5]]; + } + + static applyTransform(p, m) { + const xt = p[0] * m[0] + p[1] * m[2] + m[4]; + const yt = p[0] * m[1] + p[1] * m[3] + m[5]; + return [xt, yt]; + } + + static applyInverseTransform(p, m) { + const d = m[0] * m[3] - m[1] * m[2]; + const xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d; + const yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d; + return [xt, yt]; + } + + static getAxialAlignedBoundingBox(r, m) { + const p1 = Util.applyTransform(r, m); + const p2 = Util.applyTransform(r.slice(2, 4), m); + const p3 = Util.applyTransform([r[0], r[3]], m); + const p4 = Util.applyTransform([r[2], r[1]], m); + return [Math.min(p1[0], p2[0], p3[0], p4[0]), Math.min(p1[1], p2[1], p3[1], p4[1]), Math.max(p1[0], p2[0], p3[0], p4[0]), Math.max(p1[1], p2[1], p3[1], p4[1])]; + } + + static inverseTransform(m) { + const d = m[0] * m[3] - m[1] * m[2]; + return [m[3] / d, -m[1] / d, -m[2] / d, m[0] / d, (m[2] * m[5] - m[4] * m[3]) / d, (m[4] * m[1] - m[5] * m[0]) / d]; + } + + static apply3dTransform(m, v) { + return [m[0] * v[0] + m[1] * v[1] + m[2] * v[2], m[3] * v[0] + m[4] * v[1] + m[5] * v[2], m[6] * v[0] + m[7] * v[1] + m[8] * v[2]]; + } + + static singularValueDecompose2dScale(m) { + const transpose = [m[0], m[2], m[1], m[3]]; + const a = m[0] * transpose[0] + m[1] * transpose[2]; + const b = m[0] * transpose[1] + m[1] * transpose[3]; + const c = m[2] * transpose[0] + m[3] * transpose[2]; + const d = m[2] * transpose[1] + m[3] * transpose[3]; + const first = (a + d) / 2; + const second = Math.sqrt((a + d) ** 2 - 4 * (a * d - c * b)) / 2; + const sx = first + second || 1; + const sy = first - second || 1; + return [Math.sqrt(sx), Math.sqrt(sy)]; + } + + static normalizeRect(rect) { + const r = rect.slice(0); + + if (rect[0] > rect[2]) { + r[0] = rect[2]; + r[2] = rect[0]; + } + + if (rect[1] > rect[3]) { + r[1] = rect[3]; + r[3] = rect[1]; + } + + return r; + } + + static intersect(rect1, rect2) { + const xLow = Math.max(Math.min(rect1[0], rect1[2]), Math.min(rect2[0], rect2[2])); + const xHigh = Math.min(Math.max(rect1[0], rect1[2]), Math.max(rect2[0], rect2[2])); + + if (xLow > xHigh) { + return null; + } + + const yLow = Math.max(Math.min(rect1[1], rect1[3]), Math.min(rect2[1], rect2[3])); + const yHigh = Math.min(Math.max(rect1[1], rect1[3]), Math.max(rect2[1], rect2[3])); + + if (yLow > yHigh) { + return null; + } + + return [xLow, yLow, xHigh, yHigh]; + } + + static bezierBoundingBox(x0, y0, x1, y1, x2, y2, x3, y3) { + const tvalues = [], + bounds = [[], []]; + let a, b, c, t, t1, t2, b2ac, sqrtb2ac; + + for (let i = 0; i < 2; ++i) { + if (i === 0) { + b = 6 * x0 - 12 * x1 + 6 * x2; + a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3; + c = 3 * x1 - 3 * x0; + } else { + b = 6 * y0 - 12 * y1 + 6 * y2; + a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3; + c = 3 * y1 - 3 * y0; + } + + if (Math.abs(a) < 1e-12) { + if (Math.abs(b) < 1e-12) { + continue; + } + + t = -c / b; + + if (0 < t && t < 1) { + tvalues.push(t); + } + + continue; + } + + b2ac = b * b - 4 * c * a; + sqrtb2ac = Math.sqrt(b2ac); + + if (b2ac < 0) { + continue; + } + + t1 = (-b + sqrtb2ac) / (2 * a); + + if (0 < t1 && t1 < 1) { + tvalues.push(t1); + } + + t2 = (-b - sqrtb2ac) / (2 * a); + + if (0 < t2 && t2 < 1) { + tvalues.push(t2); + } + } + + let j = tvalues.length, + mt; + const jlen = j; + + while (j--) { + t = tvalues[j]; + mt = 1 - t; + bounds[0][j] = mt * mt * mt * x0 + 3 * mt * mt * t * x1 + 3 * mt * t * t * x2 + t * t * t * x3; + bounds[1][j] = mt * mt * mt * y0 + 3 * mt * mt * t * y1 + 3 * mt * t * t * y2 + t * t * t * y3; + } + + bounds[0][jlen] = x0; + bounds[1][jlen] = y0; + bounds[0][jlen + 1] = x3; + bounds[1][jlen + 1] = y3; + bounds[0].length = bounds[1].length = jlen + 2; + return [Math.min(...bounds[0]), Math.min(...bounds[1]), Math.max(...bounds[0]), Math.max(...bounds[1])]; + } + +} + +exports.Util = Util; +const PDFStringTranslateTable = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2d8, 0x2c7, 0x2c6, 0x2d9, 0x2dd, 0x2db, 0x2da, 0x2dc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x192, 0x2044, 0x2039, 0x203a, 0x2212, 0x2030, 0x201e, 0x201c, 0x201d, 0x2018, 0x2019, 0x201a, 0x2122, 0xfb01, 0xfb02, 0x141, 0x152, 0x160, 0x178, 0x17d, 0x131, 0x142, 0x153, 0x161, 0x17e, 0, 0x20ac]; + +function stringToPDFString(str) { + if (str[0] >= "\xEF") { + let encoding; + + if (str[0] === "\xFE" && str[1] === "\xFF") { + encoding = "utf-16be"; + } else if (str[0] === "\xFF" && str[1] === "\xFE") { + encoding = "utf-16le"; + } else if (str[0] === "\xEF" && str[1] === "\xBB" && str[2] === "\xBF") { + encoding = "utf-8"; + } + + if (encoding) { + try { + const decoder = new TextDecoder(encoding, { + fatal: true + }); + const buffer = stringToBytes(str); + return decoder.decode(buffer); + } catch (ex) { + warn(`stringToPDFString: "${ex}".`); + } + } + } + + const strBuf = []; + + for (let i = 0, ii = str.length; i < ii; i++) { + const code = PDFStringTranslateTable[str.charCodeAt(i)]; + strBuf.push(code ? String.fromCharCode(code) : str.charAt(i)); + } + + return strBuf.join(""); +} + +function escapeString(str) { + return str.replace(/([()\\\n\r])/g, match => { + if (match === "\n") { + return "\\n"; + } else if (match === "\r") { + return "\\r"; + } + + return `\\${match}`; + }); +} + +function isAscii(str) { + return /^[\x00-\x7F]*$/.test(str); +} + +function stringToUTF16BEString(str) { + const buf = ["\xFE\xFF"]; + + for (let i = 0, ii = str.length; i < ii; i++) { + const char = str.charCodeAt(i); + buf.push(String.fromCharCode(char >> 8 & 0xff), String.fromCharCode(char & 0xff)); + } + + return buf.join(""); +} + +function stringToUTF8String(str) { + return decodeURIComponent(escape(str)); +} + +function utf8StringToString(str) { + return unescape(encodeURIComponent(str)); +} + +function isArrayBuffer(v) { + return typeof v === "object" && v !== null && v.byteLength !== undefined; +} + +function isArrayEqual(arr1, arr2) { + if (arr1.length !== arr2.length) { + return false; + } + + for (let i = 0, ii = arr1.length; i < ii; i++) { + if (arr1[i] !== arr2[i]) { + return false; + } + } + + return true; +} + +function getModificationDate() { + let date = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new Date(); + const buffer = [date.getUTCFullYear().toString(), (date.getUTCMonth() + 1).toString().padStart(2, "0"), date.getUTCDate().toString().padStart(2, "0"), date.getUTCHours().toString().padStart(2, "0"), date.getUTCMinutes().toString().padStart(2, "0"), date.getUTCSeconds().toString().padStart(2, "0")]; + return buffer.join(""); +} + +function createPromiseCapability() { + const capability = Object.create(null); + let isSettled = false; + Object.defineProperty(capability, "settled", { + get() { + return isSettled; + } + + }); + capability.promise = new Promise(function (resolve, reject) { + capability.resolve = function (data) { + isSettled = true; + resolve(data); + }; + + capability.reject = function (reason) { + isSettled = true; + reject(reason); + }; + }); + return capability; +} + +/***/ }), +/* 2 */ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __w_pdfjs_require__) => { + +"use strict"; + + +var _is_node = __w_pdfjs_require__(3); + +if (!globalThis._pdfjsCompatibilityChecked) { + globalThis._pdfjsCompatibilityChecked = true; + + (function checkNodeBtoa() { + if (globalThis.btoa || !_is_node.isNodeJS) { + return; + } + + globalThis.btoa = function (chars) { + return Buffer.from(chars, "binary").toString("base64"); + }; + })(); + + (function checkNodeAtob() { + if (globalThis.atob || !_is_node.isNodeJS) { + return; + } + + globalThis.atob = function (input) { + return Buffer.from(input, "base64").toString("binary"); + }; + })(); + + (function checkDOMMatrix() { + if (globalThis.DOMMatrix || !_is_node.isNodeJS) { + return; + } + + globalThis.DOMMatrix = require("dommatrix/dist/dommatrix.js"); + })(); + + (function checkReadableStream() { + if (globalThis.ReadableStream || !_is_node.isNodeJS) { + return; + } + + globalThis.ReadableStream = require("web-streams-polyfill/dist/ponyfill.js").ReadableStream; + })(); + + (function checkArrayAt() { + if (Array.prototype.at) { + return; + } + + __w_pdfjs_require__(4); + })(); + + (function checkTypedArrayAt() { + if (Uint8Array.prototype.at) { + return; + } + + __w_pdfjs_require__(76); + })(); + + (function checkStructuredClone() { + if (globalThis.structuredClone) { + return; + } + + __w_pdfjs_require__(86); + })(); +} + +/***/ }), +/* 3 */ +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.isNodeJS = void 0; +const isNodeJS = typeof process === "object" && process + "" === "[object process]" && !process.versions.nw && !(process.versions.electron && process.type && process.type !== "browser"); +exports.isNodeJS = isNodeJS; + +/***/ }), +/* 4 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +__w_pdfjs_require__(5); +var entryUnbind = __w_pdfjs_require__(75); +module.exports = entryUnbind('Array', 'at'); + +/***/ }), +/* 5 */ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __w_pdfjs_require__) => { + +"use strict"; + +var $ = __w_pdfjs_require__(6); +var toObject = __w_pdfjs_require__(41); +var lengthOfArrayLike = __w_pdfjs_require__(65); +var toIntegerOrInfinity = __w_pdfjs_require__(63); +var addToUnscopables = __w_pdfjs_require__(70); +$({ + target: 'Array', + proto: true +}, { + at: function at(index) { + var O = toObject(this); + var len = lengthOfArrayLike(O); + var relativeIndex = toIntegerOrInfinity(index); + var k = relativeIndex >= 0 ? relativeIndex : len + relativeIndex; + return k < 0 || k >= len ? undefined : O[k]; + } +}); +addToUnscopables('at'); + +/***/ }), +/* 6 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var global = __w_pdfjs_require__(7); +var getOwnPropertyDescriptor = (__w_pdfjs_require__(8).f); +var createNonEnumerableProperty = __w_pdfjs_require__(45); +var defineBuiltIn = __w_pdfjs_require__(49); +var defineGlobalProperty = __w_pdfjs_require__(39); +var copyConstructorProperties = __w_pdfjs_require__(57); +var isForced = __w_pdfjs_require__(69); +module.exports = function (options, source) { + var TARGET = options.target; + var GLOBAL = options.global; + var STATIC = options.stat; + var FORCED, target, key, targetProperty, sourceProperty, descriptor; + if (GLOBAL) { + target = global; + } else if (STATIC) { + target = global[TARGET] || defineGlobalProperty(TARGET, {}); + } else { + target = (global[TARGET] || {}).prototype; + } + if (target) + for (key in source) { + sourceProperty = source[key]; + if (options.dontCallGetSet) { + descriptor = getOwnPropertyDescriptor(target, key); + targetProperty = descriptor && descriptor.value; + } else + targetProperty = target[key]; + FORCED = isForced(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced); + if (!FORCED && targetProperty !== undefined) { + if (typeof sourceProperty == typeof targetProperty) + continue; + copyConstructorProperties(sourceProperty, targetProperty); + } + if (options.sham || targetProperty && targetProperty.sham) { + createNonEnumerableProperty(sourceProperty, 'sham', true); + } + defineBuiltIn(target, key, sourceProperty, options); + } +}; + +/***/ }), +/* 7 */ +/***/ ((module) => { + +var check = function (it) { + return it && it.Math == Math && it; +}; +module.exports = check(typeof globalThis == 'object' && globalThis) || check(typeof window == 'object' && window) || check(typeof self == 'object' && self) || check(typeof global == 'object' && global) || (function () { + return this; +}()) || Function('return this')(); + +/***/ }), +/* 8 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +var DESCRIPTORS = __w_pdfjs_require__(9); +var call = __w_pdfjs_require__(11); +var propertyIsEnumerableModule = __w_pdfjs_require__(13); +var createPropertyDescriptor = __w_pdfjs_require__(14); +var toIndexedObject = __w_pdfjs_require__(15); +var toPropertyKey = __w_pdfjs_require__(20); +var hasOwn = __w_pdfjs_require__(40); +var IE8_DOM_DEFINE = __w_pdfjs_require__(43); +var $getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; +exports.f = DESCRIPTORS ? $getOwnPropertyDescriptor : function getOwnPropertyDescriptor(O, P) { + O = toIndexedObject(O); + P = toPropertyKey(P); + if (IE8_DOM_DEFINE) + try { + return $getOwnPropertyDescriptor(O, P); + } catch (error) { + } + if (hasOwn(O, P)) + return createPropertyDescriptor(!call(propertyIsEnumerableModule.f, O, P), O[P]); +}; + +/***/ }), +/* 9 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var fails = __w_pdfjs_require__(10); +module.exports = !fails(function () { + return Object.defineProperty({}, 1, { + get: function () { + return 7; + } + })[1] != 7; +}); + +/***/ }), +/* 10 */ +/***/ ((module) => { + +module.exports = function (exec) { + try { + return !!exec(); + } catch (error) { + return true; + } +}; + +/***/ }), +/* 11 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var NATIVE_BIND = __w_pdfjs_require__(12); +var call = Function.prototype.call; +module.exports = NATIVE_BIND ? call.bind(call) : function () { + return call.apply(call, arguments); +}; + +/***/ }), +/* 12 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var fails = __w_pdfjs_require__(10); +module.exports = !fails(function () { + var test = function () { + }.bind(); + return typeof test != 'function' || test.hasOwnProperty('prototype'); +}); + +/***/ }), +/* 13 */ +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +var $propertyIsEnumerable = {}.propertyIsEnumerable; +var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; +var NASHORN_BUG = getOwnPropertyDescriptor && !$propertyIsEnumerable.call({ 1: 2 }, 1); +exports.f = NASHORN_BUG ? function propertyIsEnumerable(V) { + var descriptor = getOwnPropertyDescriptor(this, V); + return !!descriptor && descriptor.enumerable; +} : $propertyIsEnumerable; + +/***/ }), +/* 14 */ +/***/ ((module) => { + +module.exports = function (bitmap, value) { + return { + enumerable: !(bitmap & 1), + configurable: !(bitmap & 2), + writable: !(bitmap & 4), + value: value + }; +}; + +/***/ }), +/* 15 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var IndexedObject = __w_pdfjs_require__(16); +var requireObjectCoercible = __w_pdfjs_require__(19); +module.exports = function (it) { + return IndexedObject(requireObjectCoercible(it)); +}; + +/***/ }), +/* 16 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var uncurryThis = __w_pdfjs_require__(17); +var fails = __w_pdfjs_require__(10); +var classof = __w_pdfjs_require__(18); +var $Object = Object; +var split = uncurryThis(''.split); +module.exports = fails(function () { + return !$Object('z').propertyIsEnumerable(0); +}) ? function (it) { + return classof(it) == 'String' ? split(it, '') : $Object(it); +} : $Object; + +/***/ }), +/* 17 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var NATIVE_BIND = __w_pdfjs_require__(12); +var FunctionPrototype = Function.prototype; +var bind = FunctionPrototype.bind; +var call = FunctionPrototype.call; +var uncurryThis = NATIVE_BIND && bind.bind(call, call); +module.exports = NATIVE_BIND ? function (fn) { + return fn && uncurryThis(fn); +} : function (fn) { + return fn && function () { + return call.apply(fn, arguments); + }; +}; + +/***/ }), +/* 18 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var uncurryThis = __w_pdfjs_require__(17); +var toString = uncurryThis({}.toString); +var stringSlice = uncurryThis(''.slice); +module.exports = function (it) { + return stringSlice(toString(it), 8, -1); +}; + +/***/ }), +/* 19 */ +/***/ ((module) => { + +var $TypeError = TypeError; +module.exports = function (it) { + if (it == undefined) + throw $TypeError("Can't call method on " + it); + return it; +}; + +/***/ }), +/* 20 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var toPrimitive = __w_pdfjs_require__(21); +var isSymbol = __w_pdfjs_require__(24); +module.exports = function (argument) { + var key = toPrimitive(argument, 'string'); + return isSymbol(key) ? key : key + ''; +}; + +/***/ }), +/* 21 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var call = __w_pdfjs_require__(11); +var isObject = __w_pdfjs_require__(22); +var isSymbol = __w_pdfjs_require__(24); +var getMethod = __w_pdfjs_require__(31); +var ordinaryToPrimitive = __w_pdfjs_require__(34); +var wellKnownSymbol = __w_pdfjs_require__(35); +var $TypeError = TypeError; +var TO_PRIMITIVE = wellKnownSymbol('toPrimitive'); +module.exports = function (input, pref) { + if (!isObject(input) || isSymbol(input)) + return input; + var exoticToPrim = getMethod(input, TO_PRIMITIVE); + var result; + if (exoticToPrim) { + if (pref === undefined) + pref = 'default'; + result = call(exoticToPrim, input, pref); + if (!isObject(result) || isSymbol(result)) + return result; + throw $TypeError("Can't convert object to primitive value"); + } + if (pref === undefined) + pref = 'number'; + return ordinaryToPrimitive(input, pref); +}; + +/***/ }), +/* 22 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var isCallable = __w_pdfjs_require__(23); +module.exports = function (it) { + return typeof it == 'object' ? it !== null : isCallable(it); +}; + +/***/ }), +/* 23 */ +/***/ ((module) => { + +module.exports = function (argument) { + return typeof argument == 'function'; +}; + +/***/ }), +/* 24 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var getBuiltIn = __w_pdfjs_require__(25); +var isCallable = __w_pdfjs_require__(23); +var isPrototypeOf = __w_pdfjs_require__(26); +var USE_SYMBOL_AS_UID = __w_pdfjs_require__(27); +var $Object = Object; +module.exports = USE_SYMBOL_AS_UID ? function (it) { + return typeof it == 'symbol'; +} : function (it) { + var $Symbol = getBuiltIn('Symbol'); + return isCallable($Symbol) && isPrototypeOf($Symbol.prototype, $Object(it)); +}; + +/***/ }), +/* 25 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var global = __w_pdfjs_require__(7); +var isCallable = __w_pdfjs_require__(23); +var aFunction = function (argument) { + return isCallable(argument) ? argument : undefined; +}; +module.exports = function (namespace, method) { + return arguments.length < 2 ? aFunction(global[namespace]) : global[namespace] && global[namespace][method]; +}; + +/***/ }), +/* 26 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var uncurryThis = __w_pdfjs_require__(17); +module.exports = uncurryThis({}.isPrototypeOf); + +/***/ }), +/* 27 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var NATIVE_SYMBOL = __w_pdfjs_require__(28); +module.exports = NATIVE_SYMBOL && !Symbol.sham && typeof Symbol.iterator == 'symbol'; + +/***/ }), +/* 28 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var V8_VERSION = __w_pdfjs_require__(29); +var fails = __w_pdfjs_require__(10); +module.exports = !!Object.getOwnPropertySymbols && !fails(function () { + var symbol = Symbol(); + return !String(symbol) || !(Object(symbol) instanceof Symbol) || !Symbol.sham && V8_VERSION && V8_VERSION < 41; +}); + +/***/ }), +/* 29 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var global = __w_pdfjs_require__(7); +var userAgent = __w_pdfjs_require__(30); +var process = global.process; +var Deno = global.Deno; +var versions = process && process.versions || Deno && Deno.version; +var v8 = versions && versions.v8; +var match, version; +if (v8) { + match = v8.split('.'); + version = match[0] > 0 && match[0] < 4 ? 1 : +(match[0] + match[1]); +} +if (!version && userAgent) { + match = userAgent.match(/Edge\/(\d+)/); + if (!match || match[1] >= 74) { + match = userAgent.match(/Chrome\/(\d+)/); + if (match) + version = +match[1]; + } +} +module.exports = version; + +/***/ }), +/* 30 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var getBuiltIn = __w_pdfjs_require__(25); +module.exports = getBuiltIn('navigator', 'userAgent') || ''; + +/***/ }), +/* 31 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var aCallable = __w_pdfjs_require__(32); +module.exports = function (V, P) { + var func = V[P]; + return func == null ? undefined : aCallable(func); +}; + +/***/ }), +/* 32 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var isCallable = __w_pdfjs_require__(23); +var tryToString = __w_pdfjs_require__(33); +var $TypeError = TypeError; +module.exports = function (argument) { + if (isCallable(argument)) + return argument; + throw $TypeError(tryToString(argument) + ' is not a function'); +}; + +/***/ }), +/* 33 */ +/***/ ((module) => { + +var $String = String; +module.exports = function (argument) { + try { + return $String(argument); + } catch (error) { + return 'Object'; + } +}; + +/***/ }), +/* 34 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var call = __w_pdfjs_require__(11); +var isCallable = __w_pdfjs_require__(23); +var isObject = __w_pdfjs_require__(22); +var $TypeError = TypeError; +module.exports = function (input, pref) { + var fn, val; + if (pref === 'string' && isCallable(fn = input.toString) && !isObject(val = call(fn, input))) + return val; + if (isCallable(fn = input.valueOf) && !isObject(val = call(fn, input))) + return val; + if (pref !== 'string' && isCallable(fn = input.toString) && !isObject(val = call(fn, input))) + return val; + throw $TypeError("Can't convert object to primitive value"); +}; + +/***/ }), +/* 35 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var global = __w_pdfjs_require__(7); +var shared = __w_pdfjs_require__(36); +var hasOwn = __w_pdfjs_require__(40); +var uid = __w_pdfjs_require__(42); +var NATIVE_SYMBOL = __w_pdfjs_require__(28); +var USE_SYMBOL_AS_UID = __w_pdfjs_require__(27); +var WellKnownSymbolsStore = shared('wks'); +var Symbol = global.Symbol; +var symbolFor = Symbol && Symbol['for']; +var createWellKnownSymbol = USE_SYMBOL_AS_UID ? Symbol : Symbol && Symbol.withoutSetter || uid; +module.exports = function (name) { + if (!hasOwn(WellKnownSymbolsStore, name) || !(NATIVE_SYMBOL || typeof WellKnownSymbolsStore[name] == 'string')) { + var description = 'Symbol.' + name; + if (NATIVE_SYMBOL && hasOwn(Symbol, name)) { + WellKnownSymbolsStore[name] = Symbol[name]; + } else if (USE_SYMBOL_AS_UID && symbolFor) { + WellKnownSymbolsStore[name] = symbolFor(description); + } else { + WellKnownSymbolsStore[name] = createWellKnownSymbol(description); + } + } + return WellKnownSymbolsStore[name]; +}; + +/***/ }), +/* 36 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var IS_PURE = __w_pdfjs_require__(37); +var store = __w_pdfjs_require__(38); +(module.exports = function (key, value) { + return store[key] || (store[key] = value !== undefined ? value : {}); +})('versions', []).push({ + version: '3.24.1', + mode: IS_PURE ? 'pure' : 'global', + copyright: '© 2014-2022 Denis Pushkarev (zloirock.ru)', + license: 'https://github.com/zloirock/core-js/blob/v3.24.1/LICENSE', + source: 'https://github.com/zloirock/core-js' +}); + +/***/ }), +/* 37 */ +/***/ ((module) => { + +module.exports = false; + +/***/ }), +/* 38 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var global = __w_pdfjs_require__(7); +var defineGlobalProperty = __w_pdfjs_require__(39); +var SHARED = '__core-js_shared__'; +var store = global[SHARED] || defineGlobalProperty(SHARED, {}); +module.exports = store; + +/***/ }), +/* 39 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var global = __w_pdfjs_require__(7); +var defineProperty = Object.defineProperty; +module.exports = function (key, value) { + try { + defineProperty(global, key, { + value: value, + configurable: true, + writable: true + }); + } catch (error) { + global[key] = value; + } + return value; +}; + +/***/ }), +/* 40 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var uncurryThis = __w_pdfjs_require__(17); +var toObject = __w_pdfjs_require__(41); +var hasOwnProperty = uncurryThis({}.hasOwnProperty); +module.exports = Object.hasOwn || function hasOwn(it, key) { + return hasOwnProperty(toObject(it), key); +}; + +/***/ }), +/* 41 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var requireObjectCoercible = __w_pdfjs_require__(19); +var $Object = Object; +module.exports = function (argument) { + return $Object(requireObjectCoercible(argument)); +}; + +/***/ }), +/* 42 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var uncurryThis = __w_pdfjs_require__(17); +var id = 0; +var postfix = Math.random(); +var toString = uncurryThis(1.0.toString); +module.exports = function (key) { + return 'Symbol(' + (key === undefined ? '' : key) + ')_' + toString(++id + postfix, 36); +}; + +/***/ }), +/* 43 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var DESCRIPTORS = __w_pdfjs_require__(9); +var fails = __w_pdfjs_require__(10); +var createElement = __w_pdfjs_require__(44); +module.exports = !DESCRIPTORS && !fails(function () { + return Object.defineProperty(createElement('div'), 'a', { + get: function () { + return 7; + } + }).a != 7; +}); + +/***/ }), +/* 44 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var global = __w_pdfjs_require__(7); +var isObject = __w_pdfjs_require__(22); +var document = global.document; +var EXISTS = isObject(document) && isObject(document.createElement); +module.exports = function (it) { + return EXISTS ? document.createElement(it) : {}; +}; + +/***/ }), +/* 45 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var DESCRIPTORS = __w_pdfjs_require__(9); +var definePropertyModule = __w_pdfjs_require__(46); +var createPropertyDescriptor = __w_pdfjs_require__(14); +module.exports = DESCRIPTORS ? function (object, key, value) { + return definePropertyModule.f(object, key, createPropertyDescriptor(1, value)); +} : function (object, key, value) { + object[key] = value; + return object; +}; + +/***/ }), +/* 46 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +var DESCRIPTORS = __w_pdfjs_require__(9); +var IE8_DOM_DEFINE = __w_pdfjs_require__(43); +var V8_PROTOTYPE_DEFINE_BUG = __w_pdfjs_require__(47); +var anObject = __w_pdfjs_require__(48); +var toPropertyKey = __w_pdfjs_require__(20); +var $TypeError = TypeError; +var $defineProperty = Object.defineProperty; +var $getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; +var ENUMERABLE = 'enumerable'; +var CONFIGURABLE = 'configurable'; +var WRITABLE = 'writable'; +exports.f = DESCRIPTORS ? V8_PROTOTYPE_DEFINE_BUG ? function defineProperty(O, P, Attributes) { + anObject(O); + P = toPropertyKey(P); + anObject(Attributes); + if (typeof O === 'function' && P === 'prototype' && 'value' in Attributes && WRITABLE in Attributes && !Attributes[WRITABLE]) { + var current = $getOwnPropertyDescriptor(O, P); + if (current && current[WRITABLE]) { + O[P] = Attributes.value; + Attributes = { + configurable: CONFIGURABLE in Attributes ? Attributes[CONFIGURABLE] : current[CONFIGURABLE], + enumerable: ENUMERABLE in Attributes ? Attributes[ENUMERABLE] : current[ENUMERABLE], + writable: false + }; + } + } + return $defineProperty(O, P, Attributes); +} : $defineProperty : function defineProperty(O, P, Attributes) { + anObject(O); + P = toPropertyKey(P); + anObject(Attributes); + if (IE8_DOM_DEFINE) + try { + return $defineProperty(O, P, Attributes); + } catch (error) { + } + if ('get' in Attributes || 'set' in Attributes) + throw $TypeError('Accessors not supported'); + if ('value' in Attributes) + O[P] = Attributes.value; + return O; +}; + +/***/ }), +/* 47 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var DESCRIPTORS = __w_pdfjs_require__(9); +var fails = __w_pdfjs_require__(10); +module.exports = DESCRIPTORS && fails(function () { + return Object.defineProperty(function () { + }, 'prototype', { + value: 42, + writable: false + }).prototype != 42; +}); + +/***/ }), +/* 48 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var isObject = __w_pdfjs_require__(22); +var $String = String; +var $TypeError = TypeError; +module.exports = function (argument) { + if (isObject(argument)) + return argument; + throw $TypeError($String(argument) + ' is not an object'); +}; + +/***/ }), +/* 49 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var isCallable = __w_pdfjs_require__(23); +var definePropertyModule = __w_pdfjs_require__(46); +var makeBuiltIn = __w_pdfjs_require__(50); +var defineGlobalProperty = __w_pdfjs_require__(39); +module.exports = function (O, key, value, options) { + if (!options) + options = {}; + var simple = options.enumerable; + var name = options.name !== undefined ? options.name : key; + if (isCallable(value)) + makeBuiltIn(value, name, options); + if (options.global) { + if (simple) + O[key] = value; + else + defineGlobalProperty(key, value); + } else { + try { + if (!options.unsafe) + delete O[key]; + else if (O[key]) + simple = true; + } catch (error) { + } + if (simple) + O[key] = value; + else + definePropertyModule.f(O, key, { + value: value, + enumerable: false, + configurable: !options.nonConfigurable, + writable: !options.nonWritable + }); + } + return O; +}; + +/***/ }), +/* 50 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var fails = __w_pdfjs_require__(10); +var isCallable = __w_pdfjs_require__(23); +var hasOwn = __w_pdfjs_require__(40); +var DESCRIPTORS = __w_pdfjs_require__(9); +var CONFIGURABLE_FUNCTION_NAME = (__w_pdfjs_require__(51).CONFIGURABLE); +var inspectSource = __w_pdfjs_require__(52); +var InternalStateModule = __w_pdfjs_require__(53); +var enforceInternalState = InternalStateModule.enforce; +var getInternalState = InternalStateModule.get; +var defineProperty = Object.defineProperty; +var CONFIGURABLE_LENGTH = DESCRIPTORS && !fails(function () { + return defineProperty(function () { + }, 'length', { value: 8 }).length !== 8; +}); +var TEMPLATE = String(String).split('String'); +var makeBuiltIn = module.exports = function (value, name, options) { + if (String(name).slice(0, 7) === 'Symbol(') { + name = '[' + String(name).replace(/^Symbol\(([^)]*)\)/, '$1') + ']'; + } + if (options && options.getter) + name = 'get ' + name; + if (options && options.setter) + name = 'set ' + name; + if (!hasOwn(value, 'name') || CONFIGURABLE_FUNCTION_NAME && value.name !== name) { + if (DESCRIPTORS) + defineProperty(value, 'name', { + value: name, + configurable: true + }); + else + value.name = name; + } + if (CONFIGURABLE_LENGTH && options && hasOwn(options, 'arity') && value.length !== options.arity) { + defineProperty(value, 'length', { value: options.arity }); + } + try { + if (options && hasOwn(options, 'constructor') && options.constructor) { + if (DESCRIPTORS) + defineProperty(value, 'prototype', { writable: false }); + } else if (value.prototype) + value.prototype = undefined; + } catch (error) { + } + var state = enforceInternalState(value); + if (!hasOwn(state, 'source')) { + state.source = TEMPLATE.join(typeof name == 'string' ? name : ''); + } + return value; +}; +Function.prototype.toString = makeBuiltIn(function toString() { + return isCallable(this) && getInternalState(this).source || inspectSource(this); +}, 'toString'); + +/***/ }), +/* 51 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var DESCRIPTORS = __w_pdfjs_require__(9); +var hasOwn = __w_pdfjs_require__(40); +var FunctionPrototype = Function.prototype; +var getDescriptor = DESCRIPTORS && Object.getOwnPropertyDescriptor; +var EXISTS = hasOwn(FunctionPrototype, 'name'); +var PROPER = EXISTS && function something() { +}.name === 'something'; +var CONFIGURABLE = EXISTS && (!DESCRIPTORS || DESCRIPTORS && getDescriptor(FunctionPrototype, 'name').configurable); +module.exports = { + EXISTS: EXISTS, + PROPER: PROPER, + CONFIGURABLE: CONFIGURABLE +}; + +/***/ }), +/* 52 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var uncurryThis = __w_pdfjs_require__(17); +var isCallable = __w_pdfjs_require__(23); +var store = __w_pdfjs_require__(38); +var functionToString = uncurryThis(Function.toString); +if (!isCallable(store.inspectSource)) { + store.inspectSource = function (it) { + return functionToString(it); + }; +} +module.exports = store.inspectSource; + +/***/ }), +/* 53 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var NATIVE_WEAK_MAP = __w_pdfjs_require__(54); +var global = __w_pdfjs_require__(7); +var uncurryThis = __w_pdfjs_require__(17); +var isObject = __w_pdfjs_require__(22); +var createNonEnumerableProperty = __w_pdfjs_require__(45); +var hasOwn = __w_pdfjs_require__(40); +var shared = __w_pdfjs_require__(38); +var sharedKey = __w_pdfjs_require__(55); +var hiddenKeys = __w_pdfjs_require__(56); +var OBJECT_ALREADY_INITIALIZED = 'Object already initialized'; +var TypeError = global.TypeError; +var WeakMap = global.WeakMap; +var set, get, has; +var enforce = function (it) { + return has(it) ? get(it) : set(it, {}); +}; +var getterFor = function (TYPE) { + return function (it) { + var state; + if (!isObject(it) || (state = get(it)).type !== TYPE) { + throw TypeError('Incompatible receiver, ' + TYPE + ' required'); + } + return state; + }; +}; +if (NATIVE_WEAK_MAP || shared.state) { + var store = shared.state || (shared.state = new WeakMap()); + var wmget = uncurryThis(store.get); + var wmhas = uncurryThis(store.has); + var wmset = uncurryThis(store.set); + set = function (it, metadata) { + if (wmhas(store, it)) + throw new TypeError(OBJECT_ALREADY_INITIALIZED); + metadata.facade = it; + wmset(store, it, metadata); + return metadata; + }; + get = function (it) { + return wmget(store, it) || {}; + }; + has = function (it) { + return wmhas(store, it); + }; +} else { + var STATE = sharedKey('state'); + hiddenKeys[STATE] = true; + set = function (it, metadata) { + if (hasOwn(it, STATE)) + throw new TypeError(OBJECT_ALREADY_INITIALIZED); + metadata.facade = it; + createNonEnumerableProperty(it, STATE, metadata); + return metadata; + }; + get = function (it) { + return hasOwn(it, STATE) ? it[STATE] : {}; + }; + has = function (it) { + return hasOwn(it, STATE); + }; +} +module.exports = { + set: set, + get: get, + has: has, + enforce: enforce, + getterFor: getterFor +}; + +/***/ }), +/* 54 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var global = __w_pdfjs_require__(7); +var isCallable = __w_pdfjs_require__(23); +var inspectSource = __w_pdfjs_require__(52); +var WeakMap = global.WeakMap; +module.exports = isCallable(WeakMap) && /native code/.test(inspectSource(WeakMap)); + +/***/ }), +/* 55 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var shared = __w_pdfjs_require__(36); +var uid = __w_pdfjs_require__(42); +var keys = shared('keys'); +module.exports = function (key) { + return keys[key] || (keys[key] = uid(key)); +}; + +/***/ }), +/* 56 */ +/***/ ((module) => { + +module.exports = {}; + +/***/ }), +/* 57 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var hasOwn = __w_pdfjs_require__(40); +var ownKeys = __w_pdfjs_require__(58); +var getOwnPropertyDescriptorModule = __w_pdfjs_require__(8); +var definePropertyModule = __w_pdfjs_require__(46); +module.exports = function (target, source, exceptions) { + var keys = ownKeys(source); + var defineProperty = definePropertyModule.f; + var getOwnPropertyDescriptor = getOwnPropertyDescriptorModule.f; + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + if (!hasOwn(target, key) && !(exceptions && hasOwn(exceptions, key))) { + defineProperty(target, key, getOwnPropertyDescriptor(source, key)); + } + } +}; + +/***/ }), +/* 58 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var getBuiltIn = __w_pdfjs_require__(25); +var uncurryThis = __w_pdfjs_require__(17); +var getOwnPropertyNamesModule = __w_pdfjs_require__(59); +var getOwnPropertySymbolsModule = __w_pdfjs_require__(68); +var anObject = __w_pdfjs_require__(48); +var concat = uncurryThis([].concat); +module.exports = getBuiltIn('Reflect', 'ownKeys') || function ownKeys(it) { + var keys = getOwnPropertyNamesModule.f(anObject(it)); + var getOwnPropertySymbols = getOwnPropertySymbolsModule.f; + return getOwnPropertySymbols ? concat(keys, getOwnPropertySymbols(it)) : keys; +}; + +/***/ }), +/* 59 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +var internalObjectKeys = __w_pdfjs_require__(60); +var enumBugKeys = __w_pdfjs_require__(67); +var hiddenKeys = enumBugKeys.concat('length', 'prototype'); +exports.f = Object.getOwnPropertyNames || function getOwnPropertyNames(O) { + return internalObjectKeys(O, hiddenKeys); +}; + +/***/ }), +/* 60 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var uncurryThis = __w_pdfjs_require__(17); +var hasOwn = __w_pdfjs_require__(40); +var toIndexedObject = __w_pdfjs_require__(15); +var indexOf = (__w_pdfjs_require__(61).indexOf); +var hiddenKeys = __w_pdfjs_require__(56); +var push = uncurryThis([].push); +module.exports = function (object, names) { + var O = toIndexedObject(object); + var i = 0; + var result = []; + var key; + for (key in O) + !hasOwn(hiddenKeys, key) && hasOwn(O, key) && push(result, key); + while (names.length > i) + if (hasOwn(O, key = names[i++])) { + ~indexOf(result, key) || push(result, key); + } + return result; +}; + +/***/ }), +/* 61 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var toIndexedObject = __w_pdfjs_require__(15); +var toAbsoluteIndex = __w_pdfjs_require__(62); +var lengthOfArrayLike = __w_pdfjs_require__(65); +var createMethod = function (IS_INCLUDES) { + return function ($this, el, fromIndex) { + var O = toIndexedObject($this); + var length = lengthOfArrayLike(O); + var index = toAbsoluteIndex(fromIndex, length); + var value; + if (IS_INCLUDES && el != el) + while (length > index) { + value = O[index++]; + if (value != value) + return true; + } + else + for (; length > index; index++) { + if ((IS_INCLUDES || index in O) && O[index] === el) + return IS_INCLUDES || index || 0; + } + return !IS_INCLUDES && -1; + }; +}; +module.exports = { + includes: createMethod(true), + indexOf: createMethod(false) +}; + +/***/ }), +/* 62 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var toIntegerOrInfinity = __w_pdfjs_require__(63); +var max = Math.max; +var min = Math.min; +module.exports = function (index, length) { + var integer = toIntegerOrInfinity(index); + return integer < 0 ? max(integer + length, 0) : min(integer, length); +}; + +/***/ }), +/* 63 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var trunc = __w_pdfjs_require__(64); +module.exports = function (argument) { + var number = +argument; + return number !== number || number === 0 ? 0 : trunc(number); +}; + +/***/ }), +/* 64 */ +/***/ ((module) => { + +var ceil = Math.ceil; +var floor = Math.floor; +module.exports = Math.trunc || function trunc(x) { + var n = +x; + return (n > 0 ? floor : ceil)(n); +}; + +/***/ }), +/* 65 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var toLength = __w_pdfjs_require__(66); +module.exports = function (obj) { + return toLength(obj.length); +}; + +/***/ }), +/* 66 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var toIntegerOrInfinity = __w_pdfjs_require__(63); +var min = Math.min; +module.exports = function (argument) { + return argument > 0 ? min(toIntegerOrInfinity(argument), 0x1FFFFFFFFFFFFF) : 0; +}; + +/***/ }), +/* 67 */ +/***/ ((module) => { + +module.exports = [ + 'constructor', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'toLocaleString', + 'toString', + 'valueOf' +]; + +/***/ }), +/* 68 */ +/***/ ((__unused_webpack_module, exports) => { + +exports.f = Object.getOwnPropertySymbols; + +/***/ }), +/* 69 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var fails = __w_pdfjs_require__(10); +var isCallable = __w_pdfjs_require__(23); +var replacement = /#|\.prototype\./; +var isForced = function (feature, detection) { + var value = data[normalize(feature)]; + return value == POLYFILL ? true : value == NATIVE ? false : isCallable(detection) ? fails(detection) : !!detection; +}; +var normalize = isForced.normalize = function (string) { + return String(string).replace(replacement, '.').toLowerCase(); +}; +var data = isForced.data = {}; +var NATIVE = isForced.NATIVE = 'N'; +var POLYFILL = isForced.POLYFILL = 'P'; +module.exports = isForced; + +/***/ }), +/* 70 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var wellKnownSymbol = __w_pdfjs_require__(35); +var create = __w_pdfjs_require__(71); +var defineProperty = (__w_pdfjs_require__(46).f); +var UNSCOPABLES = wellKnownSymbol('unscopables'); +var ArrayPrototype = Array.prototype; +if (ArrayPrototype[UNSCOPABLES] == undefined) { + defineProperty(ArrayPrototype, UNSCOPABLES, { + configurable: true, + value: create(null) + }); +} +module.exports = function (key) { + ArrayPrototype[UNSCOPABLES][key] = true; +}; + +/***/ }), +/* 71 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var anObject = __w_pdfjs_require__(48); +var definePropertiesModule = __w_pdfjs_require__(72); +var enumBugKeys = __w_pdfjs_require__(67); +var hiddenKeys = __w_pdfjs_require__(56); +var html = __w_pdfjs_require__(74); +var documentCreateElement = __w_pdfjs_require__(44); +var sharedKey = __w_pdfjs_require__(55); +var GT = '>'; +var LT = '<'; +var PROTOTYPE = 'prototype'; +var SCRIPT = 'script'; +var IE_PROTO = sharedKey('IE_PROTO'); +var EmptyConstructor = function () { +}; +var scriptTag = function (content) { + return LT + SCRIPT + GT + content + LT + '/' + SCRIPT + GT; +}; +var NullProtoObjectViaActiveX = function (activeXDocument) { + activeXDocument.write(scriptTag('')); + activeXDocument.close(); + var temp = activeXDocument.parentWindow.Object; + activeXDocument = null; + return temp; +}; +var NullProtoObjectViaIFrame = function () { + var iframe = documentCreateElement('iframe'); + var JS = 'java' + SCRIPT + ':'; + var iframeDocument; + iframe.style.display = 'none'; + html.appendChild(iframe); + iframe.src = String(JS); + iframeDocument = iframe.contentWindow.document; + iframeDocument.open(); + iframeDocument.write(scriptTag('document.F=Object')); + iframeDocument.close(); + return iframeDocument.F; +}; +var activeXDocument; +var NullProtoObject = function () { + try { + activeXDocument = new ActiveXObject('htmlfile'); + } catch (error) { + } + NullProtoObject = typeof document != 'undefined' ? document.domain && activeXDocument ? NullProtoObjectViaActiveX(activeXDocument) : NullProtoObjectViaIFrame() : NullProtoObjectViaActiveX(activeXDocument); + var length = enumBugKeys.length; + while (length--) + delete NullProtoObject[PROTOTYPE][enumBugKeys[length]]; + return NullProtoObject(); +}; +hiddenKeys[IE_PROTO] = true; +module.exports = Object.create || function create(O, Properties) { + var result; + if (O !== null) { + EmptyConstructor[PROTOTYPE] = anObject(O); + result = new EmptyConstructor(); + EmptyConstructor[PROTOTYPE] = null; + result[IE_PROTO] = O; + } else + result = NullProtoObject(); + return Properties === undefined ? result : definePropertiesModule.f(result, Properties); +}; + +/***/ }), +/* 72 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +var DESCRIPTORS = __w_pdfjs_require__(9); +var V8_PROTOTYPE_DEFINE_BUG = __w_pdfjs_require__(47); +var definePropertyModule = __w_pdfjs_require__(46); +var anObject = __w_pdfjs_require__(48); +var toIndexedObject = __w_pdfjs_require__(15); +var objectKeys = __w_pdfjs_require__(73); +exports.f = DESCRIPTORS && !V8_PROTOTYPE_DEFINE_BUG ? Object.defineProperties : function defineProperties(O, Properties) { + anObject(O); + var props = toIndexedObject(Properties); + var keys = objectKeys(Properties); + var length = keys.length; + var index = 0; + var key; + while (length > index) + definePropertyModule.f(O, key = keys[index++], props[key]); + return O; +}; + +/***/ }), +/* 73 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var internalObjectKeys = __w_pdfjs_require__(60); +var enumBugKeys = __w_pdfjs_require__(67); +module.exports = Object.keys || function keys(O) { + return internalObjectKeys(O, enumBugKeys); +}; + +/***/ }), +/* 74 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var getBuiltIn = __w_pdfjs_require__(25); +module.exports = getBuiltIn('document', 'documentElement'); + +/***/ }), +/* 75 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var global = __w_pdfjs_require__(7); +var uncurryThis = __w_pdfjs_require__(17); +module.exports = function (CONSTRUCTOR, METHOD) { + return uncurryThis(global[CONSTRUCTOR].prototype[METHOD]); +}; + +/***/ }), +/* 76 */ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __w_pdfjs_require__) => { + +__w_pdfjs_require__(77); + +/***/ }), +/* 77 */ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __w_pdfjs_require__) => { + +"use strict"; + +var ArrayBufferViewCore = __w_pdfjs_require__(78); +var lengthOfArrayLike = __w_pdfjs_require__(65); +var toIntegerOrInfinity = __w_pdfjs_require__(63); +var aTypedArray = ArrayBufferViewCore.aTypedArray; +var exportTypedArrayMethod = ArrayBufferViewCore.exportTypedArrayMethod; +exportTypedArrayMethod('at', function at(index) { + var O = aTypedArray(this); + var len = lengthOfArrayLike(O); + var relativeIndex = toIntegerOrInfinity(index); + var k = relativeIndex >= 0 ? relativeIndex : len + relativeIndex; + return k < 0 || k >= len ? undefined : O[k]; +}); + +/***/ }), +/* 78 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +"use strict"; + +var NATIVE_ARRAY_BUFFER = __w_pdfjs_require__(79); +var DESCRIPTORS = __w_pdfjs_require__(9); +var global = __w_pdfjs_require__(7); +var isCallable = __w_pdfjs_require__(23); +var isObject = __w_pdfjs_require__(22); +var hasOwn = __w_pdfjs_require__(40); +var classof = __w_pdfjs_require__(80); +var tryToString = __w_pdfjs_require__(33); +var createNonEnumerableProperty = __w_pdfjs_require__(45); +var defineBuiltIn = __w_pdfjs_require__(49); +var defineProperty = (__w_pdfjs_require__(46).f); +var isPrototypeOf = __w_pdfjs_require__(26); +var getPrototypeOf = __w_pdfjs_require__(82); +var setPrototypeOf = __w_pdfjs_require__(84); +var wellKnownSymbol = __w_pdfjs_require__(35); +var uid = __w_pdfjs_require__(42); +var InternalStateModule = __w_pdfjs_require__(53); +var enforceInternalState = InternalStateModule.enforce; +var getInternalState = InternalStateModule.get; +var Int8Array = global.Int8Array; +var Int8ArrayPrototype = Int8Array && Int8Array.prototype; +var Uint8ClampedArray = global.Uint8ClampedArray; +var Uint8ClampedArrayPrototype = Uint8ClampedArray && Uint8ClampedArray.prototype; +var TypedArray = Int8Array && getPrototypeOf(Int8Array); +var TypedArrayPrototype = Int8ArrayPrototype && getPrototypeOf(Int8ArrayPrototype); +var ObjectPrototype = Object.prototype; +var TypeError = global.TypeError; +var TO_STRING_TAG = wellKnownSymbol('toStringTag'); +var TYPED_ARRAY_TAG = uid('TYPED_ARRAY_TAG'); +var TYPED_ARRAY_CONSTRUCTOR = 'TypedArrayConstructor'; +var NATIVE_ARRAY_BUFFER_VIEWS = NATIVE_ARRAY_BUFFER && !!setPrototypeOf && classof(global.opera) !== 'Opera'; +var TYPED_ARRAY_TAG_REQUIRED = false; +var NAME, Constructor, Prototype; +var TypedArrayConstructorsList = { + Int8Array: 1, + Uint8Array: 1, + Uint8ClampedArray: 1, + Int16Array: 2, + Uint16Array: 2, + Int32Array: 4, + Uint32Array: 4, + Float32Array: 4, + Float64Array: 8 +}; +var BigIntArrayConstructorsList = { + BigInt64Array: 8, + BigUint64Array: 8 +}; +var isView = function isView(it) { + if (!isObject(it)) + return false; + var klass = classof(it); + return klass === 'DataView' || hasOwn(TypedArrayConstructorsList, klass) || hasOwn(BigIntArrayConstructorsList, klass); +}; +var getTypedArrayConstructor = function (it) { + var proto = getPrototypeOf(it); + if (!isObject(proto)) + return; + var state = getInternalState(proto); + return state && hasOwn(state, TYPED_ARRAY_CONSTRUCTOR) ? state[TYPED_ARRAY_CONSTRUCTOR] : getTypedArrayConstructor(proto); +}; +var isTypedArray = function (it) { + if (!isObject(it)) + return false; + var klass = classof(it); + return hasOwn(TypedArrayConstructorsList, klass) || hasOwn(BigIntArrayConstructorsList, klass); +}; +var aTypedArray = function (it) { + if (isTypedArray(it)) + return it; + throw TypeError('Target is not a typed array'); +}; +var aTypedArrayConstructor = function (C) { + if (isCallable(C) && (!setPrototypeOf || isPrototypeOf(TypedArray, C))) + return C; + throw TypeError(tryToString(C) + ' is not a typed array constructor'); +}; +var exportTypedArrayMethod = function (KEY, property, forced, options) { + if (!DESCRIPTORS) + return; + if (forced) + for (var ARRAY in TypedArrayConstructorsList) { + var TypedArrayConstructor = global[ARRAY]; + if (TypedArrayConstructor && hasOwn(TypedArrayConstructor.prototype, KEY)) + try { + delete TypedArrayConstructor.prototype[KEY]; + } catch (error) { + try { + TypedArrayConstructor.prototype[KEY] = property; + } catch (error2) { + } + } + } + if (!TypedArrayPrototype[KEY] || forced) { + defineBuiltIn(TypedArrayPrototype, KEY, forced ? property : NATIVE_ARRAY_BUFFER_VIEWS && Int8ArrayPrototype[KEY] || property, options); + } +}; +var exportTypedArrayStaticMethod = function (KEY, property, forced) { + var ARRAY, TypedArrayConstructor; + if (!DESCRIPTORS) + return; + if (setPrototypeOf) { + if (forced) + for (ARRAY in TypedArrayConstructorsList) { + TypedArrayConstructor = global[ARRAY]; + if (TypedArrayConstructor && hasOwn(TypedArrayConstructor, KEY)) + try { + delete TypedArrayConstructor[KEY]; + } catch (error) { + } + } + if (!TypedArray[KEY] || forced) { + try { + return defineBuiltIn(TypedArray, KEY, forced ? property : NATIVE_ARRAY_BUFFER_VIEWS && TypedArray[KEY] || property); + } catch (error) { + } + } else + return; + } + for (ARRAY in TypedArrayConstructorsList) { + TypedArrayConstructor = global[ARRAY]; + if (TypedArrayConstructor && (!TypedArrayConstructor[KEY] || forced)) { + defineBuiltIn(TypedArrayConstructor, KEY, property); + } + } +}; +for (NAME in TypedArrayConstructorsList) { + Constructor = global[NAME]; + Prototype = Constructor && Constructor.prototype; + if (Prototype) + enforceInternalState(Prototype)[TYPED_ARRAY_CONSTRUCTOR] = Constructor; + else + NATIVE_ARRAY_BUFFER_VIEWS = false; +} +for (NAME in BigIntArrayConstructorsList) { + Constructor = global[NAME]; + Prototype = Constructor && Constructor.prototype; + if (Prototype) + enforceInternalState(Prototype)[TYPED_ARRAY_CONSTRUCTOR] = Constructor; +} +if (!NATIVE_ARRAY_BUFFER_VIEWS || !isCallable(TypedArray) || TypedArray === Function.prototype) { + TypedArray = function TypedArray() { + throw TypeError('Incorrect invocation'); + }; + if (NATIVE_ARRAY_BUFFER_VIEWS) + for (NAME in TypedArrayConstructorsList) { + if (global[NAME]) + setPrototypeOf(global[NAME], TypedArray); + } +} +if (!NATIVE_ARRAY_BUFFER_VIEWS || !TypedArrayPrototype || TypedArrayPrototype === ObjectPrototype) { + TypedArrayPrototype = TypedArray.prototype; + if (NATIVE_ARRAY_BUFFER_VIEWS) + for (NAME in TypedArrayConstructorsList) { + if (global[NAME]) + setPrototypeOf(global[NAME].prototype, TypedArrayPrototype); + } +} +if (NATIVE_ARRAY_BUFFER_VIEWS && getPrototypeOf(Uint8ClampedArrayPrototype) !== TypedArrayPrototype) { + setPrototypeOf(Uint8ClampedArrayPrototype, TypedArrayPrototype); +} +if (DESCRIPTORS && !hasOwn(TypedArrayPrototype, TO_STRING_TAG)) { + TYPED_ARRAY_TAG_REQUIRED = true; + defineProperty(TypedArrayPrototype, TO_STRING_TAG, { + get: function () { + return isObject(this) ? this[TYPED_ARRAY_TAG] : undefined; + } + }); + for (NAME in TypedArrayConstructorsList) + if (global[NAME]) { + createNonEnumerableProperty(global[NAME], TYPED_ARRAY_TAG, NAME); + } +} +module.exports = { + NATIVE_ARRAY_BUFFER_VIEWS: NATIVE_ARRAY_BUFFER_VIEWS, + TYPED_ARRAY_TAG: TYPED_ARRAY_TAG_REQUIRED && TYPED_ARRAY_TAG, + aTypedArray: aTypedArray, + aTypedArrayConstructor: aTypedArrayConstructor, + exportTypedArrayMethod: exportTypedArrayMethod, + exportTypedArrayStaticMethod: exportTypedArrayStaticMethod, + getTypedArrayConstructor: getTypedArrayConstructor, + isView: isView, + isTypedArray: isTypedArray, + TypedArray: TypedArray, + TypedArrayPrototype: TypedArrayPrototype +}; + +/***/ }), +/* 79 */ +/***/ ((module) => { + +module.exports = typeof ArrayBuffer != 'undefined' && typeof DataView != 'undefined'; + +/***/ }), +/* 80 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var TO_STRING_TAG_SUPPORT = __w_pdfjs_require__(81); +var isCallable = __w_pdfjs_require__(23); +var classofRaw = __w_pdfjs_require__(18); +var wellKnownSymbol = __w_pdfjs_require__(35); +var TO_STRING_TAG = wellKnownSymbol('toStringTag'); +var $Object = Object; +var CORRECT_ARGUMENTS = classofRaw((function () { + return arguments; +}())) == 'Arguments'; +var tryGet = function (it, key) { + try { + return it[key]; + } catch (error) { + } +}; +module.exports = TO_STRING_TAG_SUPPORT ? classofRaw : function (it) { + var O, tag, result; + return it === undefined ? 'Undefined' : it === null ? 'Null' : typeof (tag = tryGet(O = $Object(it), TO_STRING_TAG)) == 'string' ? tag : CORRECT_ARGUMENTS ? classofRaw(O) : (result = classofRaw(O)) == 'Object' && isCallable(O.callee) ? 'Arguments' : result; +}; + +/***/ }), +/* 81 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var wellKnownSymbol = __w_pdfjs_require__(35); +var TO_STRING_TAG = wellKnownSymbol('toStringTag'); +var test = {}; +test[TO_STRING_TAG] = 'z'; +module.exports = String(test) === '[object z]'; + +/***/ }), +/* 82 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var hasOwn = __w_pdfjs_require__(40); +var isCallable = __w_pdfjs_require__(23); +var toObject = __w_pdfjs_require__(41); +var sharedKey = __w_pdfjs_require__(55); +var CORRECT_PROTOTYPE_GETTER = __w_pdfjs_require__(83); +var IE_PROTO = sharedKey('IE_PROTO'); +var $Object = Object; +var ObjectPrototype = $Object.prototype; +module.exports = CORRECT_PROTOTYPE_GETTER ? $Object.getPrototypeOf : function (O) { + var object = toObject(O); + if (hasOwn(object, IE_PROTO)) + return object[IE_PROTO]; + var constructor = object.constructor; + if (isCallable(constructor) && object instanceof constructor) { + return constructor.prototype; + } + return object instanceof $Object ? ObjectPrototype : null; +}; + +/***/ }), +/* 83 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var fails = __w_pdfjs_require__(10); +module.exports = !fails(function () { + function F() { + } + F.prototype.constructor = null; + return Object.getPrototypeOf(new F()) !== F.prototype; +}); + +/***/ }), +/* 84 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var uncurryThis = __w_pdfjs_require__(17); +var anObject = __w_pdfjs_require__(48); +var aPossiblePrototype = __w_pdfjs_require__(85); +module.exports = Object.setPrototypeOf || ('__proto__' in {} ? (function () { + var CORRECT_SETTER = false; + var test = {}; + var setter; + try { + setter = uncurryThis(Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set); + setter(test, []); + CORRECT_SETTER = test instanceof Array; + } catch (error) { + } + return function setPrototypeOf(O, proto) { + anObject(O); + aPossiblePrototype(proto); + if (CORRECT_SETTER) + setter(O, proto); + else + O.__proto__ = proto; + return O; + }; +}()) : undefined); + +/***/ }), +/* 85 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var isCallable = __w_pdfjs_require__(23); +var $String = String; +var $TypeError = TypeError; +module.exports = function (argument) { + if (typeof argument == 'object' || isCallable(argument)) + return argument; + throw $TypeError("Can't set " + $String(argument) + ' as a prototype'); +}; + +/***/ }), +/* 86 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +__w_pdfjs_require__(87); +__w_pdfjs_require__(93); +__w_pdfjs_require__(95); +__w_pdfjs_require__(117); +__w_pdfjs_require__(119); +var path = __w_pdfjs_require__(128); +module.exports = path.structuredClone; + +/***/ }), +/* 87 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +"use strict"; + +var toIndexedObject = __w_pdfjs_require__(15); +var addToUnscopables = __w_pdfjs_require__(70); +var Iterators = __w_pdfjs_require__(88); +var InternalStateModule = __w_pdfjs_require__(53); +var defineProperty = (__w_pdfjs_require__(46).f); +var defineIterator = __w_pdfjs_require__(89); +var IS_PURE = __w_pdfjs_require__(37); +var DESCRIPTORS = __w_pdfjs_require__(9); +var ARRAY_ITERATOR = 'Array Iterator'; +var setInternalState = InternalStateModule.set; +var getInternalState = InternalStateModule.getterFor(ARRAY_ITERATOR); +module.exports = defineIterator(Array, 'Array', function (iterated, kind) { + setInternalState(this, { + type: ARRAY_ITERATOR, + target: toIndexedObject(iterated), + index: 0, + kind: kind + }); +}, function () { + var state = getInternalState(this); + var target = state.target; + var kind = state.kind; + var index = state.index++; + if (!target || index >= target.length) { + state.target = undefined; + return { + value: undefined, + done: true + }; + } + if (kind == 'keys') + return { + value: index, + done: false + }; + if (kind == 'values') + return { + value: target[index], + done: false + }; + return { + value: [ + index, + target[index] + ], + done: false + }; +}, 'values'); +var values = Iterators.Arguments = Iterators.Array; +addToUnscopables('keys'); +addToUnscopables('values'); +addToUnscopables('entries'); +if (!IS_PURE && DESCRIPTORS && values.name !== 'values') + try { + defineProperty(values, 'name', { value: 'values' }); + } catch (error) { + } + +/***/ }), +/* 88 */ +/***/ ((module) => { + +module.exports = {}; + +/***/ }), +/* 89 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +"use strict"; + +var $ = __w_pdfjs_require__(6); +var call = __w_pdfjs_require__(11); +var IS_PURE = __w_pdfjs_require__(37); +var FunctionName = __w_pdfjs_require__(51); +var isCallable = __w_pdfjs_require__(23); +var createIteratorConstructor = __w_pdfjs_require__(90); +var getPrototypeOf = __w_pdfjs_require__(82); +var setPrototypeOf = __w_pdfjs_require__(84); +var setToStringTag = __w_pdfjs_require__(92); +var createNonEnumerableProperty = __w_pdfjs_require__(45); +var defineBuiltIn = __w_pdfjs_require__(49); +var wellKnownSymbol = __w_pdfjs_require__(35); +var Iterators = __w_pdfjs_require__(88); +var IteratorsCore = __w_pdfjs_require__(91); +var PROPER_FUNCTION_NAME = FunctionName.PROPER; +var CONFIGURABLE_FUNCTION_NAME = FunctionName.CONFIGURABLE; +var IteratorPrototype = IteratorsCore.IteratorPrototype; +var BUGGY_SAFARI_ITERATORS = IteratorsCore.BUGGY_SAFARI_ITERATORS; +var ITERATOR = wellKnownSymbol('iterator'); +var KEYS = 'keys'; +var VALUES = 'values'; +var ENTRIES = 'entries'; +var returnThis = function () { + return this; +}; +module.exports = function (Iterable, NAME, IteratorConstructor, next, DEFAULT, IS_SET, FORCED) { + createIteratorConstructor(IteratorConstructor, NAME, next); + var getIterationMethod = function (KIND) { + if (KIND === DEFAULT && defaultIterator) + return defaultIterator; + if (!BUGGY_SAFARI_ITERATORS && KIND in IterablePrototype) + return IterablePrototype[KIND]; + switch (KIND) { + case KEYS: + return function keys() { + return new IteratorConstructor(this, KIND); + }; + case VALUES: + return function values() { + return new IteratorConstructor(this, KIND); + }; + case ENTRIES: + return function entries() { + return new IteratorConstructor(this, KIND); + }; + } + return function () { + return new IteratorConstructor(this); + }; + }; + var TO_STRING_TAG = NAME + ' Iterator'; + var INCORRECT_VALUES_NAME = false; + var IterablePrototype = Iterable.prototype; + var nativeIterator = IterablePrototype[ITERATOR] || IterablePrototype['@@iterator'] || DEFAULT && IterablePrototype[DEFAULT]; + var defaultIterator = !BUGGY_SAFARI_ITERATORS && nativeIterator || getIterationMethod(DEFAULT); + var anyNativeIterator = NAME == 'Array' ? IterablePrototype.entries || nativeIterator : nativeIterator; + var CurrentIteratorPrototype, methods, KEY; + if (anyNativeIterator) { + CurrentIteratorPrototype = getPrototypeOf(anyNativeIterator.call(new Iterable())); + if (CurrentIteratorPrototype !== Object.prototype && CurrentIteratorPrototype.next) { + if (!IS_PURE && getPrototypeOf(CurrentIteratorPrototype) !== IteratorPrototype) { + if (setPrototypeOf) { + setPrototypeOf(CurrentIteratorPrototype, IteratorPrototype); + } else if (!isCallable(CurrentIteratorPrototype[ITERATOR])) { + defineBuiltIn(CurrentIteratorPrototype, ITERATOR, returnThis); + } + } + setToStringTag(CurrentIteratorPrototype, TO_STRING_TAG, true, true); + if (IS_PURE) + Iterators[TO_STRING_TAG] = returnThis; + } + } + if (PROPER_FUNCTION_NAME && DEFAULT == VALUES && nativeIterator && nativeIterator.name !== VALUES) { + if (!IS_PURE && CONFIGURABLE_FUNCTION_NAME) { + createNonEnumerableProperty(IterablePrototype, 'name', VALUES); + } else { + INCORRECT_VALUES_NAME = true; + defaultIterator = function values() { + return call(nativeIterator, this); + }; + } + } + if (DEFAULT) { + methods = { + values: getIterationMethod(VALUES), + keys: IS_SET ? defaultIterator : getIterationMethod(KEYS), + entries: getIterationMethod(ENTRIES) + }; + if (FORCED) + for (KEY in methods) { + if (BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME || !(KEY in IterablePrototype)) { + defineBuiltIn(IterablePrototype, KEY, methods[KEY]); + } + } + else + $({ + target: NAME, + proto: true, + forced: BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME + }, methods); + } + if ((!IS_PURE || FORCED) && IterablePrototype[ITERATOR] !== defaultIterator) { + defineBuiltIn(IterablePrototype, ITERATOR, defaultIterator, { name: DEFAULT }); + } + Iterators[NAME] = defaultIterator; + return methods; +}; + +/***/ }), +/* 90 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +"use strict"; + +var IteratorPrototype = (__w_pdfjs_require__(91).IteratorPrototype); +var create = __w_pdfjs_require__(71); +var createPropertyDescriptor = __w_pdfjs_require__(14); +var setToStringTag = __w_pdfjs_require__(92); +var Iterators = __w_pdfjs_require__(88); +var returnThis = function () { + return this; +}; +module.exports = function (IteratorConstructor, NAME, next, ENUMERABLE_NEXT) { + var TO_STRING_TAG = NAME + ' Iterator'; + IteratorConstructor.prototype = create(IteratorPrototype, { next: createPropertyDescriptor(+!ENUMERABLE_NEXT, next) }); + setToStringTag(IteratorConstructor, TO_STRING_TAG, false, true); + Iterators[TO_STRING_TAG] = returnThis; + return IteratorConstructor; +}; + +/***/ }), +/* 91 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +"use strict"; + +var fails = __w_pdfjs_require__(10); +var isCallable = __w_pdfjs_require__(23); +var create = __w_pdfjs_require__(71); +var getPrototypeOf = __w_pdfjs_require__(82); +var defineBuiltIn = __w_pdfjs_require__(49); +var wellKnownSymbol = __w_pdfjs_require__(35); +var IS_PURE = __w_pdfjs_require__(37); +var ITERATOR = wellKnownSymbol('iterator'); +var BUGGY_SAFARI_ITERATORS = false; +var IteratorPrototype, PrototypeOfArrayIteratorPrototype, arrayIterator; +if ([].keys) { + arrayIterator = [].keys(); + if (!('next' in arrayIterator)) + BUGGY_SAFARI_ITERATORS = true; + else { + PrototypeOfArrayIteratorPrototype = getPrototypeOf(getPrototypeOf(arrayIterator)); + if (PrototypeOfArrayIteratorPrototype !== Object.prototype) + IteratorPrototype = PrototypeOfArrayIteratorPrototype; + } +} +var NEW_ITERATOR_PROTOTYPE = IteratorPrototype == undefined || fails(function () { + var test = {}; + return IteratorPrototype[ITERATOR].call(test) !== test; +}); +if (NEW_ITERATOR_PROTOTYPE) + IteratorPrototype = {}; +else if (IS_PURE) + IteratorPrototype = create(IteratorPrototype); +if (!isCallable(IteratorPrototype[ITERATOR])) { + defineBuiltIn(IteratorPrototype, ITERATOR, function () { + return this; + }); +} +module.exports = { + IteratorPrototype: IteratorPrototype, + BUGGY_SAFARI_ITERATORS: BUGGY_SAFARI_ITERATORS +}; + +/***/ }), +/* 92 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var defineProperty = (__w_pdfjs_require__(46).f); +var hasOwn = __w_pdfjs_require__(40); +var wellKnownSymbol = __w_pdfjs_require__(35); +var TO_STRING_TAG = wellKnownSymbol('toStringTag'); +module.exports = function (target, TAG, STATIC) { + if (target && !STATIC) + target = target.prototype; + if (target && !hasOwn(target, TO_STRING_TAG)) { + defineProperty(target, TO_STRING_TAG, { + configurable: true, + value: TAG + }); + } +}; + +/***/ }), +/* 93 */ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var TO_STRING_TAG_SUPPORT = __w_pdfjs_require__(81); +var defineBuiltIn = __w_pdfjs_require__(49); +var toString = __w_pdfjs_require__(94); +if (!TO_STRING_TAG_SUPPORT) { + defineBuiltIn(Object.prototype, 'toString', toString, { unsafe: true }); +} + +/***/ }), +/* 94 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +"use strict"; + +var TO_STRING_TAG_SUPPORT = __w_pdfjs_require__(81); +var classof = __w_pdfjs_require__(80); +module.exports = TO_STRING_TAG_SUPPORT ? {}.toString : function toString() { + return '[object ' + classof(this) + ']'; +}; + +/***/ }), +/* 95 */ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __w_pdfjs_require__) => { + +__w_pdfjs_require__(96); + +/***/ }), +/* 96 */ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __w_pdfjs_require__) => { + +"use strict"; + +var collection = __w_pdfjs_require__(97); +var collectionStrong = __w_pdfjs_require__(114); +collection('Map', function (init) { + return function Map() { + return init(this, arguments.length ? arguments[0] : undefined); + }; +}, collectionStrong); + +/***/ }), +/* 97 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +"use strict"; + +var $ = __w_pdfjs_require__(6); +var global = __w_pdfjs_require__(7); +var uncurryThis = __w_pdfjs_require__(17); +var isForced = __w_pdfjs_require__(69); +var defineBuiltIn = __w_pdfjs_require__(49); +var InternalMetadataModule = __w_pdfjs_require__(98); +var iterate = __w_pdfjs_require__(105); +var anInstance = __w_pdfjs_require__(111); +var isCallable = __w_pdfjs_require__(23); +var isObject = __w_pdfjs_require__(22); +var fails = __w_pdfjs_require__(10); +var checkCorrectnessOfIteration = __w_pdfjs_require__(112); +var setToStringTag = __w_pdfjs_require__(92); +var inheritIfRequired = __w_pdfjs_require__(113); +module.exports = function (CONSTRUCTOR_NAME, wrapper, common) { + var IS_MAP = CONSTRUCTOR_NAME.indexOf('Map') !== -1; + var IS_WEAK = CONSTRUCTOR_NAME.indexOf('Weak') !== -1; + var ADDER = IS_MAP ? 'set' : 'add'; + var NativeConstructor = global[CONSTRUCTOR_NAME]; + var NativePrototype = NativeConstructor && NativeConstructor.prototype; + var Constructor = NativeConstructor; + var exported = {}; + var fixMethod = function (KEY) { + var uncurriedNativeMethod = uncurryThis(NativePrototype[KEY]); + defineBuiltIn(NativePrototype, KEY, KEY == 'add' ? function add(value) { + uncurriedNativeMethod(this, value === 0 ? 0 : value); + return this; + } : KEY == 'delete' ? function (key) { + return IS_WEAK && !isObject(key) ? false : uncurriedNativeMethod(this, key === 0 ? 0 : key); + } : KEY == 'get' ? function get(key) { + return IS_WEAK && !isObject(key) ? undefined : uncurriedNativeMethod(this, key === 0 ? 0 : key); + } : KEY == 'has' ? function has(key) { + return IS_WEAK && !isObject(key) ? false : uncurriedNativeMethod(this, key === 0 ? 0 : key); + } : function set(key, value) { + uncurriedNativeMethod(this, key === 0 ? 0 : key, value); + return this; + }); + }; + var REPLACE = isForced(CONSTRUCTOR_NAME, !isCallable(NativeConstructor) || !(IS_WEAK || NativePrototype.forEach && !fails(function () { + new NativeConstructor().entries().next(); + }))); + if (REPLACE) { + Constructor = common.getConstructor(wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER); + InternalMetadataModule.enable(); + } else if (isForced(CONSTRUCTOR_NAME, true)) { + var instance = new Constructor(); + var HASNT_CHAINING = instance[ADDER](IS_WEAK ? {} : -0, 1) != instance; + var THROWS_ON_PRIMITIVES = fails(function () { + instance.has(1); + }); + var ACCEPT_ITERABLES = checkCorrectnessOfIteration(function (iterable) { + new NativeConstructor(iterable); + }); + var BUGGY_ZERO = !IS_WEAK && fails(function () { + var $instance = new NativeConstructor(); + var index = 5; + while (index--) + $instance[ADDER](index, index); + return !$instance.has(-0); + }); + if (!ACCEPT_ITERABLES) { + Constructor = wrapper(function (dummy, iterable) { + anInstance(dummy, NativePrototype); + var that = inheritIfRequired(new NativeConstructor(), dummy, Constructor); + if (iterable != undefined) + iterate(iterable, that[ADDER], { + that: that, + AS_ENTRIES: IS_MAP + }); + return that; + }); + Constructor.prototype = NativePrototype; + NativePrototype.constructor = Constructor; + } + if (THROWS_ON_PRIMITIVES || BUGGY_ZERO) { + fixMethod('delete'); + fixMethod('has'); + IS_MAP && fixMethod('get'); + } + if (BUGGY_ZERO || HASNT_CHAINING) + fixMethod(ADDER); + if (IS_WEAK && NativePrototype.clear) + delete NativePrototype.clear; + } + exported[CONSTRUCTOR_NAME] = Constructor; + $({ + global: true, + constructor: true, + forced: Constructor != NativeConstructor + }, exported); + setToStringTag(Constructor, CONSTRUCTOR_NAME); + if (!IS_WEAK) + common.setStrong(Constructor, CONSTRUCTOR_NAME, IS_MAP); + return Constructor; +}; + +/***/ }), +/* 98 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var $ = __w_pdfjs_require__(6); +var uncurryThis = __w_pdfjs_require__(17); +var hiddenKeys = __w_pdfjs_require__(56); +var isObject = __w_pdfjs_require__(22); +var hasOwn = __w_pdfjs_require__(40); +var defineProperty = (__w_pdfjs_require__(46).f); +var getOwnPropertyNamesModule = __w_pdfjs_require__(59); +var getOwnPropertyNamesExternalModule = __w_pdfjs_require__(99); +var isExtensible = __w_pdfjs_require__(102); +var uid = __w_pdfjs_require__(42); +var FREEZING = __w_pdfjs_require__(104); +var REQUIRED = false; +var METADATA = uid('meta'); +var id = 0; +var setMetadata = function (it) { + defineProperty(it, METADATA, { + value: { + objectID: 'O' + id++, + weakData: {} + } + }); +}; +var fastKey = function (it, create) { + if (!isObject(it)) + return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it; + if (!hasOwn(it, METADATA)) { + if (!isExtensible(it)) + return 'F'; + if (!create) + return 'E'; + setMetadata(it); + } + return it[METADATA].objectID; +}; +var getWeakData = function (it, create) { + if (!hasOwn(it, METADATA)) { + if (!isExtensible(it)) + return true; + if (!create) + return false; + setMetadata(it); + } + return it[METADATA].weakData; +}; +var onFreeze = function (it) { + if (FREEZING && REQUIRED && isExtensible(it) && !hasOwn(it, METADATA)) + setMetadata(it); + return it; +}; +var enable = function () { + meta.enable = function () { + }; + REQUIRED = true; + var getOwnPropertyNames = getOwnPropertyNamesModule.f; + var splice = uncurryThis([].splice); + var test = {}; + test[METADATA] = 1; + if (getOwnPropertyNames(test).length) { + getOwnPropertyNamesModule.f = function (it) { + var result = getOwnPropertyNames(it); + for (var i = 0, length = result.length; i < length; i++) { + if (result[i] === METADATA) { + splice(result, i, 1); + break; + } + } + return result; + }; + $({ + target: 'Object', + stat: true, + forced: true + }, { getOwnPropertyNames: getOwnPropertyNamesExternalModule.f }); + } +}; +var meta = module.exports = { + enable: enable, + fastKey: fastKey, + getWeakData: getWeakData, + onFreeze: onFreeze +}; +hiddenKeys[METADATA] = true; + +/***/ }), +/* 99 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var classof = __w_pdfjs_require__(18); +var toIndexedObject = __w_pdfjs_require__(15); +var $getOwnPropertyNames = (__w_pdfjs_require__(59).f); +var arraySlice = __w_pdfjs_require__(100); +var windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames ? Object.getOwnPropertyNames(window) : []; +var getWindowNames = function (it) { + try { + return $getOwnPropertyNames(it); + } catch (error) { + return arraySlice(windowNames); + } +}; +module.exports.f = function getOwnPropertyNames(it) { + return windowNames && classof(it) == 'Window' ? getWindowNames(it) : $getOwnPropertyNames(toIndexedObject(it)); +}; + +/***/ }), +/* 100 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var toAbsoluteIndex = __w_pdfjs_require__(62); +var lengthOfArrayLike = __w_pdfjs_require__(65); +var createProperty = __w_pdfjs_require__(101); +var $Array = Array; +var max = Math.max; +module.exports = function (O, start, end) { + var length = lengthOfArrayLike(O); + var k = toAbsoluteIndex(start, length); + var fin = toAbsoluteIndex(end === undefined ? length : end, length); + var result = $Array(max(fin - k, 0)); + for (var n = 0; k < fin; k++, n++) + createProperty(result, n, O[k]); + result.length = n; + return result; +}; + +/***/ }), +/* 101 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +"use strict"; + +var toPropertyKey = __w_pdfjs_require__(20); +var definePropertyModule = __w_pdfjs_require__(46); +var createPropertyDescriptor = __w_pdfjs_require__(14); +module.exports = function (object, key, value) { + var propertyKey = toPropertyKey(key); + if (propertyKey in object) + definePropertyModule.f(object, propertyKey, createPropertyDescriptor(0, value)); + else + object[propertyKey] = value; +}; + +/***/ }), +/* 102 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var fails = __w_pdfjs_require__(10); +var isObject = __w_pdfjs_require__(22); +var classof = __w_pdfjs_require__(18); +var ARRAY_BUFFER_NON_EXTENSIBLE = __w_pdfjs_require__(103); +var $isExtensible = Object.isExtensible; +var FAILS_ON_PRIMITIVES = fails(function () { + $isExtensible(1); +}); +module.exports = FAILS_ON_PRIMITIVES || ARRAY_BUFFER_NON_EXTENSIBLE ? function isExtensible(it) { + if (!isObject(it)) + return false; + if (ARRAY_BUFFER_NON_EXTENSIBLE && classof(it) == 'ArrayBuffer') + return false; + return $isExtensible ? $isExtensible(it) : true; +} : $isExtensible; + +/***/ }), +/* 103 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var fails = __w_pdfjs_require__(10); +module.exports = fails(function () { + if (typeof ArrayBuffer == 'function') { + var buffer = new ArrayBuffer(8); + if (Object.isExtensible(buffer)) + Object.defineProperty(buffer, 'a', { value: 8 }); + } +}); + +/***/ }), +/* 104 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var fails = __w_pdfjs_require__(10); +module.exports = !fails(function () { + return Object.isExtensible(Object.preventExtensions({})); +}); + +/***/ }), +/* 105 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var bind = __w_pdfjs_require__(106); +var call = __w_pdfjs_require__(11); +var anObject = __w_pdfjs_require__(48); +var tryToString = __w_pdfjs_require__(33); +var isArrayIteratorMethod = __w_pdfjs_require__(107); +var lengthOfArrayLike = __w_pdfjs_require__(65); +var isPrototypeOf = __w_pdfjs_require__(26); +var getIterator = __w_pdfjs_require__(108); +var getIteratorMethod = __w_pdfjs_require__(109); +var iteratorClose = __w_pdfjs_require__(110); +var $TypeError = TypeError; +var Result = function (stopped, result) { + this.stopped = stopped; + this.result = result; +}; +var ResultPrototype = Result.prototype; +module.exports = function (iterable, unboundFunction, options) { + var that = options && options.that; + var AS_ENTRIES = !!(options && options.AS_ENTRIES); + var IS_RECORD = !!(options && options.IS_RECORD); + var IS_ITERATOR = !!(options && options.IS_ITERATOR); + var INTERRUPTED = !!(options && options.INTERRUPTED); + var fn = bind(unboundFunction, that); + var iterator, iterFn, index, length, result, next, step; + var stop = function (condition) { + if (iterator) + iteratorClose(iterator, 'normal', condition); + return new Result(true, condition); + }; + var callFn = function (value) { + if (AS_ENTRIES) { + anObject(value); + return INTERRUPTED ? fn(value[0], value[1], stop) : fn(value[0], value[1]); + } + return INTERRUPTED ? fn(value, stop) : fn(value); + }; + if (IS_RECORD) { + iterator = iterable.iterator; + } else if (IS_ITERATOR) { + iterator = iterable; + } else { + iterFn = getIteratorMethod(iterable); + if (!iterFn) + throw $TypeError(tryToString(iterable) + ' is not iterable'); + if (isArrayIteratorMethod(iterFn)) { + for (index = 0, length = lengthOfArrayLike(iterable); length > index; index++) { + result = callFn(iterable[index]); + if (result && isPrototypeOf(ResultPrototype, result)) + return result; + } + return new Result(false); + } + iterator = getIterator(iterable, iterFn); + } + next = IS_RECORD ? iterable.next : iterator.next; + while (!(step = call(next, iterator)).done) { + try { + result = callFn(step.value); + } catch (error) { + iteratorClose(iterator, 'throw', error); + } + if (typeof result == 'object' && result && isPrototypeOf(ResultPrototype, result)) + return result; + } + return new Result(false); +}; + +/***/ }), +/* 106 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var uncurryThis = __w_pdfjs_require__(17); +var aCallable = __w_pdfjs_require__(32); +var NATIVE_BIND = __w_pdfjs_require__(12); +var bind = uncurryThis(uncurryThis.bind); +module.exports = function (fn, that) { + aCallable(fn); + return that === undefined ? fn : NATIVE_BIND ? bind(fn, that) : function () { + return fn.apply(that, arguments); + }; +}; + +/***/ }), +/* 107 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var wellKnownSymbol = __w_pdfjs_require__(35); +var Iterators = __w_pdfjs_require__(88); +var ITERATOR = wellKnownSymbol('iterator'); +var ArrayPrototype = Array.prototype; +module.exports = function (it) { + return it !== undefined && (Iterators.Array === it || ArrayPrototype[ITERATOR] === it); +}; + +/***/ }), +/* 108 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var call = __w_pdfjs_require__(11); +var aCallable = __w_pdfjs_require__(32); +var anObject = __w_pdfjs_require__(48); +var tryToString = __w_pdfjs_require__(33); +var getIteratorMethod = __w_pdfjs_require__(109); +var $TypeError = TypeError; +module.exports = function (argument, usingIterator) { + var iteratorMethod = arguments.length < 2 ? getIteratorMethod(argument) : usingIterator; + if (aCallable(iteratorMethod)) + return anObject(call(iteratorMethod, argument)); + throw $TypeError(tryToString(argument) + ' is not iterable'); +}; + +/***/ }), +/* 109 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var classof = __w_pdfjs_require__(80); +var getMethod = __w_pdfjs_require__(31); +var Iterators = __w_pdfjs_require__(88); +var wellKnownSymbol = __w_pdfjs_require__(35); +var ITERATOR = wellKnownSymbol('iterator'); +module.exports = function (it) { + if (it != undefined) + return getMethod(it, ITERATOR) || getMethod(it, '@@iterator') || Iterators[classof(it)]; +}; + +/***/ }), +/* 110 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var call = __w_pdfjs_require__(11); +var anObject = __w_pdfjs_require__(48); +var getMethod = __w_pdfjs_require__(31); +module.exports = function (iterator, kind, value) { + var innerResult, innerError; + anObject(iterator); + try { + innerResult = getMethod(iterator, 'return'); + if (!innerResult) { + if (kind === 'throw') + throw value; + return value; + } + innerResult = call(innerResult, iterator); + } catch (error) { + innerError = true; + innerResult = error; + } + if (kind === 'throw') + throw value; + if (innerError) + throw innerResult; + anObject(innerResult); + return value; +}; + +/***/ }), +/* 111 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var isPrototypeOf = __w_pdfjs_require__(26); +var $TypeError = TypeError; +module.exports = function (it, Prototype) { + if (isPrototypeOf(Prototype, it)) + return it; + throw $TypeError('Incorrect invocation'); +}; + +/***/ }), +/* 112 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var wellKnownSymbol = __w_pdfjs_require__(35); +var ITERATOR = wellKnownSymbol('iterator'); +var SAFE_CLOSING = false; +try { + var called = 0; + var iteratorWithReturn = { + next: function () { + return { done: !!called++ }; + }, + 'return': function () { + SAFE_CLOSING = true; + } + }; + iteratorWithReturn[ITERATOR] = function () { + return this; + }; + Array.from(iteratorWithReturn, function () { + throw 2; + }); +} catch (error) { +} +module.exports = function (exec, SKIP_CLOSING) { + if (!SKIP_CLOSING && !SAFE_CLOSING) + return false; + var ITERATION_SUPPORT = false; + try { + var object = {}; + object[ITERATOR] = function () { + return { + next: function () { + return { done: ITERATION_SUPPORT = true }; + } + }; + }; + exec(object); + } catch (error) { + } + return ITERATION_SUPPORT; +}; + +/***/ }), +/* 113 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var isCallable = __w_pdfjs_require__(23); +var isObject = __w_pdfjs_require__(22); +var setPrototypeOf = __w_pdfjs_require__(84); +module.exports = function ($this, dummy, Wrapper) { + var NewTarget, NewTargetPrototype; + if (setPrototypeOf && isCallable(NewTarget = dummy.constructor) && NewTarget !== Wrapper && isObject(NewTargetPrototype = NewTarget.prototype) && NewTargetPrototype !== Wrapper.prototype) + setPrototypeOf($this, NewTargetPrototype); + return $this; +}; + +/***/ }), +/* 114 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +"use strict"; + +var defineProperty = (__w_pdfjs_require__(46).f); +var create = __w_pdfjs_require__(71); +var defineBuiltIns = __w_pdfjs_require__(115); +var bind = __w_pdfjs_require__(106); +var anInstance = __w_pdfjs_require__(111); +var iterate = __w_pdfjs_require__(105); +var defineIterator = __w_pdfjs_require__(89); +var setSpecies = __w_pdfjs_require__(116); +var DESCRIPTORS = __w_pdfjs_require__(9); +var fastKey = (__w_pdfjs_require__(98).fastKey); +var InternalStateModule = __w_pdfjs_require__(53); +var setInternalState = InternalStateModule.set; +var internalStateGetterFor = InternalStateModule.getterFor; +module.exports = { + getConstructor: function (wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) { + var Constructor = wrapper(function (that, iterable) { + anInstance(that, Prototype); + setInternalState(that, { + type: CONSTRUCTOR_NAME, + index: create(null), + first: undefined, + last: undefined, + size: 0 + }); + if (!DESCRIPTORS) + that.size = 0; + if (iterable != undefined) + iterate(iterable, that[ADDER], { + that: that, + AS_ENTRIES: IS_MAP + }); + }); + var Prototype = Constructor.prototype; + var getInternalState = internalStateGetterFor(CONSTRUCTOR_NAME); + var define = function (that, key, value) { + var state = getInternalState(that); + var entry = getEntry(that, key); + var previous, index; + if (entry) { + entry.value = value; + } else { + state.last = entry = { + index: index = fastKey(key, true), + key: key, + value: value, + previous: previous = state.last, + next: undefined, + removed: false + }; + if (!state.first) + state.first = entry; + if (previous) + previous.next = entry; + if (DESCRIPTORS) + state.size++; + else + that.size++; + if (index !== 'F') + state.index[index] = entry; + } + return that; + }; + var getEntry = function (that, key) { + var state = getInternalState(that); + var index = fastKey(key); + var entry; + if (index !== 'F') + return state.index[index]; + for (entry = state.first; entry; entry = entry.next) { + if (entry.key == key) + return entry; + } + }; + defineBuiltIns(Prototype, { + clear: function clear() { + var that = this; + var state = getInternalState(that); + var data = state.index; + var entry = state.first; + while (entry) { + entry.removed = true; + if (entry.previous) + entry.previous = entry.previous.next = undefined; + delete data[entry.index]; + entry = entry.next; + } + state.first = state.last = undefined; + if (DESCRIPTORS) + state.size = 0; + else + that.size = 0; + }, + 'delete': function (key) { + var that = this; + var state = getInternalState(that); + var entry = getEntry(that, key); + if (entry) { + var next = entry.next; + var prev = entry.previous; + delete state.index[entry.index]; + entry.removed = true; + if (prev) + prev.next = next; + if (next) + next.previous = prev; + if (state.first == entry) + state.first = next; + if (state.last == entry) + state.last = prev; + if (DESCRIPTORS) + state.size--; + else + that.size--; + } + return !!entry; + }, + forEach: function forEach(callbackfn) { + var state = getInternalState(this); + var boundFunction = bind(callbackfn, arguments.length > 1 ? arguments[1] : undefined); + var entry; + while (entry = entry ? entry.next : state.first) { + boundFunction(entry.value, entry.key, this); + while (entry && entry.removed) + entry = entry.previous; + } + }, + has: function has(key) { + return !!getEntry(this, key); + } + }); + defineBuiltIns(Prototype, IS_MAP ? { + get: function get(key) { + var entry = getEntry(this, key); + return entry && entry.value; + }, + set: function set(key, value) { + return define(this, key === 0 ? 0 : key, value); + } + } : { + add: function add(value) { + return define(this, value = value === 0 ? 0 : value, value); + } + }); + if (DESCRIPTORS) + defineProperty(Prototype, 'size', { + get: function () { + return getInternalState(this).size; + } + }); + return Constructor; + }, + setStrong: function (Constructor, CONSTRUCTOR_NAME, IS_MAP) { + var ITERATOR_NAME = CONSTRUCTOR_NAME + ' Iterator'; + var getInternalCollectionState = internalStateGetterFor(CONSTRUCTOR_NAME); + var getInternalIteratorState = internalStateGetterFor(ITERATOR_NAME); + defineIterator(Constructor, CONSTRUCTOR_NAME, function (iterated, kind) { + setInternalState(this, { + type: ITERATOR_NAME, + target: iterated, + state: getInternalCollectionState(iterated), + kind: kind, + last: undefined + }); + }, function () { + var state = getInternalIteratorState(this); + var kind = state.kind; + var entry = state.last; + while (entry && entry.removed) + entry = entry.previous; + if (!state.target || !(state.last = entry = entry ? entry.next : state.state.first)) { + state.target = undefined; + return { + value: undefined, + done: true + }; + } + if (kind == 'keys') + return { + value: entry.key, + done: false + }; + if (kind == 'values') + return { + value: entry.value, + done: false + }; + return { + value: [ + entry.key, + entry.value + ], + done: false + }; + }, IS_MAP ? 'entries' : 'values', !IS_MAP, true); + setSpecies(CONSTRUCTOR_NAME); + } +}; + +/***/ }), +/* 115 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var defineBuiltIn = __w_pdfjs_require__(49); +module.exports = function (target, src, options) { + for (var key in src) + defineBuiltIn(target, key, src[key], options); + return target; +}; + +/***/ }), +/* 116 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +"use strict"; + +var getBuiltIn = __w_pdfjs_require__(25); +var definePropertyModule = __w_pdfjs_require__(46); +var wellKnownSymbol = __w_pdfjs_require__(35); +var DESCRIPTORS = __w_pdfjs_require__(9); +var SPECIES = wellKnownSymbol('species'); +module.exports = function (CONSTRUCTOR_NAME) { + var Constructor = getBuiltIn(CONSTRUCTOR_NAME); + var defineProperty = definePropertyModule.f; + if (DESCRIPTORS && Constructor && !Constructor[SPECIES]) { + defineProperty(Constructor, SPECIES, { + configurable: true, + get: function () { + return this; + } + }); + } +}; + +/***/ }), +/* 117 */ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __w_pdfjs_require__) => { + +__w_pdfjs_require__(118); + +/***/ }), +/* 118 */ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __w_pdfjs_require__) => { + +"use strict"; + +var collection = __w_pdfjs_require__(97); +var collectionStrong = __w_pdfjs_require__(114); +collection('Set', function (init) { + return function Set() { + return init(this, arguments.length ? arguments[0] : undefined); + }; +}, collectionStrong); + +/***/ }), +/* 119 */ +/***/ ((__unused_webpack_module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var IS_PURE = __w_pdfjs_require__(37); +var $ = __w_pdfjs_require__(6); +var global = __w_pdfjs_require__(7); +var getBuiltin = __w_pdfjs_require__(25); +var uncurryThis = __w_pdfjs_require__(17); +var fails = __w_pdfjs_require__(10); +var uid = __w_pdfjs_require__(42); +var isCallable = __w_pdfjs_require__(23); +var isConstructor = __w_pdfjs_require__(120); +var isObject = __w_pdfjs_require__(22); +var isSymbol = __w_pdfjs_require__(24); +var iterate = __w_pdfjs_require__(105); +var anObject = __w_pdfjs_require__(48); +var classof = __w_pdfjs_require__(80); +var hasOwn = __w_pdfjs_require__(40); +var createProperty = __w_pdfjs_require__(101); +var createNonEnumerableProperty = __w_pdfjs_require__(45); +var lengthOfArrayLike = __w_pdfjs_require__(65); +var validateArgumentsLength = __w_pdfjs_require__(121); +var getRegExpFlags = __w_pdfjs_require__(122); +var ERROR_STACK_INSTALLABLE = __w_pdfjs_require__(124); +var V8 = __w_pdfjs_require__(29); +var IS_BROWSER = __w_pdfjs_require__(125); +var IS_DENO = __w_pdfjs_require__(126); +var IS_NODE = __w_pdfjs_require__(127); +var Object = global.Object; +var Date = global.Date; +var Error = global.Error; +var EvalError = global.EvalError; +var RangeError = global.RangeError; +var ReferenceError = global.ReferenceError; +var SyntaxError = global.SyntaxError; +var TypeError = global.TypeError; +var URIError = global.URIError; +var PerformanceMark = global.PerformanceMark; +var WebAssembly = global.WebAssembly; +var CompileError = WebAssembly && WebAssembly.CompileError || Error; +var LinkError = WebAssembly && WebAssembly.LinkError || Error; +var RuntimeError = WebAssembly && WebAssembly.RuntimeError || Error; +var DOMException = getBuiltin('DOMException'); +var Set = getBuiltin('Set'); +var Map = getBuiltin('Map'); +var MapPrototype = Map.prototype; +var mapHas = uncurryThis(MapPrototype.has); +var mapGet = uncurryThis(MapPrototype.get); +var mapSet = uncurryThis(MapPrototype.set); +var setAdd = uncurryThis(Set.prototype.add); +var objectKeys = getBuiltin('Object', 'keys'); +var push = uncurryThis([].push); +var booleanValueOf = uncurryThis(true.valueOf); +var numberValueOf = uncurryThis(1.0.valueOf); +var stringValueOf = uncurryThis(''.valueOf); +var getTime = uncurryThis(Date.prototype.getTime); +var PERFORMANCE_MARK = uid('structuredClone'); +var DATA_CLONE_ERROR = 'DataCloneError'; +var TRANSFERRING = 'Transferring'; +var checkBasicSemantic = function (structuredCloneImplementation) { + return !fails(function () { + var set1 = new global.Set([7]); + var set2 = structuredCloneImplementation(set1); + var number = structuredCloneImplementation(Object(7)); + return set2 == set1 || !set2.has(7) || typeof number != 'object' || number != 7; + }) && structuredCloneImplementation; +}; +var checkErrorsCloning = function (structuredCloneImplementation, $Error) { + return !fails(function () { + var error = new $Error(); + var test = structuredCloneImplementation({ + a: error, + b: error + }); + return !(test && test.a === test.b && test.a instanceof $Error && test.a.stack === error.stack); + }); +}; +var checkNewErrorsCloningSemantic = function (structuredCloneImplementation) { + return !fails(function () { + var test = structuredCloneImplementation(new global.AggregateError([1], PERFORMANCE_MARK, { cause: 3 })); + return test.name != 'AggregateError' || test.errors[0] != 1 || test.message != PERFORMANCE_MARK || test.cause != 3; + }); +}; +var nativeStructuredClone = global.structuredClone; +var FORCED_REPLACEMENT = IS_PURE || !checkErrorsCloning(nativeStructuredClone, Error) || !checkErrorsCloning(nativeStructuredClone, DOMException) || !checkNewErrorsCloningSemantic(nativeStructuredClone); +var structuredCloneFromMark = !nativeStructuredClone && checkBasicSemantic(function (value) { + return new PerformanceMark(PERFORMANCE_MARK, { detail: value }).detail; +}); +var nativeRestrictedStructuredClone = checkBasicSemantic(nativeStructuredClone) || structuredCloneFromMark; +var throwUncloneable = function (type) { + throw new DOMException('Uncloneable type: ' + type, DATA_CLONE_ERROR); +}; +var throwUnpolyfillable = function (type, kind) { + throw new DOMException((kind || 'Cloning') + ' of ' + type + ' cannot be properly polyfilled in this engine', DATA_CLONE_ERROR); +}; +var structuredCloneInternal = function (value, map) { + if (isSymbol(value)) + throwUncloneable('Symbol'); + if (!isObject(value)) + return value; + if (map) { + if (mapHas(map, value)) + return mapGet(map, value); + } else + map = new Map(); + var type = classof(value); + var deep = false; + var C, name, cloned, dataTransfer, i, length, keys, key, source, target; + switch (type) { + case 'Array': + cloned = []; + deep = true; + break; + case 'Object': + cloned = {}; + deep = true; + break; + case 'Map': + cloned = new Map(); + deep = true; + break; + case 'Set': + cloned = new Set(); + deep = true; + break; + case 'RegExp': + cloned = new RegExp(value.source, getRegExpFlags(value)); + break; + case 'Error': + name = value.name; + switch (name) { + case 'AggregateError': + cloned = getBuiltin('AggregateError')([]); + break; + case 'EvalError': + cloned = EvalError(); + break; + case 'RangeError': + cloned = RangeError(); + break; + case 'ReferenceError': + cloned = ReferenceError(); + break; + case 'SyntaxError': + cloned = SyntaxError(); + break; + case 'TypeError': + cloned = TypeError(); + break; + case 'URIError': + cloned = URIError(); + break; + case 'CompileError': + cloned = CompileError(); + break; + case 'LinkError': + cloned = LinkError(); + break; + case 'RuntimeError': + cloned = RuntimeError(); + break; + default: + cloned = Error(); + } + deep = true; + break; + case 'DOMException': + cloned = new DOMException(value.message, value.name); + deep = true; + break; + case 'DataView': + case 'Int8Array': + case 'Uint8Array': + case 'Uint8ClampedArray': + case 'Int16Array': + case 'Uint16Array': + case 'Int32Array': + case 'Uint32Array': + case 'Float32Array': + case 'Float64Array': + case 'BigInt64Array': + case 'BigUint64Array': + C = global[type]; + if (!isObject(C)) + throwUnpolyfillable(type); + cloned = new C(structuredCloneInternal(value.buffer, map), value.byteOffset, type === 'DataView' ? value.byteLength : value.length); + break; + case 'DOMQuad': + try { + cloned = new DOMQuad(structuredCloneInternal(value.p1, map), structuredCloneInternal(value.p2, map), structuredCloneInternal(value.p3, map), structuredCloneInternal(value.p4, map)); + } catch (error) { + if (nativeRestrictedStructuredClone) { + cloned = nativeRestrictedStructuredClone(value); + } else + throwUnpolyfillable(type); + } + break; + case 'FileList': + C = global.DataTransfer; + if (isConstructor(C)) { + dataTransfer = new C(); + for (i = 0, length = lengthOfArrayLike(value); i < length; i++) { + dataTransfer.items.add(structuredCloneInternal(value[i], map)); + } + cloned = dataTransfer.files; + } else if (nativeRestrictedStructuredClone) { + cloned = nativeRestrictedStructuredClone(value); + } else + throwUnpolyfillable(type); + break; + case 'ImageData': + try { + cloned = new ImageData(structuredCloneInternal(value.data, map), value.width, value.height, { colorSpace: value.colorSpace }); + } catch (error) { + if (nativeRestrictedStructuredClone) { + cloned = nativeRestrictedStructuredClone(value); + } else + throwUnpolyfillable(type); + } + break; + default: + if (nativeRestrictedStructuredClone) { + cloned = nativeRestrictedStructuredClone(value); + } else + switch (type) { + case 'BigInt': + cloned = Object(value.valueOf()); + break; + case 'Boolean': + cloned = Object(booleanValueOf(value)); + break; + case 'Number': + cloned = Object(numberValueOf(value)); + break; + case 'String': + cloned = Object(stringValueOf(value)); + break; + case 'Date': + cloned = new Date(getTime(value)); + break; + case 'ArrayBuffer': + C = global.DataView; + if (!C && typeof value.slice != 'function') + throwUnpolyfillable(type); + try { + if (typeof value.slice == 'function') { + cloned = value.slice(0); + } else { + length = value.byteLength; + cloned = new ArrayBuffer(length); + source = new C(value); + target = new C(cloned); + for (i = 0; i < length; i++) { + target.setUint8(i, source.getUint8(i)); + } + } + } catch (error) { + throw new DOMException('ArrayBuffer is detached', DATA_CLONE_ERROR); + } + break; + case 'SharedArrayBuffer': + cloned = value; + break; + case 'Blob': + try { + cloned = value.slice(0, value.size, value.type); + } catch (error) { + throwUnpolyfillable(type); + } + break; + case 'DOMPoint': + case 'DOMPointReadOnly': + C = global[type]; + try { + cloned = C.fromPoint ? C.fromPoint(value) : new C(value.x, value.y, value.z, value.w); + } catch (error) { + throwUnpolyfillable(type); + } + break; + case 'DOMRect': + case 'DOMRectReadOnly': + C = global[type]; + try { + cloned = C.fromRect ? C.fromRect(value) : new C(value.x, value.y, value.width, value.height); + } catch (error) { + throwUnpolyfillable(type); + } + break; + case 'DOMMatrix': + case 'DOMMatrixReadOnly': + C = global[type]; + try { + cloned = C.fromMatrix ? C.fromMatrix(value) : new C(value); + } catch (error) { + throwUnpolyfillable(type); + } + break; + case 'AudioData': + case 'VideoFrame': + if (!isCallable(value.clone)) + throwUnpolyfillable(type); + try { + cloned = value.clone(); + } catch (error) { + throwUncloneable(type); + } + break; + case 'File': + try { + cloned = new File([value], value.name, value); + } catch (error) { + throwUnpolyfillable(type); + } + break; + case 'CryptoKey': + case 'GPUCompilationMessage': + case 'GPUCompilationInfo': + case 'ImageBitmap': + case 'RTCCertificate': + case 'WebAssembly.Module': + throwUnpolyfillable(type); + default: + throwUncloneable(type); + } + } + mapSet(map, value, cloned); + if (deep) + switch (type) { + case 'Array': + case 'Object': + keys = objectKeys(value); + for (i = 0, length = lengthOfArrayLike(keys); i < length; i++) { + key = keys[i]; + createProperty(cloned, key, structuredCloneInternal(value[key], map)); + } + break; + case 'Map': + value.forEach(function (v, k) { + mapSet(cloned, structuredCloneInternal(k, map), structuredCloneInternal(v, map)); + }); + break; + case 'Set': + value.forEach(function (v) { + setAdd(cloned, structuredCloneInternal(v, map)); + }); + break; + case 'Error': + createNonEnumerableProperty(cloned, 'message', structuredCloneInternal(value.message, map)); + if (hasOwn(value, 'cause')) { + createNonEnumerableProperty(cloned, 'cause', structuredCloneInternal(value.cause, map)); + } + if (name == 'AggregateError') { + cloned.errors = structuredCloneInternal(value.errors, map); + } + case 'DOMException': + if (ERROR_STACK_INSTALLABLE) { + createNonEnumerableProperty(cloned, 'stack', structuredCloneInternal(value.stack, map)); + } + } + return cloned; +}; +var PROPER_TRANSFER = nativeStructuredClone && !fails(function () { + if (IS_DENO && V8 > 92 || IS_NODE && V8 > 94 || IS_BROWSER && V8 > 97) + return false; + var buffer = new ArrayBuffer(8); + var clone = nativeStructuredClone(buffer, { transfer: [buffer] }); + return buffer.byteLength != 0 || clone.byteLength != 8; +}); +var tryToTransfer = function (rawTransfer, map) { + if (!isObject(rawTransfer)) + throw TypeError('Transfer option cannot be converted to a sequence'); + var transfer = []; + iterate(rawTransfer, function (value) { + push(transfer, anObject(value)); + }); + var i = 0; + var length = lengthOfArrayLike(transfer); + var value, type, C, transferredArray, transferred, canvas, context; + if (PROPER_TRANSFER) { + transferredArray = nativeStructuredClone(transfer, { transfer: transfer }); + while (i < length) + mapSet(map, transfer[i], transferredArray[i++]); + } else + while (i < length) { + value = transfer[i++]; + if (mapHas(map, value)) + throw new DOMException('Duplicate transferable', DATA_CLONE_ERROR); + type = classof(value); + switch (type) { + case 'ImageBitmap': + C = global.OffscreenCanvas; + if (!isConstructor(C)) + throwUnpolyfillable(type, TRANSFERRING); + try { + canvas = new C(value.width, value.height); + context = canvas.getContext('bitmaprenderer'); + context.transferFromImageBitmap(value); + transferred = canvas.transferToImageBitmap(); + } catch (error) { + } + break; + case 'AudioData': + case 'VideoFrame': + if (!isCallable(value.clone) || !isCallable(value.close)) + throwUnpolyfillable(type, TRANSFERRING); + try { + transferred = value.clone(); + value.close(); + } catch (error) { + } + break; + case 'ArrayBuffer': + case 'MessagePort': + case 'OffscreenCanvas': + case 'ReadableStream': + case 'TransformStream': + case 'WritableStream': + throwUnpolyfillable(type, TRANSFERRING); + } + if (transferred === undefined) + throw new DOMException('This object cannot be transferred: ' + type, DATA_CLONE_ERROR); + mapSet(map, value, transferred); + } +}; +$({ + global: true, + enumerable: true, + sham: !PROPER_TRANSFER, + forced: FORCED_REPLACEMENT +}, { + structuredClone: function structuredClone(value) { + var options = validateArgumentsLength(arguments.length, 1) > 1 && arguments[1] != null ? anObject(arguments[1]) : undefined; + var transfer = options ? options.transfer : undefined; + var map; + if (transfer !== undefined) { + map = new Map(); + tryToTransfer(transfer, map); + } + return structuredCloneInternal(value, map); + } +}); + +/***/ }), +/* 120 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var uncurryThis = __w_pdfjs_require__(17); +var fails = __w_pdfjs_require__(10); +var isCallable = __w_pdfjs_require__(23); +var classof = __w_pdfjs_require__(80); +var getBuiltIn = __w_pdfjs_require__(25); +var inspectSource = __w_pdfjs_require__(52); +var noop = function () { +}; +var empty = []; +var construct = getBuiltIn('Reflect', 'construct'); +var constructorRegExp = /^\s*(?:class|function)\b/; +var exec = uncurryThis(constructorRegExp.exec); +var INCORRECT_TO_STRING = !constructorRegExp.exec(noop); +var isConstructorModern = function isConstructor(argument) { + if (!isCallable(argument)) + return false; + try { + construct(noop, empty, argument); + return true; + } catch (error) { + return false; + } +}; +var isConstructorLegacy = function isConstructor(argument) { + if (!isCallable(argument)) + return false; + switch (classof(argument)) { + case 'AsyncFunction': + case 'GeneratorFunction': + case 'AsyncGeneratorFunction': + return false; + } + try { + return INCORRECT_TO_STRING || !!exec(constructorRegExp, inspectSource(argument)); + } catch (error) { + return true; + } +}; +isConstructorLegacy.sham = true; +module.exports = !construct || fails(function () { + var called; + return isConstructorModern(isConstructorModern.call) || !isConstructorModern(Object) || !isConstructorModern(function () { + called = true; + }) || called; +}) ? isConstructorLegacy : isConstructorModern; + +/***/ }), +/* 121 */ +/***/ ((module) => { + +var $TypeError = TypeError; +module.exports = function (passed, required) { + if (passed < required) + throw $TypeError('Not enough arguments'); + return passed; +}; + +/***/ }), +/* 122 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var call = __w_pdfjs_require__(11); +var hasOwn = __w_pdfjs_require__(40); +var isPrototypeOf = __w_pdfjs_require__(26); +var regExpFlags = __w_pdfjs_require__(123); +var RegExpPrototype = RegExp.prototype; +module.exports = function (R) { + var flags = R.flags; + return flags === undefined && !('flags' in RegExpPrototype) && !hasOwn(R, 'flags') && isPrototypeOf(RegExpPrototype, R) ? call(regExpFlags, R) : flags; +}; + +/***/ }), +/* 123 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +"use strict"; + +var anObject = __w_pdfjs_require__(48); +module.exports = function () { + var that = anObject(this); + var result = ''; + if (that.hasIndices) + result += 'd'; + if (that.global) + result += 'g'; + if (that.ignoreCase) + result += 'i'; + if (that.multiline) + result += 'm'; + if (that.dotAll) + result += 's'; + if (that.unicode) + result += 'u'; + if (that.unicodeSets) + result += 'v'; + if (that.sticky) + result += 'y'; + return result; +}; + +/***/ }), +/* 124 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var fails = __w_pdfjs_require__(10); +var createPropertyDescriptor = __w_pdfjs_require__(14); +module.exports = !fails(function () { + var error = Error('a'); + if (!('stack' in error)) + return true; + Object.defineProperty(error, 'stack', createPropertyDescriptor(1, 7)); + return error.stack !== 7; +}); + +/***/ }), +/* 125 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var IS_DENO = __w_pdfjs_require__(126); +var IS_NODE = __w_pdfjs_require__(127); +module.exports = !IS_DENO && !IS_NODE && typeof window == 'object' && typeof document == 'object'; + +/***/ }), +/* 126 */ +/***/ ((module) => { + +module.exports = typeof Deno == 'object' && Deno && typeof Deno.version == 'object'; + +/***/ }), +/* 127 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var classof = __w_pdfjs_require__(18); +var global = __w_pdfjs_require__(7); +module.exports = classof(global.process) == 'process'; + +/***/ }), +/* 128 */ +/***/ ((module, __unused_webpack_exports, __w_pdfjs_require__) => { + +var global = __w_pdfjs_require__(7); +module.exports = global; + +/***/ }), +/* 129 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.build = exports.RenderTask = exports.PDFWorkerUtil = exports.PDFWorker = exports.PDFPageProxy = exports.PDFDocumentProxy = exports.PDFDocumentLoadingTask = exports.PDFDataRangeTransport = exports.LoopbackPort = exports.DefaultStandardFontDataFactory = exports.DefaultCanvasFactory = exports.DefaultCMapReaderFactory = void 0; +exports.getDocument = getDocument; +exports.setPDFNetworkStreamFactory = setPDFNetworkStreamFactory; +exports.version = void 0; + +var _util = __w_pdfjs_require__(1); + +var _annotation_storage = __w_pdfjs_require__(130); + +var _display_utils = __w_pdfjs_require__(133); + +var _font_loader = __w_pdfjs_require__(136); + +var _canvas = __w_pdfjs_require__(137); + +var _worker_options = __w_pdfjs_require__(140); + +var _is_node = __w_pdfjs_require__(3); + +var _message_handler = __w_pdfjs_require__(141); + +var _metadata = __w_pdfjs_require__(142); + +var _optional_content_config = __w_pdfjs_require__(143); + +var _transport_stream = __w_pdfjs_require__(144); + +var _xfa_text = __w_pdfjs_require__(145); + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } + +function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } + +function _classStaticPrivateFieldSpecSet(receiver, classConstructor, descriptor, value) { _classCheckPrivateStaticAccess(receiver, classConstructor); _classCheckPrivateStaticFieldDescriptor(descriptor, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } + +function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } + +function _classStaticPrivateFieldSpecGet(receiver, classConstructor, descriptor) { _classCheckPrivateStaticAccess(receiver, classConstructor); _classCheckPrivateStaticFieldDescriptor(descriptor, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classCheckPrivateStaticFieldDescriptor(descriptor, action) { if (descriptor === undefined) { throw new TypeError("attempted to " + action + " private static field before its declaration"); } } + +function _classCheckPrivateStaticAccess(receiver, classConstructor) { if (receiver !== classConstructor) { throw new TypeError("Private static access of wrong provenance"); } } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +const DEFAULT_RANGE_CHUNK_SIZE = 65536; +const RENDERING_CANCELLED_TIMEOUT = 100; +let DefaultCanvasFactory = _display_utils.DOMCanvasFactory; +exports.DefaultCanvasFactory = DefaultCanvasFactory; +let DefaultCMapReaderFactory = _display_utils.DOMCMapReaderFactory; +exports.DefaultCMapReaderFactory = DefaultCMapReaderFactory; +let DefaultStandardFontDataFactory = _display_utils.DOMStandardFontDataFactory; +exports.DefaultStandardFontDataFactory = DefaultStandardFontDataFactory; + +if (_is_node.isNodeJS) { + const { + NodeCanvasFactory, + NodeCMapReaderFactory, + NodeStandardFontDataFactory + } = __w_pdfjs_require__(146); + + exports.DefaultCanvasFactory = DefaultCanvasFactory = NodeCanvasFactory; + exports.DefaultCMapReaderFactory = DefaultCMapReaderFactory = NodeCMapReaderFactory; + exports.DefaultStandardFontDataFactory = DefaultStandardFontDataFactory = NodeStandardFontDataFactory; +} + +let createPDFNetworkStream; + +function setPDFNetworkStreamFactory(pdfNetworkStreamFactory) { + createPDFNetworkStream = pdfNetworkStreamFactory; +} + +function getDocument(src) { + const task = new PDFDocumentLoadingTask(); + let source; + + if (typeof src === "string" || src instanceof URL) { + source = { + url: src + }; + } else if ((0, _util.isArrayBuffer)(src)) { + source = { + data: src + }; + } else if (src instanceof PDFDataRangeTransport) { + source = { + range: src + }; + } else { + if (typeof src !== "object") { + throw new Error("Invalid parameter in getDocument, " + "need either string, URL, TypedArray, or parameter object."); + } + + if (!src.url && !src.data && !src.range) { + throw new Error("Invalid parameter object: need either .data, .range or .url"); + } + + source = src; + } + + const params = Object.create(null); + let rangeTransport = null, + worker = null; + + for (const key in source) { + const value = source[key]; + + switch (key) { + case "url": + if (typeof window !== "undefined") { + try { + params[key] = new URL(value, window.location).href; + continue; + } catch (ex) { + (0, _util.warn)(`Cannot create valid URL: "${ex}".`); + } + } else if (typeof value === "string" || value instanceof URL) { + params[key] = value.toString(); + continue; + } + + throw new Error("Invalid PDF url data: " + "either string or URL-object is expected in the url property."); + + case "range": + rangeTransport = value; + continue; + + case "worker": + worker = value; + continue; + + case "data": + if (_is_node.isNodeJS && typeof Buffer !== "undefined" && value instanceof Buffer) { + params[key] = new Uint8Array(value); + } else if (value instanceof Uint8Array) { + break; + } else if (typeof value === "string") { + params[key] = (0, _util.stringToBytes)(value); + } else if (typeof value === "object" && value !== null && !isNaN(value.length)) { + params[key] = new Uint8Array(value); + } else if ((0, _util.isArrayBuffer)(value)) { + params[key] = new Uint8Array(value); + } else { + throw new Error("Invalid PDF binary data: either TypedArray, " + "string, or array-like object is expected in the data property."); + } + + continue; + } + + params[key] = value; + } + + params.CMapReaderFactory = params.CMapReaderFactory || DefaultCMapReaderFactory; + params.StandardFontDataFactory = params.StandardFontDataFactory || DefaultStandardFontDataFactory; + params.ignoreErrors = params.stopAtErrors !== true; + params.fontExtraProperties = params.fontExtraProperties === true; + params.pdfBug = params.pdfBug === true; + params.enableXfa = params.enableXfa === true; + + if (!Number.isInteger(params.rangeChunkSize) || params.rangeChunkSize < 1) { + params.rangeChunkSize = DEFAULT_RANGE_CHUNK_SIZE; + } + + if (typeof params.docBaseUrl !== "string" || (0, _display_utils.isDataScheme)(params.docBaseUrl)) { + params.docBaseUrl = null; + } + + if (!Number.isInteger(params.maxImageSize) || params.maxImageSize < -1) { + params.maxImageSize = -1; + } + + if (typeof params.cMapUrl !== "string") { + params.cMapUrl = null; + } + + if (typeof params.standardFontDataUrl !== "string") { + params.standardFontDataUrl = null; + } + + if (typeof params.useWorkerFetch !== "boolean") { + params.useWorkerFetch = params.CMapReaderFactory === _display_utils.DOMCMapReaderFactory && params.StandardFontDataFactory === _display_utils.DOMStandardFontDataFactory; + } + + if (typeof params.isEvalSupported !== "boolean") { + params.isEvalSupported = true; + } + + if (typeof params.disableFontFace !== "boolean") { + params.disableFontFace = _is_node.isNodeJS; + } + + if (typeof params.useSystemFonts !== "boolean") { + params.useSystemFonts = !_is_node.isNodeJS && !params.disableFontFace; + } + + if (typeof params.ownerDocument !== "object" || params.ownerDocument === null) { + params.ownerDocument = globalThis.document; + } + + if (typeof params.disableRange !== "boolean") { + params.disableRange = false; + } + + if (typeof params.disableStream !== "boolean") { + params.disableStream = false; + } + + if (typeof params.disableAutoFetch !== "boolean") { + params.disableAutoFetch = false; + } + + (0, _util.setVerbosityLevel)(params.verbosity); + + if (!worker) { + const workerParams = { + verbosity: params.verbosity, + port: _worker_options.GlobalWorkerOptions.workerPort + }; + worker = workerParams.port ? PDFWorker.fromPort(workerParams) : new PDFWorker(workerParams); + task._worker = worker; + } + + const docId = task.docId; + worker.promise.then(function () { + if (task.destroyed) { + throw new Error("Loading aborted"); + } + + const workerIdPromise = _fetchDocument(worker, params, rangeTransport, docId); + + const networkStreamPromise = new Promise(function (resolve) { + let networkStream; + + if (rangeTransport) { + networkStream = new _transport_stream.PDFDataTransportStream({ + length: params.length, + initialData: params.initialData, + progressiveDone: params.progressiveDone, + contentDispositionFilename: params.contentDispositionFilename, + disableRange: params.disableRange, + disableStream: params.disableStream + }, rangeTransport); + } else if (!params.data) { + networkStream = createPDFNetworkStream({ + url: params.url, + length: params.length, + httpHeaders: params.httpHeaders, + withCredentials: params.withCredentials, + rangeChunkSize: params.rangeChunkSize, + disableRange: params.disableRange, + disableStream: params.disableStream + }); + } + + resolve(networkStream); + }); + return Promise.all([workerIdPromise, networkStreamPromise]).then(function (_ref) { + let [workerId, networkStream] = _ref; + + if (task.destroyed) { + throw new Error("Loading aborted"); + } + + const messageHandler = new _message_handler.MessageHandler(docId, workerId, worker.port); + const transport = new WorkerTransport(messageHandler, task, networkStream, params); + task._transport = transport; + messageHandler.send("Ready", null); + }); + }).catch(task._capability.reject); + return task; +} + +async function _fetchDocument(worker, source, pdfDataRangeTransport, docId) { + if (worker.destroyed) { + throw new Error("Worker was destroyed"); + } + + if (pdfDataRangeTransport) { + source.length = pdfDataRangeTransport.length; + source.initialData = pdfDataRangeTransport.initialData; + source.progressiveDone = pdfDataRangeTransport.progressiveDone; + source.contentDispositionFilename = pdfDataRangeTransport.contentDispositionFilename; + } + + const workerId = await worker.messageHandler.sendWithPromise("GetDocRequest", { + docId, + apiVersion: '2.16.105', + source: { + data: source.data, + url: source.url, + password: source.password, + disableAutoFetch: source.disableAutoFetch, + rangeChunkSize: source.rangeChunkSize, + length: source.length + }, + maxImageSize: source.maxImageSize, + disableFontFace: source.disableFontFace, + docBaseUrl: source.docBaseUrl, + ignoreErrors: source.ignoreErrors, + isEvalSupported: source.isEvalSupported, + fontExtraProperties: source.fontExtraProperties, + enableXfa: source.enableXfa, + useSystemFonts: source.useSystemFonts, + cMapUrl: source.useWorkerFetch ? source.cMapUrl : null, + standardFontDataUrl: source.useWorkerFetch ? source.standardFontDataUrl : null + }); + + if (source.data) { + source.data = null; + } + + if (worker.destroyed) { + throw new Error("Worker was destroyed"); + } + + return workerId; +} + +class PDFDocumentLoadingTask { + constructor() { + var _PDFDocumentLoadingTa, _PDFDocumentLoadingTa2; + + this._capability = (0, _util.createPromiseCapability)(); + this._transport = null; + this._worker = null; + this.docId = `d${(_classStaticPrivateFieldSpecSet(PDFDocumentLoadingTask, PDFDocumentLoadingTask, _docId, (_PDFDocumentLoadingTa = _classStaticPrivateFieldSpecGet(PDFDocumentLoadingTask, PDFDocumentLoadingTask, _docId), _PDFDocumentLoadingTa2 = _PDFDocumentLoadingTa++, _PDFDocumentLoadingTa)), _PDFDocumentLoadingTa2)}`; + this.destroyed = false; + this.onPassword = null; + this.onProgress = null; + this.onUnsupportedFeature = null; + } + + get promise() { + return this._capability.promise; + } + + async destroy() { + var _this$_transport; + + this.destroyed = true; + await ((_this$_transport = this._transport) === null || _this$_transport === void 0 ? void 0 : _this$_transport.destroy()); + this._transport = null; + + if (this._worker) { + this._worker.destroy(); + + this._worker = null; + } + } + +} + +exports.PDFDocumentLoadingTask = PDFDocumentLoadingTask; +var _docId = { + writable: true, + value: 0 +}; + +class PDFDataRangeTransport { + constructor(length, initialData) { + let progressiveDone = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + let contentDispositionFilename = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; + this.length = length; + this.initialData = initialData; + this.progressiveDone = progressiveDone; + this.contentDispositionFilename = contentDispositionFilename; + this._rangeListeners = []; + this._progressListeners = []; + this._progressiveReadListeners = []; + this._progressiveDoneListeners = []; + this._readyCapability = (0, _util.createPromiseCapability)(); + } + + addRangeListener(listener) { + this._rangeListeners.push(listener); + } + + addProgressListener(listener) { + this._progressListeners.push(listener); + } + + addProgressiveReadListener(listener) { + this._progressiveReadListeners.push(listener); + } + + addProgressiveDoneListener(listener) { + this._progressiveDoneListeners.push(listener); + } + + onDataRange(begin, chunk) { + for (const listener of this._rangeListeners) { + listener(begin, chunk); + } + } + + onDataProgress(loaded, total) { + this._readyCapability.promise.then(() => { + for (const listener of this._progressListeners) { + listener(loaded, total); + } + }); + } + + onDataProgressiveRead(chunk) { + this._readyCapability.promise.then(() => { + for (const listener of this._progressiveReadListeners) { + listener(chunk); + } + }); + } + + onDataProgressiveDone() { + this._readyCapability.promise.then(() => { + for (const listener of this._progressiveDoneListeners) { + listener(); + } + }); + } + + transportReady() { + this._readyCapability.resolve(); + } + + requestDataRange(begin, end) { + (0, _util.unreachable)("Abstract method PDFDataRangeTransport.requestDataRange"); + } + + abort() {} + +} + +exports.PDFDataRangeTransport = PDFDataRangeTransport; + +class PDFDocumentProxy { + constructor(pdfInfo, transport) { + this._pdfInfo = pdfInfo; + this._transport = transport; + Object.defineProperty(this, "fingerprint", { + get() { + (0, _display_utils.deprecated)("`PDFDocumentProxy.fingerprint`, " + "please use `PDFDocumentProxy.fingerprints` instead."); + return this.fingerprints[0]; + } + + }); + Object.defineProperty(this, "getStats", { + value: async () => { + (0, _display_utils.deprecated)("`PDFDocumentProxy.getStats`, " + "please use the `PDFDocumentProxy.stats`-getter instead."); + return this.stats || { + streamTypes: {}, + fontTypes: {} + }; + } + }); + } + + get annotationStorage() { + return this._transport.annotationStorage; + } + + get numPages() { + return this._pdfInfo.numPages; + } + + get fingerprints() { + return this._pdfInfo.fingerprints; + } + + get stats() { + return this._transport.stats; + } + + get isPureXfa() { + return !!this._transport._htmlForXfa; + } + + get allXfaHtml() { + return this._transport._htmlForXfa; + } + + getPage(pageNumber) { + return this._transport.getPage(pageNumber); + } + + getPageIndex(ref) { + return this._transport.getPageIndex(ref); + } + + getDestinations() { + return this._transport.getDestinations(); + } + + getDestination(id) { + return this._transport.getDestination(id); + } + + getPageLabels() { + return this._transport.getPageLabels(); + } + + getPageLayout() { + return this._transport.getPageLayout(); + } + + getPageMode() { + return this._transport.getPageMode(); + } + + getViewerPreferences() { + return this._transport.getViewerPreferences(); + } + + getOpenAction() { + return this._transport.getOpenAction(); + } + + getAttachments() { + return this._transport.getAttachments(); + } + + getJavaScript() { + return this._transport.getJavaScript(); + } + + getJSActions() { + return this._transport.getDocJSActions(); + } + + getOutline() { + return this._transport.getOutline(); + } + + getOptionalContentConfig() { + return this._transport.getOptionalContentConfig(); + } + + getPermissions() { + return this._transport.getPermissions(); + } + + getMetadata() { + return this._transport.getMetadata(); + } + + getMarkInfo() { + return this._transport.getMarkInfo(); + } + + getData() { + return this._transport.getData(); + } + + getDownloadInfo() { + return this._transport.downloadInfoCapability.promise; + } + + cleanup() { + let keepLoadedFonts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + return this._transport.startCleanup(keepLoadedFonts || this.isPureXfa); + } + + destroy() { + return this.loadingTask.destroy(); + } + + get loadingParams() { + return this._transport.loadingParams; + } + + get loadingTask() { + return this._transport.loadingTask; + } + + saveDocument() { + if (this._transport.annotationStorage.size <= 0) { + (0, _display_utils.deprecated)("saveDocument called while `annotationStorage` is empty, " + "please use the getData-method instead."); + } + + return this._transport.saveDocument(); + } + + getFieldObjects() { + return this._transport.getFieldObjects(); + } + + hasJSActions() { + return this._transport.hasJSActions(); + } + + getCalculationOrderIds() { + return this._transport.getCalculationOrderIds(); + } + +} + +exports.PDFDocumentProxy = PDFDocumentProxy; + +class PDFPageProxy { + constructor(pageIndex, pageInfo, transport, ownerDocument) { + let pdfBug = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false; + this._pageIndex = pageIndex; + this._pageInfo = pageInfo; + this._ownerDocument = ownerDocument; + this._transport = transport; + this._stats = pdfBug ? new _display_utils.StatTimer() : null; + this._pdfBug = pdfBug; + this.commonObjs = transport.commonObjs; + this.objs = new PDFObjects(); + this._bitmaps = new Set(); + this.cleanupAfterRender = false; + this.pendingCleanup = false; + this._intentStates = new Map(); + this._annotationPromises = new Map(); + this.destroyed = false; + } + + get pageNumber() { + return this._pageIndex + 1; + } + + get rotate() { + return this._pageInfo.rotate; + } + + get ref() { + return this._pageInfo.ref; + } + + get userUnit() { + return this._pageInfo.userUnit; + } + + get view() { + return this._pageInfo.view; + } + + getViewport() { + let { + scale, + rotation = this.rotate, + offsetX = 0, + offsetY = 0, + dontFlip = false + } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + return new _display_utils.PageViewport({ + viewBox: this.view, + scale, + rotation, + offsetX, + offsetY, + dontFlip + }); + } + + getAnnotations() { + let { + intent = "display" + } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + const intentArgs = this._transport.getRenderingIntent(intent); + + let promise = this._annotationPromises.get(intentArgs.cacheKey); + + if (!promise) { + promise = this._transport.getAnnotations(this._pageIndex, intentArgs.renderingIntent); + + this._annotationPromises.set(intentArgs.cacheKey, promise); + + promise = promise.then(annotations => { + for (const annotation of annotations) { + if (annotation.titleObj !== undefined) { + Object.defineProperty(annotation, "title", { + get() { + (0, _display_utils.deprecated)("`title`-property on annotation, please use `titleObj` instead."); + return annotation.titleObj.str; + } + + }); + } + + if (annotation.contentsObj !== undefined) { + Object.defineProperty(annotation, "contents", { + get() { + (0, _display_utils.deprecated)("`contents`-property on annotation, please use `contentsObj` instead."); + return annotation.contentsObj.str; + } + + }); + } + } + + return annotations; + }); + } + + return promise; + } + + getJSActions() { + return this._jsActionsPromise || (this._jsActionsPromise = this._transport.getPageJSActions(this._pageIndex)); + } + + async getXfa() { + var _this$_transport$_htm; + + return ((_this$_transport$_htm = this._transport._htmlForXfa) === null || _this$_transport$_htm === void 0 ? void 0 : _this$_transport$_htm.children[this._pageIndex]) || null; + } + + render(_ref2) { + var _arguments$, _arguments$2, _intentState; + + let { + canvasContext, + viewport, + intent = "display", + annotationMode = _util.AnnotationMode.ENABLE, + transform = null, + imageLayer = null, + canvasFactory = null, + background = null, + optionalContentConfigPromise = null, + annotationCanvasMap = null, + pageColors = null, + printAnnotationStorage = null + } = _ref2; + + if (((_arguments$ = arguments[0]) === null || _arguments$ === void 0 ? void 0 : _arguments$.renderInteractiveForms) !== undefined) { + (0, _display_utils.deprecated)("render no longer accepts the `renderInteractiveForms`-option, " + "please use the `annotationMode`-option instead."); + + if (arguments[0].renderInteractiveForms === true && annotationMode === _util.AnnotationMode.ENABLE) { + annotationMode = _util.AnnotationMode.ENABLE_FORMS; + } + } + + if (((_arguments$2 = arguments[0]) === null || _arguments$2 === void 0 ? void 0 : _arguments$2.includeAnnotationStorage) !== undefined) { + (0, _display_utils.deprecated)("render no longer accepts the `includeAnnotationStorage`-option, " + "please use the `annotationMode`-option instead."); + + if (arguments[0].includeAnnotationStorage === true && annotationMode === _util.AnnotationMode.ENABLE) { + annotationMode = _util.AnnotationMode.ENABLE_STORAGE; + } + } + + if (this._stats) { + this._stats.time("Overall"); + } + + const intentArgs = this._transport.getRenderingIntent(intent, annotationMode, printAnnotationStorage); + + this.pendingCleanup = false; + + if (!optionalContentConfigPromise) { + optionalContentConfigPromise = this._transport.getOptionalContentConfig(); + } + + let intentState = this._intentStates.get(intentArgs.cacheKey); + + if (!intentState) { + intentState = Object.create(null); + + this._intentStates.set(intentArgs.cacheKey, intentState); + } + + if (intentState.streamReaderCancelTimeout) { + clearTimeout(intentState.streamReaderCancelTimeout); + intentState.streamReaderCancelTimeout = null; + } + + const canvasFactoryInstance = canvasFactory || new DefaultCanvasFactory({ + ownerDocument: this._ownerDocument + }); + const intentPrint = !!(intentArgs.renderingIntent & _util.RenderingIntentFlag.PRINT); + + if (!intentState.displayReadyCapability) { + intentState.displayReadyCapability = (0, _util.createPromiseCapability)(); + intentState.operatorList = { + fnArray: [], + argsArray: [], + lastChunk: false, + separateAnnots: null + }; + + if (this._stats) { + this._stats.time("Page Request"); + } + + this._pumpOperatorList(intentArgs); + } + + const complete = error => { + intentState.renderTasks.delete(internalRenderTask); + + if (this.cleanupAfterRender || intentPrint) { + this.pendingCleanup = true; + } + + this._tryCleanup(); + + if (error) { + internalRenderTask.capability.reject(error); + + this._abortOperatorList({ + intentState, + reason: error instanceof Error ? error : new Error(error) + }); + } else { + internalRenderTask.capability.resolve(); + } + + if (this._stats) { + this._stats.timeEnd("Rendering"); + + this._stats.timeEnd("Overall"); + } + }; + + const internalRenderTask = new InternalRenderTask({ + callback: complete, + params: { + canvasContext, + viewport, + transform, + imageLayer, + background + }, + objs: this.objs, + commonObjs: this.commonObjs, + annotationCanvasMap, + operatorList: intentState.operatorList, + pageIndex: this._pageIndex, + canvasFactory: canvasFactoryInstance, + useRequestAnimationFrame: !intentPrint, + pdfBug: this._pdfBug, + pageColors + }); + ((_intentState = intentState).renderTasks || (_intentState.renderTasks = new Set())).add(internalRenderTask); + const renderTask = internalRenderTask.task; + Promise.all([intentState.displayReadyCapability.promise, optionalContentConfigPromise]).then(_ref3 => { + let [transparency, optionalContentConfig] = _ref3; + + if (this.pendingCleanup) { + complete(); + return; + } + + if (this._stats) { + this._stats.time("Rendering"); + } + + internalRenderTask.initializeGraphics({ + transparency, + optionalContentConfig + }); + internalRenderTask.operatorListChanged(); + }).catch(complete); + return renderTask; + } + + getOperatorList() { + let { + intent = "display", + annotationMode = _util.AnnotationMode.ENABLE, + printAnnotationStorage = null + } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + function operatorListChanged() { + if (intentState.operatorList.lastChunk) { + intentState.opListReadCapability.resolve(intentState.operatorList); + intentState.renderTasks.delete(opListTask); + } + } + + const intentArgs = this._transport.getRenderingIntent(intent, annotationMode, printAnnotationStorage, true); + + let intentState = this._intentStates.get(intentArgs.cacheKey); + + if (!intentState) { + intentState = Object.create(null); + + this._intentStates.set(intentArgs.cacheKey, intentState); + } + + let opListTask; + + if (!intentState.opListReadCapability) { + var _intentState2; + + opListTask = Object.create(null); + opListTask.operatorListChanged = operatorListChanged; + intentState.opListReadCapability = (0, _util.createPromiseCapability)(); + ((_intentState2 = intentState).renderTasks || (_intentState2.renderTasks = new Set())).add(opListTask); + intentState.operatorList = { + fnArray: [], + argsArray: [], + lastChunk: false, + separateAnnots: null + }; + + if (this._stats) { + this._stats.time("Page Request"); + } + + this._pumpOperatorList(intentArgs); + } + + return intentState.opListReadCapability.promise; + } + + streamTextContent() { + let { + disableCombineTextItems = false, + includeMarkedContent = false + } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + const TEXT_CONTENT_CHUNK_SIZE = 100; + return this._transport.messageHandler.sendWithStream("GetTextContent", { + pageIndex: this._pageIndex, + combineTextItems: disableCombineTextItems !== true, + includeMarkedContent: includeMarkedContent === true + }, { + highWaterMark: TEXT_CONTENT_CHUNK_SIZE, + + size(textContent) { + return textContent.items.length; + } + + }); + } + + getTextContent() { + let params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + if (this._transport._htmlForXfa) { + return this.getXfa().then(xfa => { + return _xfa_text.XfaText.textContent(xfa); + }); + } + + const readableStream = this.streamTextContent(params); + return new Promise(function (resolve, reject) { + function pump() { + reader.read().then(function (_ref4) { + let { + value, + done + } = _ref4; + + if (done) { + resolve(textContent); + return; + } + + Object.assign(textContent.styles, value.styles); + textContent.items.push(...value.items); + pump(); + }, reject); + } + + const reader = readableStream.getReader(); + const textContent = { + items: [], + styles: Object.create(null) + }; + pump(); + }); + } + + getStructTree() { + return this._structTreePromise || (this._structTreePromise = this._transport.getStructTree(this._pageIndex)); + } + + _destroy() { + this.destroyed = true; + const waitOn = []; + + for (const intentState of this._intentStates.values()) { + this._abortOperatorList({ + intentState, + reason: new Error("Page was destroyed."), + force: true + }); + + if (intentState.opListReadCapability) { + continue; + } + + for (const internalRenderTask of intentState.renderTasks) { + waitOn.push(internalRenderTask.completed); + internalRenderTask.cancel(); + } + } + + this.objs.clear(); + + for (const bitmap of this._bitmaps) { + bitmap.close(); + } + + this._bitmaps.clear(); + + this._annotationPromises.clear(); + + this._jsActionsPromise = null; + this._structTreePromise = null; + this.pendingCleanup = false; + return Promise.all(waitOn); + } + + cleanup() { + let resetStats = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + this.pendingCleanup = true; + return this._tryCleanup(resetStats); + } + + _tryCleanup() { + let resetStats = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + if (!this.pendingCleanup) { + return false; + } + + for (const { + renderTasks, + operatorList + } of this._intentStates.values()) { + if (renderTasks.size > 0 || !operatorList.lastChunk) { + return false; + } + } + + this._intentStates.clear(); + + this.objs.clear(); + + this._annotationPromises.clear(); + + this._jsActionsPromise = null; + this._structTreePromise = null; + + if (resetStats && this._stats) { + this._stats = new _display_utils.StatTimer(); + } + + for (const bitmap of this._bitmaps) { + bitmap.close(); + } + + this._bitmaps.clear(); + + this.pendingCleanup = false; + return true; + } + + _startRenderPage(transparency, cacheKey) { + const intentState = this._intentStates.get(cacheKey); + + if (!intentState) { + return; + } + + if (this._stats) { + this._stats.timeEnd("Page Request"); + } + + if (intentState.displayReadyCapability) { + intentState.displayReadyCapability.resolve(transparency); + } + } + + _renderPageChunk(operatorListChunk, intentState) { + for (let i = 0, ii = operatorListChunk.length; i < ii; i++) { + intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]); + intentState.operatorList.argsArray.push(operatorListChunk.argsArray[i]); + } + + intentState.operatorList.lastChunk = operatorListChunk.lastChunk; + intentState.operatorList.separateAnnots = operatorListChunk.separateAnnots; + + for (const internalRenderTask of intentState.renderTasks) { + internalRenderTask.operatorListChanged(); + } + + if (operatorListChunk.lastChunk) { + this._tryCleanup(); + } + } + + _pumpOperatorList(_ref5) { + let { + renderingIntent, + cacheKey, + annotationStorageMap + } = _ref5; + + const readableStream = this._transport.messageHandler.sendWithStream("GetOperatorList", { + pageIndex: this._pageIndex, + intent: renderingIntent, + cacheKey, + annotationStorage: annotationStorageMap + }); + + const reader = readableStream.getReader(); + + const intentState = this._intentStates.get(cacheKey); + + intentState.streamReader = reader; + + const pump = () => { + reader.read().then(_ref6 => { + let { + value, + done + } = _ref6; + + if (done) { + intentState.streamReader = null; + return; + } + + if (this._transport.destroyed) { + return; + } + + this._renderPageChunk(value, intentState); + + pump(); + }, reason => { + intentState.streamReader = null; + + if (this._transport.destroyed) { + return; + } + + if (intentState.operatorList) { + intentState.operatorList.lastChunk = true; + + for (const internalRenderTask of intentState.renderTasks) { + internalRenderTask.operatorListChanged(); + } + + this._tryCleanup(); + } + + if (intentState.displayReadyCapability) { + intentState.displayReadyCapability.reject(reason); + } else if (intentState.opListReadCapability) { + intentState.opListReadCapability.reject(reason); + } else { + throw reason; + } + }); + }; + + pump(); + } + + _abortOperatorList(_ref7) { + let { + intentState, + reason, + force = false + } = _ref7; + + if (!intentState.streamReader) { + return; + } + + if (!force) { + if (intentState.renderTasks.size > 0) { + return; + } + + if (reason instanceof _display_utils.RenderingCancelledException) { + intentState.streamReaderCancelTimeout = setTimeout(() => { + this._abortOperatorList({ + intentState, + reason, + force: true + }); + + intentState.streamReaderCancelTimeout = null; + }, RENDERING_CANCELLED_TIMEOUT); + return; + } + } + + intentState.streamReader.cancel(new _util.AbortException(reason.message)).catch(() => {}); + intentState.streamReader = null; + + if (this._transport.destroyed) { + return; + } + + for (const [curCacheKey, curIntentState] of this._intentStates) { + if (curIntentState === intentState) { + this._intentStates.delete(curCacheKey); + + break; + } + } + + this.cleanup(); + } + + get stats() { + return this._stats; + } + +} + +exports.PDFPageProxy = PDFPageProxy; + +class LoopbackPort { + constructor() { + this._listeners = []; + this._deferred = Promise.resolve(); + } + + postMessage(obj, transfers) { + const event = { + data: structuredClone(obj, transfers) + }; + + this._deferred.then(() => { + for (const listener of this._listeners) { + listener.call(this, event); + } + }); + } + + addEventListener(name, listener) { + this._listeners.push(listener); + } + + removeEventListener(name, listener) { + const i = this._listeners.indexOf(listener); + + this._listeners.splice(i, 1); + } + + terminate() { + this._listeners.length = 0; + } + +} + +exports.LoopbackPort = LoopbackPort; +const PDFWorkerUtil = { + isWorkerDisabled: false, + fallbackWorkerSrc: null, + fakeWorkerId: 0 +}; +exports.PDFWorkerUtil = PDFWorkerUtil; +{ + if (_is_node.isNodeJS && typeof require === "function") { + PDFWorkerUtil.isWorkerDisabled = true; + PDFWorkerUtil.fallbackWorkerSrc = "./pdf.worker.js"; + } else if (typeof document === "object") { + var _document, _document$currentScri; + + const pdfjsFilePath = (_document = document) === null || _document === void 0 ? void 0 : (_document$currentScri = _document.currentScript) === null || _document$currentScri === void 0 ? void 0 : _document$currentScri.src; + + if (pdfjsFilePath) { + PDFWorkerUtil.fallbackWorkerSrc = pdfjsFilePath.replace(/(\.(?:min\.)?js)(\?.*)?$/i, ".worker$1$2"); + } + } + + PDFWorkerUtil.isSameOrigin = function (baseUrl, otherUrl) { + let base; + + try { + base = new URL(baseUrl); + + if (!base.origin || base.origin === "null") { + return false; + } + } catch (e) { + return false; + } + + const other = new URL(otherUrl, base); + return base.origin === other.origin; + }; + + PDFWorkerUtil.createCDNWrapper = function (url) { + const wrapper = `importScripts("${url}");`; + return URL.createObjectURL(new Blob([wrapper])); + }; +} + +class PDFWorker { + constructor() { + let { + name = null, + port = null, + verbosity = (0, _util.getVerbosityLevel)() + } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + if (port && _classStaticPrivateFieldSpecGet(PDFWorker, PDFWorker, _workerPorts).has(port)) { + throw new Error("Cannot use more than one PDFWorker per port."); + } + + this.name = name; + this.destroyed = false; + this.verbosity = verbosity; + this._readyCapability = (0, _util.createPromiseCapability)(); + this._port = null; + this._webWorker = null; + this._messageHandler = null; + + if (port) { + _classStaticPrivateFieldSpecGet(PDFWorker, PDFWorker, _workerPorts).set(port, this); + + this._initializeFromPort(port); + + return; + } + + this._initialize(); + } + + get promise() { + return this._readyCapability.promise; + } + + get port() { + return this._port; + } + + get messageHandler() { + return this._messageHandler; + } + + _initializeFromPort(port) { + this._port = port; + this._messageHandler = new _message_handler.MessageHandler("main", "worker", port); + + this._messageHandler.on("ready", function () {}); + + this._readyCapability.resolve(); + } + + _initialize() { + if (!PDFWorkerUtil.isWorkerDisabled && !PDFWorker._mainThreadWorkerMessageHandler) { + let { + workerSrc + } = PDFWorker; + + try { + if (!PDFWorkerUtil.isSameOrigin(window.location.href, workerSrc)) { + workerSrc = PDFWorkerUtil.createCDNWrapper(new URL(workerSrc, window.location).href); + } + + const worker = new Worker(workerSrc); + const messageHandler = new _message_handler.MessageHandler("main", "worker", worker); + + const terminateEarly = () => { + worker.removeEventListener("error", onWorkerError); + messageHandler.destroy(); + worker.terminate(); + + if (this.destroyed) { + this._readyCapability.reject(new Error("Worker was destroyed")); + } else { + this._setupFakeWorker(); + } + }; + + const onWorkerError = () => { + if (!this._webWorker) { + terminateEarly(); + } + }; + + worker.addEventListener("error", onWorkerError); + messageHandler.on("test", data => { + worker.removeEventListener("error", onWorkerError); + + if (this.destroyed) { + terminateEarly(); + return; + } + + if (data) { + this._messageHandler = messageHandler; + this._port = worker; + this._webWorker = worker; + + this._readyCapability.resolve(); + + messageHandler.send("configure", { + verbosity: this.verbosity + }); + } else { + this._setupFakeWorker(); + + messageHandler.destroy(); + worker.terminate(); + } + }); + messageHandler.on("ready", data => { + worker.removeEventListener("error", onWorkerError); + + if (this.destroyed) { + terminateEarly(); + return; + } + + try { + sendTest(); + } catch (e) { + this._setupFakeWorker(); + } + }); + + const sendTest = () => { + const testObj = new Uint8Array(); + messageHandler.send("test", testObj, [testObj.buffer]); + }; + + sendTest(); + return; + } catch (e) { + (0, _util.info)("The worker has been disabled."); + } + } + + this._setupFakeWorker(); + } + + _setupFakeWorker() { + if (!PDFWorkerUtil.isWorkerDisabled) { + (0, _util.warn)("Setting up fake worker."); + PDFWorkerUtil.isWorkerDisabled = true; + } + + PDFWorker._setupFakeWorkerGlobal.then(WorkerMessageHandler => { + if (this.destroyed) { + this._readyCapability.reject(new Error("Worker was destroyed")); + + return; + } + + const port = new LoopbackPort(); + this._port = port; + const id = `fake${PDFWorkerUtil.fakeWorkerId++}`; + const workerHandler = new _message_handler.MessageHandler(id + "_worker", id, port); + WorkerMessageHandler.setup(workerHandler, port); + const messageHandler = new _message_handler.MessageHandler(id, id + "_worker", port); + this._messageHandler = messageHandler; + + this._readyCapability.resolve(); + + messageHandler.send("configure", { + verbosity: this.verbosity + }); + }).catch(reason => { + this._readyCapability.reject(new Error(`Setting up fake worker failed: "${reason.message}".`)); + }); + } + + destroy() { + this.destroyed = true; + + if (this._webWorker) { + this._webWorker.terminate(); + + this._webWorker = null; + } + + _classStaticPrivateFieldSpecGet(PDFWorker, PDFWorker, _workerPorts).delete(this._port); + + this._port = null; + + if (this._messageHandler) { + this._messageHandler.destroy(); + + this._messageHandler = null; + } + } + + static fromPort(params) { + if (!(params !== null && params !== void 0 && params.port)) { + throw new Error("PDFWorker.fromPort - invalid method signature."); + } + + if (_classStaticPrivateFieldSpecGet(this, PDFWorker, _workerPorts).has(params.port)) { + return _classStaticPrivateFieldSpecGet(this, PDFWorker, _workerPorts).get(params.port); + } + + return new PDFWorker(params); + } + + static get workerSrc() { + if (_worker_options.GlobalWorkerOptions.workerSrc) { + return _worker_options.GlobalWorkerOptions.workerSrc; + } + + if (PDFWorkerUtil.fallbackWorkerSrc !== null) { + if (!_is_node.isNodeJS) { + (0, _display_utils.deprecated)('No "GlobalWorkerOptions.workerSrc" specified.'); + } + + return PDFWorkerUtil.fallbackWorkerSrc; + } + + throw new Error('No "GlobalWorkerOptions.workerSrc" specified.'); + } + + static get _mainThreadWorkerMessageHandler() { + try { + var _globalThis$pdfjsWork; + + return ((_globalThis$pdfjsWork = globalThis.pdfjsWorker) === null || _globalThis$pdfjsWork === void 0 ? void 0 : _globalThis$pdfjsWork.WorkerMessageHandler) || null; + } catch (ex) { + return null; + } + } + + static get _setupFakeWorkerGlobal() { + const loader = async () => { + const mainWorkerMessageHandler = this._mainThreadWorkerMessageHandler; + + if (mainWorkerMessageHandler) { + return mainWorkerMessageHandler; + } + + if (_is_node.isNodeJS && typeof require === "function") { + const worker = eval("require")(this.workerSrc); + return worker.WorkerMessageHandler; + } + + await (0, _display_utils.loadScript)(this.workerSrc); + return window.pdfjsWorker.WorkerMessageHandler; + }; + + return (0, _util.shadow)(this, "_setupFakeWorkerGlobal", loader()); + } + +} + +exports.PDFWorker = PDFWorker; +var _workerPorts = { + writable: true, + value: new WeakMap() +}; +{ + PDFWorker.getWorkerSrc = function () { + (0, _display_utils.deprecated)("`PDFWorker.getWorkerSrc()`, please use `PDFWorker.workerSrc` instead."); + return this.workerSrc; + }; +} + +var _docStats = /*#__PURE__*/new WeakMap(); + +var _pageCache = /*#__PURE__*/new WeakMap(); + +var _pagePromises = /*#__PURE__*/new WeakMap(); + +var _metadataPromise = /*#__PURE__*/new WeakMap(); + +class WorkerTransport { + constructor(messageHandler, loadingTask, networkStream, params) { + _classPrivateFieldInitSpec(this, _docStats, { + writable: true, + value: null + }); + + _classPrivateFieldInitSpec(this, _pageCache, { + writable: true, + value: new Map() + }); + + _classPrivateFieldInitSpec(this, _pagePromises, { + writable: true, + value: new Map() + }); + + _classPrivateFieldInitSpec(this, _metadataPromise, { + writable: true, + value: null + }); + + this.messageHandler = messageHandler; + this.loadingTask = loadingTask; + this.commonObjs = new PDFObjects(); + this.fontLoader = new _font_loader.FontLoader({ + docId: loadingTask.docId, + onUnsupportedFeature: this._onUnsupportedFeature.bind(this), + ownerDocument: params.ownerDocument, + styleElement: params.styleElement + }); + this._params = params; + + if (!params.useWorkerFetch) { + this.CMapReaderFactory = new params.CMapReaderFactory({ + baseUrl: params.cMapUrl, + isCompressed: params.cMapPacked + }); + this.StandardFontDataFactory = new params.StandardFontDataFactory({ + baseUrl: params.standardFontDataUrl + }); + } + + this.destroyed = false; + this.destroyCapability = null; + this._passwordCapability = null; + this._networkStream = networkStream; + this._fullReader = null; + this._lastProgress = null; + this.downloadInfoCapability = (0, _util.createPromiseCapability)(); + this.setupMessageHandler(); + } + + get annotationStorage() { + return (0, _util.shadow)(this, "annotationStorage", new _annotation_storage.AnnotationStorage()); + } + + get stats() { + return _classPrivateFieldGet(this, _docStats); + } + + getRenderingIntent(intent) { + let annotationMode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _util.AnnotationMode.ENABLE; + let printAnnotationStorage = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + let isOpList = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; + let renderingIntent = _util.RenderingIntentFlag.DISPLAY; + let annotationMap = null; + + switch (intent) { + case "any": + renderingIntent = _util.RenderingIntentFlag.ANY; + break; + + case "display": + break; + + case "print": + renderingIntent = _util.RenderingIntentFlag.PRINT; + break; + + default: + (0, _util.warn)(`getRenderingIntent - invalid intent: ${intent}`); + } + + switch (annotationMode) { + case _util.AnnotationMode.DISABLE: + renderingIntent += _util.RenderingIntentFlag.ANNOTATIONS_DISABLE; + break; + + case _util.AnnotationMode.ENABLE: + break; + + case _util.AnnotationMode.ENABLE_FORMS: + renderingIntent += _util.RenderingIntentFlag.ANNOTATIONS_FORMS; + break; + + case _util.AnnotationMode.ENABLE_STORAGE: + renderingIntent += _util.RenderingIntentFlag.ANNOTATIONS_STORAGE; + const annotationStorage = renderingIntent & _util.RenderingIntentFlag.PRINT && printAnnotationStorage instanceof _annotation_storage.PrintAnnotationStorage ? printAnnotationStorage : this.annotationStorage; + annotationMap = annotationStorage.serializable; + break; + + default: + (0, _util.warn)(`getRenderingIntent - invalid annotationMode: ${annotationMode}`); + } + + if (isOpList) { + renderingIntent += _util.RenderingIntentFlag.OPLIST; + } + + return { + renderingIntent, + cacheKey: `${renderingIntent}_${_annotation_storage.AnnotationStorage.getHash(annotationMap)}`, + annotationStorageMap: annotationMap + }; + } + + destroy() { + if (this.destroyCapability) { + return this.destroyCapability.promise; + } + + this.destroyed = true; + this.destroyCapability = (0, _util.createPromiseCapability)(); + + if (this._passwordCapability) { + this._passwordCapability.reject(new Error("Worker was destroyed during onPassword callback")); + } + + const waitOn = []; + + for (const page of _classPrivateFieldGet(this, _pageCache).values()) { + waitOn.push(page._destroy()); + } + + _classPrivateFieldGet(this, _pageCache).clear(); + + _classPrivateFieldGet(this, _pagePromises).clear(); + + if (this.hasOwnProperty("annotationStorage")) { + this.annotationStorage.resetModified(); + } + + const terminated = this.messageHandler.sendWithPromise("Terminate", null); + waitOn.push(terminated); + Promise.all(waitOn).then(() => { + this.commonObjs.clear(); + this.fontLoader.clear(); + + _classPrivateFieldSet(this, _metadataPromise, null); + + this._getFieldObjectsPromise = null; + this._hasJSActionsPromise = null; + + if (this._networkStream) { + this._networkStream.cancelAllRequests(new _util.AbortException("Worker was terminated.")); + } + + if (this.messageHandler) { + this.messageHandler.destroy(); + this.messageHandler = null; + } + + this.destroyCapability.resolve(); + }, this.destroyCapability.reject); + return this.destroyCapability.promise; + } + + setupMessageHandler() { + const { + messageHandler, + loadingTask + } = this; + messageHandler.on("GetReader", (data, sink) => { + (0, _util.assert)(this._networkStream, "GetReader - no `IPDFStream` instance available."); + this._fullReader = this._networkStream.getFullReader(); + + this._fullReader.onProgress = evt => { + this._lastProgress = { + loaded: evt.loaded, + total: evt.total + }; + }; + + sink.onPull = () => { + this._fullReader.read().then(function (_ref8) { + let { + value, + done + } = _ref8; + + if (done) { + sink.close(); + return; + } + + (0, _util.assert)((0, _util.isArrayBuffer)(value), "GetReader - expected an ArrayBuffer."); + sink.enqueue(new Uint8Array(value), 1, [value]); + }).catch(reason => { + sink.error(reason); + }); + }; + + sink.onCancel = reason => { + this._fullReader.cancel(reason); + + sink.ready.catch(readyReason => { + if (this.destroyed) { + return; + } + + throw readyReason; + }); + }; + }); + messageHandler.on("ReaderHeadersReady", data => { + const headersCapability = (0, _util.createPromiseCapability)(); + const fullReader = this._fullReader; + fullReader.headersReady.then(() => { + if (!fullReader.isStreamingSupported || !fullReader.isRangeSupported) { + if (this._lastProgress) { + var _loadingTask$onProgre; + + (_loadingTask$onProgre = loadingTask.onProgress) === null || _loadingTask$onProgre === void 0 ? void 0 : _loadingTask$onProgre.call(loadingTask, this._lastProgress); + } + + fullReader.onProgress = evt => { + var _loadingTask$onProgre2; + + (_loadingTask$onProgre2 = loadingTask.onProgress) === null || _loadingTask$onProgre2 === void 0 ? void 0 : _loadingTask$onProgre2.call(loadingTask, { + loaded: evt.loaded, + total: evt.total + }); + }; + } + + headersCapability.resolve({ + isStreamingSupported: fullReader.isStreamingSupported, + isRangeSupported: fullReader.isRangeSupported, + contentLength: fullReader.contentLength + }); + }, headersCapability.reject); + return headersCapability.promise; + }); + messageHandler.on("GetRangeReader", (data, sink) => { + (0, _util.assert)(this._networkStream, "GetRangeReader - no `IPDFStream` instance available."); + + const rangeReader = this._networkStream.getRangeReader(data.begin, data.end); + + if (!rangeReader) { + sink.close(); + return; + } + + sink.onPull = () => { + rangeReader.read().then(function (_ref9) { + let { + value, + done + } = _ref9; + + if (done) { + sink.close(); + return; + } + + (0, _util.assert)((0, _util.isArrayBuffer)(value), "GetRangeReader - expected an ArrayBuffer."); + sink.enqueue(new Uint8Array(value), 1, [value]); + }).catch(reason => { + sink.error(reason); + }); + }; + + sink.onCancel = reason => { + rangeReader.cancel(reason); + sink.ready.catch(readyReason => { + if (this.destroyed) { + return; + } + + throw readyReason; + }); + }; + }); + messageHandler.on("GetDoc", _ref10 => { + let { + pdfInfo + } = _ref10; + this._numPages = pdfInfo.numPages; + this._htmlForXfa = pdfInfo.htmlForXfa; + delete pdfInfo.htmlForXfa; + + loadingTask._capability.resolve(new PDFDocumentProxy(pdfInfo, this)); + }); + messageHandler.on("DocException", function (ex) { + let reason; + + switch (ex.name) { + case "PasswordException": + reason = new _util.PasswordException(ex.message, ex.code); + break; + + case "InvalidPDFException": + reason = new _util.InvalidPDFException(ex.message); + break; + + case "MissingPDFException": + reason = new _util.MissingPDFException(ex.message); + break; + + case "UnexpectedResponseException": + reason = new _util.UnexpectedResponseException(ex.message, ex.status); + break; + + case "UnknownErrorException": + reason = new _util.UnknownErrorException(ex.message, ex.details); + break; + + default: + (0, _util.unreachable)("DocException - expected a valid Error."); + } + + loadingTask._capability.reject(reason); + }); + messageHandler.on("PasswordRequest", exception => { + this._passwordCapability = (0, _util.createPromiseCapability)(); + + if (loadingTask.onPassword) { + const updatePassword = password => { + if (password instanceof Error) { + this._passwordCapability.reject(password); + } else { + this._passwordCapability.resolve({ + password + }); + } + }; + + try { + loadingTask.onPassword(updatePassword, exception.code); + } catch (ex) { + this._passwordCapability.reject(ex); + } + } else { + this._passwordCapability.reject(new _util.PasswordException(exception.message, exception.code)); + } + + return this._passwordCapability.promise; + }); + messageHandler.on("DataLoaded", data => { + var _loadingTask$onProgre3; + + (_loadingTask$onProgre3 = loadingTask.onProgress) === null || _loadingTask$onProgre3 === void 0 ? void 0 : _loadingTask$onProgre3.call(loadingTask, { + loaded: data.length, + total: data.length + }); + this.downloadInfoCapability.resolve(data); + }); + messageHandler.on("StartRenderPage", data => { + if (this.destroyed) { + return; + } + + const page = _classPrivateFieldGet(this, _pageCache).get(data.pageIndex); + + page._startRenderPage(data.transparency, data.cacheKey); + }); + messageHandler.on("commonobj", _ref11 => { + var _globalThis$FontInspe; + + let [id, type, exportedData] = _ref11; + + if (this.destroyed) { + return; + } + + if (this.commonObjs.has(id)) { + return; + } + + switch (type) { + case "Font": + const params = this._params; + + if ("error" in exportedData) { + const exportedError = exportedData.error; + (0, _util.warn)(`Error during font loading: ${exportedError}`); + this.commonObjs.resolve(id, exportedError); + break; + } + + let fontRegistry = null; + + if (params.pdfBug && (_globalThis$FontInspe = globalThis.FontInspector) !== null && _globalThis$FontInspe !== void 0 && _globalThis$FontInspe.enabled) { + fontRegistry = { + registerFont(font, url) { + globalThis.FontInspector.fontAdded(font, url); + } + + }; + } + + const font = new _font_loader.FontFaceObject(exportedData, { + isEvalSupported: params.isEvalSupported, + disableFontFace: params.disableFontFace, + ignoreErrors: params.ignoreErrors, + onUnsupportedFeature: this._onUnsupportedFeature.bind(this), + fontRegistry + }); + this.fontLoader.bind(font).catch(reason => { + return messageHandler.sendWithPromise("FontFallback", { + id + }); + }).finally(() => { + if (!params.fontExtraProperties && font.data) { + font.data = null; + } + + this.commonObjs.resolve(id, font); + }); + break; + + case "FontPath": + case "Image": + this.commonObjs.resolve(id, exportedData); + break; + + default: + throw new Error(`Got unknown common object type ${type}`); + } + }); + messageHandler.on("obj", _ref12 => { + let [id, pageIndex, type, imageData] = _ref12; + + if (this.destroyed) { + return; + } + + const pageProxy = _classPrivateFieldGet(this, _pageCache).get(pageIndex); + + if (pageProxy.objs.has(id)) { + return; + } + + switch (type) { + case "Image": + pageProxy.objs.resolve(id, imageData); + const MAX_IMAGE_SIZE_TO_STORE = 8000000; + + if (imageData) { + let length; + + if (imageData.bitmap) { + const { + bitmap, + width, + height + } = imageData; + length = width * height * 4; + + pageProxy._bitmaps.add(bitmap); + } else { + var _imageData$data; + + length = ((_imageData$data = imageData.data) === null || _imageData$data === void 0 ? void 0 : _imageData$data.length) || 0; + } + + if (length > MAX_IMAGE_SIZE_TO_STORE) { + pageProxy.cleanupAfterRender = true; + } + } + + break; + + case "Pattern": + pageProxy.objs.resolve(id, imageData); + break; + + default: + throw new Error(`Got unknown object type ${type}`); + } + }); + messageHandler.on("DocProgress", data => { + var _loadingTask$onProgre4; + + if (this.destroyed) { + return; + } + + (_loadingTask$onProgre4 = loadingTask.onProgress) === null || _loadingTask$onProgre4 === void 0 ? void 0 : _loadingTask$onProgre4.call(loadingTask, { + loaded: data.loaded, + total: data.total + }); + }); + messageHandler.on("DocStats", data => { + if (this.destroyed) { + return; + } + + _classPrivateFieldSet(this, _docStats, Object.freeze({ + streamTypes: Object.freeze(data.streamTypes), + fontTypes: Object.freeze(data.fontTypes) + })); + }); + messageHandler.on("UnsupportedFeature", this._onUnsupportedFeature.bind(this)); + messageHandler.on("FetchBuiltInCMap", data => { + if (this.destroyed) { + return Promise.reject(new Error("Worker was destroyed.")); + } + + if (!this.CMapReaderFactory) { + return Promise.reject(new Error("CMapReaderFactory not initialized, see the `useWorkerFetch` parameter.")); + } + + return this.CMapReaderFactory.fetch(data); + }); + messageHandler.on("FetchStandardFontData", data => { + if (this.destroyed) { + return Promise.reject(new Error("Worker was destroyed.")); + } + + if (!this.StandardFontDataFactory) { + return Promise.reject(new Error("StandardFontDataFactory not initialized, see the `useWorkerFetch` parameter.")); + } + + return this.StandardFontDataFactory.fetch(data); + }); + } + + _onUnsupportedFeature(_ref13) { + var _this$loadingTask$onU, _this$loadingTask; + + let { + featureId + } = _ref13; + + if (this.destroyed) { + return; + } + + (_this$loadingTask$onU = (_this$loadingTask = this.loadingTask).onUnsupportedFeature) === null || _this$loadingTask$onU === void 0 ? void 0 : _this$loadingTask$onU.call(_this$loadingTask, featureId); + } + + getData() { + return this.messageHandler.sendWithPromise("GetData", null); + } + + getPage(pageNumber) { + if (!Number.isInteger(pageNumber) || pageNumber <= 0 || pageNumber > this._numPages) { + return Promise.reject(new Error("Invalid page request.")); + } + + const pageIndex = pageNumber - 1, + cachedPromise = _classPrivateFieldGet(this, _pagePromises).get(pageIndex); + + if (cachedPromise) { + return cachedPromise; + } + + const promise = this.messageHandler.sendWithPromise("GetPage", { + pageIndex + }).then(pageInfo => { + if (this.destroyed) { + throw new Error("Transport destroyed"); + } + + const page = new PDFPageProxy(pageIndex, pageInfo, this, this._params.ownerDocument, this._params.pdfBug); + + _classPrivateFieldGet(this, _pageCache).set(pageIndex, page); + + return page; + }); + + _classPrivateFieldGet(this, _pagePromises).set(pageIndex, promise); + + return promise; + } + + getPageIndex(ref) { + if (typeof ref !== "object" || ref === null || !Number.isInteger(ref.num) || ref.num < 0 || !Number.isInteger(ref.gen) || ref.gen < 0) { + return Promise.reject(new Error("Invalid pageIndex request.")); + } + + return this.messageHandler.sendWithPromise("GetPageIndex", { + num: ref.num, + gen: ref.gen + }); + } + + getAnnotations(pageIndex, intent) { + return this.messageHandler.sendWithPromise("GetAnnotations", { + pageIndex, + intent + }); + } + + saveDocument() { + var _this$_fullReader$fil, _this$_fullReader; + + return this.messageHandler.sendWithPromise("SaveDocument", { + isPureXfa: !!this._htmlForXfa, + numPages: this._numPages, + annotationStorage: this.annotationStorage.serializable, + filename: (_this$_fullReader$fil = (_this$_fullReader = this._fullReader) === null || _this$_fullReader === void 0 ? void 0 : _this$_fullReader.filename) !== null && _this$_fullReader$fil !== void 0 ? _this$_fullReader$fil : null + }).finally(() => { + this.annotationStorage.resetModified(); + }); + } + + getFieldObjects() { + return this._getFieldObjectsPromise || (this._getFieldObjectsPromise = this.messageHandler.sendWithPromise("GetFieldObjects", null)); + } + + hasJSActions() { + return this._hasJSActionsPromise || (this._hasJSActionsPromise = this.messageHandler.sendWithPromise("HasJSActions", null)); + } + + getCalculationOrderIds() { + return this.messageHandler.sendWithPromise("GetCalculationOrderIds", null); + } + + getDestinations() { + return this.messageHandler.sendWithPromise("GetDestinations", null); + } + + getDestination(id) { + if (typeof id !== "string") { + return Promise.reject(new Error("Invalid destination request.")); + } + + return this.messageHandler.sendWithPromise("GetDestination", { + id + }); + } + + getPageLabels() { + return this.messageHandler.sendWithPromise("GetPageLabels", null); + } + + getPageLayout() { + return this.messageHandler.sendWithPromise("GetPageLayout", null); + } + + getPageMode() { + return this.messageHandler.sendWithPromise("GetPageMode", null); + } + + getViewerPreferences() { + return this.messageHandler.sendWithPromise("GetViewerPreferences", null); + } + + getOpenAction() { + return this.messageHandler.sendWithPromise("GetOpenAction", null); + } + + getAttachments() { + return this.messageHandler.sendWithPromise("GetAttachments", null); + } + + getJavaScript() { + return this.messageHandler.sendWithPromise("GetJavaScript", null); + } + + getDocJSActions() { + return this.messageHandler.sendWithPromise("GetDocJSActions", null); + } + + getPageJSActions(pageIndex) { + return this.messageHandler.sendWithPromise("GetPageJSActions", { + pageIndex + }); + } + + getStructTree(pageIndex) { + return this.messageHandler.sendWithPromise("GetStructTree", { + pageIndex + }); + } + + getOutline() { + return this.messageHandler.sendWithPromise("GetOutline", null); + } + + getOptionalContentConfig() { + return this.messageHandler.sendWithPromise("GetOptionalContentConfig", null).then(results => { + return new _optional_content_config.OptionalContentConfig(results); + }); + } + + getPermissions() { + return this.messageHandler.sendWithPromise("GetPermissions", null); + } + + getMetadata() { + return _classPrivateFieldGet(this, _metadataPromise) || _classPrivateFieldSet(this, _metadataPromise, this.messageHandler.sendWithPromise("GetMetadata", null).then(results => { + var _this$_fullReader$fil2, _this$_fullReader2, _this$_fullReader$con, _this$_fullReader3; + + return { + info: results[0], + metadata: results[1] ? new _metadata.Metadata(results[1]) : null, + contentDispositionFilename: (_this$_fullReader$fil2 = (_this$_fullReader2 = this._fullReader) === null || _this$_fullReader2 === void 0 ? void 0 : _this$_fullReader2.filename) !== null && _this$_fullReader$fil2 !== void 0 ? _this$_fullReader$fil2 : null, + contentLength: (_this$_fullReader$con = (_this$_fullReader3 = this._fullReader) === null || _this$_fullReader3 === void 0 ? void 0 : _this$_fullReader3.contentLength) !== null && _this$_fullReader$con !== void 0 ? _this$_fullReader$con : null + }; + })); + } + + getMarkInfo() { + return this.messageHandler.sendWithPromise("GetMarkInfo", null); + } + + async startCleanup() { + let keepLoadedFonts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + await this.messageHandler.sendWithPromise("Cleanup", null); + + if (this.destroyed) { + return; + } + + for (const page of _classPrivateFieldGet(this, _pageCache).values()) { + const cleanupSuccessful = page.cleanup(); + + if (!cleanupSuccessful) { + throw new Error(`startCleanup: Page ${page.pageNumber} is currently rendering.`); + } + } + + this.commonObjs.clear(); + + if (!keepLoadedFonts) { + this.fontLoader.clear(); + } + + _classPrivateFieldSet(this, _metadataPromise, null); + + this._getFieldObjectsPromise = null; + this._hasJSActionsPromise = null; + } + + get loadingParams() { + const params = this._params; + return (0, _util.shadow)(this, "loadingParams", { + disableAutoFetch: params.disableAutoFetch, + enableXfa: params.enableXfa + }); + } + +} + +var _objs = /*#__PURE__*/new WeakMap(); + +var _ensureObj = /*#__PURE__*/new WeakSet(); + +class PDFObjects { + constructor() { + _classPrivateMethodInitSpec(this, _ensureObj); + + _classPrivateFieldInitSpec(this, _objs, { + writable: true, + value: Object.create(null) + }); + } + + get(objId) { + let callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + + if (callback) { + const obj = _classPrivateMethodGet(this, _ensureObj, _ensureObj2).call(this, objId); + + obj.capability.promise.then(() => callback(obj.data)); + return null; + } + + const obj = _classPrivateFieldGet(this, _objs)[objId]; + + if (!(obj !== null && obj !== void 0 && obj.capability.settled)) { + throw new Error(`Requesting object that isn't resolved yet ${objId}.`); + } + + return obj.data; + } + + has(objId) { + const obj = _classPrivateFieldGet(this, _objs)[objId]; + + return (obj === null || obj === void 0 ? void 0 : obj.capability.settled) || false; + } + + resolve(objId) { + let data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + + const obj = _classPrivateMethodGet(this, _ensureObj, _ensureObj2).call(this, objId); + + obj.data = data; + obj.capability.resolve(); + } + + clear() { + _classPrivateFieldSet(this, _objs, Object.create(null)); + } + +} + +function _ensureObj2(objId) { + const obj = _classPrivateFieldGet(this, _objs)[objId]; + + if (obj) { + return obj; + } + + return _classPrivateFieldGet(this, _objs)[objId] = { + capability: (0, _util.createPromiseCapability)(), + data: null + }; +} + +var _internalRenderTask = /*#__PURE__*/new WeakMap(); + +class RenderTask { + constructor(internalRenderTask) { + _classPrivateFieldInitSpec(this, _internalRenderTask, { + writable: true, + value: null + }); + + _classPrivateFieldSet(this, _internalRenderTask, internalRenderTask); + + this.onContinue = null; + } + + get promise() { + return _classPrivateFieldGet(this, _internalRenderTask).capability.promise; + } + + cancel() { + _classPrivateFieldGet(this, _internalRenderTask).cancel(); + } + + get separateAnnots() { + const { + separateAnnots + } = _classPrivateFieldGet(this, _internalRenderTask).operatorList; + + if (!separateAnnots) { + return false; + } + + const { + annotationCanvasMap + } = _classPrivateFieldGet(this, _internalRenderTask); + + return separateAnnots.form || separateAnnots.canvas && (annotationCanvasMap === null || annotationCanvasMap === void 0 ? void 0 : annotationCanvasMap.size) > 0; + } + +} + +exports.RenderTask = RenderTask; + +class InternalRenderTask { + constructor(_ref14) { + let { + callback, + params, + objs, + commonObjs, + annotationCanvasMap, + operatorList, + pageIndex, + canvasFactory, + useRequestAnimationFrame = false, + pdfBug = false, + pageColors = null + } = _ref14; + this.callback = callback; + this.params = params; + this.objs = objs; + this.commonObjs = commonObjs; + this.annotationCanvasMap = annotationCanvasMap; + this.operatorListIdx = null; + this.operatorList = operatorList; + this._pageIndex = pageIndex; + this.canvasFactory = canvasFactory; + this._pdfBug = pdfBug; + this.pageColors = pageColors; + this.running = false; + this.graphicsReadyCallback = null; + this.graphicsReady = false; + this._useRequestAnimationFrame = useRequestAnimationFrame === true && typeof window !== "undefined"; + this.cancelled = false; + this.capability = (0, _util.createPromiseCapability)(); + this.task = new RenderTask(this); + this._cancelBound = this.cancel.bind(this); + this._continueBound = this._continue.bind(this); + this._scheduleNextBound = this._scheduleNext.bind(this); + this._nextBound = this._next.bind(this); + this._canvas = params.canvasContext.canvas; + } + + get completed() { + return this.capability.promise.catch(function () {}); + } + + initializeGraphics(_ref15) { + var _globalThis$StepperMa; + + let { + transparency = false, + optionalContentConfig + } = _ref15; + + if (this.cancelled) { + return; + } + + if (this._canvas) { + if (_classStaticPrivateFieldSpecGet(InternalRenderTask, InternalRenderTask, _canvasInUse).has(this._canvas)) { + throw new Error("Cannot use the same canvas during multiple render() operations. " + "Use different canvas or ensure previous operations were " + "cancelled or completed."); + } + + _classStaticPrivateFieldSpecGet(InternalRenderTask, InternalRenderTask, _canvasInUse).add(this._canvas); + } + + if (this._pdfBug && (_globalThis$StepperMa = globalThis.StepperManager) !== null && _globalThis$StepperMa !== void 0 && _globalThis$StepperMa.enabled) { + this.stepper = globalThis.StepperManager.create(this._pageIndex); + this.stepper.init(this.operatorList); + this.stepper.nextBreakPoint = this.stepper.getNextBreakPoint(); + } + + const { + canvasContext, + viewport, + transform, + imageLayer, + background + } = this.params; + this.gfx = new _canvas.CanvasGraphics(canvasContext, this.commonObjs, this.objs, this.canvasFactory, imageLayer, optionalContentConfig, this.annotationCanvasMap, this.pageColors); + this.gfx.beginDrawing({ + transform, + viewport, + transparency, + background + }); + this.operatorListIdx = 0; + this.graphicsReady = true; + + if (this.graphicsReadyCallback) { + this.graphicsReadyCallback(); + } + } + + cancel() { + let error = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + this.running = false; + this.cancelled = true; + + if (this.gfx) { + this.gfx.endDrawing(); + } + + if (this._canvas) { + _classStaticPrivateFieldSpecGet(InternalRenderTask, InternalRenderTask, _canvasInUse).delete(this._canvas); + } + + this.callback(error || new _display_utils.RenderingCancelledException(`Rendering cancelled, page ${this._pageIndex + 1}`, "canvas")); + } + + operatorListChanged() { + if (!this.graphicsReady) { + if (!this.graphicsReadyCallback) { + this.graphicsReadyCallback = this._continueBound; + } + + return; + } + + if (this.stepper) { + this.stepper.updateOperatorList(this.operatorList); + } + + if (this.running) { + return; + } + + this._continue(); + } + + _continue() { + this.running = true; + + if (this.cancelled) { + return; + } + + if (this.task.onContinue) { + this.task.onContinue(this._scheduleNextBound); + } else { + this._scheduleNext(); + } + } + + _scheduleNext() { + if (this._useRequestAnimationFrame) { + window.requestAnimationFrame(() => { + this._nextBound().catch(this._cancelBound); + }); + } else { + Promise.resolve().then(this._nextBound).catch(this._cancelBound); + } + } + + async _next() { + if (this.cancelled) { + return; + } + + this.operatorListIdx = this.gfx.executeOperatorList(this.operatorList, this.operatorListIdx, this._continueBound, this.stepper); + + if (this.operatorListIdx === this.operatorList.argsArray.length) { + this.running = false; + + if (this.operatorList.lastChunk) { + this.gfx.endDrawing(); + + if (this._canvas) { + _classStaticPrivateFieldSpecGet(InternalRenderTask, InternalRenderTask, _canvasInUse).delete(this._canvas); + } + + this.callback(); + } + } + } + +} + +var _canvasInUse = { + writable: true, + value: new WeakSet() +}; +const version = '2.16.105'; +exports.version = version; +const build = '172ccdbe5'; +exports.build = build; + +/***/ }), +/* 130 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PrintAnnotationStorage = exports.AnnotationStorage = void 0; + +var _util = __w_pdfjs_require__(1); + +var _editor = __w_pdfjs_require__(131); + +var _murmurhash = __w_pdfjs_require__(135); + +function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } + +function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } + +function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } + +function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +var _setModified = /*#__PURE__*/new WeakSet(); + +class AnnotationStorage { + constructor() { + _classPrivateMethodInitSpec(this, _setModified); + + this._storage = new Map(); + this._modified = false; + this.onSetModified = null; + this.onResetModified = null; + this.onAnnotationEditor = null; + } + + getValue(key, defaultValue) { + const value = this._storage.get(key); + + if (value === undefined) { + return defaultValue; + } + + return Object.assign(defaultValue, value); + } + + getRawValue(key) { + return this._storage.get(key); + } + + remove(key) { + this._storage.delete(key); + + if (this._storage.size === 0) { + this.resetModified(); + } + + if (typeof this.onAnnotationEditor === "function") { + for (const value of this._storage.values()) { + if (value instanceof _editor.AnnotationEditor) { + return; + } + } + + this.onAnnotationEditor(null); + } + } + + setValue(key, value) { + const obj = this._storage.get(key); + + let modified = false; + + if (obj !== undefined) { + for (const [entry, val] of Object.entries(value)) { + if (obj[entry] !== val) { + modified = true; + obj[entry] = val; + } + } + } else { + modified = true; + + this._storage.set(key, value); + } + + if (modified) { + _classPrivateMethodGet(this, _setModified, _setModified2).call(this); + } + + if (value instanceof _editor.AnnotationEditor && typeof this.onAnnotationEditor === "function") { + this.onAnnotationEditor(value.constructor._type); + } + } + + has(key) { + return this._storage.has(key); + } + + getAll() { + return this._storage.size > 0 ? (0, _util.objectFromMap)(this._storage) : null; + } + + get size() { + return this._storage.size; + } + + resetModified() { + if (this._modified) { + this._modified = false; + + if (typeof this.onResetModified === "function") { + this.onResetModified(); + } + } + } + + get print() { + return new PrintAnnotationStorage(this); + } + + get serializable() { + if (this._storage.size === 0) { + return null; + } + + const clone = new Map(); + + for (const [key, val] of this._storage) { + const serialized = val instanceof _editor.AnnotationEditor ? val.serialize() : val; + + if (serialized) { + clone.set(key, serialized); + } + } + + return clone; + } + + static getHash(map) { + if (!map) { + return ""; + } + + const hash = new _murmurhash.MurmurHash3_64(); + + for (const [key, val] of map) { + hash.update(`${key}:${JSON.stringify(val)}`); + } + + return hash.hexdigest(); + } + +} + +exports.AnnotationStorage = AnnotationStorage; + +function _setModified2() { + if (!this._modified) { + this._modified = true; + + if (typeof this.onSetModified === "function") { + this.onSetModified(); + } + } +} + +var _serializable = /*#__PURE__*/new WeakMap(); + +class PrintAnnotationStorage extends AnnotationStorage { + constructor(parent) { + super(); + + _classPrivateFieldInitSpec(this, _serializable, { + writable: true, + value: null + }); + + _classPrivateFieldSet(this, _serializable, structuredClone(parent.serializable)); + } + + get print() { + (0, _util.unreachable)("Should not call PrintAnnotationStorage.print"); + } + + get serializable() { + return _classPrivateFieldGet(this, _serializable); + } + +} + +exports.PrintAnnotationStorage = PrintAnnotationStorage; + +/***/ }), +/* 131 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.AnnotationEditor = void 0; + +var _tools = __w_pdfjs_require__(132); + +var _util = __w_pdfjs_require__(1); + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } + +function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } + +function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +var _boundFocusin = /*#__PURE__*/new WeakMap(); + +var _boundFocusout = /*#__PURE__*/new WeakMap(); + +var _hasBeenSelected = /*#__PURE__*/new WeakMap(); + +var _isEditing = /*#__PURE__*/new WeakMap(); + +var _isInEditMode = /*#__PURE__*/new WeakMap(); + +var _zIndex = /*#__PURE__*/new WeakMap(); + +class AnnotationEditor { + constructor(parameters) { + _classPrivateFieldInitSpec(this, _boundFocusin, { + writable: true, + value: this.focusin.bind(this) + }); + + _classPrivateFieldInitSpec(this, _boundFocusout, { + writable: true, + value: this.focusout.bind(this) + }); + + _classPrivateFieldInitSpec(this, _hasBeenSelected, { + writable: true, + value: false + }); + + _classPrivateFieldInitSpec(this, _isEditing, { + writable: true, + value: false + }); + + _classPrivateFieldInitSpec(this, _isInEditMode, { + writable: true, + value: false + }); + + _classPrivateFieldInitSpec(this, _zIndex, { + writable: true, + value: AnnotationEditor._zIndex++ + }); + + if (this.constructor === AnnotationEditor) { + (0, _util.unreachable)("Cannot initialize AnnotationEditor."); + } + + this.parent = parameters.parent; + this.id = parameters.id; + this.width = this.height = null; + this.pageIndex = parameters.parent.pageIndex; + this.name = parameters.name; + this.div = null; + const [width, height] = this.parent.viewportBaseDimensions; + this.x = parameters.x / width; + this.y = parameters.y / height; + this.rotation = this.parent.viewport.rotation; + this.isAttachedToDOM = false; + } + + static get _defaultLineColor() { + return (0, _util.shadow)(this, "_defaultLineColor", this._colorManager.getHexCode("CanvasText")); + } + + setInBackground() { + this.div.style.zIndex = 0; + } + + setInForeground() { + this.div.style.zIndex = _classPrivateFieldGet(this, _zIndex); + } + + focusin(event) { + if (!_classPrivateFieldGet(this, _hasBeenSelected)) { + this.parent.setSelected(this); + } else { + _classPrivateFieldSet(this, _hasBeenSelected, false); + } + } + + focusout(event) { + if (!this.isAttachedToDOM) { + return; + } + + const target = event.relatedTarget; + + if (target !== null && target !== void 0 && target.closest(`#${this.id}`)) { + return; + } + + event.preventDefault(); + + if (!this.parent.isMultipleSelection) { + this.commitOrRemove(); + } + } + + commitOrRemove() { + if (this.isEmpty()) { + this.remove(); + } else { + this.commit(); + } + } + + commit() { + this.parent.addToAnnotationStorage(this); + } + + dragstart(event) { + const rect = this.parent.div.getBoundingClientRect(); + this.startX = event.clientX - rect.x; + this.startY = event.clientY - rect.y; + event.dataTransfer.setData("text/plain", this.id); + event.dataTransfer.effectAllowed = "move"; + } + + setAt(x, y, tx, ty) { + const [width, height] = this.parent.viewportBaseDimensions; + [tx, ty] = this.screenToPageTranslation(tx, ty); + this.x = (x + tx) / width; + this.y = (y + ty) / height; + this.div.style.left = `${100 * this.x}%`; + this.div.style.top = `${100 * this.y}%`; + } + + translate(x, y) { + const [width, height] = this.parent.viewportBaseDimensions; + [x, y] = this.screenToPageTranslation(x, y); + this.x += x / width; + this.y += y / height; + this.div.style.left = `${100 * this.x}%`; + this.div.style.top = `${100 * this.y}%`; + } + + screenToPageTranslation(x, y) { + const { + rotation + } = this.parent.viewport; + + switch (rotation) { + case 90: + return [y, -x]; + + case 180: + return [-x, -y]; + + case 270: + return [-y, x]; + + default: + return [x, y]; + } + } + + setDims(width, height) { + const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions; + this.div.style.width = `${100 * width / parentWidth}%`; + this.div.style.height = `${100 * height / parentHeight}%`; + } + + getInitialTranslation() { + return [0, 0]; + } + + render() { + this.div = document.createElement("div"); + this.div.setAttribute("data-editor-rotation", (360 - this.rotation) % 360); + this.div.className = this.name; + this.div.setAttribute("id", this.id); + this.div.setAttribute("tabIndex", 0); + this.setInForeground(); + this.div.addEventListener("focusin", _classPrivateFieldGet(this, _boundFocusin)); + this.div.addEventListener("focusout", _classPrivateFieldGet(this, _boundFocusout)); + const [tx, ty] = this.getInitialTranslation(); + this.translate(tx, ty); + (0, _tools.bindEvents)(this, this.div, ["dragstart", "pointerdown"]); + return this.div; + } + + pointerdown(event) { + const isMac = _tools.KeyboardManager.platform.isMac; + + if (event.button !== 0 || event.ctrlKey && isMac) { + event.preventDefault(); + return; + } + + if (event.ctrlKey && !isMac || event.shiftKey || event.metaKey && isMac) { + this.parent.toggleSelected(this); + } else { + this.parent.setSelected(this); + } + + _classPrivateFieldSet(this, _hasBeenSelected, true); + } + + getRect(tx, ty) { + const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions; + const [pageWidth, pageHeight] = this.parent.pageDimensions; + const shiftX = pageWidth * tx / parentWidth; + const shiftY = pageHeight * ty / parentHeight; + const x = this.x * pageWidth; + const y = this.y * pageHeight; + const width = this.width * pageWidth; + const height = this.height * pageHeight; + + switch (this.rotation) { + case 0: + return [x + shiftX, pageHeight - y - shiftY - height, x + shiftX + width, pageHeight - y - shiftY]; + + case 90: + return [x + shiftY, pageHeight - y + shiftX, x + shiftY + height, pageHeight - y + shiftX + width]; + + case 180: + return [x - shiftX - width, pageHeight - y + shiftY, x - shiftX, pageHeight - y + shiftY + height]; + + case 270: + return [x - shiftY - height, pageHeight - y - shiftX - width, x - shiftY, pageHeight - y - shiftX]; + + default: + throw new Error("Invalid rotation"); + } + } + + getRectInCurrentCoords(rect, pageHeight) { + const [x1, y1, x2, y2] = rect; + const width = x2 - x1; + const height = y2 - y1; + + switch (this.rotation) { + case 0: + return [x1, pageHeight - y2, width, height]; + + case 90: + return [x1, pageHeight - y1, height, width]; + + case 180: + return [x2, pageHeight - y1, width, height]; + + case 270: + return [x2, pageHeight - y2, height, width]; + + default: + throw new Error("Invalid rotation"); + } + } + + onceAdded() {} + + isEmpty() { + return false; + } + + enableEditMode() { + _classPrivateFieldSet(this, _isInEditMode, true); + } + + disableEditMode() { + _classPrivateFieldSet(this, _isInEditMode, false); + } + + isInEditMode() { + return _classPrivateFieldGet(this, _isInEditMode); + } + + shouldGetKeyboardEvents() { + return false; + } + + needsToBeRebuilt() { + return this.div && !this.isAttachedToDOM; + } + + rebuild() { + var _this$div; + + (_this$div = this.div) === null || _this$div === void 0 ? void 0 : _this$div.addEventListener("focusin", _classPrivateFieldGet(this, _boundFocusin)); + } + + serialize() { + (0, _util.unreachable)("An editor must be serializable"); + } + + static deserialize(data, parent) { + const editor = new this.prototype.constructor({ + parent, + id: parent.getNextId() + }); + editor.rotation = data.rotation; + const [pageWidth, pageHeight] = parent.pageDimensions; + const [x, y, width, height] = editor.getRectInCurrentCoords(data.rect, pageHeight); + editor.x = x / pageWidth; + editor.y = y / pageHeight; + editor.width = width / pageWidth; + editor.height = height / pageHeight; + return editor; + } + + remove() { + this.div.removeEventListener("focusin", _classPrivateFieldGet(this, _boundFocusin)); + this.div.removeEventListener("focusout", _classPrivateFieldGet(this, _boundFocusout)); + + if (!this.isEmpty()) { + this.commit(); + } + + this.parent.remove(this); + } + + select() { + var _this$div2; + + (_this$div2 = this.div) === null || _this$div2 === void 0 ? void 0 : _this$div2.classList.add("selectedEditor"); + } + + unselect() { + var _this$div3; + + (_this$div3 = this.div) === null || _this$div3 === void 0 ? void 0 : _this$div3.classList.remove("selectedEditor"); + } + + updateParams(type, value) {} + + disableEditing() {} + + enableEditing() {} + + get propertiesToUpdate() { + return {}; + } + + get contentDiv() { + return this.div; + } + + get isEditing() { + return _classPrivateFieldGet(this, _isEditing); + } + + set isEditing(value) { + _classPrivateFieldSet(this, _isEditing, value); + + if (value) { + this.parent.setSelected(this); + this.parent.setActiveEditor(this); + } else { + this.parent.setActiveEditor(null); + } + } + +} + +exports.AnnotationEditor = AnnotationEditor; + +_defineProperty(AnnotationEditor, "_colorManager", new _tools.ColorManager()); + +_defineProperty(AnnotationEditor, "_zIndex", 1); + +/***/ }), +/* 132 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.KeyboardManager = exports.CommandManager = exports.ColorManager = exports.AnnotationEditorUIManager = void 0; +exports.bindEvents = bindEvents; +exports.opacityToHex = opacityToHex; + +var _util = __w_pdfjs_require__(1); + +var _display_utils = __w_pdfjs_require__(133); + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } + +function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } + +function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +function bindEvents(obj, element, names) { + for (const name of names) { + element.addEventListener(name, obj[name].bind(obj)); + } +} + +function opacityToHex(opacity) { + return Math.round(Math.min(255, Math.max(1, 255 * opacity))).toString(16).padStart(2, "0"); +} + +var _id = /*#__PURE__*/new WeakMap(); + +class IdManager { + constructor() { + _classPrivateFieldInitSpec(this, _id, { + writable: true, + value: 0 + }); + } + + getId() { + var _this$id, _this$id2; + + return `${_util.AnnotationEditorPrefix}${(_classPrivateFieldSet(this, _id, (_this$id = _classPrivateFieldGet(this, _id), _this$id2 = _this$id++, _this$id)), _this$id2)}`; + } + +} + +var _commands = /*#__PURE__*/new WeakMap(); + +var _locked = /*#__PURE__*/new WeakMap(); + +var _maxSize = /*#__PURE__*/new WeakMap(); + +var _position = /*#__PURE__*/new WeakMap(); + +class CommandManager { + constructor() { + let maxSize = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 128; + + _classPrivateFieldInitSpec(this, _commands, { + writable: true, + value: [] + }); + + _classPrivateFieldInitSpec(this, _locked, { + writable: true, + value: false + }); + + _classPrivateFieldInitSpec(this, _maxSize, { + writable: true, + value: void 0 + }); + + _classPrivateFieldInitSpec(this, _position, { + writable: true, + value: -1 + }); + + _classPrivateFieldSet(this, _maxSize, maxSize); + } + + add(_ref) { + let { + cmd, + undo, + mustExec, + type = NaN, + overwriteIfSameType = false, + keepUndo = false + } = _ref; + + if (mustExec) { + cmd(); + } + + if (_classPrivateFieldGet(this, _locked)) { + return; + } + + const save = { + cmd, + undo, + type + }; + + if (_classPrivateFieldGet(this, _position) === -1) { + if (_classPrivateFieldGet(this, _commands).length > 0) { + _classPrivateFieldGet(this, _commands).length = 0; + } + + _classPrivateFieldSet(this, _position, 0); + + _classPrivateFieldGet(this, _commands).push(save); + + return; + } + + if (overwriteIfSameType && _classPrivateFieldGet(this, _commands)[_classPrivateFieldGet(this, _position)].type === type) { + if (keepUndo) { + save.undo = _classPrivateFieldGet(this, _commands)[_classPrivateFieldGet(this, _position)].undo; + } + + _classPrivateFieldGet(this, _commands)[_classPrivateFieldGet(this, _position)] = save; + return; + } + + const next = _classPrivateFieldGet(this, _position) + 1; + + if (next === _classPrivateFieldGet(this, _maxSize)) { + _classPrivateFieldGet(this, _commands).splice(0, 1); + } else { + _classPrivateFieldSet(this, _position, next); + + if (next < _classPrivateFieldGet(this, _commands).length) { + _classPrivateFieldGet(this, _commands).splice(next); + } + } + + _classPrivateFieldGet(this, _commands).push(save); + } + + undo() { + if (_classPrivateFieldGet(this, _position) === -1) { + return; + } + + _classPrivateFieldSet(this, _locked, true); + + _classPrivateFieldGet(this, _commands)[_classPrivateFieldGet(this, _position)].undo(); + + _classPrivateFieldSet(this, _locked, false); + + _classPrivateFieldSet(this, _position, _classPrivateFieldGet(this, _position) - 1); + } + + redo() { + if (_classPrivateFieldGet(this, _position) < _classPrivateFieldGet(this, _commands).length - 1) { + _classPrivateFieldSet(this, _position, _classPrivateFieldGet(this, _position) + 1); + + _classPrivateFieldSet(this, _locked, true); + + _classPrivateFieldGet(this, _commands)[_classPrivateFieldGet(this, _position)].cmd(); + + _classPrivateFieldSet(this, _locked, false); + } + } + + hasSomethingToUndo() { + return _classPrivateFieldGet(this, _position) !== -1; + } + + hasSomethingToRedo() { + return _classPrivateFieldGet(this, _position) < _classPrivateFieldGet(this, _commands).length - 1; + } + + destroy() { + _classPrivateFieldSet(this, _commands, null); + } + +} + +exports.CommandManager = CommandManager; + +var _serialize = /*#__PURE__*/new WeakSet(); + +class KeyboardManager { + constructor(callbacks) { + _classPrivateMethodInitSpec(this, _serialize); + + this.buffer = []; + this.callbacks = new Map(); + this.allKeys = new Set(); + const isMac = KeyboardManager.platform.isMac; + + for (const [keys, callback] of callbacks) { + for (const key of keys) { + const isMacKey = key.startsWith("mac+"); + + if (isMac && isMacKey) { + this.callbacks.set(key.slice(4), callback); + this.allKeys.add(key.split("+").at(-1)); + } else if (!isMac && !isMacKey) { + this.callbacks.set(key, callback); + this.allKeys.add(key.split("+").at(-1)); + } + } + } + } + + static get platform() { + const platform = typeof navigator !== "undefined" ? navigator.platform : ""; + return (0, _util.shadow)(this, "platform", { + isWin: platform.includes("Win"), + isMac: platform.includes("Mac") + }); + } + + exec(self, event) { + if (!this.allKeys.has(event.key)) { + return; + } + + const callback = this.callbacks.get(_classPrivateMethodGet(this, _serialize, _serialize2).call(this, event)); + + if (!callback) { + return; + } + + callback.bind(self)(); + event.stopPropagation(); + event.preventDefault(); + } + +} + +exports.KeyboardManager = KeyboardManager; + +function _serialize2(event) { + if (event.altKey) { + this.buffer.push("alt"); + } + + if (event.ctrlKey) { + this.buffer.push("ctrl"); + } + + if (event.metaKey) { + this.buffer.push("meta"); + } + + if (event.shiftKey) { + this.buffer.push("shift"); + } + + this.buffer.push(event.key); + const str = this.buffer.join("+"); + this.buffer.length = 0; + return str; +} + +var _elements = /*#__PURE__*/new WeakMap(); + +class ClipboardManager { + constructor() { + _classPrivateFieldInitSpec(this, _elements, { + writable: true, + value: null + }); + } + + copy(element) { + if (!element) { + return; + } + + if (Array.isArray(element)) { + _classPrivateFieldSet(this, _elements, element.map(el => el.serialize())); + } else { + _classPrivateFieldSet(this, _elements, [element.serialize()]); + } + + _classPrivateFieldSet(this, _elements, _classPrivateFieldGet(this, _elements).filter(el => !!el)); + + if (_classPrivateFieldGet(this, _elements).length === 0) { + _classPrivateFieldSet(this, _elements, null); + } + } + + paste() { + return _classPrivateFieldGet(this, _elements); + } + + isEmpty() { + return _classPrivateFieldGet(this, _elements) === null; + } + + destroy() { + _classPrivateFieldSet(this, _elements, null); + } + +} + +class ColorManager { + get _colors() { + const colors = new Map([["CanvasText", null], ["Canvas", null]]); + (0, _display_utils.getColorValues)(colors); + return (0, _util.shadow)(this, "_colors", colors); + } + + convert(color) { + const rgb = (0, _display_utils.getRGB)(color); + + if (!window.matchMedia("(forced-colors: active)").matches) { + return rgb; + } + + for (const [name, RGB] of this._colors) { + if (RGB.every((x, i) => x === rgb[i])) { + return ColorManager._colorsMapping.get(name); + } + } + + return rgb; + } + + getHexCode(name) { + const rgb = this._colors.get(name); + + if (!rgb) { + return name; + } + + return _util.Util.makeHexColor(...rgb); + } + +} + +exports.ColorManager = ColorManager; + +_defineProperty(ColorManager, "_colorsMapping", new Map([["CanvasText", [0, 0, 0]], ["Canvas", [255, 255, 255]]])); + +var _activeEditor = /*#__PURE__*/new WeakMap(); + +var _allEditors = /*#__PURE__*/new WeakMap(); + +var _allLayers = /*#__PURE__*/new WeakMap(); + +var _clipboardManager = /*#__PURE__*/new WeakMap(); + +var _commandManager = /*#__PURE__*/new WeakMap(); + +var _currentPageIndex = /*#__PURE__*/new WeakMap(); + +var _editorTypes = /*#__PURE__*/new WeakMap(); + +var _eventBus = /*#__PURE__*/new WeakMap(); + +var _idManager = /*#__PURE__*/new WeakMap(); + +var _isEnabled = /*#__PURE__*/new WeakMap(); + +var _mode = /*#__PURE__*/new WeakMap(); + +var _selectedEditors = /*#__PURE__*/new WeakMap(); + +var _boundKeydown = /*#__PURE__*/new WeakMap(); + +var _boundOnEditingAction = /*#__PURE__*/new WeakMap(); + +var _boundOnPageChanging = /*#__PURE__*/new WeakMap(); + +var _previousStates = /*#__PURE__*/new WeakMap(); + +var _container = /*#__PURE__*/new WeakMap(); + +var _addKeyboardManager = /*#__PURE__*/new WeakSet(); + +var _removeKeyboardManager = /*#__PURE__*/new WeakSet(); + +var _dispatchUpdateStates = /*#__PURE__*/new WeakSet(); + +var _dispatchUpdateUI = /*#__PURE__*/new WeakSet(); + +var _enableAll = /*#__PURE__*/new WeakSet(); + +var _disableAll = /*#__PURE__*/new WeakSet(); + +var _addEditorToLayer = /*#__PURE__*/new WeakSet(); + +var _isEmpty = /*#__PURE__*/new WeakSet(); + +var _selectEditors = /*#__PURE__*/new WeakSet(); + +class AnnotationEditorUIManager { + constructor(container, eventBus) { + _classPrivateMethodInitSpec(this, _selectEditors); + + _classPrivateMethodInitSpec(this, _isEmpty); + + _classPrivateMethodInitSpec(this, _addEditorToLayer); + + _classPrivateMethodInitSpec(this, _disableAll); + + _classPrivateMethodInitSpec(this, _enableAll); + + _classPrivateMethodInitSpec(this, _dispatchUpdateUI); + + _classPrivateMethodInitSpec(this, _dispatchUpdateStates); + + _classPrivateMethodInitSpec(this, _removeKeyboardManager); + + _classPrivateMethodInitSpec(this, _addKeyboardManager); + + _classPrivateFieldInitSpec(this, _activeEditor, { + writable: true, + value: null + }); + + _classPrivateFieldInitSpec(this, _allEditors, { + writable: true, + value: new Map() + }); + + _classPrivateFieldInitSpec(this, _allLayers, { + writable: true, + value: new Map() + }); + + _classPrivateFieldInitSpec(this, _clipboardManager, { + writable: true, + value: new ClipboardManager() + }); + + _classPrivateFieldInitSpec(this, _commandManager, { + writable: true, + value: new CommandManager() + }); + + _classPrivateFieldInitSpec(this, _currentPageIndex, { + writable: true, + value: 0 + }); + + _classPrivateFieldInitSpec(this, _editorTypes, { + writable: true, + value: null + }); + + _classPrivateFieldInitSpec(this, _eventBus, { + writable: true, + value: null + }); + + _classPrivateFieldInitSpec(this, _idManager, { + writable: true, + value: new IdManager() + }); + + _classPrivateFieldInitSpec(this, _isEnabled, { + writable: true, + value: false + }); + + _classPrivateFieldInitSpec(this, _mode, { + writable: true, + value: _util.AnnotationEditorType.NONE + }); + + _classPrivateFieldInitSpec(this, _selectedEditors, { + writable: true, + value: new Set() + }); + + _classPrivateFieldInitSpec(this, _boundKeydown, { + writable: true, + value: this.keydown.bind(this) + }); + + _classPrivateFieldInitSpec(this, _boundOnEditingAction, { + writable: true, + value: this.onEditingAction.bind(this) + }); + + _classPrivateFieldInitSpec(this, _boundOnPageChanging, { + writable: true, + value: this.onPageChanging.bind(this) + }); + + _classPrivateFieldInitSpec(this, _previousStates, { + writable: true, + value: { + isEditing: false, + isEmpty: true, + hasEmptyClipboard: true, + hasSomethingToUndo: false, + hasSomethingToRedo: false, + hasSelectedEditor: false + } + }); + + _classPrivateFieldInitSpec(this, _container, { + writable: true, + value: null + }); + + _classPrivateFieldSet(this, _container, container); + + _classPrivateFieldSet(this, _eventBus, eventBus); + + _classPrivateFieldGet(this, _eventBus)._on("editingaction", _classPrivateFieldGet(this, _boundOnEditingAction)); + + _classPrivateFieldGet(this, _eventBus)._on("pagechanging", _classPrivateFieldGet(this, _boundOnPageChanging)); + } + + destroy() { + _classPrivateMethodGet(this, _removeKeyboardManager, _removeKeyboardManager2).call(this); + + _classPrivateFieldGet(this, _eventBus)._off("editingaction", _classPrivateFieldGet(this, _boundOnEditingAction)); + + _classPrivateFieldGet(this, _eventBus)._off("pagechanging", _classPrivateFieldGet(this, _boundOnPageChanging)); + + for (const layer of _classPrivateFieldGet(this, _allLayers).values()) { + layer.destroy(); + } + + _classPrivateFieldGet(this, _allLayers).clear(); + + _classPrivateFieldGet(this, _allEditors).clear(); + + _classPrivateFieldSet(this, _activeEditor, null); + + _classPrivateFieldGet(this, _selectedEditors).clear(); + + _classPrivateFieldGet(this, _clipboardManager).destroy(); + + _classPrivateFieldGet(this, _commandManager).destroy(); + } + + onPageChanging(_ref2) { + let { + pageNumber + } = _ref2; + + _classPrivateFieldSet(this, _currentPageIndex, pageNumber - 1); + } + + focusMainContainer() { + _classPrivateFieldGet(this, _container).focus(); + } + + keydown(event) { + var _this$getActive; + + if (!((_this$getActive = this.getActive()) !== null && _this$getActive !== void 0 && _this$getActive.shouldGetKeyboardEvents())) { + AnnotationEditorUIManager._keyboardManager.exec(this, event); + } + } + + onEditingAction(details) { + if (["undo", "redo", "cut", "copy", "paste", "delete", "selectAll"].includes(details.name)) { + this[details.name](); + } + } + + setEditingState(isEditing) { + if (isEditing) { + _classPrivateMethodGet(this, _addKeyboardManager, _addKeyboardManager2).call(this); + + _classPrivateMethodGet(this, _dispatchUpdateStates, _dispatchUpdateStates2).call(this, { + isEditing: _classPrivateFieldGet(this, _mode) !== _util.AnnotationEditorType.NONE, + isEmpty: _classPrivateMethodGet(this, _isEmpty, _isEmpty2).call(this), + hasSomethingToUndo: _classPrivateFieldGet(this, _commandManager).hasSomethingToUndo(), + hasSomethingToRedo: _classPrivateFieldGet(this, _commandManager).hasSomethingToRedo(), + hasSelectedEditor: false, + hasEmptyClipboard: _classPrivateFieldGet(this, _clipboardManager).isEmpty() + }); + } else { + _classPrivateMethodGet(this, _removeKeyboardManager, _removeKeyboardManager2).call(this); + + _classPrivateMethodGet(this, _dispatchUpdateStates, _dispatchUpdateStates2).call(this, { + isEditing: false + }); + } + } + + registerEditorTypes(types) { + _classPrivateFieldSet(this, _editorTypes, types); + + for (const editorType of _classPrivateFieldGet(this, _editorTypes)) { + _classPrivateMethodGet(this, _dispatchUpdateUI, _dispatchUpdateUI2).call(this, editorType.defaultPropertiesToUpdate); + } + } + + getId() { + return _classPrivateFieldGet(this, _idManager).getId(); + } + + addLayer(layer) { + _classPrivateFieldGet(this, _allLayers).set(layer.pageIndex, layer); + + if (_classPrivateFieldGet(this, _isEnabled)) { + layer.enable(); + } else { + layer.disable(); + } + } + + removeLayer(layer) { + _classPrivateFieldGet(this, _allLayers).delete(layer.pageIndex); + } + + updateMode(mode) { + _classPrivateFieldSet(this, _mode, mode); + + if (mode === _util.AnnotationEditorType.NONE) { + this.setEditingState(false); + + _classPrivateMethodGet(this, _disableAll, _disableAll2).call(this); + } else { + this.setEditingState(true); + + _classPrivateMethodGet(this, _enableAll, _enableAll2).call(this); + + for (const layer of _classPrivateFieldGet(this, _allLayers).values()) { + layer.updateMode(mode); + } + } + } + + updateToolbar(mode) { + if (mode === _classPrivateFieldGet(this, _mode)) { + return; + } + + _classPrivateFieldGet(this, _eventBus).dispatch("switchannotationeditormode", { + source: this, + mode + }); + } + + updateParams(type, value) { + for (const editor of _classPrivateFieldGet(this, _selectedEditors)) { + editor.updateParams(type, value); + } + + for (const editorType of _classPrivateFieldGet(this, _editorTypes)) { + editorType.updateDefaultParams(type, value); + } + } + + getEditors(pageIndex) { + const editors = []; + + for (const editor of _classPrivateFieldGet(this, _allEditors).values()) { + if (editor.pageIndex === pageIndex) { + editors.push(editor); + } + } + + return editors; + } + + getEditor(id) { + return _classPrivateFieldGet(this, _allEditors).get(id); + } + + addEditor(editor) { + _classPrivateFieldGet(this, _allEditors).set(editor.id, editor); + } + + removeEditor(editor) { + _classPrivateFieldGet(this, _allEditors).delete(editor.id); + + this.unselect(editor); + } + + setActiveEditor(editor) { + if (_classPrivateFieldGet(this, _activeEditor) === editor) { + return; + } + + _classPrivateFieldSet(this, _activeEditor, editor); + + if (editor) { + _classPrivateMethodGet(this, _dispatchUpdateUI, _dispatchUpdateUI2).call(this, editor.propertiesToUpdate); + } + } + + toggleSelected(editor) { + if (_classPrivateFieldGet(this, _selectedEditors).has(editor)) { + _classPrivateFieldGet(this, _selectedEditors).delete(editor); + + editor.unselect(); + + _classPrivateMethodGet(this, _dispatchUpdateStates, _dispatchUpdateStates2).call(this, { + hasSelectedEditor: this.hasSelection + }); + + return; + } + + _classPrivateFieldGet(this, _selectedEditors).add(editor); + + editor.select(); + + _classPrivateMethodGet(this, _dispatchUpdateUI, _dispatchUpdateUI2).call(this, editor.propertiesToUpdate); + + _classPrivateMethodGet(this, _dispatchUpdateStates, _dispatchUpdateStates2).call(this, { + hasSelectedEditor: true + }); + } + + setSelected(editor) { + for (const ed of _classPrivateFieldGet(this, _selectedEditors)) { + if (ed !== editor) { + ed.unselect(); + } + } + + _classPrivateFieldGet(this, _selectedEditors).clear(); + + _classPrivateFieldGet(this, _selectedEditors).add(editor); + + editor.select(); + + _classPrivateMethodGet(this, _dispatchUpdateUI, _dispatchUpdateUI2).call(this, editor.propertiesToUpdate); + + _classPrivateMethodGet(this, _dispatchUpdateStates, _dispatchUpdateStates2).call(this, { + hasSelectedEditor: true + }); + } + + isSelected(editor) { + return _classPrivateFieldGet(this, _selectedEditors).has(editor); + } + + unselect(editor) { + editor.unselect(); + + _classPrivateFieldGet(this, _selectedEditors).delete(editor); + + _classPrivateMethodGet(this, _dispatchUpdateStates, _dispatchUpdateStates2).call(this, { + hasSelectedEditor: this.hasSelection + }); + } + + get hasSelection() { + return _classPrivateFieldGet(this, _selectedEditors).size !== 0; + } + + undo() { + _classPrivateFieldGet(this, _commandManager).undo(); + + _classPrivateMethodGet(this, _dispatchUpdateStates, _dispatchUpdateStates2).call(this, { + hasSomethingToUndo: _classPrivateFieldGet(this, _commandManager).hasSomethingToUndo(), + hasSomethingToRedo: true, + isEmpty: _classPrivateMethodGet(this, _isEmpty, _isEmpty2).call(this) + }); + } + + redo() { + _classPrivateFieldGet(this, _commandManager).redo(); + + _classPrivateMethodGet(this, _dispatchUpdateStates, _dispatchUpdateStates2).call(this, { + hasSomethingToUndo: true, + hasSomethingToRedo: _classPrivateFieldGet(this, _commandManager).hasSomethingToRedo(), + isEmpty: _classPrivateMethodGet(this, _isEmpty, _isEmpty2).call(this) + }); + } + + addCommands(params) { + _classPrivateFieldGet(this, _commandManager).add(params); + + _classPrivateMethodGet(this, _dispatchUpdateStates, _dispatchUpdateStates2).call(this, { + hasSomethingToUndo: true, + hasSomethingToRedo: false, + isEmpty: _classPrivateMethodGet(this, _isEmpty, _isEmpty2).call(this) + }); + } + + delete() { + if (_classPrivateFieldGet(this, _activeEditor)) { + _classPrivateFieldGet(this, _activeEditor).commitOrRemove(); + } + + if (!this.hasSelection) { + return; + } + + const editors = [..._classPrivateFieldGet(this, _selectedEditors)]; + + const cmd = () => { + for (const editor of editors) { + editor.remove(); + } + }; + + const undo = () => { + for (const editor of editors) { + _classPrivateMethodGet(this, _addEditorToLayer, _addEditorToLayer2).call(this, editor); + } + }; + + this.addCommands({ + cmd, + undo, + mustExec: true + }); + } + + copy() { + if (_classPrivateFieldGet(this, _activeEditor)) { + _classPrivateFieldGet(this, _activeEditor).commitOrRemove(); + } + + if (this.hasSelection) { + const editors = []; + + for (const editor of _classPrivateFieldGet(this, _selectedEditors)) { + if (!editor.isEmpty()) { + editors.push(editor); + } + } + + if (editors.length === 0) { + return; + } + + _classPrivateFieldGet(this, _clipboardManager).copy(editors); + + _classPrivateMethodGet(this, _dispatchUpdateStates, _dispatchUpdateStates2).call(this, { + hasEmptyClipboard: false + }); + } + } + + cut() { + this.copy(); + this.delete(); + } + + paste() { + if (_classPrivateFieldGet(this, _clipboardManager).isEmpty()) { + return; + } + + this.unselectAll(); + + const layer = _classPrivateFieldGet(this, _allLayers).get(_classPrivateFieldGet(this, _currentPageIndex)); + + const newEditors = _classPrivateFieldGet(this, _clipboardManager).paste().map(data => layer.deserialize(data)); + + const cmd = () => { + for (const editor of newEditors) { + _classPrivateMethodGet(this, _addEditorToLayer, _addEditorToLayer2).call(this, editor); + } + + _classPrivateMethodGet(this, _selectEditors, _selectEditors2).call(this, newEditors); + }; + + const undo = () => { + for (const editor of newEditors) { + editor.remove(); + } + }; + + this.addCommands({ + cmd, + undo, + mustExec: true + }); + } + + selectAll() { + for (const editor of _classPrivateFieldGet(this, _selectedEditors)) { + editor.commit(); + } + + _classPrivateMethodGet(this, _selectEditors, _selectEditors2).call(this, _classPrivateFieldGet(this, _allEditors).values()); + } + + unselectAll() { + if (_classPrivateFieldGet(this, _activeEditor)) { + _classPrivateFieldGet(this, _activeEditor).commitOrRemove(); + + return; + } + + if (_classPrivateMethodGet(this, _selectEditors, _selectEditors2).size === 0) { + return; + } + + for (const editor of _classPrivateFieldGet(this, _selectedEditors)) { + editor.unselect(); + } + + _classPrivateFieldGet(this, _selectedEditors).clear(); + + _classPrivateMethodGet(this, _dispatchUpdateStates, _dispatchUpdateStates2).call(this, { + hasSelectedEditor: false + }); + } + + isActive(editor) { + return _classPrivateFieldGet(this, _activeEditor) === editor; + } + + getActive() { + return _classPrivateFieldGet(this, _activeEditor); + } + + getMode() { + return _classPrivateFieldGet(this, _mode); + } + +} + +exports.AnnotationEditorUIManager = AnnotationEditorUIManager; + +function _addKeyboardManager2() { + _classPrivateFieldGet(this, _container).addEventListener("keydown", _classPrivateFieldGet(this, _boundKeydown)); +} + +function _removeKeyboardManager2() { + _classPrivateFieldGet(this, _container).removeEventListener("keydown", _classPrivateFieldGet(this, _boundKeydown)); +} + +function _dispatchUpdateStates2(details) { + const hasChanged = Object.entries(details).some(_ref3 => { + let [key, value] = _ref3; + return _classPrivateFieldGet(this, _previousStates)[key] !== value; + }); + + if (hasChanged) { + _classPrivateFieldGet(this, _eventBus).dispatch("annotationeditorstateschanged", { + source: this, + details: Object.assign(_classPrivateFieldGet(this, _previousStates), details) + }); + } +} + +function _dispatchUpdateUI2(details) { + _classPrivateFieldGet(this, _eventBus).dispatch("annotationeditorparamschanged", { + source: this, + details + }); +} + +function _enableAll2() { + if (!_classPrivateFieldGet(this, _isEnabled)) { + _classPrivateFieldSet(this, _isEnabled, true); + + for (const layer of _classPrivateFieldGet(this, _allLayers).values()) { + layer.enable(); + } + } +} + +function _disableAll2() { + this.unselectAll(); + + if (_classPrivateFieldGet(this, _isEnabled)) { + _classPrivateFieldSet(this, _isEnabled, false); + + for (const layer of _classPrivateFieldGet(this, _allLayers).values()) { + layer.disable(); + } + } +} + +function _addEditorToLayer2(editor) { + const layer = _classPrivateFieldGet(this, _allLayers).get(editor.pageIndex); + + if (layer) { + layer.addOrRebuild(editor); + } else { + this.addEditor(editor); + } +} + +function _isEmpty2() { + if (_classPrivateFieldGet(this, _allEditors).size === 0) { + return true; + } + + if (_classPrivateFieldGet(this, _allEditors).size === 1) { + for (const editor of _classPrivateFieldGet(this, _allEditors).values()) { + return editor.isEmpty(); + } + } + + return false; +} + +function _selectEditors2(editors) { + _classPrivateFieldGet(this, _selectedEditors).clear(); + + for (const editor of editors) { + if (editor.isEmpty()) { + continue; + } + + _classPrivateFieldGet(this, _selectedEditors).add(editor); + + editor.select(); + } + + _classPrivateMethodGet(this, _dispatchUpdateStates, _dispatchUpdateStates2).call(this, { + hasSelectedEditor: true + }); +} + +_defineProperty(AnnotationEditorUIManager, "_keyboardManager", new KeyboardManager([[["ctrl+a", "mac+meta+a"], AnnotationEditorUIManager.prototype.selectAll], [["ctrl+c", "mac+meta+c"], AnnotationEditorUIManager.prototype.copy], [["ctrl+v", "mac+meta+v"], AnnotationEditorUIManager.prototype.paste], [["ctrl+x", "mac+meta+x"], AnnotationEditorUIManager.prototype.cut], [["ctrl+z", "mac+meta+z"], AnnotationEditorUIManager.prototype.undo], [["ctrl+y", "ctrl+shift+Z", "mac+meta+shift+Z"], AnnotationEditorUIManager.prototype.redo], [["Backspace", "alt+Backspace", "ctrl+Backspace", "shift+Backspace", "mac+Backspace", "mac+alt+Backspace", "mac+ctrl+Backspace", "Delete", "ctrl+Delete", "shift+Delete"], AnnotationEditorUIManager.prototype.delete], [["Escape", "mac+Escape"], AnnotationEditorUIManager.prototype.unselectAll]])); + +/***/ }), +/* 133 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.StatTimer = exports.RenderingCancelledException = exports.PixelsPerInch = exports.PageViewport = exports.PDFDateString = exports.DOMStandardFontDataFactory = exports.DOMSVGFactory = exports.DOMCanvasFactory = exports.DOMCMapReaderFactory = exports.AnnotationPrefix = void 0; +exports.deprecated = deprecated; +exports.getColorValues = getColorValues; +exports.getCurrentTransform = getCurrentTransform; +exports.getCurrentTransformInverse = getCurrentTransformInverse; +exports.getFilenameFromUrl = getFilenameFromUrl; +exports.getPdfFilenameFromUrl = getPdfFilenameFromUrl; +exports.getRGB = getRGB; +exports.getXfaPageViewport = getXfaPageViewport; +exports.isDataScheme = isDataScheme; +exports.isPdfFile = isPdfFile; +exports.isValidFetchUrl = isValidFetchUrl; +exports.loadScript = loadScript; + +var _base_factory = __w_pdfjs_require__(134); + +var _util = __w_pdfjs_require__(1); + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +const SVG_NS = "http://www.w3.org/2000/svg"; +const AnnotationPrefix = "pdfjs_internal_id_"; +exports.AnnotationPrefix = AnnotationPrefix; + +class PixelsPerInch {} + +exports.PixelsPerInch = PixelsPerInch; + +_defineProperty(PixelsPerInch, "CSS", 96.0); + +_defineProperty(PixelsPerInch, "PDF", 72.0); + +_defineProperty(PixelsPerInch, "PDF_TO_CSS_UNITS", PixelsPerInch.CSS / PixelsPerInch.PDF); + +class DOMCanvasFactory extends _base_factory.BaseCanvasFactory { + constructor() { + let { + ownerDocument = globalThis.document + } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + super(); + this._document = ownerDocument; + } + + _createCanvas(width, height) { + const canvas = this._document.createElement("canvas"); + + canvas.width = width; + canvas.height = height; + return canvas; + } + +} + +exports.DOMCanvasFactory = DOMCanvasFactory; + +async function fetchData(url) { + let asTypedArray = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + if (isValidFetchUrl(url, document.baseURI)) { + const response = await fetch(url); + + if (!response.ok) { + throw new Error(response.statusText); + } + + return asTypedArray ? new Uint8Array(await response.arrayBuffer()) : (0, _util.stringToBytes)(await response.text()); + } + + return new Promise((resolve, reject) => { + const request = new XMLHttpRequest(); + request.open("GET", url, true); + + if (asTypedArray) { + request.responseType = "arraybuffer"; + } + + request.onreadystatechange = () => { + if (request.readyState !== XMLHttpRequest.DONE) { + return; + } + + if (request.status === 200 || request.status === 0) { + let data; + + if (asTypedArray && request.response) { + data = new Uint8Array(request.response); + } else if (!asTypedArray && request.responseText) { + data = (0, _util.stringToBytes)(request.responseText); + } + + if (data) { + resolve(data); + return; + } + } + + reject(new Error(request.statusText)); + }; + + request.send(null); + }); +} + +class DOMCMapReaderFactory extends _base_factory.BaseCMapReaderFactory { + _fetchData(url, compressionType) { + return fetchData(url, this.isCompressed).then(data => { + return { + cMapData: data, + compressionType + }; + }); + } + +} + +exports.DOMCMapReaderFactory = DOMCMapReaderFactory; + +class DOMStandardFontDataFactory extends _base_factory.BaseStandardFontDataFactory { + _fetchData(url) { + return fetchData(url, true); + } + +} + +exports.DOMStandardFontDataFactory = DOMStandardFontDataFactory; + +class DOMSVGFactory extends _base_factory.BaseSVGFactory { + _createSVG(type) { + return document.createElementNS(SVG_NS, type); + } + +} + +exports.DOMSVGFactory = DOMSVGFactory; + +class PageViewport { + constructor(_ref) { + let { + viewBox, + scale, + rotation, + offsetX = 0, + offsetY = 0, + dontFlip = false + } = _ref; + this.viewBox = viewBox; + this.scale = scale; + this.rotation = rotation; + this.offsetX = offsetX; + this.offsetY = offsetY; + const centerX = (viewBox[2] + viewBox[0]) / 2; + const centerY = (viewBox[3] + viewBox[1]) / 2; + let rotateA, rotateB, rotateC, rotateD; + rotation %= 360; + + if (rotation < 0) { + rotation += 360; + } + + switch (rotation) { + case 180: + rotateA = -1; + rotateB = 0; + rotateC = 0; + rotateD = 1; + break; + + case 90: + rotateA = 0; + rotateB = 1; + rotateC = 1; + rotateD = 0; + break; + + case 270: + rotateA = 0; + rotateB = -1; + rotateC = -1; + rotateD = 0; + break; + + case 0: + rotateA = 1; + rotateB = 0; + rotateC = 0; + rotateD = -1; + break; + + default: + throw new Error("PageViewport: Invalid rotation, must be a multiple of 90 degrees."); + } + + if (dontFlip) { + rotateC = -rotateC; + rotateD = -rotateD; + } + + let offsetCanvasX, offsetCanvasY; + let width, height; + + if (rotateA === 0) { + offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX; + offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY; + width = Math.abs(viewBox[3] - viewBox[1]) * scale; + height = Math.abs(viewBox[2] - viewBox[0]) * scale; + } else { + offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX; + offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY; + width = Math.abs(viewBox[2] - viewBox[0]) * scale; + height = Math.abs(viewBox[3] - viewBox[1]) * scale; + } + + this.transform = [rotateA * scale, rotateB * scale, rotateC * scale, rotateD * scale, offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY, offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY]; + this.width = width; + this.height = height; + } + + clone() { + let { + scale = this.scale, + rotation = this.rotation, + offsetX = this.offsetX, + offsetY = this.offsetY, + dontFlip = false + } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + return new PageViewport({ + viewBox: this.viewBox.slice(), + scale, + rotation, + offsetX, + offsetY, + dontFlip + }); + } + + convertToViewportPoint(x, y) { + return _util.Util.applyTransform([x, y], this.transform); + } + + convertToViewportRectangle(rect) { + const topLeft = _util.Util.applyTransform([rect[0], rect[1]], this.transform); + + const bottomRight = _util.Util.applyTransform([rect[2], rect[3]], this.transform); + + return [topLeft[0], topLeft[1], bottomRight[0], bottomRight[1]]; + } + + convertToPdfPoint(x, y) { + return _util.Util.applyInverseTransform([x, y], this.transform); + } + +} + +exports.PageViewport = PageViewport; + +class RenderingCancelledException extends _util.BaseException { + constructor(msg, type) { + super(msg, "RenderingCancelledException"); + this.type = type; + } + +} + +exports.RenderingCancelledException = RenderingCancelledException; + +function isDataScheme(url) { + const ii = url.length; + let i = 0; + + while (i < ii && url[i].trim() === "") { + i++; + } + + return url.substring(i, i + 5).toLowerCase() === "data:"; +} + +function isPdfFile(filename) { + return typeof filename === "string" && /\.pdf$/i.test(filename); +} + +function getFilenameFromUrl(url) { + const anchor = url.indexOf("#"); + const query = url.indexOf("?"); + const end = Math.min(anchor > 0 ? anchor : url.length, query > 0 ? query : url.length); + return url.substring(url.lastIndexOf("/", end) + 1, end); +} + +function getPdfFilenameFromUrl(url) { + let defaultFilename = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "document.pdf"; + + if (typeof url !== "string") { + return defaultFilename; + } + + if (isDataScheme(url)) { + (0, _util.warn)('getPdfFilenameFromUrl: ignore "data:"-URL for performance reasons.'); + return defaultFilename; + } + + const reURI = /^(?:(?:[^:]+:)?\/\/[^/]+)?([^?#]*)(\?[^#]*)?(#.*)?$/; + const reFilename = /[^/?#=]+\.pdf\b(?!.*\.pdf\b)/i; + const splitURI = reURI.exec(url); + let suggestedFilename = reFilename.exec(splitURI[1]) || reFilename.exec(splitURI[2]) || reFilename.exec(splitURI[3]); + + if (suggestedFilename) { + suggestedFilename = suggestedFilename[0]; + + if (suggestedFilename.includes("%")) { + try { + suggestedFilename = reFilename.exec(decodeURIComponent(suggestedFilename))[0]; + } catch (ex) {} + } + } + + return suggestedFilename || defaultFilename; +} + +class StatTimer { + constructor() { + this.started = Object.create(null); + this.times = []; + } + + time(name) { + if (name in this.started) { + (0, _util.warn)(`Timer is already running for ${name}`); + } + + this.started[name] = Date.now(); + } + + timeEnd(name) { + if (!(name in this.started)) { + (0, _util.warn)(`Timer has not been started for ${name}`); + } + + this.times.push({ + name, + start: this.started[name], + end: Date.now() + }); + delete this.started[name]; + } + + toString() { + const outBuf = []; + let longest = 0; + + for (const time of this.times) { + const name = time.name; + + if (name.length > longest) { + longest = name.length; + } + } + + for (const time of this.times) { + const duration = time.end - time.start; + outBuf.push(`${time.name.padEnd(longest)} ${duration}ms\n`); + } + + return outBuf.join(""); + } + +} + +exports.StatTimer = StatTimer; + +function isValidFetchUrl(url, baseUrl) { + try { + const { + protocol + } = baseUrl ? new URL(url, baseUrl) : new URL(url); + return protocol === "http:" || protocol === "https:"; + } catch (ex) { + return false; + } +} + +function loadScript(src) { + let removeScriptElement = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + return new Promise((resolve, reject) => { + const script = document.createElement("script"); + script.src = src; + + script.onload = function (evt) { + if (removeScriptElement) { + script.remove(); + } + + resolve(evt); + }; + + script.onerror = function () { + reject(new Error(`Cannot load script at: ${script.src}`)); + }; + + (document.head || document.documentElement).append(script); + }); +} + +function deprecated(details) { + console.log("Deprecated API usage: " + details); +} + +let pdfDateStringRegex; + +class PDFDateString { + static toDateObject(input) { + if (!input || typeof input !== "string") { + return null; + } + + if (!pdfDateStringRegex) { + pdfDateStringRegex = new RegExp("^D:" + "(\\d{4})" + "(\\d{2})?" + "(\\d{2})?" + "(\\d{2})?" + "(\\d{2})?" + "(\\d{2})?" + "([Z|+|-])?" + "(\\d{2})?" + "'?" + "(\\d{2})?" + "'?"); + } + + const matches = pdfDateStringRegex.exec(input); + + if (!matches) { + return null; + } + + const year = parseInt(matches[1], 10); + let month = parseInt(matches[2], 10); + month = month >= 1 && month <= 12 ? month - 1 : 0; + let day = parseInt(matches[3], 10); + day = day >= 1 && day <= 31 ? day : 1; + let hour = parseInt(matches[4], 10); + hour = hour >= 0 && hour <= 23 ? hour : 0; + let minute = parseInt(matches[5], 10); + minute = minute >= 0 && minute <= 59 ? minute : 0; + let second = parseInt(matches[6], 10); + second = second >= 0 && second <= 59 ? second : 0; + const universalTimeRelation = matches[7] || "Z"; + let offsetHour = parseInt(matches[8], 10); + offsetHour = offsetHour >= 0 && offsetHour <= 23 ? offsetHour : 0; + let offsetMinute = parseInt(matches[9], 10) || 0; + offsetMinute = offsetMinute >= 0 && offsetMinute <= 59 ? offsetMinute : 0; + + if (universalTimeRelation === "-") { + hour += offsetHour; + minute += offsetMinute; + } else if (universalTimeRelation === "+") { + hour -= offsetHour; + minute -= offsetMinute; + } + + return new Date(Date.UTC(year, month, day, hour, minute, second)); + } + +} + +exports.PDFDateString = PDFDateString; + +function getXfaPageViewport(xfaPage, _ref2) { + let { + scale = 1, + rotation = 0 + } = _ref2; + const { + width, + height + } = xfaPage.attributes.style; + const viewBox = [0, 0, parseInt(width), parseInt(height)]; + return new PageViewport({ + viewBox, + scale, + rotation + }); +} + +function getRGB(color) { + if (color.startsWith("#")) { + const colorRGB = parseInt(color.slice(1), 16); + return [(colorRGB & 0xff0000) >> 16, (colorRGB & 0x00ff00) >> 8, colorRGB & 0x0000ff]; + } + + if (color.startsWith("rgb(")) { + return color.slice(4, -1).split(",").map(x => parseInt(x)); + } + + if (color.startsWith("rgba(")) { + return color.slice(5, -1).split(",").map(x => parseInt(x)).slice(0, 3); + } + + (0, _util.warn)(`Not a valid color format: "${color}"`); + return [0, 0, 0]; +} + +function getColorValues(colors) { + const span = document.createElement("span"); + span.style.visibility = "hidden"; + document.body.append(span); + + for (const name of colors.keys()) { + span.style.color = name; + const computedColor = window.getComputedStyle(span).color; + colors.set(name, getRGB(computedColor)); + } + + span.remove(); +} + +function getCurrentTransform(ctx) { + const { + a, + b, + c, + d, + e, + f + } = ctx.getTransform(); + return [a, b, c, d, e, f]; +} + +function getCurrentTransformInverse(ctx) { + const { + a, + b, + c, + d, + e, + f + } = ctx.getTransform().invertSelf(); + return [a, b, c, d, e, f]; +} + +/***/ }), +/* 134 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.BaseStandardFontDataFactory = exports.BaseSVGFactory = exports.BaseCanvasFactory = exports.BaseCMapReaderFactory = void 0; + +var _util = __w_pdfjs_require__(1); + +class BaseCanvasFactory { + constructor() { + if (this.constructor === BaseCanvasFactory) { + (0, _util.unreachable)("Cannot initialize BaseCanvasFactory."); + } + } + + create(width, height) { + if (width <= 0 || height <= 0) { + throw new Error("Invalid canvas size"); + } + + const canvas = this._createCanvas(width, height); + + return { + canvas, + context: canvas.getContext("2d") + }; + } + + reset(canvasAndContext, width, height) { + if (!canvasAndContext.canvas) { + throw new Error("Canvas is not specified"); + } + + if (width <= 0 || height <= 0) { + throw new Error("Invalid canvas size"); + } + + canvasAndContext.canvas.width = width; + canvasAndContext.canvas.height = height; + } + + destroy(canvasAndContext) { + if (!canvasAndContext.canvas) { + throw new Error("Canvas is not specified"); + } + + canvasAndContext.canvas.width = 0; + canvasAndContext.canvas.height = 0; + canvasAndContext.canvas = null; + canvasAndContext.context = null; + } + + _createCanvas(width, height) { + (0, _util.unreachable)("Abstract method `_createCanvas` called."); + } + +} + +exports.BaseCanvasFactory = BaseCanvasFactory; + +class BaseCMapReaderFactory { + constructor(_ref) { + let { + baseUrl = null, + isCompressed = false + } = _ref; + + if (this.constructor === BaseCMapReaderFactory) { + (0, _util.unreachable)("Cannot initialize BaseCMapReaderFactory."); + } + + this.baseUrl = baseUrl; + this.isCompressed = isCompressed; + } + + async fetch(_ref2) { + let { + name + } = _ref2; + + if (!this.baseUrl) { + throw new Error('The CMap "baseUrl" parameter must be specified, ensure that ' + 'the "cMapUrl" and "cMapPacked" API parameters are provided.'); + } + + if (!name) { + throw new Error("CMap name must be specified."); + } + + const url = this.baseUrl + name + (this.isCompressed ? ".bcmap" : ""); + const compressionType = this.isCompressed ? _util.CMapCompressionType.BINARY : _util.CMapCompressionType.NONE; + return this._fetchData(url, compressionType).catch(reason => { + throw new Error(`Unable to load ${this.isCompressed ? "binary " : ""}CMap at: ${url}`); + }); + } + + _fetchData(url, compressionType) { + (0, _util.unreachable)("Abstract method `_fetchData` called."); + } + +} + +exports.BaseCMapReaderFactory = BaseCMapReaderFactory; + +class BaseStandardFontDataFactory { + constructor(_ref3) { + let { + baseUrl = null + } = _ref3; + + if (this.constructor === BaseStandardFontDataFactory) { + (0, _util.unreachable)("Cannot initialize BaseStandardFontDataFactory."); + } + + this.baseUrl = baseUrl; + } + + async fetch(_ref4) { + let { + filename + } = _ref4; + + if (!this.baseUrl) { + throw new Error('The standard font "baseUrl" parameter must be specified, ensure that ' + 'the "standardFontDataUrl" API parameter is provided.'); + } + + if (!filename) { + throw new Error("Font filename must be specified."); + } + + const url = `${this.baseUrl}${filename}`; + return this._fetchData(url).catch(reason => { + throw new Error(`Unable to load font data at: ${url}`); + }); + } + + _fetchData(url) { + (0, _util.unreachable)("Abstract method `_fetchData` called."); + } + +} + +exports.BaseStandardFontDataFactory = BaseStandardFontDataFactory; + +class BaseSVGFactory { + constructor() { + if (this.constructor === BaseSVGFactory) { + (0, _util.unreachable)("Cannot initialize BaseSVGFactory."); + } + } + + create(width, height) { + let skipDimensions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + + if (width <= 0 || height <= 0) { + throw new Error("Invalid SVG dimensions"); + } + + const svg = this._createSVG("svg:svg"); + + svg.setAttribute("version", "1.1"); + + if (!skipDimensions) { + svg.setAttribute("width", `${width}px`); + svg.setAttribute("height", `${height}px`); + } + + svg.setAttribute("preserveAspectRatio", "none"); + svg.setAttribute("viewBox", `0 0 ${width} ${height}`); + return svg; + } + + createElement(type) { + if (typeof type !== "string") { + throw new Error("Invalid SVG element type"); + } + + return this._createSVG(type); + } + + _createSVG(type) { + (0, _util.unreachable)("Abstract method `_createSVG` called."); + } + +} + +exports.BaseSVGFactory = BaseSVGFactory; + +/***/ }), +/* 135 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.MurmurHash3_64 = void 0; + +var _util = __w_pdfjs_require__(1); + +const SEED = 0xc3d2e1f0; +const MASK_HIGH = 0xffff0000; +const MASK_LOW = 0xffff; + +class MurmurHash3_64 { + constructor(seed) { + this.h1 = seed ? seed & 0xffffffff : SEED; + this.h2 = seed ? seed & 0xffffffff : SEED; + } + + update(input) { + let data, length; + + if (typeof input === "string") { + data = new Uint8Array(input.length * 2); + length = 0; + + for (let i = 0, ii = input.length; i < ii; i++) { + const code = input.charCodeAt(i); + + if (code <= 0xff) { + data[length++] = code; + } else { + data[length++] = code >>> 8; + data[length++] = code & 0xff; + } + } + } else if ((0, _util.isArrayBuffer)(input)) { + data = input.slice(); + length = data.byteLength; + } else { + throw new Error("Wrong data format in MurmurHash3_64_update. " + "Input must be a string or array."); + } + + const blockCounts = length >> 2; + const tailLength = length - blockCounts * 4; + const dataUint32 = new Uint32Array(data.buffer, 0, blockCounts); + let k1 = 0, + k2 = 0; + let h1 = this.h1, + h2 = this.h2; + const C1 = 0xcc9e2d51, + C2 = 0x1b873593; + const C1_LOW = C1 & MASK_LOW, + C2_LOW = C2 & MASK_LOW; + + for (let i = 0; i < blockCounts; i++) { + if (i & 1) { + k1 = dataUint32[i]; + k1 = k1 * C1 & MASK_HIGH | k1 * C1_LOW & MASK_LOW; + k1 = k1 << 15 | k1 >>> 17; + k1 = k1 * C2 & MASK_HIGH | k1 * C2_LOW & MASK_LOW; + h1 ^= k1; + h1 = h1 << 13 | h1 >>> 19; + h1 = h1 * 5 + 0xe6546b64; + } else { + k2 = dataUint32[i]; + k2 = k2 * C1 & MASK_HIGH | k2 * C1_LOW & MASK_LOW; + k2 = k2 << 15 | k2 >>> 17; + k2 = k2 * C2 & MASK_HIGH | k2 * C2_LOW & MASK_LOW; + h2 ^= k2; + h2 = h2 << 13 | h2 >>> 19; + h2 = h2 * 5 + 0xe6546b64; + } + } + + k1 = 0; + + switch (tailLength) { + case 3: + k1 ^= data[blockCounts * 4 + 2] << 16; + + case 2: + k1 ^= data[blockCounts * 4 + 1] << 8; + + case 1: + k1 ^= data[blockCounts * 4]; + k1 = k1 * C1 & MASK_HIGH | k1 * C1_LOW & MASK_LOW; + k1 = k1 << 15 | k1 >>> 17; + k1 = k1 * C2 & MASK_HIGH | k1 * C2_LOW & MASK_LOW; + + if (blockCounts & 1) { + h1 ^= k1; + } else { + h2 ^= k1; + } + + } + + this.h1 = h1; + this.h2 = h2; + } + + hexdigest() { + let h1 = this.h1, + h2 = this.h2; + h1 ^= h2 >>> 1; + h1 = h1 * 0xed558ccd & MASK_HIGH | h1 * 0x8ccd & MASK_LOW; + h2 = h2 * 0xff51afd7 & MASK_HIGH | ((h2 << 16 | h1 >>> 16) * 0xafd7ed55 & MASK_HIGH) >>> 16; + h1 ^= h2 >>> 1; + h1 = h1 * 0x1a85ec53 & MASK_HIGH | h1 * 0xec53 & MASK_LOW; + h2 = h2 * 0xc4ceb9fe & MASK_HIGH | ((h2 << 16 | h1 >>> 16) * 0xb9fe1a85 & MASK_HIGH) >>> 16; + h1 ^= h2 >>> 1; + const hex1 = (h1 >>> 0).toString(16), + hex2 = (h2 >>> 0).toString(16); + return hex1.padStart(8, "0") + hex2.padStart(8, "0"); + } + +} + +exports.MurmurHash3_64 = MurmurHash3_64; + +/***/ }), +/* 136 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.FontLoader = exports.FontFaceObject = void 0; + +var _util = __w_pdfjs_require__(1); + +class BaseFontLoader { + constructor(_ref) { + let { + docId, + onUnsupportedFeature, + ownerDocument = globalThis.document, + styleElement = null + } = _ref; + + if (this.constructor === BaseFontLoader) { + (0, _util.unreachable)("Cannot initialize BaseFontLoader."); + } + + this.docId = docId; + this._onUnsupportedFeature = onUnsupportedFeature; + this._document = ownerDocument; + this.nativeFontFaces = []; + this.styleElement = null; + } + + addNativeFontFace(nativeFontFace) { + this.nativeFontFaces.push(nativeFontFace); + + this._document.fonts.add(nativeFontFace); + } + + insertRule(rule) { + let styleElement = this.styleElement; + + if (!styleElement) { + styleElement = this.styleElement = this._document.createElement("style"); + styleElement.id = `PDFJS_FONT_STYLE_TAG_${this.docId}`; + + this._document.documentElement.getElementsByTagName("head")[0].append(styleElement); + } + + const styleSheet = styleElement.sheet; + styleSheet.insertRule(rule, styleSheet.cssRules.length); + } + + clear() { + for (const nativeFontFace of this.nativeFontFaces) { + this._document.fonts.delete(nativeFontFace); + } + + this.nativeFontFaces.length = 0; + + if (this.styleElement) { + this.styleElement.remove(); + this.styleElement = null; + } + } + + async bind(font) { + if (font.attached || font.missingFile) { + return; + } + + font.attached = true; + + if (this.isFontLoadingAPISupported) { + const nativeFontFace = font.createNativeFontFace(); + + if (nativeFontFace) { + this.addNativeFontFace(nativeFontFace); + + try { + await nativeFontFace.loaded; + } catch (ex) { + this._onUnsupportedFeature({ + featureId: _util.UNSUPPORTED_FEATURES.errorFontLoadNative + }); + + (0, _util.warn)(`Failed to load font '${nativeFontFace.family}': '${ex}'.`); + font.disableFontFace = true; + throw ex; + } + } + + return; + } + + const rule = font.createFontFaceRule(); + + if (rule) { + this.insertRule(rule); + + if (this.isSyncFontLoadingSupported) { + return; + } + + await new Promise(resolve => { + const request = this._queueLoadingCallback(resolve); + + this._prepareFontLoadEvent([rule], [font], request); + }); + } + } + + _queueLoadingCallback(callback) { + (0, _util.unreachable)("Abstract method `_queueLoadingCallback`."); + } + + get isFontLoadingAPISupported() { + var _this$_document; + + const hasFonts = !!((_this$_document = this._document) !== null && _this$_document !== void 0 && _this$_document.fonts); + return (0, _util.shadow)(this, "isFontLoadingAPISupported", hasFonts); + } + + get isSyncFontLoadingSupported() { + (0, _util.unreachable)("Abstract method `isSyncFontLoadingSupported`."); + } + + get _loadTestFont() { + (0, _util.unreachable)("Abstract method `_loadTestFont`."); + } + + _prepareFontLoadEvent(rules, fontsToLoad, request) { + (0, _util.unreachable)("Abstract method `_prepareFontLoadEvent`."); + } + +} + +let FontLoader; +exports.FontLoader = FontLoader; +{ + exports.FontLoader = FontLoader = class GenericFontLoader extends BaseFontLoader { + constructor(params) { + super(params); + this.loadingContext = { + requests: [], + nextRequestId: 0 + }; + this.loadTestFontId = 0; + } + + get isSyncFontLoadingSupported() { + let supported = false; + + if (typeof navigator === "undefined") { + supported = true; + } else { + const m = /Mozilla\/5.0.*?rv:(\d+).*? Gecko/.exec(navigator.userAgent); + + if ((m === null || m === void 0 ? void 0 : m[1]) >= 14) { + supported = true; + } + } + + return (0, _util.shadow)(this, "isSyncFontLoadingSupported", supported); + } + + _queueLoadingCallback(callback) { + function completeRequest() { + (0, _util.assert)(!request.done, "completeRequest() cannot be called twice."); + request.done = true; + + while (context.requests.length > 0 && context.requests[0].done) { + const otherRequest = context.requests.shift(); + setTimeout(otherRequest.callback, 0); + } + } + + const context = this.loadingContext; + const request = { + id: `pdfjs-font-loading-${context.nextRequestId++}`, + done: false, + complete: completeRequest, + callback + }; + context.requests.push(request); + return request; + } + + get _loadTestFont() { + const getLoadTestFont = function () { + return atob("T1RUTwALAIAAAwAwQ0ZGIDHtZg4AAAOYAAAAgUZGVE1lkzZwAAAEHAAAABxHREVGABQA" + "FQAABDgAAAAeT1MvMlYNYwkAAAEgAAAAYGNtYXABDQLUAAACNAAAAUJoZWFk/xVFDQAA" + "ALwAAAA2aGhlYQdkA+oAAAD0AAAAJGhtdHgD6AAAAAAEWAAAAAZtYXhwAAJQAAAAARgA" + "AAAGbmFtZVjmdH4AAAGAAAAAsXBvc3T/hgAzAAADeAAAACAAAQAAAAEAALZRFsRfDzz1" + "AAsD6AAAAADOBOTLAAAAAM4KHDwAAAAAA+gDIQAAAAgAAgAAAAAAAAABAAADIQAAAFoD" + "6AAAAAAD6AABAAAAAAAAAAAAAAAAAAAAAQAAUAAAAgAAAAQD6AH0AAUAAAKKArwAAACM" + "AooCvAAAAeAAMQECAAACAAYJAAAAAAAAAAAAAQAAAAAAAAAAAAAAAFBmRWQAwAAuAC4D" + "IP84AFoDIQAAAAAAAQAAAAAAAAAAACAAIAABAAAADgCuAAEAAAAAAAAAAQAAAAEAAAAA" + "AAEAAQAAAAEAAAAAAAIAAQAAAAEAAAAAAAMAAQAAAAEAAAAAAAQAAQAAAAEAAAAAAAUA" + "AQAAAAEAAAAAAAYAAQAAAAMAAQQJAAAAAgABAAMAAQQJAAEAAgABAAMAAQQJAAIAAgAB" + "AAMAAQQJAAMAAgABAAMAAQQJAAQAAgABAAMAAQQJAAUAAgABAAMAAQQJAAYAAgABWABY" + "AAAAAAAAAwAAAAMAAAAcAAEAAAAAADwAAwABAAAAHAAEACAAAAAEAAQAAQAAAC7//wAA" + "AC7////TAAEAAAAAAAABBgAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAD/gwAyAAAAAQAAAAAAAAAAAAAAAAAA" + "AAABAAQEAAEBAQJYAAEBASH4DwD4GwHEAvgcA/gXBIwMAYuL+nz5tQXkD5j3CBLnEQAC" + "AQEBIVhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYAAABAQAADwACAQEEE/t3" + "Dov6fAH6fAT+fPp8+nwHDosMCvm1Cvm1DAz6fBQAAAAAAAABAAAAAMmJbzEAAAAAzgTj" + "FQAAAADOBOQpAAEAAAAAAAAADAAUAAQAAAABAAAAAgABAAAAAAAAAAAD6AAAAAAAAA=="); + }; + + return (0, _util.shadow)(this, "_loadTestFont", getLoadTestFont()); + } + + _prepareFontLoadEvent(rules, fonts, request) { + function int32(data, offset) { + return data.charCodeAt(offset) << 24 | data.charCodeAt(offset + 1) << 16 | data.charCodeAt(offset + 2) << 8 | data.charCodeAt(offset + 3) & 0xff; + } + + function spliceString(s, offset, remove, insert) { + const chunk1 = s.substring(0, offset); + const chunk2 = s.substring(offset + remove); + return chunk1 + insert + chunk2; + } + + let i, ii; + + const canvas = this._document.createElement("canvas"); + + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext("2d"); + let called = 0; + + function isFontReady(name, callback) { + called++; + + if (called > 30) { + (0, _util.warn)("Load test font never loaded."); + callback(); + return; + } + + ctx.font = "30px " + name; + ctx.fillText(".", 0, 20); + const imageData = ctx.getImageData(0, 0, 1, 1); + + if (imageData.data[3] > 0) { + callback(); + return; + } + + setTimeout(isFontReady.bind(null, name, callback)); + } + + const loadTestFontId = `lt${Date.now()}${this.loadTestFontId++}`; + let data = this._loadTestFont; + const COMMENT_OFFSET = 976; + data = spliceString(data, COMMENT_OFFSET, loadTestFontId.length, loadTestFontId); + const CFF_CHECKSUM_OFFSET = 16; + const XXXX_VALUE = 0x58585858; + let checksum = int32(data, CFF_CHECKSUM_OFFSET); + + for (i = 0, ii = loadTestFontId.length - 3; i < ii; i += 4) { + checksum = checksum - XXXX_VALUE + int32(loadTestFontId, i) | 0; + } + + if (i < loadTestFontId.length) { + checksum = checksum - XXXX_VALUE + int32(loadTestFontId + "XXX", i) | 0; + } + + data = spliceString(data, CFF_CHECKSUM_OFFSET, 4, (0, _util.string32)(checksum)); + const url = `url(data:font/opentype;base64,${btoa(data)});`; + const rule = `@font-face {font-family:"${loadTestFontId}";src:${url}}`; + this.insertRule(rule); + const names = []; + + for (const font of fonts) { + names.push(font.loadedName); + } + + names.push(loadTestFontId); + + const div = this._document.createElement("div"); + + div.style.visibility = "hidden"; + div.style.width = div.style.height = "10px"; + div.style.position = "absolute"; + div.style.top = div.style.left = "0px"; + + for (const name of names) { + const span = this._document.createElement("span"); + + span.textContent = "Hi"; + span.style.fontFamily = name; + div.append(span); + } + + this._document.body.append(div); + + isFontReady(loadTestFontId, () => { + div.remove(); + request.complete(); + }); + } + + }; +} + +class FontFaceObject { + constructor(translatedData, _ref2) { + let { + isEvalSupported = true, + disableFontFace = false, + ignoreErrors = false, + onUnsupportedFeature, + fontRegistry = null + } = _ref2; + this.compiledGlyphs = Object.create(null); + + for (const i in translatedData) { + this[i] = translatedData[i]; + } + + this.isEvalSupported = isEvalSupported !== false; + this.disableFontFace = disableFontFace === true; + this.ignoreErrors = ignoreErrors === true; + this._onUnsupportedFeature = onUnsupportedFeature; + this.fontRegistry = fontRegistry; + } + + createNativeFontFace() { + if (!this.data || this.disableFontFace) { + return null; + } + + let nativeFontFace; + + if (!this.cssFontInfo) { + nativeFontFace = new FontFace(this.loadedName, this.data, {}); + } else { + const css = { + weight: this.cssFontInfo.fontWeight + }; + + if (this.cssFontInfo.italicAngle) { + css.style = `oblique ${this.cssFontInfo.italicAngle}deg`; + } + + nativeFontFace = new FontFace(this.cssFontInfo.fontFamily, this.data, css); + } + + if (this.fontRegistry) { + this.fontRegistry.registerFont(this); + } + + return nativeFontFace; + } + + createFontFaceRule() { + if (!this.data || this.disableFontFace) { + return null; + } + + const data = (0, _util.bytesToString)(this.data); + const url = `url(data:${this.mimetype};base64,${btoa(data)});`; + let rule; + + if (!this.cssFontInfo) { + rule = `@font-face {font-family:"${this.loadedName}";src:${url}}`; + } else { + let css = `font-weight: ${this.cssFontInfo.fontWeight};`; + + if (this.cssFontInfo.italicAngle) { + css += `font-style: oblique ${this.cssFontInfo.italicAngle}deg;`; + } + + rule = `@font-face {font-family:"${this.cssFontInfo.fontFamily}";${css}src:${url}}`; + } + + if (this.fontRegistry) { + this.fontRegistry.registerFont(this, url); + } + + return rule; + } + + getPathGenerator(objs, character) { + if (this.compiledGlyphs[character] !== undefined) { + return this.compiledGlyphs[character]; + } + + let cmds; + + try { + cmds = objs.get(this.loadedName + "_path_" + character); + } catch (ex) { + if (!this.ignoreErrors) { + throw ex; + } + + this._onUnsupportedFeature({ + featureId: _util.UNSUPPORTED_FEATURES.errorFontGetPath + }); + + (0, _util.warn)(`getPathGenerator - ignoring character: "${ex}".`); + return this.compiledGlyphs[character] = function (c, size) {}; + } + + if (this.isEvalSupported && _util.FeatureTest.isEvalSupported) { + const jsBuf = []; + + for (const current of cmds) { + const args = current.args !== undefined ? current.args.join(",") : ""; + jsBuf.push("c.", current.cmd, "(", args, ");\n"); + } + + return this.compiledGlyphs[character] = new Function("c", "size", jsBuf.join("")); + } + + return this.compiledGlyphs[character] = function (c, size) { + for (const current of cmds) { + if (current.cmd === "scale") { + current.args = [size, -size]; + } + + c[current.cmd].apply(c, current.args); + } + }; + } + +} + +exports.FontFaceObject = FontFaceObject; + +/***/ }), +/* 137 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.CanvasGraphics = void 0; + +var _display_utils = __w_pdfjs_require__(133); + +var _util = __w_pdfjs_require__(1); + +var _pattern_helper = __w_pdfjs_require__(138); + +var _image_utils = __w_pdfjs_require__(139); + +var _is_node = __w_pdfjs_require__(3); + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +const MIN_FONT_SIZE = 16; +const MAX_FONT_SIZE = 100; +const MAX_GROUP_SIZE = 4096; +const EXECUTION_TIME = 15; +const EXECUTION_STEPS = 10; +const MAX_SIZE_TO_COMPILE = _is_node.isNodeJS && typeof Path2D === "undefined" ? -1 : 1000; +const FULL_CHUNK_HEIGHT = 16; + +function mirrorContextOperations(ctx, destCtx) { + if (ctx._removeMirroring) { + throw new Error("Context is already forwarding operations."); + } + + ctx.__originalSave = ctx.save; + ctx.__originalRestore = ctx.restore; + ctx.__originalRotate = ctx.rotate; + ctx.__originalScale = ctx.scale; + ctx.__originalTranslate = ctx.translate; + ctx.__originalTransform = ctx.transform; + ctx.__originalSetTransform = ctx.setTransform; + ctx.__originalResetTransform = ctx.resetTransform; + ctx.__originalClip = ctx.clip; + ctx.__originalMoveTo = ctx.moveTo; + ctx.__originalLineTo = ctx.lineTo; + ctx.__originalBezierCurveTo = ctx.bezierCurveTo; + ctx.__originalRect = ctx.rect; + ctx.__originalClosePath = ctx.closePath; + ctx.__originalBeginPath = ctx.beginPath; + + ctx._removeMirroring = () => { + ctx.save = ctx.__originalSave; + ctx.restore = ctx.__originalRestore; + ctx.rotate = ctx.__originalRotate; + ctx.scale = ctx.__originalScale; + ctx.translate = ctx.__originalTranslate; + ctx.transform = ctx.__originalTransform; + ctx.setTransform = ctx.__originalSetTransform; + ctx.resetTransform = ctx.__originalResetTransform; + ctx.clip = ctx.__originalClip; + ctx.moveTo = ctx.__originalMoveTo; + ctx.lineTo = ctx.__originalLineTo; + ctx.bezierCurveTo = ctx.__originalBezierCurveTo; + ctx.rect = ctx.__originalRect; + ctx.closePath = ctx.__originalClosePath; + ctx.beginPath = ctx.__originalBeginPath; + delete ctx._removeMirroring; + }; + + ctx.save = function ctxSave() { + destCtx.save(); + + this.__originalSave(); + }; + + ctx.restore = function ctxRestore() { + destCtx.restore(); + + this.__originalRestore(); + }; + + ctx.translate = function ctxTranslate(x, y) { + destCtx.translate(x, y); + + this.__originalTranslate(x, y); + }; + + ctx.scale = function ctxScale(x, y) { + destCtx.scale(x, y); + + this.__originalScale(x, y); + }; + + ctx.transform = function ctxTransform(a, b, c, d, e, f) { + destCtx.transform(a, b, c, d, e, f); + + this.__originalTransform(a, b, c, d, e, f); + }; + + ctx.setTransform = function ctxSetTransform(a, b, c, d, e, f) { + destCtx.setTransform(a, b, c, d, e, f); + + this.__originalSetTransform(a, b, c, d, e, f); + }; + + ctx.resetTransform = function ctxResetTransform() { + destCtx.resetTransform(); + + this.__originalResetTransform(); + }; + + ctx.rotate = function ctxRotate(angle) { + destCtx.rotate(angle); + + this.__originalRotate(angle); + }; + + ctx.clip = function ctxRotate(rule) { + destCtx.clip(rule); + + this.__originalClip(rule); + }; + + ctx.moveTo = function (x, y) { + destCtx.moveTo(x, y); + + this.__originalMoveTo(x, y); + }; + + ctx.lineTo = function (x, y) { + destCtx.lineTo(x, y); + + this.__originalLineTo(x, y); + }; + + ctx.bezierCurveTo = function (cp1x, cp1y, cp2x, cp2y, x, y) { + destCtx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y); + + this.__originalBezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y); + }; + + ctx.rect = function (x, y, width, height) { + destCtx.rect(x, y, width, height); + + this.__originalRect(x, y, width, height); + }; + + ctx.closePath = function () { + destCtx.closePath(); + + this.__originalClosePath(); + }; + + ctx.beginPath = function () { + destCtx.beginPath(); + + this.__originalBeginPath(); + }; +} + +class CachedCanvases { + constructor(canvasFactory) { + this.canvasFactory = canvasFactory; + this.cache = Object.create(null); + } + + getCanvas(id, width, height) { + let canvasEntry; + + if (this.cache[id] !== undefined) { + canvasEntry = this.cache[id]; + this.canvasFactory.reset(canvasEntry, width, height); + } else { + canvasEntry = this.canvasFactory.create(width, height); + this.cache[id] = canvasEntry; + } + + return canvasEntry; + } + + delete(id) { + delete this.cache[id]; + } + + clear() { + for (const id in this.cache) { + const canvasEntry = this.cache[id]; + this.canvasFactory.destroy(canvasEntry); + delete this.cache[id]; + } + } + +} + +function drawImageAtIntegerCoords(ctx, srcImg, srcX, srcY, srcW, srcH, destX, destY, destW, destH) { + const [a, b, c, d, tx, ty] = (0, _display_utils.getCurrentTransform)(ctx); + + if (b === 0 && c === 0) { + const tlX = destX * a + tx; + const rTlX = Math.round(tlX); + const tlY = destY * d + ty; + const rTlY = Math.round(tlY); + const brX = (destX + destW) * a + tx; + const rWidth = Math.abs(Math.round(brX) - rTlX) || 1; + const brY = (destY + destH) * d + ty; + const rHeight = Math.abs(Math.round(brY) - rTlY) || 1; + ctx.setTransform(Math.sign(a), 0, 0, Math.sign(d), rTlX, rTlY); + ctx.drawImage(srcImg, srcX, srcY, srcW, srcH, 0, 0, rWidth, rHeight); + ctx.setTransform(a, b, c, d, tx, ty); + return [rWidth, rHeight]; + } + + if (a === 0 && d === 0) { + const tlX = destY * c + tx; + const rTlX = Math.round(tlX); + const tlY = destX * b + ty; + const rTlY = Math.round(tlY); + const brX = (destY + destH) * c + tx; + const rWidth = Math.abs(Math.round(brX) - rTlX) || 1; + const brY = (destX + destW) * b + ty; + const rHeight = Math.abs(Math.round(brY) - rTlY) || 1; + ctx.setTransform(0, Math.sign(b), Math.sign(c), 0, rTlX, rTlY); + ctx.drawImage(srcImg, srcX, srcY, srcW, srcH, 0, 0, rHeight, rWidth); + ctx.setTransform(a, b, c, d, tx, ty); + return [rHeight, rWidth]; + } + + ctx.drawImage(srcImg, srcX, srcY, srcW, srcH, destX, destY, destW, destH); + const scaleX = Math.hypot(a, b); + const scaleY = Math.hypot(c, d); + return [scaleX * destW, scaleY * destH]; +} + +function compileType3Glyph(imgData) { + const { + width, + height + } = imgData; + + if (width > MAX_SIZE_TO_COMPILE || height > MAX_SIZE_TO_COMPILE) { + return null; + } + + const POINT_TO_PROCESS_LIMIT = 1000; + const POINT_TYPES = new Uint8Array([0, 2, 4, 0, 1, 0, 5, 4, 8, 10, 0, 8, 0, 2, 1, 0]); + const width1 = width + 1; + let points = new Uint8Array(width1 * (height + 1)); + let i, j, j0; + const lineSize = width + 7 & ~7; + let data = new Uint8Array(lineSize * height), + pos = 0; + + for (const elem of imgData.data) { + let mask = 128; + + while (mask > 0) { + data[pos++] = elem & mask ? 0 : 255; + mask >>= 1; + } + } + + let count = 0; + pos = 0; + + if (data[pos] !== 0) { + points[0] = 1; + ++count; + } + + for (j = 1; j < width; j++) { + if (data[pos] !== data[pos + 1]) { + points[j] = data[pos] ? 2 : 1; + ++count; + } + + pos++; + } + + if (data[pos] !== 0) { + points[j] = 2; + ++count; + } + + for (i = 1; i < height; i++) { + pos = i * lineSize; + j0 = i * width1; + + if (data[pos - lineSize] !== data[pos]) { + points[j0] = data[pos] ? 1 : 8; + ++count; + } + + let sum = (data[pos] ? 4 : 0) + (data[pos - lineSize] ? 8 : 0); + + for (j = 1; j < width; j++) { + sum = (sum >> 2) + (data[pos + 1] ? 4 : 0) + (data[pos - lineSize + 1] ? 8 : 0); + + if (POINT_TYPES[sum]) { + points[j0 + j] = POINT_TYPES[sum]; + ++count; + } + + pos++; + } + + if (data[pos - lineSize] !== data[pos]) { + points[j0 + j] = data[pos] ? 2 : 4; + ++count; + } + + if (count > POINT_TO_PROCESS_LIMIT) { + return null; + } + } + + pos = lineSize * (height - 1); + j0 = i * width1; + + if (data[pos] !== 0) { + points[j0] = 8; + ++count; + } + + for (j = 1; j < width; j++) { + if (data[pos] !== data[pos + 1]) { + points[j0 + j] = data[pos] ? 4 : 8; + ++count; + } + + pos++; + } + + if (data[pos] !== 0) { + points[j0 + j] = 4; + ++count; + } + + if (count > POINT_TO_PROCESS_LIMIT) { + return null; + } + + const steps = new Int32Array([0, width1, -1, 0, -width1, 0, 0, 0, 1]); + const path = new Path2D(); + + for (i = 0; count && i <= height; i++) { + let p = i * width1; + const end = p + width; + + while (p < end && !points[p]) { + p++; + } + + if (p === end) { + continue; + } + + path.moveTo(p % width1, i); + const p0 = p; + let type = points[p]; + + do { + const step = steps[type]; + + do { + p += step; + } while (!points[p]); + + const pp = points[p]; + + if (pp !== 5 && pp !== 10) { + type = pp; + points[p] = 0; + } else { + type = pp & 0x33 * type >> 4; + points[p] &= type >> 2 | type << 2; + } + + path.lineTo(p % width1, p / width1 | 0); + + if (!points[p]) { + --count; + } + } while (p0 !== p); + + --i; + } + + data = null; + points = null; + + const drawOutline = function (c) { + c.save(); + c.scale(1 / width, -1 / height); + c.translate(0, -height); + c.fill(path); + c.beginPath(); + c.restore(); + }; + + return drawOutline; +} + +class CanvasExtraState { + constructor(width, height) { + this.alphaIsShape = false; + this.fontSize = 0; + this.fontSizeScale = 1; + this.textMatrix = _util.IDENTITY_MATRIX; + this.textMatrixScale = 1; + this.fontMatrix = _util.FONT_IDENTITY_MATRIX; + this.leading = 0; + this.x = 0; + this.y = 0; + this.lineX = 0; + this.lineY = 0; + this.charSpacing = 0; + this.wordSpacing = 0; + this.textHScale = 1; + this.textRenderingMode = _util.TextRenderingMode.FILL; + this.textRise = 0; + this.fillColor = "#000000"; + this.strokeColor = "#000000"; + this.patternFill = false; + this.fillAlpha = 1; + this.strokeAlpha = 1; + this.lineWidth = 1; + this.activeSMask = null; + this.transferMaps = null; + this.startNewPathAndClipBox([0, 0, width, height]); + } + + clone() { + const clone = Object.create(this); + clone.clipBox = this.clipBox.slice(); + return clone; + } + + setCurrentPoint(x, y) { + this.x = x; + this.y = y; + } + + updatePathMinMax(transform, x, y) { + [x, y] = _util.Util.applyTransform([x, y], transform); + this.minX = Math.min(this.minX, x); + this.minY = Math.min(this.minY, y); + this.maxX = Math.max(this.maxX, x); + this.maxY = Math.max(this.maxY, y); + } + + updateRectMinMax(transform, rect) { + const p1 = _util.Util.applyTransform(rect, transform); + + const p2 = _util.Util.applyTransform(rect.slice(2), transform); + + this.minX = Math.min(this.minX, p1[0], p2[0]); + this.minY = Math.min(this.minY, p1[1], p2[1]); + this.maxX = Math.max(this.maxX, p1[0], p2[0]); + this.maxY = Math.max(this.maxY, p1[1], p2[1]); + } + + updateScalingPathMinMax(transform, minMax) { + _util.Util.scaleMinMax(transform, minMax); + + this.minX = Math.min(this.minX, minMax[0]); + this.maxX = Math.max(this.maxX, minMax[1]); + this.minY = Math.min(this.minY, minMax[2]); + this.maxY = Math.max(this.maxY, minMax[3]); + } + + updateCurvePathMinMax(transform, x0, y0, x1, y1, x2, y2, x3, y3, minMax) { + const box = _util.Util.bezierBoundingBox(x0, y0, x1, y1, x2, y2, x3, y3); + + if (minMax) { + minMax[0] = Math.min(minMax[0], box[0], box[2]); + minMax[1] = Math.max(minMax[1], box[0], box[2]); + minMax[2] = Math.min(minMax[2], box[1], box[3]); + minMax[3] = Math.max(minMax[3], box[1], box[3]); + return; + } + + this.updateRectMinMax(transform, box); + } + + getPathBoundingBox() { + let pathType = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _pattern_helper.PathType.FILL; + let transform = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + const box = [this.minX, this.minY, this.maxX, this.maxY]; + + if (pathType === _pattern_helper.PathType.STROKE) { + if (!transform) { + (0, _util.unreachable)("Stroke bounding box must include transform."); + } + + const scale = _util.Util.singularValueDecompose2dScale(transform); + + const xStrokePad = scale[0] * this.lineWidth / 2; + const yStrokePad = scale[1] * this.lineWidth / 2; + box[0] -= xStrokePad; + box[1] -= yStrokePad; + box[2] += xStrokePad; + box[3] += yStrokePad; + } + + return box; + } + + updateClipFromPath() { + const intersect = _util.Util.intersect(this.clipBox, this.getPathBoundingBox()); + + this.startNewPathAndClipBox(intersect || [0, 0, 0, 0]); + } + + isEmptyClip() { + return this.minX === Infinity; + } + + startNewPathAndClipBox(box) { + this.clipBox = box; + this.minX = Infinity; + this.minY = Infinity; + this.maxX = 0; + this.maxY = 0; + } + + getClippedPathBoundingBox() { + let pathType = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _pattern_helper.PathType.FILL; + let transform = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + return _util.Util.intersect(this.clipBox, this.getPathBoundingBox(pathType, transform)); + } + +} + +function putBinaryImageData(ctx, imgData) { + let transferMaps = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + + if (typeof ImageData !== "undefined" && imgData instanceof ImageData) { + ctx.putImageData(imgData, 0, 0); + return; + } + + const height = imgData.height, + width = imgData.width; + const partialChunkHeight = height % FULL_CHUNK_HEIGHT; + const fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT; + const totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1; + const chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT); + let srcPos = 0, + destPos; + const src = imgData.data; + const dest = chunkImgData.data; + let i, j, thisChunkHeight, elemsInThisChunk; + let transferMapRed, transferMapGreen, transferMapBlue, transferMapGray; + + if (transferMaps) { + switch (transferMaps.length) { + case 1: + transferMapRed = transferMaps[0]; + transferMapGreen = transferMaps[0]; + transferMapBlue = transferMaps[0]; + transferMapGray = transferMaps[0]; + break; + + case 4: + transferMapRed = transferMaps[0]; + transferMapGreen = transferMaps[1]; + transferMapBlue = transferMaps[2]; + transferMapGray = transferMaps[3]; + break; + } + } + + if (imgData.kind === _util.ImageKind.GRAYSCALE_1BPP) { + const srcLength = src.byteLength; + const dest32 = new Uint32Array(dest.buffer, 0, dest.byteLength >> 2); + const dest32DataLength = dest32.length; + const fullSrcDiff = width + 7 >> 3; + let white = 0xffffffff; + let black = _util.FeatureTest.isLittleEndian ? 0xff000000 : 0x000000ff; + + if (transferMapGray) { + if (transferMapGray[0] === 0xff && transferMapGray[0xff] === 0) { + [white, black] = [black, white]; + } + } + + for (i = 0; i < totalChunks; i++) { + thisChunkHeight = i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight; + destPos = 0; + + for (j = 0; j < thisChunkHeight; j++) { + const srcDiff = srcLength - srcPos; + let k = 0; + const kEnd = srcDiff > fullSrcDiff ? width : srcDiff * 8 - 7; + const kEndUnrolled = kEnd & ~7; + let mask = 0; + let srcByte = 0; + + for (; k < kEndUnrolled; k += 8) { + srcByte = src[srcPos++]; + dest32[destPos++] = srcByte & 128 ? white : black; + dest32[destPos++] = srcByte & 64 ? white : black; + dest32[destPos++] = srcByte & 32 ? white : black; + dest32[destPos++] = srcByte & 16 ? white : black; + dest32[destPos++] = srcByte & 8 ? white : black; + dest32[destPos++] = srcByte & 4 ? white : black; + dest32[destPos++] = srcByte & 2 ? white : black; + dest32[destPos++] = srcByte & 1 ? white : black; + } + + for (; k < kEnd; k++) { + if (mask === 0) { + srcByte = src[srcPos++]; + mask = 128; + } + + dest32[destPos++] = srcByte & mask ? white : black; + mask >>= 1; + } + } + + while (destPos < dest32DataLength) { + dest32[destPos++] = 0; + } + + ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT); + } + } else if (imgData.kind === _util.ImageKind.RGBA_32BPP) { + const hasTransferMaps = !!(transferMapRed || transferMapGreen || transferMapBlue); + j = 0; + elemsInThisChunk = width * FULL_CHUNK_HEIGHT * 4; + + for (i = 0; i < fullChunks; i++) { + dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk)); + srcPos += elemsInThisChunk; + + if (hasTransferMaps) { + for (let k = 0; k < elemsInThisChunk; k += 4) { + if (transferMapRed) { + dest[k + 0] = transferMapRed[dest[k + 0]]; + } + + if (transferMapGreen) { + dest[k + 1] = transferMapGreen[dest[k + 1]]; + } + + if (transferMapBlue) { + dest[k + 2] = transferMapBlue[dest[k + 2]]; + } + } + } + + ctx.putImageData(chunkImgData, 0, j); + j += FULL_CHUNK_HEIGHT; + } + + if (i < totalChunks) { + elemsInThisChunk = width * partialChunkHeight * 4; + dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk)); + + if (hasTransferMaps) { + for (let k = 0; k < elemsInThisChunk; k += 4) { + if (transferMapRed) { + dest[k + 0] = transferMapRed[dest[k + 0]]; + } + + if (transferMapGreen) { + dest[k + 1] = transferMapGreen[dest[k + 1]]; + } + + if (transferMapBlue) { + dest[k + 2] = transferMapBlue[dest[k + 2]]; + } + } + } + + ctx.putImageData(chunkImgData, 0, j); + } + } else if (imgData.kind === _util.ImageKind.RGB_24BPP) { + const hasTransferMaps = !!(transferMapRed || transferMapGreen || transferMapBlue); + thisChunkHeight = FULL_CHUNK_HEIGHT; + elemsInThisChunk = width * thisChunkHeight; + + for (i = 0; i < totalChunks; i++) { + if (i >= fullChunks) { + thisChunkHeight = partialChunkHeight; + elemsInThisChunk = width * thisChunkHeight; + } + + destPos = 0; + + for (j = elemsInThisChunk; j--;) { + dest[destPos++] = src[srcPos++]; + dest[destPos++] = src[srcPos++]; + dest[destPos++] = src[srcPos++]; + dest[destPos++] = 255; + } + + if (hasTransferMaps) { + for (let k = 0; k < destPos; k += 4) { + if (transferMapRed) { + dest[k + 0] = transferMapRed[dest[k + 0]]; + } + + if (transferMapGreen) { + dest[k + 1] = transferMapGreen[dest[k + 1]]; + } + + if (transferMapBlue) { + dest[k + 2] = transferMapBlue[dest[k + 2]]; + } + } + } + + ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT); + } + } else { + throw new Error(`bad image kind: ${imgData.kind}`); + } +} + +function putBinaryImageMask(ctx, imgData) { + if (imgData.bitmap) { + ctx.drawImage(imgData.bitmap, 0, 0); + return; + } + + const height = imgData.height, + width = imgData.width; + const partialChunkHeight = height % FULL_CHUNK_HEIGHT; + const fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT; + const totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1; + const chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT); + let srcPos = 0; + const src = imgData.data; + const dest = chunkImgData.data; + + for (let i = 0; i < totalChunks; i++) { + const thisChunkHeight = i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight; + ({ + srcPos + } = (0, _image_utils.applyMaskImageData)({ + src, + srcPos, + dest, + width, + height: thisChunkHeight + })); + ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT); + } +} + +function copyCtxState(sourceCtx, destCtx) { + const properties = ["strokeStyle", "fillStyle", "fillRule", "globalAlpha", "lineWidth", "lineCap", "lineJoin", "miterLimit", "globalCompositeOperation", "font"]; + + for (let i = 0, ii = properties.length; i < ii; i++) { + const property = properties[i]; + + if (sourceCtx[property] !== undefined) { + destCtx[property] = sourceCtx[property]; + } + } + + if (sourceCtx.setLineDash !== undefined) { + destCtx.setLineDash(sourceCtx.getLineDash()); + destCtx.lineDashOffset = sourceCtx.lineDashOffset; + } +} + +function resetCtxToDefault(ctx, foregroundColor) { + ctx.strokeStyle = ctx.fillStyle = foregroundColor || "#000000"; + ctx.fillRule = "nonzero"; + ctx.globalAlpha = 1; + ctx.lineWidth = 1; + ctx.lineCap = "butt"; + ctx.lineJoin = "miter"; + ctx.miterLimit = 10; + ctx.globalCompositeOperation = "source-over"; + ctx.font = "10px sans-serif"; + + if (ctx.setLineDash !== undefined) { + ctx.setLineDash([]); + ctx.lineDashOffset = 0; + } +} + +function composeSMaskBackdrop(bytes, r0, g0, b0) { + const length = bytes.length; + + for (let i = 3; i < length; i += 4) { + const alpha = bytes[i]; + + if (alpha === 0) { + bytes[i - 3] = r0; + bytes[i - 2] = g0; + bytes[i - 1] = b0; + } else if (alpha < 255) { + const alpha_ = 255 - alpha; + bytes[i - 3] = bytes[i - 3] * alpha + r0 * alpha_ >> 8; + bytes[i - 2] = bytes[i - 2] * alpha + g0 * alpha_ >> 8; + bytes[i - 1] = bytes[i - 1] * alpha + b0 * alpha_ >> 8; + } + } +} + +function composeSMaskAlpha(maskData, layerData, transferMap) { + const length = maskData.length; + const scale = 1 / 255; + + for (let i = 3; i < length; i += 4) { + const alpha = transferMap ? transferMap[maskData[i]] : maskData[i]; + layerData[i] = layerData[i] * alpha * scale | 0; + } +} + +function composeSMaskLuminosity(maskData, layerData, transferMap) { + const length = maskData.length; + + for (let i = 3; i < length; i += 4) { + const y = maskData[i - 3] * 77 + maskData[i - 2] * 152 + maskData[i - 1] * 28; + layerData[i] = transferMap ? layerData[i] * transferMap[y >> 8] >> 8 : layerData[i] * y >> 16; + } +} + +function genericComposeSMask(maskCtx, layerCtx, width, height, subtype, backdrop, transferMap, layerOffsetX, layerOffsetY, maskOffsetX, maskOffsetY) { + const hasBackdrop = !!backdrop; + const r0 = hasBackdrop ? backdrop[0] : 0; + const g0 = hasBackdrop ? backdrop[1] : 0; + const b0 = hasBackdrop ? backdrop[2] : 0; + let composeFn; + + if (subtype === "Luminosity") { + composeFn = composeSMaskLuminosity; + } else { + composeFn = composeSMaskAlpha; + } + + const PIXELS_TO_PROCESS = 1048576; + const chunkSize = Math.min(height, Math.ceil(PIXELS_TO_PROCESS / width)); + + for (let row = 0; row < height; row += chunkSize) { + const chunkHeight = Math.min(chunkSize, height - row); + const maskData = maskCtx.getImageData(layerOffsetX - maskOffsetX, row + (layerOffsetY - maskOffsetY), width, chunkHeight); + const layerData = layerCtx.getImageData(layerOffsetX, row + layerOffsetY, width, chunkHeight); + + if (hasBackdrop) { + composeSMaskBackdrop(maskData.data, r0, g0, b0); + } + + composeFn(maskData.data, layerData.data, transferMap); + layerCtx.putImageData(layerData, layerOffsetX, row + layerOffsetY); + } +} + +function composeSMask(ctx, smask, layerCtx, layerBox) { + const layerOffsetX = layerBox[0]; + const layerOffsetY = layerBox[1]; + const layerWidth = layerBox[2] - layerOffsetX; + const layerHeight = layerBox[3] - layerOffsetY; + + if (layerWidth === 0 || layerHeight === 0) { + return; + } + + genericComposeSMask(smask.context, layerCtx, layerWidth, layerHeight, smask.subtype, smask.backdrop, smask.transferMap, layerOffsetX, layerOffsetY, smask.offsetX, smask.offsetY); + ctx.save(); + ctx.globalAlpha = 1; + ctx.globalCompositeOperation = "source-over"; + ctx.setTransform(1, 0, 0, 1, 0, 0); + ctx.drawImage(layerCtx.canvas, 0, 0); + ctx.restore(); +} + +function getImageSmoothingEnabled(transform, interpolate) { + const scale = _util.Util.singularValueDecompose2dScale(transform); + + scale[0] = Math.fround(scale[0]); + scale[1] = Math.fround(scale[1]); + const actualScale = Math.fround((globalThis.devicePixelRatio || 1) * _display_utils.PixelsPerInch.PDF_TO_CSS_UNITS); + + if (interpolate !== undefined) { + return interpolate; + } else if (scale[0] <= actualScale || scale[1] <= actualScale) { + return true; + } + + return false; +} + +const LINE_CAP_STYLES = ["butt", "round", "square"]; +const LINE_JOIN_STYLES = ["miter", "round", "bevel"]; +const NORMAL_CLIP = {}; +const EO_CLIP = {}; + +var _restoreInitialState = /*#__PURE__*/new WeakSet(); + +class CanvasGraphics { + constructor(canvasCtx, commonObjs, objs, canvasFactory, imageLayer, optionalContentConfig, annotationCanvasMap, pageColors) { + _classPrivateMethodInitSpec(this, _restoreInitialState); + + this.ctx = canvasCtx; + this.current = new CanvasExtraState(this.ctx.canvas.width, this.ctx.canvas.height); + this.stateStack = []; + this.pendingClip = null; + this.pendingEOFill = false; + this.res = null; + this.xobjs = null; + this.commonObjs = commonObjs; + this.objs = objs; + this.canvasFactory = canvasFactory; + this.imageLayer = imageLayer; + this.groupStack = []; + this.processingType3 = null; + this.baseTransform = null; + this.baseTransformStack = []; + this.groupLevel = 0; + this.smaskStack = []; + this.smaskCounter = 0; + this.tempSMask = null; + this.suspendedCtx = null; + this.contentVisible = true; + this.markedContentStack = []; + this.optionalContentConfig = optionalContentConfig; + this.cachedCanvases = new CachedCanvases(this.canvasFactory); + this.cachedPatterns = new Map(); + this.annotationCanvasMap = annotationCanvasMap; + this.viewportScale = 1; + this.outputScaleX = 1; + this.outputScaleY = 1; + this.backgroundColor = (pageColors === null || pageColors === void 0 ? void 0 : pageColors.background) || null; + this.foregroundColor = (pageColors === null || pageColors === void 0 ? void 0 : pageColors.foreground) || null; + this._cachedScaleForStroking = null; + this._cachedGetSinglePixelWidth = null; + this._cachedBitmapsMap = new Map(); + } + + getObject(data) { + let fallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + + if (typeof data === "string") { + return data.startsWith("g_") ? this.commonObjs.get(data) : this.objs.get(data); + } + + return fallback; + } + + beginDrawing(_ref) { + let { + transform, + viewport, + transparency = false, + background = null + } = _ref; + const width = this.ctx.canvas.width; + const height = this.ctx.canvas.height; + const defaultBackgroundColor = background || "#ffffff"; + this.ctx.save(); + + if (this.foregroundColor && this.backgroundColor) { + this.ctx.fillStyle = this.foregroundColor; + const fg = this.foregroundColor = this.ctx.fillStyle; + this.ctx.fillStyle = this.backgroundColor; + const bg = this.backgroundColor = this.ctx.fillStyle; + let isValidDefaultBg = true; + let defaultBg = defaultBackgroundColor; + this.ctx.fillStyle = defaultBackgroundColor; + defaultBg = this.ctx.fillStyle; + isValidDefaultBg = typeof defaultBg === "string" && /^#[0-9A-Fa-f]{6}$/.test(defaultBg); + + if (fg === "#000000" && bg === "#ffffff" || fg === bg || !isValidDefaultBg) { + this.foregroundColor = this.backgroundColor = null; + } else { + const [rB, gB, bB] = (0, _display_utils.getRGB)(defaultBg); + + const newComp = x => { + x /= 255; + return x <= 0.03928 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4; + }; + + const lumB = Math.round(0.2126 * newComp(rB) + 0.7152 * newComp(gB) + 0.0722 * newComp(bB)); + + this.selectColor = (r, g, b) => { + const lumC = 0.2126 * newComp(r) + 0.7152 * newComp(g) + 0.0722 * newComp(b); + return Math.round(lumC) === lumB ? bg : fg; + }; + } + } + + this.ctx.fillStyle = this.backgroundColor || defaultBackgroundColor; + this.ctx.fillRect(0, 0, width, height); + this.ctx.restore(); + + if (transparency) { + const transparentCanvas = this.cachedCanvases.getCanvas("transparent", width, height); + this.compositeCtx = this.ctx; + this.transparentCanvas = transparentCanvas.canvas; + this.ctx = transparentCanvas.context; + this.ctx.save(); + this.ctx.transform(...(0, _display_utils.getCurrentTransform)(this.compositeCtx)); + } + + this.ctx.save(); + resetCtxToDefault(this.ctx, this.foregroundColor); + + if (transform) { + this.ctx.transform(...transform); + this.outputScaleX = transform[0]; + this.outputScaleY = transform[0]; + } + + this.ctx.transform(...viewport.transform); + this.viewportScale = viewport.scale; + this.baseTransform = (0, _display_utils.getCurrentTransform)(this.ctx); + + if (this.imageLayer) { + (0, _display_utils.deprecated)("The `imageLayer` functionality will be removed in the future."); + this.imageLayer.beginLayout(); + } + } + + executeOperatorList(operatorList, executionStartIdx, continueCallback, stepper) { + const argsArray = operatorList.argsArray; + const fnArray = operatorList.fnArray; + let i = executionStartIdx || 0; + const argsArrayLen = argsArray.length; + + if (argsArrayLen === i) { + return i; + } + + const chunkOperations = argsArrayLen - i > EXECUTION_STEPS && typeof continueCallback === "function"; + const endTime = chunkOperations ? Date.now() + EXECUTION_TIME : 0; + let steps = 0; + const commonObjs = this.commonObjs; + const objs = this.objs; + let fnId; + + while (true) { + if (stepper !== undefined && i === stepper.nextBreakPoint) { + stepper.breakIt(i, continueCallback); + return i; + } + + fnId = fnArray[i]; + + if (fnId !== _util.OPS.dependency) { + this[fnId].apply(this, argsArray[i]); + } else { + for (const depObjId of argsArray[i]) { + const objsPool = depObjId.startsWith("g_") ? commonObjs : objs; + + if (!objsPool.has(depObjId)) { + objsPool.get(depObjId, continueCallback); + return i; + } + } + } + + i++; + + if (i === argsArrayLen) { + return i; + } + + if (chunkOperations && ++steps > EXECUTION_STEPS) { + if (Date.now() > endTime) { + continueCallback(); + return i; + } + + steps = 0; + } + } + } + + endDrawing() { + _classPrivateMethodGet(this, _restoreInitialState, _restoreInitialState2).call(this); + + this.cachedCanvases.clear(); + this.cachedPatterns.clear(); + + for (const cache of this._cachedBitmapsMap.values()) { + for (const canvas of cache.values()) { + if (typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement) { + canvas.width = canvas.height = 0; + } + } + + cache.clear(); + } + + this._cachedBitmapsMap.clear(); + + if (this.imageLayer) { + this.imageLayer.endLayout(); + } + } + + _scaleImage(img, inverseTransform) { + const width = img.width; + const height = img.height; + let widthScale = Math.max(Math.hypot(inverseTransform[0], inverseTransform[1]), 1); + let heightScale = Math.max(Math.hypot(inverseTransform[2], inverseTransform[3]), 1); + let paintWidth = width, + paintHeight = height; + let tmpCanvasId = "prescale1"; + let tmpCanvas, tmpCtx; + + while (widthScale > 2 && paintWidth > 1 || heightScale > 2 && paintHeight > 1) { + let newWidth = paintWidth, + newHeight = paintHeight; + + if (widthScale > 2 && paintWidth > 1) { + newWidth = Math.ceil(paintWidth / 2); + widthScale /= paintWidth / newWidth; + } + + if (heightScale > 2 && paintHeight > 1) { + newHeight = Math.ceil(paintHeight / 2); + heightScale /= paintHeight / newHeight; + } + + tmpCanvas = this.cachedCanvases.getCanvas(tmpCanvasId, newWidth, newHeight); + tmpCtx = tmpCanvas.context; + tmpCtx.clearRect(0, 0, newWidth, newHeight); + tmpCtx.drawImage(img, 0, 0, paintWidth, paintHeight, 0, 0, newWidth, newHeight); + img = tmpCanvas.canvas; + paintWidth = newWidth; + paintHeight = newHeight; + tmpCanvasId = tmpCanvasId === "prescale1" ? "prescale2" : "prescale1"; + } + + return { + img, + paintWidth, + paintHeight + }; + } + + _createMaskCanvas(img) { + const ctx = this.ctx; + const { + width, + height + } = img; + const fillColor = this.current.fillColor; + const isPatternFill = this.current.patternFill; + const currentTransform = (0, _display_utils.getCurrentTransform)(ctx); + let cache, cacheKey, scaled, maskCanvas; + + if ((img.bitmap || img.data) && img.count > 1) { + const mainKey = img.bitmap || img.data.buffer; + const withoutTranslation = currentTransform.slice(0, 4); + cacheKey = JSON.stringify(isPatternFill ? withoutTranslation : [withoutTranslation, fillColor]); + cache = this._cachedBitmapsMap.get(mainKey); + + if (!cache) { + cache = new Map(); + + this._cachedBitmapsMap.set(mainKey, cache); + } + + const cachedImage = cache.get(cacheKey); + + if (cachedImage && !isPatternFill) { + const offsetX = Math.round(Math.min(currentTransform[0], currentTransform[2]) + currentTransform[4]); + const offsetY = Math.round(Math.min(currentTransform[1], currentTransform[3]) + currentTransform[5]); + return { + canvas: cachedImage, + offsetX, + offsetY + }; + } + + scaled = cachedImage; + } + + if (!scaled) { + maskCanvas = this.cachedCanvases.getCanvas("maskCanvas", width, height); + putBinaryImageMask(maskCanvas.context, img); + } + + let maskToCanvas = _util.Util.transform(currentTransform, [1 / width, 0, 0, -1 / height, 0, 0]); + + maskToCanvas = _util.Util.transform(maskToCanvas, [1, 0, 0, 1, 0, -height]); + + const cord1 = _util.Util.applyTransform([0, 0], maskToCanvas); + + const cord2 = _util.Util.applyTransform([width, height], maskToCanvas); + + const rect = _util.Util.normalizeRect([cord1[0], cord1[1], cord2[0], cord2[1]]); + + const drawnWidth = Math.round(rect[2] - rect[0]) || 1; + const drawnHeight = Math.round(rect[3] - rect[1]) || 1; + const fillCanvas = this.cachedCanvases.getCanvas("fillCanvas", drawnWidth, drawnHeight); + const fillCtx = fillCanvas.context; + const offsetX = Math.min(cord1[0], cord2[0]); + const offsetY = Math.min(cord1[1], cord2[1]); + fillCtx.translate(-offsetX, -offsetY); + fillCtx.transform(...maskToCanvas); + + if (!scaled) { + scaled = this._scaleImage(maskCanvas.canvas, (0, _display_utils.getCurrentTransformInverse)(fillCtx)); + scaled = scaled.img; + + if (cache && isPatternFill) { + cache.set(cacheKey, scaled); + } + } + + fillCtx.imageSmoothingEnabled = getImageSmoothingEnabled((0, _display_utils.getCurrentTransform)(fillCtx), img.interpolate); + drawImageAtIntegerCoords(fillCtx, scaled, 0, 0, scaled.width, scaled.height, 0, 0, width, height); + fillCtx.globalCompositeOperation = "source-in"; + + const inverse = _util.Util.transform((0, _display_utils.getCurrentTransformInverse)(fillCtx), [1, 0, 0, 1, -offsetX, -offsetY]); + + fillCtx.fillStyle = isPatternFill ? fillColor.getPattern(ctx, this, inverse, _pattern_helper.PathType.FILL) : fillColor; + fillCtx.fillRect(0, 0, width, height); + + if (cache && !isPatternFill) { + this.cachedCanvases.delete("fillCanvas"); + cache.set(cacheKey, fillCanvas.canvas); + } + + return { + canvas: fillCanvas.canvas, + offsetX: Math.round(offsetX), + offsetY: Math.round(offsetY) + }; + } + + setLineWidth(width) { + if (width !== this.current.lineWidth) { + this._cachedScaleForStroking = null; + } + + this.current.lineWidth = width; + this.ctx.lineWidth = width; + } + + setLineCap(style) { + this.ctx.lineCap = LINE_CAP_STYLES[style]; + } + + setLineJoin(style) { + this.ctx.lineJoin = LINE_JOIN_STYLES[style]; + } + + setMiterLimit(limit) { + this.ctx.miterLimit = limit; + } + + setDash(dashArray, dashPhase) { + const ctx = this.ctx; + + if (ctx.setLineDash !== undefined) { + ctx.setLineDash(dashArray); + ctx.lineDashOffset = dashPhase; + } + } + + setRenderingIntent(intent) {} + + setFlatness(flatness) {} + + setGState(states) { + for (let i = 0, ii = states.length; i < ii; i++) { + const state = states[i]; + const key = state[0]; + const value = state[1]; + + switch (key) { + case "LW": + this.setLineWidth(value); + break; + + case "LC": + this.setLineCap(value); + break; + + case "LJ": + this.setLineJoin(value); + break; + + case "ML": + this.setMiterLimit(value); + break; + + case "D": + this.setDash(value[0], value[1]); + break; + + case "RI": + this.setRenderingIntent(value); + break; + + case "FL": + this.setFlatness(value); + break; + + case "Font": + this.setFont(value[0], value[1]); + break; + + case "CA": + this.current.strokeAlpha = state[1]; + break; + + case "ca": + this.current.fillAlpha = state[1]; + this.ctx.globalAlpha = state[1]; + break; + + case "BM": + this.ctx.globalCompositeOperation = value; + break; + + case "SMask": + this.current.activeSMask = value ? this.tempSMask : null; + this.tempSMask = null; + this.checkSMaskState(); + break; + + case "TR": + this.current.transferMaps = value; + } + } + } + + get inSMaskMode() { + return !!this.suspendedCtx; + } + + checkSMaskState() { + const inSMaskMode = this.inSMaskMode; + + if (this.current.activeSMask && !inSMaskMode) { + this.beginSMaskMode(); + } else if (!this.current.activeSMask && inSMaskMode) { + this.endSMaskMode(); + } + } + + beginSMaskMode() { + if (this.inSMaskMode) { + throw new Error("beginSMaskMode called while already in smask mode"); + } + + const drawnWidth = this.ctx.canvas.width; + const drawnHeight = this.ctx.canvas.height; + const cacheId = "smaskGroupAt" + this.groupLevel; + const scratchCanvas = this.cachedCanvases.getCanvas(cacheId, drawnWidth, drawnHeight); + this.suspendedCtx = this.ctx; + this.ctx = scratchCanvas.context; + const ctx = this.ctx; + ctx.setTransform(...(0, _display_utils.getCurrentTransform)(this.suspendedCtx)); + copyCtxState(this.suspendedCtx, ctx); + mirrorContextOperations(ctx, this.suspendedCtx); + this.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]); + } + + endSMaskMode() { + if (!this.inSMaskMode) { + throw new Error("endSMaskMode called while not in smask mode"); + } + + this.ctx._removeMirroring(); + + copyCtxState(this.ctx, this.suspendedCtx); + this.ctx = this.suspendedCtx; + this.suspendedCtx = null; + } + + compose(dirtyBox) { + if (!this.current.activeSMask) { + return; + } + + if (!dirtyBox) { + dirtyBox = [0, 0, this.ctx.canvas.width, this.ctx.canvas.height]; + } else { + dirtyBox[0] = Math.floor(dirtyBox[0]); + dirtyBox[1] = Math.floor(dirtyBox[1]); + dirtyBox[2] = Math.ceil(dirtyBox[2]); + dirtyBox[3] = Math.ceil(dirtyBox[3]); + } + + const smask = this.current.activeSMask; + const suspendedCtx = this.suspendedCtx; + composeSMask(suspendedCtx, smask, this.ctx, dirtyBox); + this.ctx.save(); + this.ctx.setTransform(1, 0, 0, 1, 0, 0); + this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); + this.ctx.restore(); + } + + save() { + if (this.inSMaskMode) { + copyCtxState(this.ctx, this.suspendedCtx); + this.suspendedCtx.save(); + } else { + this.ctx.save(); + } + + const old = this.current; + this.stateStack.push(old); + this.current = old.clone(); + } + + restore() { + if (this.stateStack.length === 0 && this.inSMaskMode) { + this.endSMaskMode(); + } + + if (this.stateStack.length !== 0) { + this.current = this.stateStack.pop(); + + if (this.inSMaskMode) { + this.suspendedCtx.restore(); + copyCtxState(this.suspendedCtx, this.ctx); + } else { + this.ctx.restore(); + } + + this.checkSMaskState(); + this.pendingClip = null; + this._cachedScaleForStroking = null; + this._cachedGetSinglePixelWidth = null; + } + } + + transform(a, b, c, d, e, f) { + this.ctx.transform(a, b, c, d, e, f); + this._cachedScaleForStroking = null; + this._cachedGetSinglePixelWidth = null; + } + + constructPath(ops, args, minMax) { + const ctx = this.ctx; + const current = this.current; + let x = current.x, + y = current.y; + let startX, startY; + const currentTransform = (0, _display_utils.getCurrentTransform)(ctx); + const isScalingMatrix = currentTransform[0] === 0 && currentTransform[3] === 0 || currentTransform[1] === 0 && currentTransform[2] === 0; + const minMaxForBezier = isScalingMatrix ? minMax.slice(0) : null; + + for (let i = 0, j = 0, ii = ops.length; i < ii; i++) { + switch (ops[i] | 0) { + case _util.OPS.rectangle: + x = args[j++]; + y = args[j++]; + const width = args[j++]; + const height = args[j++]; + const xw = x + width; + const yh = y + height; + ctx.moveTo(x, y); + + if (width === 0 || height === 0) { + ctx.lineTo(xw, yh); + } else { + ctx.lineTo(xw, y); + ctx.lineTo(xw, yh); + ctx.lineTo(x, yh); + } + + if (!isScalingMatrix) { + current.updateRectMinMax(currentTransform, [x, y, xw, yh]); + } + + ctx.closePath(); + break; + + case _util.OPS.moveTo: + x = args[j++]; + y = args[j++]; + ctx.moveTo(x, y); + + if (!isScalingMatrix) { + current.updatePathMinMax(currentTransform, x, y); + } + + break; + + case _util.OPS.lineTo: + x = args[j++]; + y = args[j++]; + ctx.lineTo(x, y); + + if (!isScalingMatrix) { + current.updatePathMinMax(currentTransform, x, y); + } + + break; + + case _util.OPS.curveTo: + startX = x; + startY = y; + x = args[j + 4]; + y = args[j + 5]; + ctx.bezierCurveTo(args[j], args[j + 1], args[j + 2], args[j + 3], x, y); + current.updateCurvePathMinMax(currentTransform, startX, startY, args[j], args[j + 1], args[j + 2], args[j + 3], x, y, minMaxForBezier); + j += 6; + break; + + case _util.OPS.curveTo2: + startX = x; + startY = y; + ctx.bezierCurveTo(x, y, args[j], args[j + 1], args[j + 2], args[j + 3]); + current.updateCurvePathMinMax(currentTransform, startX, startY, x, y, args[j], args[j + 1], args[j + 2], args[j + 3], minMaxForBezier); + x = args[j + 2]; + y = args[j + 3]; + j += 4; + break; + + case _util.OPS.curveTo3: + startX = x; + startY = y; + x = args[j + 2]; + y = args[j + 3]; + ctx.bezierCurveTo(args[j], args[j + 1], x, y, x, y); + current.updateCurvePathMinMax(currentTransform, startX, startY, args[j], args[j + 1], x, y, x, y, minMaxForBezier); + j += 4; + break; + + case _util.OPS.closePath: + ctx.closePath(); + break; + } + } + + if (isScalingMatrix) { + current.updateScalingPathMinMax(currentTransform, minMaxForBezier); + } + + current.setCurrentPoint(x, y); + } + + closePath() { + this.ctx.closePath(); + } + + stroke(consumePath) { + consumePath = typeof consumePath !== "undefined" ? consumePath : true; + const ctx = this.ctx; + const strokeColor = this.current.strokeColor; + ctx.globalAlpha = this.current.strokeAlpha; + + if (this.contentVisible) { + if (typeof strokeColor === "object" && strokeColor !== null && strokeColor !== void 0 && strokeColor.getPattern) { + ctx.save(); + ctx.strokeStyle = strokeColor.getPattern(ctx, this, (0, _display_utils.getCurrentTransformInverse)(ctx), _pattern_helper.PathType.STROKE); + this.rescaleAndStroke(false); + ctx.restore(); + } else { + this.rescaleAndStroke(true); + } + } + + if (consumePath) { + this.consumePath(this.current.getClippedPathBoundingBox()); + } + + ctx.globalAlpha = this.current.fillAlpha; + } + + closeStroke() { + this.closePath(); + this.stroke(); + } + + fill(consumePath) { + consumePath = typeof consumePath !== "undefined" ? consumePath : true; + const ctx = this.ctx; + const fillColor = this.current.fillColor; + const isPatternFill = this.current.patternFill; + let needRestore = false; + + if (isPatternFill) { + ctx.save(); + ctx.fillStyle = fillColor.getPattern(ctx, this, (0, _display_utils.getCurrentTransformInverse)(ctx), _pattern_helper.PathType.FILL); + needRestore = true; + } + + const intersect = this.current.getClippedPathBoundingBox(); + + if (this.contentVisible && intersect !== null) { + if (this.pendingEOFill) { + ctx.fill("evenodd"); + this.pendingEOFill = false; + } else { + ctx.fill(); + } + } + + if (needRestore) { + ctx.restore(); + } + + if (consumePath) { + this.consumePath(intersect); + } + } + + eoFill() { + this.pendingEOFill = true; + this.fill(); + } + + fillStroke() { + this.fill(false); + this.stroke(false); + this.consumePath(); + } + + eoFillStroke() { + this.pendingEOFill = true; + this.fillStroke(); + } + + closeFillStroke() { + this.closePath(); + this.fillStroke(); + } + + closeEOFillStroke() { + this.pendingEOFill = true; + this.closePath(); + this.fillStroke(); + } + + endPath() { + this.consumePath(); + } + + clip() { + this.pendingClip = NORMAL_CLIP; + } + + eoClip() { + this.pendingClip = EO_CLIP; + } + + beginText() { + this.current.textMatrix = _util.IDENTITY_MATRIX; + this.current.textMatrixScale = 1; + this.current.x = this.current.lineX = 0; + this.current.y = this.current.lineY = 0; + } + + endText() { + const paths = this.pendingTextPaths; + const ctx = this.ctx; + + if (paths === undefined) { + ctx.beginPath(); + return; + } + + ctx.save(); + ctx.beginPath(); + + for (const path of paths) { + ctx.setTransform(...path.transform); + ctx.translate(path.x, path.y); + path.addToPath(ctx, path.fontSize); + } + + ctx.restore(); + ctx.clip(); + ctx.beginPath(); + delete this.pendingTextPaths; + } + + setCharSpacing(spacing) { + this.current.charSpacing = spacing; + } + + setWordSpacing(spacing) { + this.current.wordSpacing = spacing; + } + + setHScale(scale) { + this.current.textHScale = scale / 100; + } + + setLeading(leading) { + this.current.leading = -leading; + } + + setFont(fontRefName, size) { + const fontObj = this.commonObjs.get(fontRefName); + const current = this.current; + + if (!fontObj) { + throw new Error(`Can't find font for ${fontRefName}`); + } + + current.fontMatrix = fontObj.fontMatrix || _util.FONT_IDENTITY_MATRIX; + + if (current.fontMatrix[0] === 0 || current.fontMatrix[3] === 0) { + (0, _util.warn)("Invalid font matrix for font " + fontRefName); + } + + if (size < 0) { + size = -size; + current.fontDirection = -1; + } else { + current.fontDirection = 1; + } + + this.current.font = fontObj; + this.current.fontSize = size; + + if (fontObj.isType3Font) { + return; + } + + const name = fontObj.loadedName || "sans-serif"; + let bold = "normal"; + + if (fontObj.black) { + bold = "900"; + } else if (fontObj.bold) { + bold = "bold"; + } + + const italic = fontObj.italic ? "italic" : "normal"; + const typeface = `"${name}", ${fontObj.fallbackName}`; + let browserFontSize = size; + + if (size < MIN_FONT_SIZE) { + browserFontSize = MIN_FONT_SIZE; + } else if (size > MAX_FONT_SIZE) { + browserFontSize = MAX_FONT_SIZE; + } + + this.current.fontSizeScale = size / browserFontSize; + this.ctx.font = `${italic} ${bold} ${browserFontSize}px ${typeface}`; + } + + setTextRenderingMode(mode) { + this.current.textRenderingMode = mode; + } + + setTextRise(rise) { + this.current.textRise = rise; + } + + moveText(x, y) { + this.current.x = this.current.lineX += x; + this.current.y = this.current.lineY += y; + } + + setLeadingMoveText(x, y) { + this.setLeading(-y); + this.moveText(x, y); + } + + setTextMatrix(a, b, c, d, e, f) { + this.current.textMatrix = [a, b, c, d, e, f]; + this.current.textMatrixScale = Math.hypot(a, b); + this.current.x = this.current.lineX = 0; + this.current.y = this.current.lineY = 0; + } + + nextLine() { + this.moveText(0, this.current.leading); + } + + paintChar(character, x, y, patternTransform) { + const ctx = this.ctx; + const current = this.current; + const font = current.font; + const textRenderingMode = current.textRenderingMode; + const fontSize = current.fontSize / current.fontSizeScale; + const fillStrokeMode = textRenderingMode & _util.TextRenderingMode.FILL_STROKE_MASK; + const isAddToPathSet = !!(textRenderingMode & _util.TextRenderingMode.ADD_TO_PATH_FLAG); + const patternFill = current.patternFill && !font.missingFile; + let addToPath; + + if (font.disableFontFace || isAddToPathSet || patternFill) { + addToPath = font.getPathGenerator(this.commonObjs, character); + } + + if (font.disableFontFace || patternFill) { + ctx.save(); + ctx.translate(x, y); + ctx.beginPath(); + addToPath(ctx, fontSize); + + if (patternTransform) { + ctx.setTransform(...patternTransform); + } + + if (fillStrokeMode === _util.TextRenderingMode.FILL || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) { + ctx.fill(); + } + + if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) { + ctx.stroke(); + } + + ctx.restore(); + } else { + if (fillStrokeMode === _util.TextRenderingMode.FILL || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) { + ctx.fillText(character, x, y); + } + + if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) { + ctx.strokeText(character, x, y); + } + } + + if (isAddToPathSet) { + const paths = this.pendingTextPaths || (this.pendingTextPaths = []); + paths.push({ + transform: (0, _display_utils.getCurrentTransform)(ctx), + x, + y, + fontSize, + addToPath + }); + } + } + + get isFontSubpixelAAEnabled() { + const { + context: ctx + } = this.cachedCanvases.getCanvas("isFontSubpixelAAEnabled", 10, 10); + ctx.scale(1.5, 1); + ctx.fillText("I", 0, 10); + const data = ctx.getImageData(0, 0, 10, 10).data; + let enabled = false; + + for (let i = 3; i < data.length; i += 4) { + if (data[i] > 0 && data[i] < 255) { + enabled = true; + break; + } + } + + return (0, _util.shadow)(this, "isFontSubpixelAAEnabled", enabled); + } + + showText(glyphs) { + const current = this.current; + const font = current.font; + + if (font.isType3Font) { + return this.showType3Text(glyphs); + } + + const fontSize = current.fontSize; + + if (fontSize === 0) { + return undefined; + } + + const ctx = this.ctx; + const fontSizeScale = current.fontSizeScale; + const charSpacing = current.charSpacing; + const wordSpacing = current.wordSpacing; + const fontDirection = current.fontDirection; + const textHScale = current.textHScale * fontDirection; + const glyphsLength = glyphs.length; + const vertical = font.vertical; + const spacingDir = vertical ? 1 : -1; + const defaultVMetrics = font.defaultVMetrics; + const widthAdvanceScale = fontSize * current.fontMatrix[0]; + const simpleFillText = current.textRenderingMode === _util.TextRenderingMode.FILL && !font.disableFontFace && !current.patternFill; + ctx.save(); + ctx.transform(...current.textMatrix); + ctx.translate(current.x, current.y + current.textRise); + + if (fontDirection > 0) { + ctx.scale(textHScale, -1); + } else { + ctx.scale(textHScale, 1); + } + + let patternTransform; + + if (current.patternFill) { + ctx.save(); + const pattern = current.fillColor.getPattern(ctx, this, (0, _display_utils.getCurrentTransformInverse)(ctx), _pattern_helper.PathType.FILL); + patternTransform = (0, _display_utils.getCurrentTransform)(ctx); + ctx.restore(); + ctx.fillStyle = pattern; + } + + let lineWidth = current.lineWidth; + const scale = current.textMatrixScale; + + if (scale === 0 || lineWidth === 0) { + const fillStrokeMode = current.textRenderingMode & _util.TextRenderingMode.FILL_STROKE_MASK; + + if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) { + lineWidth = this.getSinglePixelWidth(); + } + } else { + lineWidth /= scale; + } + + if (fontSizeScale !== 1.0) { + ctx.scale(fontSizeScale, fontSizeScale); + lineWidth /= fontSizeScale; + } + + ctx.lineWidth = lineWidth; + let x = 0, + i; + + for (i = 0; i < glyphsLength; ++i) { + const glyph = glyphs[i]; + + if (typeof glyph === "number") { + x += spacingDir * glyph * fontSize / 1000; + continue; + } + + let restoreNeeded = false; + const spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing; + const character = glyph.fontChar; + const accent = glyph.accent; + let scaledX, scaledY; + let width = glyph.width; + + if (vertical) { + const vmetric = glyph.vmetric || defaultVMetrics; + const vx = -(glyph.vmetric ? vmetric[1] : width * 0.5) * widthAdvanceScale; + const vy = vmetric[2] * widthAdvanceScale; + width = vmetric ? -vmetric[0] : width; + scaledX = vx / fontSizeScale; + scaledY = (x + vy) / fontSizeScale; + } else { + scaledX = x / fontSizeScale; + scaledY = 0; + } + + if (font.remeasure && width > 0) { + const measuredWidth = ctx.measureText(character).width * 1000 / fontSize * fontSizeScale; + + if (width < measuredWidth && this.isFontSubpixelAAEnabled) { + const characterScaleX = width / measuredWidth; + restoreNeeded = true; + ctx.save(); + ctx.scale(characterScaleX, 1); + scaledX /= characterScaleX; + } else if (width !== measuredWidth) { + scaledX += (width - measuredWidth) / 2000 * fontSize / fontSizeScale; + } + } + + if (this.contentVisible && (glyph.isInFont || font.missingFile)) { + if (simpleFillText && !accent) { + ctx.fillText(character, scaledX, scaledY); + } else { + this.paintChar(character, scaledX, scaledY, patternTransform); + + if (accent) { + const scaledAccentX = scaledX + fontSize * accent.offset.x / fontSizeScale; + const scaledAccentY = scaledY - fontSize * accent.offset.y / fontSizeScale; + this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY, patternTransform); + } + } + } + + let charWidth; + + if (vertical) { + charWidth = width * widthAdvanceScale - spacing * fontDirection; + } else { + charWidth = width * widthAdvanceScale + spacing * fontDirection; + } + + x += charWidth; + + if (restoreNeeded) { + ctx.restore(); + } + } + + if (vertical) { + current.y -= x; + } else { + current.x += x * textHScale; + } + + ctx.restore(); + this.compose(); + return undefined; + } + + showType3Text(glyphs) { + const ctx = this.ctx; + const current = this.current; + const font = current.font; + const fontSize = current.fontSize; + const fontDirection = current.fontDirection; + const spacingDir = font.vertical ? 1 : -1; + const charSpacing = current.charSpacing; + const wordSpacing = current.wordSpacing; + const textHScale = current.textHScale * fontDirection; + const fontMatrix = current.fontMatrix || _util.FONT_IDENTITY_MATRIX; + const glyphsLength = glyphs.length; + const isTextInvisible = current.textRenderingMode === _util.TextRenderingMode.INVISIBLE; + let i, glyph, width, spacingLength; + + if (isTextInvisible || fontSize === 0) { + return; + } + + this._cachedScaleForStroking = null; + this._cachedGetSinglePixelWidth = null; + ctx.save(); + ctx.transform(...current.textMatrix); + ctx.translate(current.x, current.y); + ctx.scale(textHScale, fontDirection); + + for (i = 0; i < glyphsLength; ++i) { + glyph = glyphs[i]; + + if (typeof glyph === "number") { + spacingLength = spacingDir * glyph * fontSize / 1000; + this.ctx.translate(spacingLength, 0); + current.x += spacingLength * textHScale; + continue; + } + + const spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing; + const operatorList = font.charProcOperatorList[glyph.operatorListId]; + + if (!operatorList) { + (0, _util.warn)(`Type3 character "${glyph.operatorListId}" is not available.`); + continue; + } + + if (this.contentVisible) { + this.processingType3 = glyph; + this.save(); + ctx.scale(fontSize, fontSize); + ctx.transform(...fontMatrix); + this.executeOperatorList(operatorList); + this.restore(); + } + + const transformed = _util.Util.applyTransform([glyph.width, 0], fontMatrix); + + width = transformed[0] * fontSize + spacing; + ctx.translate(width, 0); + current.x += width * textHScale; + } + + ctx.restore(); + this.processingType3 = null; + } + + setCharWidth(xWidth, yWidth) {} + + setCharWidthAndBounds(xWidth, yWidth, llx, lly, urx, ury) { + this.ctx.rect(llx, lly, urx - llx, ury - lly); + this.ctx.clip(); + this.endPath(); + } + + getColorN_Pattern(IR) { + let pattern; + + if (IR[0] === "TilingPattern") { + const color = IR[1]; + const baseTransform = this.baseTransform || (0, _display_utils.getCurrentTransform)(this.ctx); + const canvasGraphicsFactory = { + createCanvasGraphics: ctx => { + return new CanvasGraphics(ctx, this.commonObjs, this.objs, this.canvasFactory); + } + }; + pattern = new _pattern_helper.TilingPattern(IR, color, this.ctx, canvasGraphicsFactory, baseTransform); + } else { + pattern = this._getPattern(IR[1], IR[2]); + } + + return pattern; + } + + setStrokeColorN() { + this.current.strokeColor = this.getColorN_Pattern(arguments); + } + + setFillColorN() { + this.current.fillColor = this.getColorN_Pattern(arguments); + this.current.patternFill = true; + } + + setStrokeRGBColor(r, g, b) { + var _this$selectColor; + + const color = ((_this$selectColor = this.selectColor) === null || _this$selectColor === void 0 ? void 0 : _this$selectColor.call(this, r, g, b)) || _util.Util.makeHexColor(r, g, b); + + this.ctx.strokeStyle = color; + this.current.strokeColor = color; + } + + setFillRGBColor(r, g, b) { + var _this$selectColor2; + + const color = ((_this$selectColor2 = this.selectColor) === null || _this$selectColor2 === void 0 ? void 0 : _this$selectColor2.call(this, r, g, b)) || _util.Util.makeHexColor(r, g, b); + + this.ctx.fillStyle = color; + this.current.fillColor = color; + this.current.patternFill = false; + } + + _getPattern(objId) { + let matrix = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + let pattern; + + if (this.cachedPatterns.has(objId)) { + pattern = this.cachedPatterns.get(objId); + } else { + pattern = (0, _pattern_helper.getShadingPattern)(this.objs.get(objId)); + this.cachedPatterns.set(objId, pattern); + } + + if (matrix) { + pattern.matrix = matrix; + } + + return pattern; + } + + shadingFill(objId) { + if (!this.contentVisible) { + return; + } + + const ctx = this.ctx; + this.save(); + + const pattern = this._getPattern(objId); + + ctx.fillStyle = pattern.getPattern(ctx, this, (0, _display_utils.getCurrentTransformInverse)(ctx), _pattern_helper.PathType.SHADING); + const inv = (0, _display_utils.getCurrentTransformInverse)(ctx); + + if (inv) { + const canvas = ctx.canvas; + const width = canvas.width; + const height = canvas.height; + + const bl = _util.Util.applyTransform([0, 0], inv); + + const br = _util.Util.applyTransform([0, height], inv); + + const ul = _util.Util.applyTransform([width, 0], inv); + + const ur = _util.Util.applyTransform([width, height], inv); + + const x0 = Math.min(bl[0], br[0], ul[0], ur[0]); + const y0 = Math.min(bl[1], br[1], ul[1], ur[1]); + const x1 = Math.max(bl[0], br[0], ul[0], ur[0]); + const y1 = Math.max(bl[1], br[1], ul[1], ur[1]); + this.ctx.fillRect(x0, y0, x1 - x0, y1 - y0); + } else { + this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10); + } + + this.compose(this.current.getClippedPathBoundingBox()); + this.restore(); + } + + beginInlineImage() { + (0, _util.unreachable)("Should not call beginInlineImage"); + } + + beginImageData() { + (0, _util.unreachable)("Should not call beginImageData"); + } + + paintFormXObjectBegin(matrix, bbox) { + if (!this.contentVisible) { + return; + } + + this.save(); + this.baseTransformStack.push(this.baseTransform); + + if (Array.isArray(matrix) && matrix.length === 6) { + this.transform(...matrix); + } + + this.baseTransform = (0, _display_utils.getCurrentTransform)(this.ctx); + + if (bbox) { + const width = bbox[2] - bbox[0]; + const height = bbox[3] - bbox[1]; + this.ctx.rect(bbox[0], bbox[1], width, height); + this.current.updateRectMinMax((0, _display_utils.getCurrentTransform)(this.ctx), bbox); + this.clip(); + this.endPath(); + } + } + + paintFormXObjectEnd() { + if (!this.contentVisible) { + return; + } + + this.restore(); + this.baseTransform = this.baseTransformStack.pop(); + } + + beginGroup(group) { + if (!this.contentVisible) { + return; + } + + this.save(); + + if (this.inSMaskMode) { + this.endSMaskMode(); + this.current.activeSMask = null; + } + + const currentCtx = this.ctx; + + if (!group.isolated) { + (0, _util.info)("TODO: Support non-isolated groups."); + } + + if (group.knockout) { + (0, _util.warn)("Knockout groups not supported."); + } + + const currentTransform = (0, _display_utils.getCurrentTransform)(currentCtx); + + if (group.matrix) { + currentCtx.transform(...group.matrix); + } + + if (!group.bbox) { + throw new Error("Bounding box is required."); + } + + let bounds = _util.Util.getAxialAlignedBoundingBox(group.bbox, (0, _display_utils.getCurrentTransform)(currentCtx)); + + const canvasBounds = [0, 0, currentCtx.canvas.width, currentCtx.canvas.height]; + bounds = _util.Util.intersect(bounds, canvasBounds) || [0, 0, 0, 0]; + const offsetX = Math.floor(bounds[0]); + const offsetY = Math.floor(bounds[1]); + let drawnWidth = Math.max(Math.ceil(bounds[2]) - offsetX, 1); + let drawnHeight = Math.max(Math.ceil(bounds[3]) - offsetY, 1); + let scaleX = 1, + scaleY = 1; + + if (drawnWidth > MAX_GROUP_SIZE) { + scaleX = drawnWidth / MAX_GROUP_SIZE; + drawnWidth = MAX_GROUP_SIZE; + } + + if (drawnHeight > MAX_GROUP_SIZE) { + scaleY = drawnHeight / MAX_GROUP_SIZE; + drawnHeight = MAX_GROUP_SIZE; + } + + this.current.startNewPathAndClipBox([0, 0, drawnWidth, drawnHeight]); + let cacheId = "groupAt" + this.groupLevel; + + if (group.smask) { + cacheId += "_smask_" + this.smaskCounter++ % 2; + } + + const scratchCanvas = this.cachedCanvases.getCanvas(cacheId, drawnWidth, drawnHeight); + const groupCtx = scratchCanvas.context; + groupCtx.scale(1 / scaleX, 1 / scaleY); + groupCtx.translate(-offsetX, -offsetY); + groupCtx.transform(...currentTransform); + + if (group.smask) { + this.smaskStack.push({ + canvas: scratchCanvas.canvas, + context: groupCtx, + offsetX, + offsetY, + scaleX, + scaleY, + subtype: group.smask.subtype, + backdrop: group.smask.backdrop, + transferMap: group.smask.transferMap || null, + startTransformInverse: null + }); + } else { + currentCtx.setTransform(1, 0, 0, 1, 0, 0); + currentCtx.translate(offsetX, offsetY); + currentCtx.scale(scaleX, scaleY); + currentCtx.save(); + } + + copyCtxState(currentCtx, groupCtx); + this.ctx = groupCtx; + this.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]); + this.groupStack.push(currentCtx); + this.groupLevel++; + } + + endGroup(group) { + if (!this.contentVisible) { + return; + } + + this.groupLevel--; + const groupCtx = this.ctx; + const ctx = this.groupStack.pop(); + this.ctx = ctx; + this.ctx.imageSmoothingEnabled = false; + + if (group.smask) { + this.tempSMask = this.smaskStack.pop(); + this.restore(); + } else { + this.ctx.restore(); + const currentMtx = (0, _display_utils.getCurrentTransform)(this.ctx); + this.restore(); + this.ctx.save(); + this.ctx.setTransform(...currentMtx); + + const dirtyBox = _util.Util.getAxialAlignedBoundingBox([0, 0, groupCtx.canvas.width, groupCtx.canvas.height], currentMtx); + + this.ctx.drawImage(groupCtx.canvas, 0, 0); + this.ctx.restore(); + this.compose(dirtyBox); + } + } + + beginAnnotation(id, rect, transform, matrix, hasOwnCanvas) { + _classPrivateMethodGet(this, _restoreInitialState, _restoreInitialState2).call(this); + + resetCtxToDefault(this.ctx, this.foregroundColor); + this.ctx.save(); + this.save(); + + if (this.baseTransform) { + this.ctx.setTransform(...this.baseTransform); + } + + if (Array.isArray(rect) && rect.length === 4) { + const width = rect[2] - rect[0]; + const height = rect[3] - rect[1]; + + if (hasOwnCanvas && this.annotationCanvasMap) { + transform = transform.slice(); + transform[4] -= rect[0]; + transform[5] -= rect[1]; + rect = rect.slice(); + rect[0] = rect[1] = 0; + rect[2] = width; + rect[3] = height; + + const [scaleX, scaleY] = _util.Util.singularValueDecompose2dScale((0, _display_utils.getCurrentTransform)(this.ctx)); + + const { + viewportScale + } = this; + const canvasWidth = Math.ceil(width * this.outputScaleX * viewportScale); + const canvasHeight = Math.ceil(height * this.outputScaleY * viewportScale); + this.annotationCanvas = this.canvasFactory.create(canvasWidth, canvasHeight); + const { + canvas, + context + } = this.annotationCanvas; + this.annotationCanvasMap.set(id, canvas); + this.annotationCanvas.savedCtx = this.ctx; + this.ctx = context; + this.ctx.setTransform(scaleX, 0, 0, -scaleY, 0, height * scaleY); + resetCtxToDefault(this.ctx, this.foregroundColor); + } else { + resetCtxToDefault(this.ctx, this.foregroundColor); + this.ctx.rect(rect[0], rect[1], width, height); + this.ctx.clip(); + this.endPath(); + } + } + + this.current = new CanvasExtraState(this.ctx.canvas.width, this.ctx.canvas.height); + this.transform(...transform); + this.transform(...matrix); + } + + endAnnotation() { + if (this.annotationCanvas) { + this.ctx = this.annotationCanvas.savedCtx; + delete this.annotationCanvas.savedCtx; + delete this.annotationCanvas; + } + } + + paintImageMaskXObject(img) { + if (!this.contentVisible) { + return; + } + + const count = img.count; + img = this.getObject(img.data, img); + img.count = count; + const ctx = this.ctx; + const glyph = this.processingType3; + + if (glyph) { + if (glyph.compiled === undefined) { + glyph.compiled = compileType3Glyph(img); + } + + if (glyph.compiled) { + glyph.compiled(ctx); + return; + } + } + + const mask = this._createMaskCanvas(img); + + const maskCanvas = mask.canvas; + ctx.save(); + ctx.setTransform(1, 0, 0, 1, 0, 0); + ctx.drawImage(maskCanvas, mask.offsetX, mask.offsetY); + ctx.restore(); + this.compose(); + } + + paintImageMaskXObjectRepeat(img, scaleX) { + let skewX = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; + let skewY = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0; + let scaleY = arguments.length > 4 ? arguments[4] : undefined; + let positions = arguments.length > 5 ? arguments[5] : undefined; + + if (!this.contentVisible) { + return; + } + + img = this.getObject(img.data, img); + const ctx = this.ctx; + ctx.save(); + const currentTransform = (0, _display_utils.getCurrentTransform)(ctx); + ctx.transform(scaleX, skewX, skewY, scaleY, 0, 0); + + const mask = this._createMaskCanvas(img); + + ctx.setTransform(1, 0, 0, 1, 0, 0); + + for (let i = 0, ii = positions.length; i < ii; i += 2) { + const trans = _util.Util.transform(currentTransform, [scaleX, skewX, skewY, scaleY, positions[i], positions[i + 1]]); + + const [x, y] = _util.Util.applyTransform([0, 0], trans); + + ctx.drawImage(mask.canvas, x, y); + } + + ctx.restore(); + this.compose(); + } + + paintImageMaskXObjectGroup(images) { + if (!this.contentVisible) { + return; + } + + const ctx = this.ctx; + const fillColor = this.current.fillColor; + const isPatternFill = this.current.patternFill; + + for (const image of images) { + const { + data, + width, + height, + transform + } = image; + const maskCanvas = this.cachedCanvases.getCanvas("maskCanvas", width, height); + const maskCtx = maskCanvas.context; + maskCtx.save(); + const img = this.getObject(data, image); + putBinaryImageMask(maskCtx, img); + maskCtx.globalCompositeOperation = "source-in"; + maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this, (0, _display_utils.getCurrentTransformInverse)(ctx), _pattern_helper.PathType.FILL) : fillColor; + maskCtx.fillRect(0, 0, width, height); + maskCtx.restore(); + ctx.save(); + ctx.transform(...transform); + ctx.scale(1, -1); + drawImageAtIntegerCoords(ctx, maskCanvas.canvas, 0, 0, width, height, 0, -1, 1, 1); + ctx.restore(); + } + + this.compose(); + } + + paintImageXObject(objId) { + if (!this.contentVisible) { + return; + } + + const imgData = this.getObject(objId); + + if (!imgData) { + (0, _util.warn)("Dependent image isn't ready yet"); + return; + } + + this.paintInlineImageXObject(imgData); + } + + paintImageXObjectRepeat(objId, scaleX, scaleY, positions) { + if (!this.contentVisible) { + return; + } + + const imgData = this.getObject(objId); + + if (!imgData) { + (0, _util.warn)("Dependent image isn't ready yet"); + return; + } + + const width = imgData.width; + const height = imgData.height; + const map = []; + + for (let i = 0, ii = positions.length; i < ii; i += 2) { + map.push({ + transform: [scaleX, 0, 0, scaleY, positions[i], positions[i + 1]], + x: 0, + y: 0, + w: width, + h: height + }); + } + + this.paintInlineImageXObjectGroup(imgData, map); + } + + paintInlineImageXObject(imgData) { + if (!this.contentVisible) { + return; + } + + const width = imgData.width; + const height = imgData.height; + const ctx = this.ctx; + this.save(); + ctx.scale(1 / width, -1 / height); + let imgToPaint; + + if (typeof HTMLElement === "function" && imgData instanceof HTMLElement || !imgData.data) { + imgToPaint = imgData; + } else { + const tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", width, height); + const tmpCtx = tmpCanvas.context; + putBinaryImageData(tmpCtx, imgData, this.current.transferMaps); + imgToPaint = tmpCanvas.canvas; + } + + const scaled = this._scaleImage(imgToPaint, (0, _display_utils.getCurrentTransformInverse)(ctx)); + + ctx.imageSmoothingEnabled = getImageSmoothingEnabled((0, _display_utils.getCurrentTransform)(ctx), imgData.interpolate); + const [rWidth, rHeight] = drawImageAtIntegerCoords(ctx, scaled.img, 0, 0, scaled.paintWidth, scaled.paintHeight, 0, -height, width, height); + + if (this.imageLayer) { + const [left, top] = _util.Util.applyTransform([0, -height], (0, _display_utils.getCurrentTransform)(this.ctx)); + + this.imageLayer.appendImage({ + imgData, + left, + top, + width: rWidth, + height: rHeight + }); + } + + this.compose(); + this.restore(); + } + + paintInlineImageXObjectGroup(imgData, map) { + if (!this.contentVisible) { + return; + } + + const ctx = this.ctx; + const w = imgData.width; + const h = imgData.height; + const tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", w, h); + const tmpCtx = tmpCanvas.context; + putBinaryImageData(tmpCtx, imgData, this.current.transferMaps); + + for (const entry of map) { + ctx.save(); + ctx.transform(...entry.transform); + ctx.scale(1, -1); + drawImageAtIntegerCoords(ctx, tmpCanvas.canvas, entry.x, entry.y, entry.w, entry.h, 0, -1, 1, 1); + + if (this.imageLayer) { + const [left, top] = _util.Util.applyTransform([entry.x, entry.y], (0, _display_utils.getCurrentTransform)(this.ctx)); + + this.imageLayer.appendImage({ + imgData, + left, + top, + width: w, + height: h + }); + } + + ctx.restore(); + } + + this.compose(); + } + + paintSolidColorImageMask() { + if (!this.contentVisible) { + return; + } + + this.ctx.fillRect(0, 0, 1, 1); + this.compose(); + } + + markPoint(tag) {} + + markPointProps(tag, properties) {} + + beginMarkedContent(tag) { + this.markedContentStack.push({ + visible: true + }); + } + + beginMarkedContentProps(tag, properties) { + if (tag === "OC") { + this.markedContentStack.push({ + visible: this.optionalContentConfig.isVisible(properties) + }); + } else { + this.markedContentStack.push({ + visible: true + }); + } + + this.contentVisible = this.isContentVisible(); + } + + endMarkedContent() { + this.markedContentStack.pop(); + this.contentVisible = this.isContentVisible(); + } + + beginCompat() {} + + endCompat() {} + + consumePath(clipBox) { + const isEmpty = this.current.isEmptyClip(); + + if (this.pendingClip) { + this.current.updateClipFromPath(); + } + + if (!this.pendingClip) { + this.compose(clipBox); + } + + const ctx = this.ctx; + + if (this.pendingClip) { + if (!isEmpty) { + if (this.pendingClip === EO_CLIP) { + ctx.clip("evenodd"); + } else { + ctx.clip(); + } + } + + this.pendingClip = null; + } + + this.current.startNewPathAndClipBox(this.current.clipBox); + ctx.beginPath(); + } + + getSinglePixelWidth() { + if (!this._cachedGetSinglePixelWidth) { + const m = (0, _display_utils.getCurrentTransform)(this.ctx); + + if (m[1] === 0 && m[2] === 0) { + this._cachedGetSinglePixelWidth = 1 / Math.min(Math.abs(m[0]), Math.abs(m[3])); + } else { + const absDet = Math.abs(m[0] * m[3] - m[2] * m[1]); + const normX = Math.hypot(m[0], m[2]); + const normY = Math.hypot(m[1], m[3]); + this._cachedGetSinglePixelWidth = Math.max(normX, normY) / absDet; + } + } + + return this._cachedGetSinglePixelWidth; + } + + getScaleForStroking() { + if (!this._cachedScaleForStroking) { + const { + lineWidth + } = this.current; + const m = (0, _display_utils.getCurrentTransform)(this.ctx); + let scaleX, scaleY; + + if (m[1] === 0 && m[2] === 0) { + const normX = Math.abs(m[0]); + const normY = Math.abs(m[3]); + + if (lineWidth === 0) { + scaleX = 1 / normX; + scaleY = 1 / normY; + } else { + const scaledXLineWidth = normX * lineWidth; + const scaledYLineWidth = normY * lineWidth; + scaleX = scaledXLineWidth < 1 ? 1 / scaledXLineWidth : 1; + scaleY = scaledYLineWidth < 1 ? 1 / scaledYLineWidth : 1; + } + } else { + const absDet = Math.abs(m[0] * m[3] - m[2] * m[1]); + const normX = Math.hypot(m[0], m[1]); + const normY = Math.hypot(m[2], m[3]); + + if (lineWidth === 0) { + scaleX = normY / absDet; + scaleY = normX / absDet; + } else { + const baseArea = lineWidth * absDet; + scaleX = normY > baseArea ? normY / baseArea : 1; + scaleY = normX > baseArea ? normX / baseArea : 1; + } + } + + this._cachedScaleForStroking = [scaleX, scaleY]; + } + + return this._cachedScaleForStroking; + } + + rescaleAndStroke(saveRestore) { + const { + ctx + } = this; + const { + lineWidth + } = this.current; + const [scaleX, scaleY] = this.getScaleForStroking(); + ctx.lineWidth = lineWidth || 1; + + if (scaleX === 1 && scaleY === 1) { + ctx.stroke(); + return; + } + + let savedMatrix, savedDashes, savedDashOffset; + + if (saveRestore) { + savedMatrix = (0, _display_utils.getCurrentTransform)(ctx); + savedDashes = ctx.getLineDash().slice(); + savedDashOffset = ctx.lineDashOffset; + } + + ctx.scale(scaleX, scaleY); + const scale = Math.max(scaleX, scaleY); + ctx.setLineDash(ctx.getLineDash().map(x => x / scale)); + ctx.lineDashOffset /= scale; + ctx.stroke(); + + if (saveRestore) { + ctx.setTransform(...savedMatrix); + ctx.setLineDash(savedDashes); + ctx.lineDashOffset = savedDashOffset; + } + } + + isContentVisible() { + for (let i = this.markedContentStack.length - 1; i >= 0; i--) { + if (!this.markedContentStack[i].visible) { + return false; + } + } + + return true; + } + +} + +exports.CanvasGraphics = CanvasGraphics; + +function _restoreInitialState2() { + while (this.stateStack.length || this.inSMaskMode) { + this.restore(); + } + + this.ctx.restore(); + + if (this.transparentCanvas) { + this.ctx = this.compositeCtx; + this.ctx.save(); + this.ctx.setTransform(1, 0, 0, 1, 0, 0); + this.ctx.drawImage(this.transparentCanvas, 0, 0); + this.ctx.restore(); + this.transparentCanvas = null; + } +} + +for (const op in _util.OPS) { + if (CanvasGraphics.prototype[op] !== undefined) { + CanvasGraphics.prototype[_util.OPS[op]] = CanvasGraphics.prototype[op]; + } +} + +/***/ }), +/* 138 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.TilingPattern = exports.PathType = void 0; +exports.getShadingPattern = getShadingPattern; + +var _util = __w_pdfjs_require__(1); + +var _display_utils = __w_pdfjs_require__(133); + +var _is_node = __w_pdfjs_require__(3); + +const PathType = { + FILL: "Fill", + STROKE: "Stroke", + SHADING: "Shading" +}; +exports.PathType = PathType; + +function applyBoundingBox(ctx, bbox) { + if (!bbox || _is_node.isNodeJS) { + return; + } + + const width = bbox[2] - bbox[0]; + const height = bbox[3] - bbox[1]; + const region = new Path2D(); + region.rect(bbox[0], bbox[1], width, height); + ctx.clip(region); +} + +class BaseShadingPattern { + constructor() { + if (this.constructor === BaseShadingPattern) { + (0, _util.unreachable)("Cannot initialize BaseShadingPattern."); + } + } + + getPattern() { + (0, _util.unreachable)("Abstract method `getPattern` called."); + } + +} + +class RadialAxialShadingPattern extends BaseShadingPattern { + constructor(IR) { + super(); + this._type = IR[1]; + this._bbox = IR[2]; + this._colorStops = IR[3]; + this._p0 = IR[4]; + this._p1 = IR[5]; + this._r0 = IR[6]; + this._r1 = IR[7]; + this.matrix = null; + } + + _createGradient(ctx) { + let grad; + + if (this._type === "axial") { + grad = ctx.createLinearGradient(this._p0[0], this._p0[1], this._p1[0], this._p1[1]); + } else if (this._type === "radial") { + grad = ctx.createRadialGradient(this._p0[0], this._p0[1], this._r0, this._p1[0], this._p1[1], this._r1); + } + + for (const colorStop of this._colorStops) { + grad.addColorStop(colorStop[0], colorStop[1]); + } + + return grad; + } + + getPattern(ctx, owner, inverse, pathType) { + let pattern; + + if (pathType === PathType.STROKE || pathType === PathType.FILL) { + const ownerBBox = owner.current.getClippedPathBoundingBox(pathType, (0, _display_utils.getCurrentTransform)(ctx)) || [0, 0, 0, 0]; + const width = Math.ceil(ownerBBox[2] - ownerBBox[0]) || 1; + const height = Math.ceil(ownerBBox[3] - ownerBBox[1]) || 1; + const tmpCanvas = owner.cachedCanvases.getCanvas("pattern", width, height, true); + const tmpCtx = tmpCanvas.context; + tmpCtx.clearRect(0, 0, tmpCtx.canvas.width, tmpCtx.canvas.height); + tmpCtx.beginPath(); + tmpCtx.rect(0, 0, tmpCtx.canvas.width, tmpCtx.canvas.height); + tmpCtx.translate(-ownerBBox[0], -ownerBBox[1]); + inverse = _util.Util.transform(inverse, [1, 0, 0, 1, ownerBBox[0], ownerBBox[1]]); + tmpCtx.transform(...owner.baseTransform); + + if (this.matrix) { + tmpCtx.transform(...this.matrix); + } + + applyBoundingBox(tmpCtx, this._bbox); + tmpCtx.fillStyle = this._createGradient(tmpCtx); + tmpCtx.fill(); + pattern = ctx.createPattern(tmpCanvas.canvas, "no-repeat"); + const domMatrix = new DOMMatrix(inverse); + + try { + pattern.setTransform(domMatrix); + } catch (ex) { + (0, _util.warn)(`RadialAxialShadingPattern.getPattern: "${ex === null || ex === void 0 ? void 0 : ex.message}".`); + } + } else { + applyBoundingBox(ctx, this._bbox); + pattern = this._createGradient(ctx); + } + + return pattern; + } + +} + +function drawTriangle(data, context, p1, p2, p3, c1, c2, c3) { + const coords = context.coords, + colors = context.colors; + const bytes = data.data, + rowSize = data.width * 4; + let tmp; + + if (coords[p1 + 1] > coords[p2 + 1]) { + tmp = p1; + p1 = p2; + p2 = tmp; + tmp = c1; + c1 = c2; + c2 = tmp; + } + + if (coords[p2 + 1] > coords[p3 + 1]) { + tmp = p2; + p2 = p3; + p3 = tmp; + tmp = c2; + c2 = c3; + c3 = tmp; + } + + if (coords[p1 + 1] > coords[p2 + 1]) { + tmp = p1; + p1 = p2; + p2 = tmp; + tmp = c1; + c1 = c2; + c2 = tmp; + } + + const x1 = (coords[p1] + context.offsetX) * context.scaleX; + const y1 = (coords[p1 + 1] + context.offsetY) * context.scaleY; + const x2 = (coords[p2] + context.offsetX) * context.scaleX; + const y2 = (coords[p2 + 1] + context.offsetY) * context.scaleY; + const x3 = (coords[p3] + context.offsetX) * context.scaleX; + const y3 = (coords[p3 + 1] + context.offsetY) * context.scaleY; + + if (y1 >= y3) { + return; + } + + const c1r = colors[c1], + c1g = colors[c1 + 1], + c1b = colors[c1 + 2]; + const c2r = colors[c2], + c2g = colors[c2 + 1], + c2b = colors[c2 + 2]; + const c3r = colors[c3], + c3g = colors[c3 + 1], + c3b = colors[c3 + 2]; + const minY = Math.round(y1), + maxY = Math.round(y3); + let xa, car, cag, cab; + let xb, cbr, cbg, cbb; + + for (let y = minY; y <= maxY; y++) { + if (y < y2) { + let k; + + if (y < y1) { + k = 0; + } else { + k = (y1 - y) / (y1 - y2); + } + + xa = x1 - (x1 - x2) * k; + car = c1r - (c1r - c2r) * k; + cag = c1g - (c1g - c2g) * k; + cab = c1b - (c1b - c2b) * k; + } else { + let k; + + if (y > y3) { + k = 1; + } else if (y2 === y3) { + k = 0; + } else { + k = (y2 - y) / (y2 - y3); + } + + xa = x2 - (x2 - x3) * k; + car = c2r - (c2r - c3r) * k; + cag = c2g - (c2g - c3g) * k; + cab = c2b - (c2b - c3b) * k; + } + + let k; + + if (y < y1) { + k = 0; + } else if (y > y3) { + k = 1; + } else { + k = (y1 - y) / (y1 - y3); + } + + xb = x1 - (x1 - x3) * k; + cbr = c1r - (c1r - c3r) * k; + cbg = c1g - (c1g - c3g) * k; + cbb = c1b - (c1b - c3b) * k; + const x1_ = Math.round(Math.min(xa, xb)); + const x2_ = Math.round(Math.max(xa, xb)); + let j = rowSize * y + x1_ * 4; + + for (let x = x1_; x <= x2_; x++) { + k = (xa - x) / (xa - xb); + + if (k < 0) { + k = 0; + } else if (k > 1) { + k = 1; + } + + bytes[j++] = car - (car - cbr) * k | 0; + bytes[j++] = cag - (cag - cbg) * k | 0; + bytes[j++] = cab - (cab - cbb) * k | 0; + bytes[j++] = 255; + } + } +} + +function drawFigure(data, figure, context) { + const ps = figure.coords; + const cs = figure.colors; + let i, ii; + + switch (figure.type) { + case "lattice": + const verticesPerRow = figure.verticesPerRow; + const rows = Math.floor(ps.length / verticesPerRow) - 1; + const cols = verticesPerRow - 1; + + for (i = 0; i < rows; i++) { + let q = i * verticesPerRow; + + for (let j = 0; j < cols; j++, q++) { + drawTriangle(data, context, ps[q], ps[q + 1], ps[q + verticesPerRow], cs[q], cs[q + 1], cs[q + verticesPerRow]); + drawTriangle(data, context, ps[q + verticesPerRow + 1], ps[q + 1], ps[q + verticesPerRow], cs[q + verticesPerRow + 1], cs[q + 1], cs[q + verticesPerRow]); + } + } + + break; + + case "triangles": + for (i = 0, ii = ps.length; i < ii; i += 3) { + drawTriangle(data, context, ps[i], ps[i + 1], ps[i + 2], cs[i], cs[i + 1], cs[i + 2]); + } + + break; + + default: + throw new Error("illegal figure"); + } +} + +class MeshShadingPattern extends BaseShadingPattern { + constructor(IR) { + super(); + this._coords = IR[2]; + this._colors = IR[3]; + this._figures = IR[4]; + this._bounds = IR[5]; + this._bbox = IR[7]; + this._background = IR[8]; + this.matrix = null; + } + + _createMeshCanvas(combinedScale, backgroundColor, cachedCanvases) { + const EXPECTED_SCALE = 1.1; + const MAX_PATTERN_SIZE = 3000; + const BORDER_SIZE = 2; + const offsetX = Math.floor(this._bounds[0]); + const offsetY = Math.floor(this._bounds[1]); + const boundsWidth = Math.ceil(this._bounds[2]) - offsetX; + const boundsHeight = Math.ceil(this._bounds[3]) - offsetY; + const width = Math.min(Math.ceil(Math.abs(boundsWidth * combinedScale[0] * EXPECTED_SCALE)), MAX_PATTERN_SIZE); + const height = Math.min(Math.ceil(Math.abs(boundsHeight * combinedScale[1] * EXPECTED_SCALE)), MAX_PATTERN_SIZE); + const scaleX = boundsWidth / width; + const scaleY = boundsHeight / height; + const context = { + coords: this._coords, + colors: this._colors, + offsetX: -offsetX, + offsetY: -offsetY, + scaleX: 1 / scaleX, + scaleY: 1 / scaleY + }; + const paddedWidth = width + BORDER_SIZE * 2; + const paddedHeight = height + BORDER_SIZE * 2; + const tmpCanvas = cachedCanvases.getCanvas("mesh", paddedWidth, paddedHeight, false); + const tmpCtx = tmpCanvas.context; + const data = tmpCtx.createImageData(width, height); + + if (backgroundColor) { + const bytes = data.data; + + for (let i = 0, ii = bytes.length; i < ii; i += 4) { + bytes[i] = backgroundColor[0]; + bytes[i + 1] = backgroundColor[1]; + bytes[i + 2] = backgroundColor[2]; + bytes[i + 3] = 255; + } + } + + for (const figure of this._figures) { + drawFigure(data, figure, context); + } + + tmpCtx.putImageData(data, BORDER_SIZE, BORDER_SIZE); + const canvas = tmpCanvas.canvas; + return { + canvas, + offsetX: offsetX - BORDER_SIZE * scaleX, + offsetY: offsetY - BORDER_SIZE * scaleY, + scaleX, + scaleY + }; + } + + getPattern(ctx, owner, inverse, pathType) { + applyBoundingBox(ctx, this._bbox); + let scale; + + if (pathType === PathType.SHADING) { + scale = _util.Util.singularValueDecompose2dScale((0, _display_utils.getCurrentTransform)(ctx)); + } else { + scale = _util.Util.singularValueDecompose2dScale(owner.baseTransform); + + if (this.matrix) { + const matrixScale = _util.Util.singularValueDecompose2dScale(this.matrix); + + scale = [scale[0] * matrixScale[0], scale[1] * matrixScale[1]]; + } + } + + const temporaryPatternCanvas = this._createMeshCanvas(scale, pathType === PathType.SHADING ? null : this._background, owner.cachedCanvases); + + if (pathType !== PathType.SHADING) { + ctx.setTransform(...owner.baseTransform); + + if (this.matrix) { + ctx.transform(...this.matrix); + } + } + + ctx.translate(temporaryPatternCanvas.offsetX, temporaryPatternCanvas.offsetY); + ctx.scale(temporaryPatternCanvas.scaleX, temporaryPatternCanvas.scaleY); + return ctx.createPattern(temporaryPatternCanvas.canvas, "no-repeat"); + } + +} + +class DummyShadingPattern extends BaseShadingPattern { + getPattern() { + return "hotpink"; + } + +} + +function getShadingPattern(IR) { + switch (IR[0]) { + case "RadialAxial": + return new RadialAxialShadingPattern(IR); + + case "Mesh": + return new MeshShadingPattern(IR); + + case "Dummy": + return new DummyShadingPattern(); + } + + throw new Error(`Unknown IR type: ${IR[0]}`); +} + +const PaintType = { + COLORED: 1, + UNCOLORED: 2 +}; + +class TilingPattern { + static get MAX_PATTERN_SIZE() { + return (0, _util.shadow)(this, "MAX_PATTERN_SIZE", 3000); + } + + constructor(IR, color, ctx, canvasGraphicsFactory, baseTransform) { + this.operatorList = IR[2]; + this.matrix = IR[3] || [1, 0, 0, 1, 0, 0]; + this.bbox = IR[4]; + this.xstep = IR[5]; + this.ystep = IR[6]; + this.paintType = IR[7]; + this.tilingType = IR[8]; + this.color = color; + this.ctx = ctx; + this.canvasGraphicsFactory = canvasGraphicsFactory; + this.baseTransform = baseTransform; + } + + createPatternCanvas(owner) { + const operatorList = this.operatorList; + const bbox = this.bbox; + const xstep = this.xstep; + const ystep = this.ystep; + const paintType = this.paintType; + const tilingType = this.tilingType; + const color = this.color; + const canvasGraphicsFactory = this.canvasGraphicsFactory; + (0, _util.info)("TilingType: " + tilingType); + const x0 = bbox[0], + y0 = bbox[1], + x1 = bbox[2], + y1 = bbox[3]; + + const matrixScale = _util.Util.singularValueDecompose2dScale(this.matrix); + + const curMatrixScale = _util.Util.singularValueDecompose2dScale(this.baseTransform); + + const combinedScale = [matrixScale[0] * curMatrixScale[0], matrixScale[1] * curMatrixScale[1]]; + const dimx = this.getSizeAndScale(xstep, this.ctx.canvas.width, combinedScale[0]); + const dimy = this.getSizeAndScale(ystep, this.ctx.canvas.height, combinedScale[1]); + const tmpCanvas = owner.cachedCanvases.getCanvas("pattern", dimx.size, dimy.size, true); + const tmpCtx = tmpCanvas.context; + const graphics = canvasGraphicsFactory.createCanvasGraphics(tmpCtx); + graphics.groupLevel = owner.groupLevel; + this.setFillAndStrokeStyleToContext(graphics, paintType, color); + let adjustedX0 = x0; + let adjustedY0 = y0; + let adjustedX1 = x1; + let adjustedY1 = y1; + + if (x0 < 0) { + adjustedX0 = 0; + adjustedX1 += Math.abs(x0); + } + + if (y0 < 0) { + adjustedY0 = 0; + adjustedY1 += Math.abs(y0); + } + + tmpCtx.translate(-(dimx.scale * adjustedX0), -(dimy.scale * adjustedY0)); + graphics.transform(dimx.scale, 0, 0, dimy.scale, 0, 0); + tmpCtx.save(); + this.clipBbox(graphics, adjustedX0, adjustedY0, adjustedX1, adjustedY1); + graphics.baseTransform = (0, _display_utils.getCurrentTransform)(graphics.ctx); + graphics.executeOperatorList(operatorList); + graphics.endDrawing(); + return { + canvas: tmpCanvas.canvas, + scaleX: dimx.scale, + scaleY: dimy.scale, + offsetX: adjustedX0, + offsetY: adjustedY0 + }; + } + + getSizeAndScale(step, realOutputSize, scale) { + step = Math.abs(step); + const maxSize = Math.max(TilingPattern.MAX_PATTERN_SIZE, realOutputSize); + let size = Math.ceil(step * scale); + + if (size >= maxSize) { + size = maxSize; + } else { + scale = size / step; + } + + return { + scale, + size + }; + } + + clipBbox(graphics, x0, y0, x1, y1) { + const bboxWidth = x1 - x0; + const bboxHeight = y1 - y0; + graphics.ctx.rect(x0, y0, bboxWidth, bboxHeight); + graphics.current.updateRectMinMax((0, _display_utils.getCurrentTransform)(graphics.ctx), [x0, y0, x1, y1]); + graphics.clip(); + graphics.endPath(); + } + + setFillAndStrokeStyleToContext(graphics, paintType, color) { + const context = graphics.ctx, + current = graphics.current; + + switch (paintType) { + case PaintType.COLORED: + const ctx = this.ctx; + context.fillStyle = ctx.fillStyle; + context.strokeStyle = ctx.strokeStyle; + current.fillColor = ctx.fillStyle; + current.strokeColor = ctx.strokeStyle; + break; + + case PaintType.UNCOLORED: + const cssColor = _util.Util.makeHexColor(color[0], color[1], color[2]); + + context.fillStyle = cssColor; + context.strokeStyle = cssColor; + current.fillColor = cssColor; + current.strokeColor = cssColor; + break; + + default: + throw new _util.FormatError(`Unsupported paint type: ${paintType}`); + } + } + + getPattern(ctx, owner, inverse, pathType) { + let matrix = inverse; + + if (pathType !== PathType.SHADING) { + matrix = _util.Util.transform(matrix, owner.baseTransform); + + if (this.matrix) { + matrix = _util.Util.transform(matrix, this.matrix); + } + } + + const temporaryPatternCanvas = this.createPatternCanvas(owner); + let domMatrix = new DOMMatrix(matrix); + domMatrix = domMatrix.translate(temporaryPatternCanvas.offsetX, temporaryPatternCanvas.offsetY); + domMatrix = domMatrix.scale(1 / temporaryPatternCanvas.scaleX, 1 / temporaryPatternCanvas.scaleY); + const pattern = ctx.createPattern(temporaryPatternCanvas.canvas, "repeat"); + + try { + pattern.setTransform(domMatrix); + } catch (ex) { + (0, _util.warn)(`TilingPattern.getPattern: "${ex === null || ex === void 0 ? void 0 : ex.message}".`); + } + + return pattern; + } + +} + +exports.TilingPattern = TilingPattern; + +/***/ }), +/* 139 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.applyMaskImageData = applyMaskImageData; + +var _util = __w_pdfjs_require__(1); + +function applyMaskImageData(_ref) { + let { + src, + srcPos = 0, + dest, + destPos = 0, + width, + height, + inverseDecode = false + } = _ref; + const opaque = _util.FeatureTest.isLittleEndian ? 0xff000000 : 0x000000ff; + const [zeroMapping, oneMapping] = !inverseDecode ? [opaque, 0] : [0, opaque]; + const widthInSource = width >> 3; + const widthRemainder = width & 7; + const srcLength = src.length; + dest = new Uint32Array(dest.buffer); + + for (let i = 0; i < height; i++) { + for (const max = srcPos + widthInSource; srcPos < max; srcPos++) { + const elem = srcPos < srcLength ? src[srcPos] : 255; + dest[destPos++] = elem & 0b10000000 ? oneMapping : zeroMapping; + dest[destPos++] = elem & 0b1000000 ? oneMapping : zeroMapping; + dest[destPos++] = elem & 0b100000 ? oneMapping : zeroMapping; + dest[destPos++] = elem & 0b10000 ? oneMapping : zeroMapping; + dest[destPos++] = elem & 0b1000 ? oneMapping : zeroMapping; + dest[destPos++] = elem & 0b100 ? oneMapping : zeroMapping; + dest[destPos++] = elem & 0b10 ? oneMapping : zeroMapping; + dest[destPos++] = elem & 0b1 ? oneMapping : zeroMapping; + } + + if (widthRemainder === 0) { + continue; + } + + const elem = srcPos < srcLength ? src[srcPos++] : 255; + + for (let j = 0; j < widthRemainder; j++) { + dest[destPos++] = elem & 1 << 7 - j ? oneMapping : zeroMapping; + } + } + + return { + srcPos, + destPos + }; +} + +/***/ }), +/* 140 */ +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.GlobalWorkerOptions = void 0; +const GlobalWorkerOptions = Object.create(null); +exports.GlobalWorkerOptions = GlobalWorkerOptions; +GlobalWorkerOptions.workerPort = GlobalWorkerOptions.workerPort === undefined ? null : GlobalWorkerOptions.workerPort; +GlobalWorkerOptions.workerSrc = GlobalWorkerOptions.workerSrc === undefined ? "" : GlobalWorkerOptions.workerSrc; + +/***/ }), +/* 141 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.MessageHandler = void 0; + +var _util = __w_pdfjs_require__(1); + +const CallbackKind = { + UNKNOWN: 0, + DATA: 1, + ERROR: 2 +}; +const StreamKind = { + UNKNOWN: 0, + CANCEL: 1, + CANCEL_COMPLETE: 2, + CLOSE: 3, + ENQUEUE: 4, + ERROR: 5, + PULL: 6, + PULL_COMPLETE: 7, + START_COMPLETE: 8 +}; + +function wrapReason(reason) { + if (!(reason instanceof Error || typeof reason === "object" && reason !== null)) { + (0, _util.unreachable)('wrapReason: Expected "reason" to be a (possibly cloned) Error.'); + } + + switch (reason.name) { + case "AbortException": + return new _util.AbortException(reason.message); + + case "MissingPDFException": + return new _util.MissingPDFException(reason.message); + + case "PasswordException": + return new _util.PasswordException(reason.message, reason.code); + + case "UnexpectedResponseException": + return new _util.UnexpectedResponseException(reason.message, reason.status); + + case "UnknownErrorException": + return new _util.UnknownErrorException(reason.message, reason.details); + + default: + return new _util.UnknownErrorException(reason.message, reason.toString()); + } +} + +class MessageHandler { + constructor(sourceName, targetName, comObj) { + this.sourceName = sourceName; + this.targetName = targetName; + this.comObj = comObj; + this.callbackId = 1; + this.streamId = 1; + this.streamSinks = Object.create(null); + this.streamControllers = Object.create(null); + this.callbackCapabilities = Object.create(null); + this.actionHandler = Object.create(null); + + this._onComObjOnMessage = event => { + const data = event.data; + + if (data.targetName !== this.sourceName) { + return; + } + + if (data.stream) { + this._processStreamMessage(data); + + return; + } + + if (data.callback) { + const callbackId = data.callbackId; + const capability = this.callbackCapabilities[callbackId]; + + if (!capability) { + throw new Error(`Cannot resolve callback ${callbackId}`); + } + + delete this.callbackCapabilities[callbackId]; + + if (data.callback === CallbackKind.DATA) { + capability.resolve(data.data); + } else if (data.callback === CallbackKind.ERROR) { + capability.reject(wrapReason(data.reason)); + } else { + throw new Error("Unexpected callback case"); + } + + return; + } + + const action = this.actionHandler[data.action]; + + if (!action) { + throw new Error(`Unknown action from worker: ${data.action}`); + } + + if (data.callbackId) { + const cbSourceName = this.sourceName; + const cbTargetName = data.sourceName; + new Promise(function (resolve) { + resolve(action(data.data)); + }).then(function (result) { + comObj.postMessage({ + sourceName: cbSourceName, + targetName: cbTargetName, + callback: CallbackKind.DATA, + callbackId: data.callbackId, + data: result + }); + }, function (reason) { + comObj.postMessage({ + sourceName: cbSourceName, + targetName: cbTargetName, + callback: CallbackKind.ERROR, + callbackId: data.callbackId, + reason: wrapReason(reason) + }); + }); + return; + } + + if (data.streamId) { + this._createStreamSink(data); + + return; + } + + action(data.data); + }; + + comObj.addEventListener("message", this._onComObjOnMessage); + } + + on(actionName, handler) { + const ah = this.actionHandler; + + if (ah[actionName]) { + throw new Error(`There is already an actionName called "${actionName}"`); + } + + ah[actionName] = handler; + } + + send(actionName, data, transfers) { + this.comObj.postMessage({ + sourceName: this.sourceName, + targetName: this.targetName, + action: actionName, + data + }, transfers); + } + + sendWithPromise(actionName, data, transfers) { + const callbackId = this.callbackId++; + const capability = (0, _util.createPromiseCapability)(); + this.callbackCapabilities[callbackId] = capability; + + try { + this.comObj.postMessage({ + sourceName: this.sourceName, + targetName: this.targetName, + action: actionName, + callbackId, + data + }, transfers); + } catch (ex) { + capability.reject(ex); + } + + return capability.promise; + } + + sendWithStream(actionName, data, queueingStrategy, transfers) { + const streamId = this.streamId++, + sourceName = this.sourceName, + targetName = this.targetName, + comObj = this.comObj; + return new ReadableStream({ + start: controller => { + const startCapability = (0, _util.createPromiseCapability)(); + this.streamControllers[streamId] = { + controller, + startCall: startCapability, + pullCall: null, + cancelCall: null, + isClosed: false + }; + comObj.postMessage({ + sourceName, + targetName, + action: actionName, + streamId, + data, + desiredSize: controller.desiredSize + }, transfers); + return startCapability.promise; + }, + pull: controller => { + const pullCapability = (0, _util.createPromiseCapability)(); + this.streamControllers[streamId].pullCall = pullCapability; + comObj.postMessage({ + sourceName, + targetName, + stream: StreamKind.PULL, + streamId, + desiredSize: controller.desiredSize + }); + return pullCapability.promise; + }, + cancel: reason => { + (0, _util.assert)(reason instanceof Error, "cancel must have a valid reason"); + const cancelCapability = (0, _util.createPromiseCapability)(); + this.streamControllers[streamId].cancelCall = cancelCapability; + this.streamControllers[streamId].isClosed = true; + comObj.postMessage({ + sourceName, + targetName, + stream: StreamKind.CANCEL, + streamId, + reason: wrapReason(reason) + }); + return cancelCapability.promise; + } + }, queueingStrategy); + } + + _createStreamSink(data) { + const streamId = data.streamId, + sourceName = this.sourceName, + targetName = data.sourceName, + comObj = this.comObj; + const self = this, + action = this.actionHandler[data.action]; + const streamSink = { + enqueue(chunk) { + let size = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1; + let transfers = arguments.length > 2 ? arguments[2] : undefined; + + if (this.isCancelled) { + return; + } + + const lastDesiredSize = this.desiredSize; + this.desiredSize -= size; + + if (lastDesiredSize > 0 && this.desiredSize <= 0) { + this.sinkCapability = (0, _util.createPromiseCapability)(); + this.ready = this.sinkCapability.promise; + } + + comObj.postMessage({ + sourceName, + targetName, + stream: StreamKind.ENQUEUE, + streamId, + chunk + }, transfers); + }, + + close() { + if (this.isCancelled) { + return; + } + + this.isCancelled = true; + comObj.postMessage({ + sourceName, + targetName, + stream: StreamKind.CLOSE, + streamId + }); + delete self.streamSinks[streamId]; + }, + + error(reason) { + (0, _util.assert)(reason instanceof Error, "error must have a valid reason"); + + if (this.isCancelled) { + return; + } + + this.isCancelled = true; + comObj.postMessage({ + sourceName, + targetName, + stream: StreamKind.ERROR, + streamId, + reason: wrapReason(reason) + }); + }, + + sinkCapability: (0, _util.createPromiseCapability)(), + onPull: null, + onCancel: null, + isCancelled: false, + desiredSize: data.desiredSize, + ready: null + }; + streamSink.sinkCapability.resolve(); + streamSink.ready = streamSink.sinkCapability.promise; + this.streamSinks[streamId] = streamSink; + new Promise(function (resolve) { + resolve(action(data.data, streamSink)); + }).then(function () { + comObj.postMessage({ + sourceName, + targetName, + stream: StreamKind.START_COMPLETE, + streamId, + success: true + }); + }, function (reason) { + comObj.postMessage({ + sourceName, + targetName, + stream: StreamKind.START_COMPLETE, + streamId, + reason: wrapReason(reason) + }); + }); + } + + _processStreamMessage(data) { + const streamId = data.streamId, + sourceName = this.sourceName, + targetName = data.sourceName, + comObj = this.comObj; + const streamController = this.streamControllers[streamId], + streamSink = this.streamSinks[streamId]; + + switch (data.stream) { + case StreamKind.START_COMPLETE: + if (data.success) { + streamController.startCall.resolve(); + } else { + streamController.startCall.reject(wrapReason(data.reason)); + } + + break; + + case StreamKind.PULL_COMPLETE: + if (data.success) { + streamController.pullCall.resolve(); + } else { + streamController.pullCall.reject(wrapReason(data.reason)); + } + + break; + + case StreamKind.PULL: + if (!streamSink) { + comObj.postMessage({ + sourceName, + targetName, + stream: StreamKind.PULL_COMPLETE, + streamId, + success: true + }); + break; + } + + if (streamSink.desiredSize <= 0 && data.desiredSize > 0) { + streamSink.sinkCapability.resolve(); + } + + streamSink.desiredSize = data.desiredSize; + new Promise(function (resolve) { + resolve(streamSink.onPull && streamSink.onPull()); + }).then(function () { + comObj.postMessage({ + sourceName, + targetName, + stream: StreamKind.PULL_COMPLETE, + streamId, + success: true + }); + }, function (reason) { + comObj.postMessage({ + sourceName, + targetName, + stream: StreamKind.PULL_COMPLETE, + streamId, + reason: wrapReason(reason) + }); + }); + break; + + case StreamKind.ENQUEUE: + (0, _util.assert)(streamController, "enqueue should have stream controller"); + + if (streamController.isClosed) { + break; + } + + streamController.controller.enqueue(data.chunk); + break; + + case StreamKind.CLOSE: + (0, _util.assert)(streamController, "close should have stream controller"); + + if (streamController.isClosed) { + break; + } + + streamController.isClosed = true; + streamController.controller.close(); + + this._deleteStreamController(streamController, streamId); + + break; + + case StreamKind.ERROR: + (0, _util.assert)(streamController, "error should have stream controller"); + streamController.controller.error(wrapReason(data.reason)); + + this._deleteStreamController(streamController, streamId); + + break; + + case StreamKind.CANCEL_COMPLETE: + if (data.success) { + streamController.cancelCall.resolve(); + } else { + streamController.cancelCall.reject(wrapReason(data.reason)); + } + + this._deleteStreamController(streamController, streamId); + + break; + + case StreamKind.CANCEL: + if (!streamSink) { + break; + } + + new Promise(function (resolve) { + resolve(streamSink.onCancel && streamSink.onCancel(wrapReason(data.reason))); + }).then(function () { + comObj.postMessage({ + sourceName, + targetName, + stream: StreamKind.CANCEL_COMPLETE, + streamId, + success: true + }); + }, function (reason) { + comObj.postMessage({ + sourceName, + targetName, + stream: StreamKind.CANCEL_COMPLETE, + streamId, + reason: wrapReason(reason) + }); + }); + streamSink.sinkCapability.reject(wrapReason(data.reason)); + streamSink.isCancelled = true; + delete this.streamSinks[streamId]; + break; + + default: + throw new Error("Unexpected stream case"); + } + } + + async _deleteStreamController(streamController, streamId) { + await Promise.allSettled([streamController.startCall && streamController.startCall.promise, streamController.pullCall && streamController.pullCall.promise, streamController.cancelCall && streamController.cancelCall.promise]); + delete this.streamControllers[streamId]; + } + + destroy() { + this.comObj.removeEventListener("message", this._onComObjOnMessage); + } + +} + +exports.MessageHandler = MessageHandler; + +/***/ }), +/* 142 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.Metadata = void 0; + +var _util = __w_pdfjs_require__(1); + +function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } + +function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } + +function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } + +var _metadataMap = /*#__PURE__*/new WeakMap(); + +var _data = /*#__PURE__*/new WeakMap(); + +class Metadata { + constructor(_ref) { + let { + parsedData, + rawData + } = _ref; + + _classPrivateFieldInitSpec(this, _metadataMap, { + writable: true, + value: void 0 + }); + + _classPrivateFieldInitSpec(this, _data, { + writable: true, + value: void 0 + }); + + _classPrivateFieldSet(this, _metadataMap, parsedData); + + _classPrivateFieldSet(this, _data, rawData); + } + + getRaw() { + return _classPrivateFieldGet(this, _data); + } + + get(name) { + var _classPrivateFieldGet2; + + return (_classPrivateFieldGet2 = _classPrivateFieldGet(this, _metadataMap).get(name)) !== null && _classPrivateFieldGet2 !== void 0 ? _classPrivateFieldGet2 : null; + } + + getAll() { + return (0, _util.objectFromMap)(_classPrivateFieldGet(this, _metadataMap)); + } + + has(name) { + return _classPrivateFieldGet(this, _metadataMap).has(name); + } + +} + +exports.Metadata = Metadata; + +/***/ }), +/* 143 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.OptionalContentConfig = void 0; + +var _util = __w_pdfjs_require__(1); + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } + +function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } + +function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +const INTERNAL = Symbol("INTERNAL"); + +var _visible = /*#__PURE__*/new WeakMap(); + +class OptionalContentGroup { + constructor(name, intent) { + _classPrivateFieldInitSpec(this, _visible, { + writable: true, + value: true + }); + + this.name = name; + this.intent = intent; + } + + get visible() { + return _classPrivateFieldGet(this, _visible); + } + + _setVisible(internal, visible) { + if (internal !== INTERNAL) { + (0, _util.unreachable)("Internal method `_setVisible` called."); + } + + _classPrivateFieldSet(this, _visible, visible); + } + +} + +var _cachedHasInitialVisibility = /*#__PURE__*/new WeakMap(); + +var _groups = /*#__PURE__*/new WeakMap(); + +var _initialVisibility = /*#__PURE__*/new WeakMap(); + +var _order = /*#__PURE__*/new WeakMap(); + +var _evaluateVisibilityExpression = /*#__PURE__*/new WeakSet(); + +class OptionalContentConfig { + constructor(data) { + _classPrivateMethodInitSpec(this, _evaluateVisibilityExpression); + + _classPrivateFieldInitSpec(this, _cachedHasInitialVisibility, { + writable: true, + value: true + }); + + _classPrivateFieldInitSpec(this, _groups, { + writable: true, + value: new Map() + }); + + _classPrivateFieldInitSpec(this, _initialVisibility, { + writable: true, + value: null + }); + + _classPrivateFieldInitSpec(this, _order, { + writable: true, + value: null + }); + + this.name = null; + this.creator = null; + + if (data === null) { + return; + } + + this.name = data.name; + this.creator = data.creator; + + _classPrivateFieldSet(this, _order, data.order); + + for (const group of data.groups) { + _classPrivateFieldGet(this, _groups).set(group.id, new OptionalContentGroup(group.name, group.intent)); + } + + if (data.baseState === "OFF") { + for (const group of _classPrivateFieldGet(this, _groups).values()) { + group._setVisible(INTERNAL, false); + } + } + + for (const on of data.on) { + _classPrivateFieldGet(this, _groups).get(on)._setVisible(INTERNAL, true); + } + + for (const off of data.off) { + _classPrivateFieldGet(this, _groups).get(off)._setVisible(INTERNAL, false); + } + + _classPrivateFieldSet(this, _initialVisibility, new Map()); + + for (const [id, group] of _classPrivateFieldGet(this, _groups)) { + _classPrivateFieldGet(this, _initialVisibility).set(id, group.visible); + } + } + + isVisible(group) { + if (_classPrivateFieldGet(this, _groups).size === 0) { + return true; + } + + if (!group) { + (0, _util.warn)("Optional content group not defined."); + return true; + } + + if (group.type === "OCG") { + if (!_classPrivateFieldGet(this, _groups).has(group.id)) { + (0, _util.warn)(`Optional content group not found: ${group.id}`); + return true; + } + + return _classPrivateFieldGet(this, _groups).get(group.id).visible; + } else if (group.type === "OCMD") { + if (group.expression) { + return _classPrivateMethodGet(this, _evaluateVisibilityExpression, _evaluateVisibilityExpression2).call(this, group.expression); + } + + if (!group.policy || group.policy === "AnyOn") { + for (const id of group.ids) { + if (!_classPrivateFieldGet(this, _groups).has(id)) { + (0, _util.warn)(`Optional content group not found: ${id}`); + return true; + } + + if (_classPrivateFieldGet(this, _groups).get(id).visible) { + return true; + } + } + + return false; + } else if (group.policy === "AllOn") { + for (const id of group.ids) { + if (!_classPrivateFieldGet(this, _groups).has(id)) { + (0, _util.warn)(`Optional content group not found: ${id}`); + return true; + } + + if (!_classPrivateFieldGet(this, _groups).get(id).visible) { + return false; + } + } + + return true; + } else if (group.policy === "AnyOff") { + for (const id of group.ids) { + if (!_classPrivateFieldGet(this, _groups).has(id)) { + (0, _util.warn)(`Optional content group not found: ${id}`); + return true; + } + + if (!_classPrivateFieldGet(this, _groups).get(id).visible) { + return true; + } + } + + return false; + } else if (group.policy === "AllOff") { + for (const id of group.ids) { + if (!_classPrivateFieldGet(this, _groups).has(id)) { + (0, _util.warn)(`Optional content group not found: ${id}`); + return true; + } + + if (_classPrivateFieldGet(this, _groups).get(id).visible) { + return false; + } + } + + return true; + } + + (0, _util.warn)(`Unknown optional content policy ${group.policy}.`); + return true; + } + + (0, _util.warn)(`Unknown group type ${group.type}.`); + return true; + } + + setVisibility(id) { + let visible = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + + if (!_classPrivateFieldGet(this, _groups).has(id)) { + (0, _util.warn)(`Optional content group not found: ${id}`); + return; + } + + _classPrivateFieldGet(this, _groups).get(id)._setVisible(INTERNAL, !!visible); + + _classPrivateFieldSet(this, _cachedHasInitialVisibility, null); + } + + get hasInitialVisibility() { + if (_classPrivateFieldGet(this, _cachedHasInitialVisibility) !== null) { + return _classPrivateFieldGet(this, _cachedHasInitialVisibility); + } + + for (const [id, group] of _classPrivateFieldGet(this, _groups)) { + const visible = _classPrivateFieldGet(this, _initialVisibility).get(id); + + if (group.visible !== visible) { + return _classPrivateFieldSet(this, _cachedHasInitialVisibility, false); + } + } + + return _classPrivateFieldSet(this, _cachedHasInitialVisibility, true); + } + + getOrder() { + if (!_classPrivateFieldGet(this, _groups).size) { + return null; + } + + if (_classPrivateFieldGet(this, _order)) { + return _classPrivateFieldGet(this, _order).slice(); + } + + return [..._classPrivateFieldGet(this, _groups).keys()]; + } + + getGroups() { + return _classPrivateFieldGet(this, _groups).size > 0 ? (0, _util.objectFromMap)(_classPrivateFieldGet(this, _groups)) : null; + } + + getGroup(id) { + return _classPrivateFieldGet(this, _groups).get(id) || null; + } + +} + +exports.OptionalContentConfig = OptionalContentConfig; + +function _evaluateVisibilityExpression2(array) { + const length = array.length; + + if (length < 2) { + return true; + } + + const operator = array[0]; + + for (let i = 1; i < length; i++) { + const element = array[i]; + let state; + + if (Array.isArray(element)) { + state = _classPrivateMethodGet(this, _evaluateVisibilityExpression, _evaluateVisibilityExpression2).call(this, element); + } else if (_classPrivateFieldGet(this, _groups).has(element)) { + state = _classPrivateFieldGet(this, _groups).get(element).visible; + } else { + (0, _util.warn)(`Optional content group not found: ${element}`); + return true; + } + + switch (operator) { + case "And": + if (!state) { + return false; + } + + break; + + case "Or": + if (state) { + return true; + } + + break; + + case "Not": + return !state; + + default: + return true; + } + } + + return operator === "And"; +} + +/***/ }), +/* 144 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFDataTransportStream = void 0; + +var _util = __w_pdfjs_require__(1); + +var _display_utils = __w_pdfjs_require__(133); + +class PDFDataTransportStream { + constructor(params, pdfDataRangeTransport) { + (0, _util.assert)(pdfDataRangeTransport, 'PDFDataTransportStream - missing required "pdfDataRangeTransport" argument.'); + this._queuedChunks = []; + this._progressiveDone = params.progressiveDone || false; + this._contentDispositionFilename = params.contentDispositionFilename || null; + const initialData = params.initialData; + + if ((initialData === null || initialData === void 0 ? void 0 : initialData.length) > 0) { + const buffer = new Uint8Array(initialData).buffer; + + this._queuedChunks.push(buffer); + } + + this._pdfDataRangeTransport = pdfDataRangeTransport; + this._isStreamingSupported = !params.disableStream; + this._isRangeSupported = !params.disableRange; + this._contentLength = params.length; + this._fullRequestReader = null; + this._rangeReaders = []; + + this._pdfDataRangeTransport.addRangeListener((begin, chunk) => { + this._onReceiveData({ + begin, + chunk + }); + }); + + this._pdfDataRangeTransport.addProgressListener((loaded, total) => { + this._onProgress({ + loaded, + total + }); + }); + + this._pdfDataRangeTransport.addProgressiveReadListener(chunk => { + this._onReceiveData({ + chunk + }); + }); + + this._pdfDataRangeTransport.addProgressiveDoneListener(() => { + this._onProgressiveDone(); + }); + + this._pdfDataRangeTransport.transportReady(); + } + + _onReceiveData(args) { + const buffer = new Uint8Array(args.chunk).buffer; + + if (args.begin === undefined) { + if (this._fullRequestReader) { + this._fullRequestReader._enqueue(buffer); + } else { + this._queuedChunks.push(buffer); + } + } else { + const found = this._rangeReaders.some(function (rangeReader) { + if (rangeReader._begin !== args.begin) { + return false; + } + + rangeReader._enqueue(buffer); + + return true; + }); + + (0, _util.assert)(found, "_onReceiveData - no `PDFDataTransportStreamRangeReader` instance found."); + } + } + + get _progressiveDataLength() { + var _this$_fullRequestRea, _this$_fullRequestRea2; + + return (_this$_fullRequestRea = (_this$_fullRequestRea2 = this._fullRequestReader) === null || _this$_fullRequestRea2 === void 0 ? void 0 : _this$_fullRequestRea2._loaded) !== null && _this$_fullRequestRea !== void 0 ? _this$_fullRequestRea : 0; + } + + _onProgress(evt) { + if (evt.total === undefined) { + const firstReader = this._rangeReaders[0]; + + if (firstReader !== null && firstReader !== void 0 && firstReader.onProgress) { + firstReader.onProgress({ + loaded: evt.loaded + }); + } + } else { + const fullReader = this._fullRequestReader; + + if (fullReader !== null && fullReader !== void 0 && fullReader.onProgress) { + fullReader.onProgress({ + loaded: evt.loaded, + total: evt.total + }); + } + } + } + + _onProgressiveDone() { + if (this._fullRequestReader) { + this._fullRequestReader.progressiveDone(); + } + + this._progressiveDone = true; + } + + _removeRangeReader(reader) { + const i = this._rangeReaders.indexOf(reader); + + if (i >= 0) { + this._rangeReaders.splice(i, 1); + } + } + + getFullReader() { + (0, _util.assert)(!this._fullRequestReader, "PDFDataTransportStream.getFullReader can only be called once."); + const queuedChunks = this._queuedChunks; + this._queuedChunks = null; + return new PDFDataTransportStreamReader(this, queuedChunks, this._progressiveDone, this._contentDispositionFilename); + } + + getRangeReader(begin, end) { + if (end <= this._progressiveDataLength) { + return null; + } + + const reader = new PDFDataTransportStreamRangeReader(this, begin, end); + + this._pdfDataRangeTransport.requestDataRange(begin, end); + + this._rangeReaders.push(reader); + + return reader; + } + + cancelAllRequests(reason) { + if (this._fullRequestReader) { + this._fullRequestReader.cancel(reason); + } + + for (const reader of this._rangeReaders.slice(0)) { + reader.cancel(reason); + } + + this._pdfDataRangeTransport.abort(); + } + +} + +exports.PDFDataTransportStream = PDFDataTransportStream; + +class PDFDataTransportStreamReader { + constructor(stream, queuedChunks) { + let progressiveDone = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + let contentDispositionFilename = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; + this._stream = stream; + this._done = progressiveDone || false; + this._filename = (0, _display_utils.isPdfFile)(contentDispositionFilename) ? contentDispositionFilename : null; + this._queuedChunks = queuedChunks || []; + this._loaded = 0; + + for (const chunk of this._queuedChunks) { + this._loaded += chunk.byteLength; + } + + this._requests = []; + this._headersReady = Promise.resolve(); + stream._fullRequestReader = this; + this.onProgress = null; + } + + _enqueue(chunk) { + if (this._done) { + return; + } + + if (this._requests.length > 0) { + const requestCapability = this._requests.shift(); + + requestCapability.resolve({ + value: chunk, + done: false + }); + } else { + this._queuedChunks.push(chunk); + } + + this._loaded += chunk.byteLength; + } + + get headersReady() { + return this._headersReady; + } + + get filename() { + return this._filename; + } + + get isRangeSupported() { + return this._stream._isRangeSupported; + } + + get isStreamingSupported() { + return this._stream._isStreamingSupported; + } + + get contentLength() { + return this._stream._contentLength; + } + + async read() { + if (this._queuedChunks.length > 0) { + const chunk = this._queuedChunks.shift(); + + return { + value: chunk, + done: false + }; + } + + if (this._done) { + return { + value: undefined, + done: true + }; + } + + const requestCapability = (0, _util.createPromiseCapability)(); + + this._requests.push(requestCapability); + + return requestCapability.promise; + } + + cancel(reason) { + this._done = true; + + for (const requestCapability of this._requests) { + requestCapability.resolve({ + value: undefined, + done: true + }); + } + + this._requests.length = 0; + } + + progressiveDone() { + if (this._done) { + return; + } + + this._done = true; + } + +} + +class PDFDataTransportStreamRangeReader { + constructor(stream, begin, end) { + this._stream = stream; + this._begin = begin; + this._end = end; + this._queuedChunk = null; + this._requests = []; + this._done = false; + this.onProgress = null; + } + + _enqueue(chunk) { + if (this._done) { + return; + } + + if (this._requests.length === 0) { + this._queuedChunk = chunk; + } else { + const requestsCapability = this._requests.shift(); + + requestsCapability.resolve({ + value: chunk, + done: false + }); + + for (const requestCapability of this._requests) { + requestCapability.resolve({ + value: undefined, + done: true + }); + } + + this._requests.length = 0; + } + + this._done = true; + + this._stream._removeRangeReader(this); + } + + get isStreamingSupported() { + return false; + } + + async read() { + if (this._queuedChunk) { + const chunk = this._queuedChunk; + this._queuedChunk = null; + return { + value: chunk, + done: false + }; + } + + if (this._done) { + return { + value: undefined, + done: true + }; + } + + const requestCapability = (0, _util.createPromiseCapability)(); + + this._requests.push(requestCapability); + + return requestCapability.promise; + } + + cancel(reason) { + this._done = true; + + for (const requestCapability of this._requests) { + requestCapability.resolve({ + value: undefined, + done: true + }); + } + + this._requests.length = 0; + + this._stream._removeRangeReader(this); + } + +} + +/***/ }), +/* 145 */ +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.XfaText = void 0; + +class XfaText { + static textContent(xfa) { + const items = []; + const output = { + items, + styles: Object.create(null) + }; + + function walk(node) { + var _node$attributes; + + if (!node) { + return; + } + + let str = null; + const name = node.name; + + if (name === "#text") { + str = node.value; + } else if (!XfaText.shouldBuildText(name)) { + return; + } else if (node !== null && node !== void 0 && (_node$attributes = node.attributes) !== null && _node$attributes !== void 0 && _node$attributes.textContent) { + str = node.attributes.textContent; + } else if (node.value) { + str = node.value; + } + + if (str !== null) { + items.push({ + str + }); + } + + if (!node.children) { + return; + } + + for (const child of node.children) { + walk(child); + } + } + + walk(xfa); + return output; + } + + static shouldBuildText(name) { + return !(name === "textarea" || name === "input" || name === "option" || name === "select"); + } + +} + +exports.XfaText = XfaText; + +/***/ }), +/* 146 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.NodeStandardFontDataFactory = exports.NodeCanvasFactory = exports.NodeCMapReaderFactory = void 0; + +var _base_factory = __w_pdfjs_require__(134); + +; + +const fetchData = function (url) { + return new Promise((resolve, reject) => { + const fs = require("fs"); + + fs.readFile(url, (error, data) => { + if (error || !data) { + reject(new Error(error)); + return; + } + + resolve(new Uint8Array(data)); + }); + }); +}; + +class NodeCanvasFactory extends _base_factory.BaseCanvasFactory { + _createCanvas(width, height) { + const Canvas = require("canvas"); + + return Canvas.createCanvas(width, height); + } + +} + +exports.NodeCanvasFactory = NodeCanvasFactory; + +class NodeCMapReaderFactory extends _base_factory.BaseCMapReaderFactory { + _fetchData(url, compressionType) { + return fetchData(url).then(data => { + return { + cMapData: data, + compressionType + }; + }); + } + +} + +exports.NodeCMapReaderFactory = NodeCMapReaderFactory; + +class NodeStandardFontDataFactory extends _base_factory.BaseStandardFontDataFactory { + _fetchData(url) { + return fetchData(url); + } + +} + +exports.NodeStandardFontDataFactory = NodeStandardFontDataFactory; + +/***/ }), +/* 147 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.AnnotationEditorLayer = void 0; + +var _tools = __w_pdfjs_require__(132); + +var _util = __w_pdfjs_require__(1); + +var _freetext = __w_pdfjs_require__(148); + +var _ink = __w_pdfjs_require__(149); + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } + +function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } + +function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } + +var _accessibilityManager = /*#__PURE__*/new WeakMap(); + +var _allowClick = /*#__PURE__*/new WeakMap(); + +var _boundPointerup = /*#__PURE__*/new WeakMap(); + +var _boundPointerdown = /*#__PURE__*/new WeakMap(); + +var _editors = /*#__PURE__*/new WeakMap(); + +var _hadPointerDown = /*#__PURE__*/new WeakMap(); + +var _isCleaningUp = /*#__PURE__*/new WeakMap(); + +var _uiManager = /*#__PURE__*/new WeakMap(); + +var _changeParent = /*#__PURE__*/new WeakSet(); + +var _createNewEditor = /*#__PURE__*/new WeakSet(); + +var _createAndAddNewEditor = /*#__PURE__*/new WeakSet(); + +var _cleanup = /*#__PURE__*/new WeakSet(); + +class AnnotationEditorLayer { + constructor(options) { + _classPrivateMethodInitSpec(this, _cleanup); + + _classPrivateMethodInitSpec(this, _createAndAddNewEditor); + + _classPrivateMethodInitSpec(this, _createNewEditor); + + _classPrivateMethodInitSpec(this, _changeParent); + + _classPrivateFieldInitSpec(this, _accessibilityManager, { + writable: true, + value: void 0 + }); + + _classPrivateFieldInitSpec(this, _allowClick, { + writable: true, + value: false + }); + + _classPrivateFieldInitSpec(this, _boundPointerup, { + writable: true, + value: this.pointerup.bind(this) + }); + + _classPrivateFieldInitSpec(this, _boundPointerdown, { + writable: true, + value: this.pointerdown.bind(this) + }); + + _classPrivateFieldInitSpec(this, _editors, { + writable: true, + value: new Map() + }); + + _classPrivateFieldInitSpec(this, _hadPointerDown, { + writable: true, + value: false + }); + + _classPrivateFieldInitSpec(this, _isCleaningUp, { + writable: true, + value: false + }); + + _classPrivateFieldInitSpec(this, _uiManager, { + writable: true, + value: void 0 + }); + + if (!AnnotationEditorLayer._initialized) { + AnnotationEditorLayer._initialized = true; + + _freetext.FreeTextEditor.initialize(options.l10n); + + _ink.InkEditor.initialize(options.l10n); + + options.uiManager.registerEditorTypes([_freetext.FreeTextEditor, _ink.InkEditor]); + } + + _classPrivateFieldSet(this, _uiManager, options.uiManager); + + this.annotationStorage = options.annotationStorage; + this.pageIndex = options.pageIndex; + this.div = options.div; + + _classPrivateFieldSet(this, _accessibilityManager, options.accessibilityManager); + + _classPrivateFieldGet(this, _uiManager).addLayer(this); + } + + updateToolbar(mode) { + _classPrivateFieldGet(this, _uiManager).updateToolbar(mode); + } + + updateMode() { + let mode = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _classPrivateFieldGet(this, _uiManager).getMode(); + + _classPrivateMethodGet(this, _cleanup, _cleanup2).call(this); + + if (mode === _util.AnnotationEditorType.INK) { + this.addInkEditorIfNeeded(false); + this.disableClick(); + } else { + this.enableClick(); + } + + _classPrivateFieldGet(this, _uiManager).unselectAll(); + } + + addInkEditorIfNeeded(isCommitting) { + if (!isCommitting && _classPrivateFieldGet(this, _uiManager).getMode() !== _util.AnnotationEditorType.INK) { + return; + } + + if (!isCommitting) { + for (const editor of _classPrivateFieldGet(this, _editors).values()) { + if (editor.isEmpty()) { + editor.setInBackground(); + return; + } + } + } + + const editor = _classPrivateMethodGet(this, _createAndAddNewEditor, _createAndAddNewEditor2).call(this, { + offsetX: 0, + offsetY: 0 + }); + + editor.setInBackground(); + } + + setEditingState(isEditing) { + _classPrivateFieldGet(this, _uiManager).setEditingState(isEditing); + } + + addCommands(params) { + _classPrivateFieldGet(this, _uiManager).addCommands(params); + } + + enable() { + this.div.style.pointerEvents = "auto"; + + for (const editor of _classPrivateFieldGet(this, _editors).values()) { + editor.enableEditing(); + } + } + + disable() { + this.div.style.pointerEvents = "none"; + + for (const editor of _classPrivateFieldGet(this, _editors).values()) { + editor.disableEditing(); + } + } + + setActiveEditor(editor) { + const currentActive = _classPrivateFieldGet(this, _uiManager).getActive(); + + if (currentActive === editor) { + return; + } + + _classPrivateFieldGet(this, _uiManager).setActiveEditor(editor); + } + + enableClick() { + this.div.addEventListener("pointerdown", _classPrivateFieldGet(this, _boundPointerdown)); + this.div.addEventListener("pointerup", _classPrivateFieldGet(this, _boundPointerup)); + } + + disableClick() { + this.div.removeEventListener("pointerdown", _classPrivateFieldGet(this, _boundPointerdown)); + this.div.removeEventListener("pointerup", _classPrivateFieldGet(this, _boundPointerup)); + } + + attach(editor) { + _classPrivateFieldGet(this, _editors).set(editor.id, editor); + } + + detach(editor) { + var _classPrivateFieldGet2; + + _classPrivateFieldGet(this, _editors).delete(editor.id); + + (_classPrivateFieldGet2 = _classPrivateFieldGet(this, _accessibilityManager)) === null || _classPrivateFieldGet2 === void 0 ? void 0 : _classPrivateFieldGet2.removePointerInTextLayer(editor.contentDiv); + } + + remove(editor) { + _classPrivateFieldGet(this, _uiManager).removeEditor(editor); + + this.detach(editor); + this.annotationStorage.remove(editor.id); + editor.div.style.display = "none"; + setTimeout(() => { + editor.div.style.display = ""; + editor.div.remove(); + editor.isAttachedToDOM = false; + + if (document.activeElement === document.body) { + _classPrivateFieldGet(this, _uiManager).focusMainContainer(); + } + }, 0); + + if (!_classPrivateFieldGet(this, _isCleaningUp)) { + this.addInkEditorIfNeeded(false); + } + } + + add(editor) { + _classPrivateMethodGet(this, _changeParent, _changeParent2).call(this, editor); + + _classPrivateFieldGet(this, _uiManager).addEditor(editor); + + this.attach(editor); + + if (!editor.isAttachedToDOM) { + const div = editor.render(); + this.div.append(div); + editor.isAttachedToDOM = true; + } + + this.moveEditorInDOM(editor); + editor.onceAdded(); + this.addToAnnotationStorage(editor); + } + + moveEditorInDOM(editor) { + var _classPrivateFieldGet3; + + (_classPrivateFieldGet3 = _classPrivateFieldGet(this, _accessibilityManager)) === null || _classPrivateFieldGet3 === void 0 ? void 0 : _classPrivateFieldGet3.moveElementInDOM(this.div, editor.div, editor.contentDiv, true); + } + + addToAnnotationStorage(editor) { + if (!editor.isEmpty() && !this.annotationStorage.has(editor.id)) { + this.annotationStorage.setValue(editor.id, editor); + } + } + + addOrRebuild(editor) { + if (editor.needsToBeRebuilt()) { + editor.rebuild(); + } else { + this.add(editor); + } + } + + addANewEditor(editor) { + const cmd = () => { + this.addOrRebuild(editor); + }; + + const undo = () => { + editor.remove(); + }; + + this.addCommands({ + cmd, + undo, + mustExec: true + }); + } + + addUndoableEditor(editor) { + const cmd = () => { + this.addOrRebuild(editor); + }; + + const undo = () => { + editor.remove(); + }; + + this.addCommands({ + cmd, + undo, + mustExec: false + }); + } + + getNextId() { + return _classPrivateFieldGet(this, _uiManager).getId(); + } + + deserialize(data) { + switch (data.annotationType) { + case _util.AnnotationEditorType.FREETEXT: + return _freetext.FreeTextEditor.deserialize(data, this); + + case _util.AnnotationEditorType.INK: + return _ink.InkEditor.deserialize(data, this); + } + + return null; + } + + setSelected(editor) { + _classPrivateFieldGet(this, _uiManager).setSelected(editor); + } + + toggleSelected(editor) { + _classPrivateFieldGet(this, _uiManager).toggleSelected(editor); + } + + isSelected(editor) { + return _classPrivateFieldGet(this, _uiManager).isSelected(editor); + } + + unselect(editor) { + _classPrivateFieldGet(this, _uiManager).unselect(editor); + } + + pointerup(event) { + const isMac = _tools.KeyboardManager.platform.isMac; + + if (event.button !== 0 || event.ctrlKey && isMac) { + return; + } + + if (event.target !== this.div) { + return; + } + + if (!_classPrivateFieldGet(this, _hadPointerDown)) { + return; + } + + _classPrivateFieldSet(this, _hadPointerDown, false); + + if (!_classPrivateFieldGet(this, _allowClick)) { + _classPrivateFieldSet(this, _allowClick, true); + + return; + } + + _classPrivateMethodGet(this, _createAndAddNewEditor, _createAndAddNewEditor2).call(this, event); + } + + pointerdown(event) { + const isMac = _tools.KeyboardManager.platform.isMac; + + if (event.button !== 0 || event.ctrlKey && isMac) { + return; + } + + if (event.target !== this.div) { + return; + } + + _classPrivateFieldSet(this, _hadPointerDown, true); + + const editor = _classPrivateFieldGet(this, _uiManager).getActive(); + + _classPrivateFieldSet(this, _allowClick, !editor || editor.isEmpty()); + } + + drop(event) { + const id = event.dataTransfer.getData("text/plain"); + + const editor = _classPrivateFieldGet(this, _uiManager).getEditor(id); + + if (!editor) { + return; + } + + event.preventDefault(); + event.dataTransfer.dropEffect = "move"; + + _classPrivateMethodGet(this, _changeParent, _changeParent2).call(this, editor); + + const rect = this.div.getBoundingClientRect(); + const endX = event.clientX - rect.x; + const endY = event.clientY - rect.y; + editor.translate(endX - editor.startX, endY - editor.startY); + this.moveEditorInDOM(editor); + editor.div.focus(); + } + + dragover(event) { + event.preventDefault(); + } + + destroy() { + var _classPrivateFieldGet4; + + if (((_classPrivateFieldGet4 = _classPrivateFieldGet(this, _uiManager).getActive()) === null || _classPrivateFieldGet4 === void 0 ? void 0 : _classPrivateFieldGet4.parent) === this) { + _classPrivateFieldGet(this, _uiManager).setActiveEditor(null); + } + + for (const editor of _classPrivateFieldGet(this, _editors).values()) { + var _classPrivateFieldGet5; + + (_classPrivateFieldGet5 = _classPrivateFieldGet(this, _accessibilityManager)) === null || _classPrivateFieldGet5 === void 0 ? void 0 : _classPrivateFieldGet5.removePointerInTextLayer(editor.contentDiv); + editor.isAttachedToDOM = false; + editor.div.remove(); + editor.parent = null; + } + + this.div = null; + + _classPrivateFieldGet(this, _editors).clear(); + + _classPrivateFieldGet(this, _uiManager).removeLayer(this); + } + + render(parameters) { + this.viewport = parameters.viewport; + (0, _tools.bindEvents)(this, this.div, ["dragover", "drop"]); + this.setDimensions(); + + for (const editor of _classPrivateFieldGet(this, _uiManager).getEditors(this.pageIndex)) { + this.add(editor); + } + + this.updateMode(); + } + + update(parameters) { + this.viewport = parameters.viewport; + this.setDimensions(); + this.updateMode(); + } + + get scaleFactor() { + return this.viewport.scale; + } + + get pageDimensions() { + const [pageLLx, pageLLy, pageURx, pageURy] = this.viewport.viewBox; + const width = pageURx - pageLLx; + const height = pageURy - pageLLy; + return [width, height]; + } + + get viewportBaseDimensions() { + const { + width, + height, + rotation + } = this.viewport; + return rotation % 180 === 0 ? [width, height] : [height, width]; + } + + setDimensions() { + const { + width, + height, + rotation + } = this.viewport; + const flipOrientation = rotation % 180 !== 0, + widthStr = Math.floor(width) + "px", + heightStr = Math.floor(height) + "px"; + this.div.style.width = flipOrientation ? heightStr : widthStr; + this.div.style.height = flipOrientation ? widthStr : heightStr; + this.div.setAttribute("data-main-rotation", rotation); + } + +} + +exports.AnnotationEditorLayer = AnnotationEditorLayer; + +function _changeParent2(editor) { + var _editor$parent; + + if (editor.parent === this) { + return; + } + + this.attach(editor); + editor.pageIndex = this.pageIndex; + (_editor$parent = editor.parent) === null || _editor$parent === void 0 ? void 0 : _editor$parent.detach(editor); + editor.parent = this; + + if (editor.div && editor.isAttachedToDOM) { + editor.div.remove(); + this.div.append(editor.div); + } +} + +function _createNewEditor2(params) { + switch (_classPrivateFieldGet(this, _uiManager).getMode()) { + case _util.AnnotationEditorType.FREETEXT: + return new _freetext.FreeTextEditor(params); + + case _util.AnnotationEditorType.INK: + return new _ink.InkEditor(params); + } + + return null; +} + +function _createAndAddNewEditor2(event) { + const id = this.getNextId(); + + const editor = _classPrivateMethodGet(this, _createNewEditor, _createNewEditor2).call(this, { + parent: this, + id, + x: event.offsetX, + y: event.offsetY + }); + + if (editor) { + this.add(editor); + } + + return editor; +} + +function _cleanup2() { + _classPrivateFieldSet(this, _isCleaningUp, true); + + for (const editor of _classPrivateFieldGet(this, _editors).values()) { + if (editor.isEmpty()) { + editor.remove(); + } + } + + _classPrivateFieldSet(this, _isCleaningUp, false); +} + +_defineProperty(AnnotationEditorLayer, "_initialized", false); + +/***/ }), +/* 148 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.FreeTextEditor = void 0; + +var _util = __w_pdfjs_require__(1); + +var _tools = __w_pdfjs_require__(132); + +var _editor = __w_pdfjs_require__(131); + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } + +function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } + +function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } + +var _boundEditorDivBlur = /*#__PURE__*/new WeakMap(); + +var _boundEditorDivFocus = /*#__PURE__*/new WeakMap(); + +var _boundEditorDivKeydown = /*#__PURE__*/new WeakMap(); + +var _color = /*#__PURE__*/new WeakMap(); + +var _content = /*#__PURE__*/new WeakMap(); + +var _hasAlreadyBeenCommitted = /*#__PURE__*/new WeakMap(); + +var _fontSize = /*#__PURE__*/new WeakMap(); + +var _updateFontSize = /*#__PURE__*/new WeakSet(); + +var _updateColor = /*#__PURE__*/new WeakSet(); + +var _extractText = /*#__PURE__*/new WeakSet(); + +var _setEditorDimensions = /*#__PURE__*/new WeakSet(); + +class FreeTextEditor extends _editor.AnnotationEditor { + constructor(params) { + super({ ...params, + name: "freeTextEditor" + }); + + _classPrivateMethodInitSpec(this, _setEditorDimensions); + + _classPrivateMethodInitSpec(this, _extractText); + + _classPrivateMethodInitSpec(this, _updateColor); + + _classPrivateMethodInitSpec(this, _updateFontSize); + + _classPrivateFieldInitSpec(this, _boundEditorDivBlur, { + writable: true, + value: this.editorDivBlur.bind(this) + }); + + _classPrivateFieldInitSpec(this, _boundEditorDivFocus, { + writable: true, + value: this.editorDivFocus.bind(this) + }); + + _classPrivateFieldInitSpec(this, _boundEditorDivKeydown, { + writable: true, + value: this.editorDivKeydown.bind(this) + }); + + _classPrivateFieldInitSpec(this, _color, { + writable: true, + value: void 0 + }); + + _classPrivateFieldInitSpec(this, _content, { + writable: true, + value: "" + }); + + _classPrivateFieldInitSpec(this, _hasAlreadyBeenCommitted, { + writable: true, + value: false + }); + + _classPrivateFieldInitSpec(this, _fontSize, { + writable: true, + value: void 0 + }); + + _classPrivateFieldSet(this, _color, params.color || FreeTextEditor._defaultColor || _editor.AnnotationEditor._defaultLineColor); + + _classPrivateFieldSet(this, _fontSize, params.fontSize || FreeTextEditor._defaultFontSize); + } + + static initialize(l10n) { + this._l10nPromise = new Map(["free_text_default_content", "editor_free_text_aria_label"].map(str => [str, l10n.get(str)])); + const style = getComputedStyle(document.documentElement); + this._internalPadding = parseFloat(style.getPropertyValue("--freetext-padding")); + } + + static updateDefaultParams(type, value) { + switch (type) { + case _util.AnnotationEditorParamsType.FREETEXT_SIZE: + FreeTextEditor._defaultFontSize = value; + break; + + case _util.AnnotationEditorParamsType.FREETEXT_COLOR: + FreeTextEditor._defaultColor = value; + break; + } + } + + updateParams(type, value) { + switch (type) { + case _util.AnnotationEditorParamsType.FREETEXT_SIZE: + _classPrivateMethodGet(this, _updateFontSize, _updateFontSize2).call(this, value); + + break; + + case _util.AnnotationEditorParamsType.FREETEXT_COLOR: + _classPrivateMethodGet(this, _updateColor, _updateColor2).call(this, value); + + break; + } + } + + static get defaultPropertiesToUpdate() { + return [[_util.AnnotationEditorParamsType.FREETEXT_SIZE, FreeTextEditor._defaultFontSize], [_util.AnnotationEditorParamsType.FREETEXT_COLOR, FreeTextEditor._defaultColor || _editor.AnnotationEditor._defaultLineColor]]; + } + + get propertiesToUpdate() { + return [[_util.AnnotationEditorParamsType.FREETEXT_SIZE, _classPrivateFieldGet(this, _fontSize)], [_util.AnnotationEditorParamsType.FREETEXT_COLOR, _classPrivateFieldGet(this, _color)]]; + } + + getInitialTranslation() { + return [-FreeTextEditor._internalPadding * this.parent.scaleFactor, -(FreeTextEditor._internalPadding + _classPrivateFieldGet(this, _fontSize)) * this.parent.scaleFactor]; + } + + rebuild() { + super.rebuild(); + + if (this.div === null) { + return; + } + + if (!this.isAttachedToDOM) { + this.parent.add(this); + } + } + + enableEditMode() { + if (this.isInEditMode()) { + return; + } + + this.parent.setEditingState(false); + this.parent.updateToolbar(_util.AnnotationEditorType.FREETEXT); + super.enableEditMode(); + this.enableEditing(); + this.overlayDiv.classList.remove("enabled"); + this.editorDiv.contentEditable = true; + this.div.draggable = false; + this.editorDiv.addEventListener("keydown", _classPrivateFieldGet(this, _boundEditorDivKeydown)); + this.editorDiv.addEventListener("focus", _classPrivateFieldGet(this, _boundEditorDivFocus)); + this.editorDiv.addEventListener("blur", _classPrivateFieldGet(this, _boundEditorDivBlur)); + } + + disableEditMode() { + if (!this.isInEditMode()) { + return; + } + + this.parent.setEditingState(true); + super.disableEditMode(); + this.disableEditing(); + this.overlayDiv.classList.add("enabled"); + this.editorDiv.contentEditable = false; + this.div.draggable = true; + this.editorDiv.removeEventListener("keydown", _classPrivateFieldGet(this, _boundEditorDivKeydown)); + this.editorDiv.removeEventListener("focus", _classPrivateFieldGet(this, _boundEditorDivFocus)); + this.editorDiv.removeEventListener("blur", _classPrivateFieldGet(this, _boundEditorDivBlur)); + this.div.focus(); + this.isEditing = false; + } + + focusin(event) { + super.focusin(event); + + if (event.target !== this.editorDiv) { + this.editorDiv.focus(); + } + } + + onceAdded() { + if (this.width) { + return; + } + + this.enableEditMode(); + this.editorDiv.focus(); + } + + isEmpty() { + return !this.editorDiv || this.editorDiv.innerText.trim() === ""; + } + + remove() { + this.isEditing = false; + this.parent.setEditingState(true); + super.remove(); + } + + commit() { + super.commit(); + + if (!_classPrivateFieldGet(this, _hasAlreadyBeenCommitted)) { + _classPrivateFieldSet(this, _hasAlreadyBeenCommitted, true); + + this.parent.addUndoableEditor(this); + } + + this.disableEditMode(); + + _classPrivateFieldSet(this, _content, _classPrivateMethodGet(this, _extractText, _extractText2).call(this).trimEnd()); + + _classPrivateMethodGet(this, _setEditorDimensions, _setEditorDimensions2).call(this); + } + + shouldGetKeyboardEvents() { + return this.isInEditMode(); + } + + dblclick(event) { + this.enableEditMode(); + this.editorDiv.focus(); + } + + keydown(event) { + if (event.target === this.div && event.key === "Enter") { + this.enableEditMode(); + this.editorDiv.focus(); + } + } + + editorDivKeydown(event) { + FreeTextEditor._keyboardManager.exec(this, event); + } + + editorDivFocus(event) { + this.isEditing = true; + } + + editorDivBlur(event) { + this.isEditing = false; + } + + disableEditing() { + this.editorDiv.setAttribute("role", "comment"); + this.editorDiv.removeAttribute("aria-multiline"); + } + + enableEditing() { + this.editorDiv.setAttribute("role", "textbox"); + this.editorDiv.setAttribute("aria-multiline", true); + } + + render() { + if (this.div) { + return this.div; + } + + let baseX, baseY; + + if (this.width) { + baseX = this.x; + baseY = this.y; + } + + super.render(); + this.editorDiv = document.createElement("div"); + this.editorDiv.className = "internal"; + this.editorDiv.setAttribute("id", `${this.id}-editor`); + this.enableEditing(); + + FreeTextEditor._l10nPromise.get("editor_free_text_aria_label").then(msg => { + var _this$editorDiv; + + return (_this$editorDiv = this.editorDiv) === null || _this$editorDiv === void 0 ? void 0 : _this$editorDiv.setAttribute("aria-label", msg); + }); + + FreeTextEditor._l10nPromise.get("free_text_default_content").then(msg => { + var _this$editorDiv2; + + return (_this$editorDiv2 = this.editorDiv) === null || _this$editorDiv2 === void 0 ? void 0 : _this$editorDiv2.setAttribute("default-content", msg); + }); + + this.editorDiv.contentEditable = true; + const { + style + } = this.editorDiv; + style.fontSize = `calc(${_classPrivateFieldGet(this, _fontSize)}px * var(--scale-factor))`; + style.color = _classPrivateFieldGet(this, _color); + this.div.append(this.editorDiv); + this.overlayDiv = document.createElement("div"); + this.overlayDiv.classList.add("overlay", "enabled"); + this.div.append(this.overlayDiv); + (0, _tools.bindEvents)(this, this.div, ["dblclick", "keydown"]); + + if (this.width) { + const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions; + this.setAt(baseX * parentWidth, baseY * parentHeight, this.width * parentWidth, this.height * parentHeight); + + for (const line of _classPrivateFieldGet(this, _content).split("\n")) { + const div = document.createElement("div"); + div.append(line ? document.createTextNode(line) : document.createElement("br")); + this.editorDiv.append(div); + } + + this.div.draggable = true; + this.editorDiv.contentEditable = false; + } else { + this.div.draggable = false; + this.editorDiv.contentEditable = true; + } + + return this.div; + } + + get contentDiv() { + return this.editorDiv; + } + + static deserialize(data, parent) { + const editor = super.deserialize(data, parent); + + _classPrivateFieldSet(editor, _fontSize, data.fontSize); + + _classPrivateFieldSet(editor, _color, _util.Util.makeHexColor(...data.color)); + + _classPrivateFieldSet(editor, _content, data.value); + + return editor; + } + + serialize() { + if (this.isEmpty()) { + return null; + } + + const padding = FreeTextEditor._internalPadding * this.parent.scaleFactor; + const rect = this.getRect(padding, padding); + + const color = _editor.AnnotationEditor._colorManager.convert(getComputedStyle(this.editorDiv).color); + + return { + annotationType: _util.AnnotationEditorType.FREETEXT, + color, + fontSize: _classPrivateFieldGet(this, _fontSize), + value: _classPrivateFieldGet(this, _content), + pageIndex: this.parent.pageIndex, + rect, + rotation: this.rotation + }; + } + +} + +exports.FreeTextEditor = FreeTextEditor; + +function _updateFontSize2(fontSize) { + const setFontsize = size => { + this.editorDiv.style.fontSize = `calc(${size}px * var(--scale-factor))`; + this.translate(0, -(size - _classPrivateFieldGet(this, _fontSize)) * this.parent.scaleFactor); + + _classPrivateFieldSet(this, _fontSize, size); + + _classPrivateMethodGet(this, _setEditorDimensions, _setEditorDimensions2).call(this); + }; + + const savedFontsize = _classPrivateFieldGet(this, _fontSize); + + this.parent.addCommands({ + cmd: () => { + setFontsize(fontSize); + }, + undo: () => { + setFontsize(savedFontsize); + }, + mustExec: true, + type: _util.AnnotationEditorParamsType.FREETEXT_SIZE, + overwriteIfSameType: true, + keepUndo: true + }); +} + +function _updateColor2(color) { + const savedColor = _classPrivateFieldGet(this, _color); + + this.parent.addCommands({ + cmd: () => { + _classPrivateFieldSet(this, _color, color); + + this.editorDiv.style.color = color; + }, + undo: () => { + _classPrivateFieldSet(this, _color, savedColor); + + this.editorDiv.style.color = savedColor; + }, + mustExec: true, + type: _util.AnnotationEditorParamsType.FREETEXT_COLOR, + overwriteIfSameType: true, + keepUndo: true + }); +} + +function _extractText2() { + const divs = this.editorDiv.getElementsByTagName("div"); + + if (divs.length === 0) { + return this.editorDiv.innerText; + } + + const buffer = []; + + for (let i = 0, ii = divs.length; i < ii; i++) { + const div = divs[i]; + const first = div.firstChild; + + if ((first === null || first === void 0 ? void 0 : first.nodeName) === "#text") { + buffer.push(first.data); + } else { + buffer.push(""); + } + } + + return buffer.join("\n"); +} + +function _setEditorDimensions2() { + const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions; + const rect = this.div.getBoundingClientRect(); + this.width = rect.width / parentWidth; + this.height = rect.height / parentHeight; +} + +_defineProperty(FreeTextEditor, "_freeTextDefaultContent", ""); + +_defineProperty(FreeTextEditor, "_l10nPromise", void 0); + +_defineProperty(FreeTextEditor, "_internalPadding", 0); + +_defineProperty(FreeTextEditor, "_defaultColor", null); + +_defineProperty(FreeTextEditor, "_defaultFontSize", 10); + +_defineProperty(FreeTextEditor, "_keyboardManager", new _tools.KeyboardManager([[["ctrl+Enter", "mac+meta+Enter", "Escape", "mac+Escape"], FreeTextEditor.prototype.commitOrRemove]])); + +_defineProperty(FreeTextEditor, "_type", "freetext"); + +/***/ }), +/* 149 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.InkEditor = void 0; +Object.defineProperty(exports, "fitCurve", ({ + enumerable: true, + get: function () { + return _pdfjsFitCurve.fitCurve; + } +})); + +var _util = __w_pdfjs_require__(1); + +var _editor = __w_pdfjs_require__(131); + +var _pdfjsFitCurve = __w_pdfjs_require__(150); + +var _tools = __w_pdfjs_require__(132); + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classStaticPrivateMethodGet(receiver, classConstructor, method) { _classCheckPrivateStaticAccess(receiver, classConstructor); return method; } + +function _classCheckPrivateStaticAccess(receiver, classConstructor) { if (receiver !== classConstructor) { throw new TypeError("Private static access of wrong provenance"); } } + +function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } + +function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } + +function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +const RESIZER_SIZE = 16; + +var _aspectRatio = /*#__PURE__*/new WeakMap(); + +var _baseHeight = /*#__PURE__*/new WeakMap(); + +var _baseWidth = /*#__PURE__*/new WeakMap(); + +var _boundCanvasPointermove = /*#__PURE__*/new WeakMap(); + +var _boundCanvasPointerleave = /*#__PURE__*/new WeakMap(); + +var _boundCanvasPointerup = /*#__PURE__*/new WeakMap(); + +var _boundCanvasPointerdown = /*#__PURE__*/new WeakMap(); + +var _disableEditing = /*#__PURE__*/new WeakMap(); + +var _isCanvasInitialized = /*#__PURE__*/new WeakMap(); + +var _lastPoint = /*#__PURE__*/new WeakMap(); + +var _observer = /*#__PURE__*/new WeakMap(); + +var _realWidth = /*#__PURE__*/new WeakMap(); + +var _realHeight = /*#__PURE__*/new WeakMap(); + +var _requestFrameCallback = /*#__PURE__*/new WeakMap(); + +var _updateThickness = /*#__PURE__*/new WeakSet(); + +var _updateColor = /*#__PURE__*/new WeakSet(); + +var _updateOpacity = /*#__PURE__*/new WeakSet(); + +var _getInitialBBox = /*#__PURE__*/new WeakSet(); + +var _setStroke = /*#__PURE__*/new WeakSet(); + +var _startDrawing = /*#__PURE__*/new WeakSet(); + +var _draw = /*#__PURE__*/new WeakSet(); + +var _stopDrawing = /*#__PURE__*/new WeakSet(); + +var _redraw = /*#__PURE__*/new WeakSet(); + +var _endDrawing = /*#__PURE__*/new WeakSet(); + +var _createCanvas = /*#__PURE__*/new WeakSet(); + +var _createObserver = /*#__PURE__*/new WeakSet(); + +var _setCanvasDims = /*#__PURE__*/new WeakSet(); + +var _setScaleFactor = /*#__PURE__*/new WeakSet(); + +var _updateTransform = /*#__PURE__*/new WeakSet(); + +var _serializePaths = /*#__PURE__*/new WeakSet(); + +var _extractPointsOnBezier = /*#__PURE__*/new WeakSet(); + +var _isAlmostFlat = /*#__PURE__*/new WeakSet(); + +var _getBbox = /*#__PURE__*/new WeakSet(); + +var _getPadding = /*#__PURE__*/new WeakSet(); + +var _fitToContent = /*#__PURE__*/new WeakSet(); + +var _setMinDims = /*#__PURE__*/new WeakSet(); + +class InkEditor extends _editor.AnnotationEditor { + constructor(params) { + super({ ...params, + name: "inkEditor" + }); + + _classPrivateMethodInitSpec(this, _setMinDims); + + _classPrivateMethodInitSpec(this, _fitToContent); + + _classPrivateMethodInitSpec(this, _getPadding); + + _classPrivateMethodInitSpec(this, _getBbox); + + _classPrivateMethodInitSpec(this, _isAlmostFlat); + + _classPrivateMethodInitSpec(this, _extractPointsOnBezier); + + _classPrivateMethodInitSpec(this, _serializePaths); + + _classPrivateMethodInitSpec(this, _updateTransform); + + _classPrivateMethodInitSpec(this, _setScaleFactor); + + _classPrivateMethodInitSpec(this, _setCanvasDims); + + _classPrivateMethodInitSpec(this, _createObserver); + + _classPrivateMethodInitSpec(this, _createCanvas); + + _classPrivateMethodInitSpec(this, _endDrawing); + + _classPrivateMethodInitSpec(this, _redraw); + + _classPrivateMethodInitSpec(this, _stopDrawing); + + _classPrivateMethodInitSpec(this, _draw); + + _classPrivateMethodInitSpec(this, _startDrawing); + + _classPrivateMethodInitSpec(this, _setStroke); + + _classPrivateMethodInitSpec(this, _getInitialBBox); + + _classPrivateMethodInitSpec(this, _updateOpacity); + + _classPrivateMethodInitSpec(this, _updateColor); + + _classPrivateMethodInitSpec(this, _updateThickness); + + _classPrivateFieldInitSpec(this, _aspectRatio, { + writable: true, + value: 0 + }); + + _classPrivateFieldInitSpec(this, _baseHeight, { + writable: true, + value: 0 + }); + + _classPrivateFieldInitSpec(this, _baseWidth, { + writable: true, + value: 0 + }); + + _classPrivateFieldInitSpec(this, _boundCanvasPointermove, { + writable: true, + value: this.canvasPointermove.bind(this) + }); + + _classPrivateFieldInitSpec(this, _boundCanvasPointerleave, { + writable: true, + value: this.canvasPointerleave.bind(this) + }); + + _classPrivateFieldInitSpec(this, _boundCanvasPointerup, { + writable: true, + value: this.canvasPointerup.bind(this) + }); + + _classPrivateFieldInitSpec(this, _boundCanvasPointerdown, { + writable: true, + value: this.canvasPointerdown.bind(this) + }); + + _classPrivateFieldInitSpec(this, _disableEditing, { + writable: true, + value: false + }); + + _classPrivateFieldInitSpec(this, _isCanvasInitialized, { + writable: true, + value: false + }); + + _classPrivateFieldInitSpec(this, _lastPoint, { + writable: true, + value: null + }); + + _classPrivateFieldInitSpec(this, _observer, { + writable: true, + value: null + }); + + _classPrivateFieldInitSpec(this, _realWidth, { + writable: true, + value: 0 + }); + + _classPrivateFieldInitSpec(this, _realHeight, { + writable: true, + value: 0 + }); + + _classPrivateFieldInitSpec(this, _requestFrameCallback, { + writable: true, + value: null + }); + + this.color = params.color || null; + this.thickness = params.thickness || null; + this.opacity = params.opacity || null; + this.paths = []; + this.bezierPath2D = []; + this.currentPath = []; + this.scaleFactor = 1; + this.translationX = this.translationY = 0; + this.x = 0; + this.y = 0; + } + + static initialize(l10n) { + this._l10nPromise = new Map(["editor_ink_canvas_aria_label", "editor_ink_aria_label"].map(str => [str, l10n.get(str)])); + } + + static updateDefaultParams(type, value) { + switch (type) { + case _util.AnnotationEditorParamsType.INK_THICKNESS: + InkEditor._defaultThickness = value; + break; + + case _util.AnnotationEditorParamsType.INK_COLOR: + InkEditor._defaultColor = value; + break; + + case _util.AnnotationEditorParamsType.INK_OPACITY: + InkEditor._defaultOpacity = value / 100; + break; + } + } + + updateParams(type, value) { + switch (type) { + case _util.AnnotationEditorParamsType.INK_THICKNESS: + _classPrivateMethodGet(this, _updateThickness, _updateThickness2).call(this, value); + + break; + + case _util.AnnotationEditorParamsType.INK_COLOR: + _classPrivateMethodGet(this, _updateColor, _updateColor2).call(this, value); + + break; + + case _util.AnnotationEditorParamsType.INK_OPACITY: + _classPrivateMethodGet(this, _updateOpacity, _updateOpacity2).call(this, value); + + break; + } + } + + static get defaultPropertiesToUpdate() { + return [[_util.AnnotationEditorParamsType.INK_THICKNESS, InkEditor._defaultThickness], [_util.AnnotationEditorParamsType.INK_COLOR, InkEditor._defaultColor || _editor.AnnotationEditor._defaultLineColor], [_util.AnnotationEditorParamsType.INK_OPACITY, Math.round(InkEditor._defaultOpacity * 100)]]; + } + + get propertiesToUpdate() { + var _this$opacity; + + return [[_util.AnnotationEditorParamsType.INK_THICKNESS, this.thickness || InkEditor._defaultThickness], [_util.AnnotationEditorParamsType.INK_COLOR, this.color || InkEditor._defaultColor || _editor.AnnotationEditor._defaultLineColor], [_util.AnnotationEditorParamsType.INK_OPACITY, Math.round(100 * ((_this$opacity = this.opacity) !== null && _this$opacity !== void 0 ? _this$opacity : InkEditor._defaultOpacity))]]; + } + + rebuild() { + super.rebuild(); + + if (this.div === null) { + return; + } + + if (!this.canvas) { + _classPrivateMethodGet(this, _createCanvas, _createCanvas2).call(this); + + _classPrivateMethodGet(this, _createObserver, _createObserver2).call(this); + } + + if (!this.isAttachedToDOM) { + this.parent.add(this); + + _classPrivateMethodGet(this, _setCanvasDims, _setCanvasDims2).call(this); + } + + _classPrivateMethodGet(this, _fitToContent, _fitToContent2).call(this); + } + + remove() { + if (this.canvas === null) { + return; + } + + if (!this.isEmpty()) { + this.commit(); + } + + this.canvas.width = this.canvas.height = 0; + this.canvas.remove(); + this.canvas = null; + + _classPrivateFieldGet(this, _observer).disconnect(); + + _classPrivateFieldSet(this, _observer, null); + + super.remove(); + } + + enableEditMode() { + if (_classPrivateFieldGet(this, _disableEditing) || this.canvas === null) { + return; + } + + super.enableEditMode(); + this.div.draggable = false; + this.canvas.addEventListener("pointerdown", _classPrivateFieldGet(this, _boundCanvasPointerdown)); + this.canvas.addEventListener("pointerup", _classPrivateFieldGet(this, _boundCanvasPointerup)); + } + + disableEditMode() { + if (!this.isInEditMode() || this.canvas === null) { + return; + } + + super.disableEditMode(); + this.div.draggable = !this.isEmpty(); + this.div.classList.remove("editing"); + this.canvas.removeEventListener("pointerdown", _classPrivateFieldGet(this, _boundCanvasPointerdown)); + this.canvas.removeEventListener("pointerup", _classPrivateFieldGet(this, _boundCanvasPointerup)); + } + + onceAdded() { + this.div.draggable = !this.isEmpty(); + } + + isEmpty() { + return this.paths.length === 0 || this.paths.length === 1 && this.paths[0].length === 0; + } + + commit() { + if (_classPrivateFieldGet(this, _disableEditing)) { + return; + } + + super.commit(); + this.isEditing = false; + this.disableEditMode(); + this.setInForeground(); + + _classPrivateFieldSet(this, _disableEditing, true); + + this.div.classList.add("disabled"); + + _classPrivateMethodGet(this, _fitToContent, _fitToContent2).call(this, true); + + this.parent.addInkEditorIfNeeded(true); + this.parent.moveEditorInDOM(this); + this.div.focus(); + } + + focusin(event) { + super.focusin(event); + this.enableEditMode(); + } + + canvasPointerdown(event) { + if (event.button !== 0 || !this.isInEditMode() || _classPrivateFieldGet(this, _disableEditing)) { + return; + } + + this.setInForeground(); + + if (event.type !== "mouse") { + this.div.focus(); + } + + event.stopPropagation(); + this.canvas.addEventListener("pointerleave", _classPrivateFieldGet(this, _boundCanvasPointerleave)); + this.canvas.addEventListener("pointermove", _classPrivateFieldGet(this, _boundCanvasPointermove)); + + _classPrivateMethodGet(this, _startDrawing, _startDrawing2).call(this, event.offsetX, event.offsetY); + } + + canvasPointermove(event) { + event.stopPropagation(); + + _classPrivateMethodGet(this, _draw, _draw2).call(this, event.offsetX, event.offsetY); + } + + canvasPointerup(event) { + if (event.button !== 0) { + return; + } + + if (this.isInEditMode() && this.currentPath.length !== 0) { + event.stopPropagation(); + + _classPrivateMethodGet(this, _endDrawing, _endDrawing2).call(this, event); + + this.setInBackground(); + } + } + + canvasPointerleave(event) { + _classPrivateMethodGet(this, _endDrawing, _endDrawing2).call(this, event); + + this.setInBackground(); + } + + render() { + if (this.div) { + return this.div; + } + + let baseX, baseY; + + if (this.width) { + baseX = this.x; + baseY = this.y; + } + + super.render(); + + InkEditor._l10nPromise.get("editor_ink_aria_label").then(msg => { + var _this$div; + + return (_this$div = this.div) === null || _this$div === void 0 ? void 0 : _this$div.setAttribute("aria-label", msg); + }); + + const [x, y, w, h] = _classPrivateMethodGet(this, _getInitialBBox, _getInitialBBox2).call(this); + + this.setAt(x, y, 0, 0); + this.setDims(w, h); + + _classPrivateMethodGet(this, _createCanvas, _createCanvas2).call(this); + + if (this.width) { + const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions; + this.setAt(baseX * parentWidth, baseY * parentHeight, this.width * parentWidth, this.height * parentHeight); + + _classPrivateFieldSet(this, _isCanvasInitialized, true); + + _classPrivateMethodGet(this, _setCanvasDims, _setCanvasDims2).call(this); + + this.setDims(this.width * parentWidth, this.height * parentHeight); + + _classPrivateMethodGet(this, _redraw, _redraw2).call(this); + + _classPrivateMethodGet(this, _setMinDims, _setMinDims2).call(this); + + this.div.classList.add("disabled"); + } else { + this.div.classList.add("editing"); + this.enableEditMode(); + } + + _classPrivateMethodGet(this, _createObserver, _createObserver2).call(this); + + return this.div; + } + + setDimensions(width, height) { + const roundedWidth = Math.round(width); + const roundedHeight = Math.round(height); + + if (_classPrivateFieldGet(this, _realWidth) === roundedWidth && _classPrivateFieldGet(this, _realHeight) === roundedHeight) { + return; + } + + _classPrivateFieldSet(this, _realWidth, roundedWidth); + + _classPrivateFieldSet(this, _realHeight, roundedHeight); + + this.canvas.style.visibility = "hidden"; + + if (_classPrivateFieldGet(this, _aspectRatio) && Math.abs(_classPrivateFieldGet(this, _aspectRatio) - width / height) > 1e-2) { + height = Math.ceil(width / _classPrivateFieldGet(this, _aspectRatio)); + this.setDims(width, height); + } + + const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions; + this.width = width / parentWidth; + this.height = height / parentHeight; + + if (_classPrivateFieldGet(this, _disableEditing)) { + _classPrivateMethodGet(this, _setScaleFactor, _setScaleFactor2).call(this, width, height); + } + + _classPrivateMethodGet(this, _setCanvasDims, _setCanvasDims2).call(this); + + _classPrivateMethodGet(this, _redraw, _redraw2).call(this); + + this.canvas.style.visibility = "visible"; + } + + static deserialize(data, parent) { + const editor = super.deserialize(data, parent); + editor.thickness = data.thickness; + editor.color = _util.Util.makeHexColor(...data.color); + editor.opacity = data.opacity; + const [pageWidth, pageHeight] = parent.pageDimensions; + const width = editor.width * pageWidth; + const height = editor.height * pageHeight; + const scaleFactor = parent.scaleFactor; + const padding = data.thickness / 2; + + _classPrivateFieldSet(editor, _aspectRatio, width / height); + + _classPrivateFieldSet(editor, _disableEditing, true); + + _classPrivateFieldSet(editor, _realWidth, Math.round(width)); + + _classPrivateFieldSet(editor, _realHeight, Math.round(height)); + + for (const { + bezier + } of data.paths) { + const path = []; + editor.paths.push(path); + let p0 = scaleFactor * (bezier[0] - padding); + let p1 = scaleFactor * (height - bezier[1] - padding); + + for (let i = 2, ii = bezier.length; i < ii; i += 6) { + const p10 = scaleFactor * (bezier[i] - padding); + const p11 = scaleFactor * (height - bezier[i + 1] - padding); + const p20 = scaleFactor * (bezier[i + 2] - padding); + const p21 = scaleFactor * (height - bezier[i + 3] - padding); + const p30 = scaleFactor * (bezier[i + 4] - padding); + const p31 = scaleFactor * (height - bezier[i + 5] - padding); + path.push([[p0, p1], [p10, p11], [p20, p21], [p30, p31]]); + p0 = p30; + p1 = p31; + } + + const path2D = _classStaticPrivateMethodGet(this, InkEditor, _buildPath2D).call(this, path); + + editor.bezierPath2D.push(path2D); + } + + const bbox = _classPrivateMethodGet(editor, _getBbox, _getBbox2).call(editor); + + _classPrivateFieldSet(editor, _baseWidth, Math.max(RESIZER_SIZE, bbox[2] - bbox[0])); + + _classPrivateFieldSet(editor, _baseHeight, Math.max(RESIZER_SIZE, bbox[3] - bbox[1])); + + _classPrivateMethodGet(editor, _setScaleFactor, _setScaleFactor2).call(editor, width, height); + + return editor; + } + + serialize() { + if (this.isEmpty()) { + return null; + } + + const rect = this.getRect(0, 0); + const height = this.rotation % 180 === 0 ? rect[3] - rect[1] : rect[2] - rect[0]; + + const color = _editor.AnnotationEditor._colorManager.convert(this.ctx.strokeStyle); + + return { + annotationType: _util.AnnotationEditorType.INK, + color, + thickness: this.thickness, + opacity: this.opacity, + paths: _classPrivateMethodGet(this, _serializePaths, _serializePaths2).call(this, this.scaleFactor / this.parent.scaleFactor, this.translationX, this.translationY, height), + pageIndex: this.parent.pageIndex, + rect, + rotation: this.rotation + }; + } + +} + +exports.InkEditor = InkEditor; + +function _updateThickness2(thickness) { + const savedThickness = this.thickness; + this.parent.addCommands({ + cmd: () => { + this.thickness = thickness; + + _classPrivateMethodGet(this, _fitToContent, _fitToContent2).call(this); + }, + undo: () => { + this.thickness = savedThickness; + + _classPrivateMethodGet(this, _fitToContent, _fitToContent2).call(this); + }, + mustExec: true, + type: _util.AnnotationEditorParamsType.INK_THICKNESS, + overwriteIfSameType: true, + keepUndo: true + }); +} + +function _updateColor2(color) { + const savedColor = this.color; + this.parent.addCommands({ + cmd: () => { + this.color = color; + + _classPrivateMethodGet(this, _redraw, _redraw2).call(this); + }, + undo: () => { + this.color = savedColor; + + _classPrivateMethodGet(this, _redraw, _redraw2).call(this); + }, + mustExec: true, + type: _util.AnnotationEditorParamsType.INK_COLOR, + overwriteIfSameType: true, + keepUndo: true + }); +} + +function _updateOpacity2(opacity) { + opacity /= 100; + const savedOpacity = this.opacity; + this.parent.addCommands({ + cmd: () => { + this.opacity = opacity; + + _classPrivateMethodGet(this, _redraw, _redraw2).call(this); + }, + undo: () => { + this.opacity = savedOpacity; + + _classPrivateMethodGet(this, _redraw, _redraw2).call(this); + }, + mustExec: true, + type: _util.AnnotationEditorParamsType.INK_OPACITY, + overwriteIfSameType: true, + keepUndo: true + }); +} + +function _getInitialBBox2() { + const { + width, + height, + rotation + } = this.parent.viewport; + + switch (rotation) { + case 90: + return [0, width, width, height]; + + case 180: + return [width, height, width, height]; + + case 270: + return [height, 0, width, height]; + + default: + return [0, 0, width, height]; + } +} + +function _setStroke2() { + this.ctx.lineWidth = this.thickness * this.parent.scaleFactor / this.scaleFactor; + this.ctx.lineCap = "round"; + this.ctx.lineJoin = "round"; + this.ctx.miterLimit = 10; + this.ctx.strokeStyle = `${this.color}${(0, _tools.opacityToHex)(this.opacity)}`; +} + +function _startDrawing2(x, y) { + this.isEditing = true; + + if (!_classPrivateFieldGet(this, _isCanvasInitialized)) { + var _this$opacity2; + + _classPrivateFieldSet(this, _isCanvasInitialized, true); + + _classPrivateMethodGet(this, _setCanvasDims, _setCanvasDims2).call(this); + + this.thickness || (this.thickness = InkEditor._defaultThickness); + this.color || (this.color = InkEditor._defaultColor || _editor.AnnotationEditor._defaultLineColor); + (_this$opacity2 = this.opacity) !== null && _this$opacity2 !== void 0 ? _this$opacity2 : this.opacity = InkEditor._defaultOpacity; + } + + this.currentPath.push([x, y]); + + _classPrivateFieldSet(this, _lastPoint, null); + + _classPrivateMethodGet(this, _setStroke, _setStroke2).call(this); + + this.ctx.beginPath(); + this.ctx.moveTo(x, y); + + _classPrivateFieldSet(this, _requestFrameCallback, () => { + if (!_classPrivateFieldGet(this, _requestFrameCallback)) { + return; + } + + if (_classPrivateFieldGet(this, _lastPoint)) { + if (this.isEmpty()) { + this.ctx.setTransform(1, 0, 0, 1, 0, 0); + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + } else { + _classPrivateMethodGet(this, _redraw, _redraw2).call(this); + } + + this.ctx.lineTo(..._classPrivateFieldGet(this, _lastPoint)); + + _classPrivateFieldSet(this, _lastPoint, null); + + this.ctx.stroke(); + } + + window.requestAnimationFrame(_classPrivateFieldGet(this, _requestFrameCallback)); + }); + + window.requestAnimationFrame(_classPrivateFieldGet(this, _requestFrameCallback)); +} + +function _draw2(x, y) { + const [lastX, lastY] = this.currentPath.at(-1); + + if (x === lastX && y === lastY) { + return; + } + + this.currentPath.push([x, y]); + + _classPrivateFieldSet(this, _lastPoint, [x, y]); +} + +function _stopDrawing2(x, y) { + this.ctx.closePath(); + + _classPrivateFieldSet(this, _requestFrameCallback, null); + + x = Math.min(Math.max(x, 0), this.canvas.width); + y = Math.min(Math.max(y, 0), this.canvas.height); + const [lastX, lastY] = this.currentPath.at(-1); + + if (x !== lastX || y !== lastY) { + this.currentPath.push([x, y]); + } + + let bezier; + + if (this.currentPath.length !== 1) { + bezier = (0, _pdfjsFitCurve.fitCurve)(this.currentPath, 30, null); + } else { + const xy = [x, y]; + bezier = [[xy, xy.slice(), xy.slice(), xy]]; + } + + const path2D = _classStaticPrivateMethodGet(InkEditor, InkEditor, _buildPath2D).call(InkEditor, bezier); + + this.currentPath.length = 0; + + const cmd = () => { + this.paths.push(bezier); + this.bezierPath2D.push(path2D); + this.rebuild(); + }; + + const undo = () => { + this.paths.pop(); + this.bezierPath2D.pop(); + + if (this.paths.length === 0) { + this.remove(); + } else { + if (!this.canvas) { + _classPrivateMethodGet(this, _createCanvas, _createCanvas2).call(this); + + _classPrivateMethodGet(this, _createObserver, _createObserver2).call(this); + } + + _classPrivateMethodGet(this, _fitToContent, _fitToContent2).call(this); + } + }; + + this.parent.addCommands({ + cmd, + undo, + mustExec: true + }); +} + +function _redraw2() { + if (this.isEmpty()) { + _classPrivateMethodGet(this, _updateTransform, _updateTransform2).call(this); + + return; + } + + _classPrivateMethodGet(this, _setStroke, _setStroke2).call(this); + + const { + canvas, + ctx + } = this; + ctx.setTransform(1, 0, 0, 1, 0, 0); + ctx.clearRect(0, 0, canvas.width, canvas.height); + + _classPrivateMethodGet(this, _updateTransform, _updateTransform2).call(this); + + for (const path of this.bezierPath2D) { + ctx.stroke(path); + } +} + +function _endDrawing2(event) { + _classPrivateMethodGet(this, _stopDrawing, _stopDrawing2).call(this, event.offsetX, event.offsetY); + + this.canvas.removeEventListener("pointerleave", _classPrivateFieldGet(this, _boundCanvasPointerleave)); + this.canvas.removeEventListener("pointermove", _classPrivateFieldGet(this, _boundCanvasPointermove)); + this.parent.addToAnnotationStorage(this); +} + +function _createCanvas2() { + this.canvas = document.createElement("canvas"); + this.canvas.width = this.canvas.height = 0; + this.canvas.className = "inkEditorCanvas"; + + InkEditor._l10nPromise.get("editor_ink_canvas_aria_label").then(msg => { + var _this$canvas; + + return (_this$canvas = this.canvas) === null || _this$canvas === void 0 ? void 0 : _this$canvas.setAttribute("aria-label", msg); + }); + + this.div.append(this.canvas); + this.ctx = this.canvas.getContext("2d"); +} + +function _createObserver2() { + _classPrivateFieldSet(this, _observer, new ResizeObserver(entries => { + const rect = entries[0].contentRect; + + if (rect.width && rect.height) { + this.setDimensions(rect.width, rect.height); + } + })); + + _classPrivateFieldGet(this, _observer).observe(this.div); +} + +function _setCanvasDims2() { + if (!_classPrivateFieldGet(this, _isCanvasInitialized)) { + return; + } + + const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions; + this.canvas.width = Math.ceil(this.width * parentWidth); + this.canvas.height = Math.ceil(this.height * parentHeight); + + _classPrivateMethodGet(this, _updateTransform, _updateTransform2).call(this); +} + +function _setScaleFactor2(width, height) { + const padding = _classPrivateMethodGet(this, _getPadding, _getPadding2).call(this); + + const scaleFactorW = (width - padding) / _classPrivateFieldGet(this, _baseWidth); + + const scaleFactorH = (height - padding) / _classPrivateFieldGet(this, _baseHeight); + + this.scaleFactor = Math.min(scaleFactorW, scaleFactorH); +} + +function _updateTransform2() { + const padding = _classPrivateMethodGet(this, _getPadding, _getPadding2).call(this) / 2; + this.ctx.setTransform(this.scaleFactor, 0, 0, this.scaleFactor, this.translationX * this.scaleFactor + padding, this.translationY * this.scaleFactor + padding); +} + +function _buildPath2D(bezier) { + const path2D = new Path2D(); + + for (let i = 0, ii = bezier.length; i < ii; i++) { + const [first, control1, control2, second] = bezier[i]; + + if (i === 0) { + path2D.moveTo(...first); + } + + path2D.bezierCurveTo(control1[0], control1[1], control2[0], control2[1], second[0], second[1]); + } + + return path2D; +} + +function _serializePaths2(s, tx, ty, h) { + const NUMBER_OF_POINTS_ON_BEZIER_CURVE = 4; + const paths = []; + const padding = this.thickness / 2; + let buffer, points; + + for (const bezier of this.paths) { + buffer = []; + points = []; + + for (let i = 0, ii = bezier.length; i < ii; i++) { + const [first, control1, control2, second] = bezier[i]; + const p10 = s * (first[0] + tx) + padding; + const p11 = h - s * (first[1] + ty) - padding; + const p20 = s * (control1[0] + tx) + padding; + const p21 = h - s * (control1[1] + ty) - padding; + const p30 = s * (control2[0] + tx) + padding; + const p31 = h - s * (control2[1] + ty) - padding; + const p40 = s * (second[0] + tx) + padding; + const p41 = h - s * (second[1] + ty) - padding; + + if (i === 0) { + buffer.push(p10, p11); + points.push(p10, p11); + } + + buffer.push(p20, p21, p30, p31, p40, p41); + + _classPrivateMethodGet(this, _extractPointsOnBezier, _extractPointsOnBezier2).call(this, p10, p11, p20, p21, p30, p31, p40, p41, NUMBER_OF_POINTS_ON_BEZIER_CURVE, points); + } + + paths.push({ + bezier: buffer, + points + }); + } + + return paths; +} + +function _extractPointsOnBezier2(p10, p11, p20, p21, p30, p31, p40, p41, n, points) { + if (_classPrivateMethodGet(this, _isAlmostFlat, _isAlmostFlat2).call(this, p10, p11, p20, p21, p30, p31, p40, p41)) { + points.push(p40, p41); + return; + } + + for (let i = 1; i < n - 1; i++) { + const t = i / n; + const mt = 1 - t; + let q10 = t * p10 + mt * p20; + let q11 = t * p11 + mt * p21; + let q20 = t * p20 + mt * p30; + let q21 = t * p21 + mt * p31; + const q30 = t * p30 + mt * p40; + const q31 = t * p31 + mt * p41; + q10 = t * q10 + mt * q20; + q11 = t * q11 + mt * q21; + q20 = t * q20 + mt * q30; + q21 = t * q21 + mt * q31; + q10 = t * q10 + mt * q20; + q11 = t * q11 + mt * q21; + points.push(q10, q11); + } + + points.push(p40, p41); +} + +function _isAlmostFlat2(p10, p11, p20, p21, p30, p31, p40, p41) { + const tol = 10; + const ax = (3 * p20 - 2 * p10 - p40) ** 2; + const ay = (3 * p21 - 2 * p11 - p41) ** 2; + const bx = (3 * p30 - p10 - 2 * p40) ** 2; + const by = (3 * p31 - p11 - 2 * p41) ** 2; + return Math.max(ax, bx) + Math.max(ay, by) <= tol; +} + +function _getBbox2() { + let xMin = Infinity; + let xMax = -Infinity; + let yMin = Infinity; + let yMax = -Infinity; + + for (const path of this.paths) { + for (const [first, control1, control2, second] of path) { + const bbox = _util.Util.bezierBoundingBox(...first, ...control1, ...control2, ...second); + + xMin = Math.min(xMin, bbox[0]); + yMin = Math.min(yMin, bbox[1]); + xMax = Math.max(xMax, bbox[2]); + yMax = Math.max(yMax, bbox[3]); + } + } + + return [xMin, yMin, xMax, yMax]; +} + +function _getPadding2() { + return _classPrivateFieldGet(this, _disableEditing) ? Math.ceil(this.thickness * this.parent.scaleFactor) : 0; +} + +function _fitToContent2() { + let firstTime = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + if (this.isEmpty()) { + return; + } + + if (!_classPrivateFieldGet(this, _disableEditing)) { + _classPrivateMethodGet(this, _redraw, _redraw2).call(this); + + return; + } + + const bbox = _classPrivateMethodGet(this, _getBbox, _getBbox2).call(this); + + const padding = _classPrivateMethodGet(this, _getPadding, _getPadding2).call(this); + + _classPrivateFieldSet(this, _baseWidth, Math.max(RESIZER_SIZE, bbox[2] - bbox[0])); + + _classPrivateFieldSet(this, _baseHeight, Math.max(RESIZER_SIZE, bbox[3] - bbox[1])); + + const width = Math.ceil(padding + _classPrivateFieldGet(this, _baseWidth) * this.scaleFactor); + const height = Math.ceil(padding + _classPrivateFieldGet(this, _baseHeight) * this.scaleFactor); + const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions; + this.width = width / parentWidth; + this.height = height / parentHeight; + + _classPrivateFieldSet(this, _aspectRatio, width / height); + + _classPrivateMethodGet(this, _setMinDims, _setMinDims2).call(this); + + const prevTranslationX = this.translationX; + const prevTranslationY = this.translationY; + this.translationX = -bbox[0]; + this.translationY = -bbox[1]; + + _classPrivateMethodGet(this, _setCanvasDims, _setCanvasDims2).call(this); + + _classPrivateMethodGet(this, _redraw, _redraw2).call(this); + + _classPrivateFieldSet(this, _realWidth, width); + + _classPrivateFieldSet(this, _realHeight, height); + + this.setDims(width, height); + const unscaledPadding = firstTime ? padding / this.scaleFactor / 2 : 0; + this.translate(prevTranslationX - this.translationX - unscaledPadding, prevTranslationY - this.translationY - unscaledPadding); +} + +function _setMinDims2() { + const { + style + } = this.div; + + if (_classPrivateFieldGet(this, _aspectRatio) >= 1) { + style.minHeight = `${RESIZER_SIZE}px`; + style.minWidth = `${Math.round(_classPrivateFieldGet(this, _aspectRatio) * RESIZER_SIZE)}px`; + } else { + style.minWidth = `${RESIZER_SIZE}px`; + style.minHeight = `${Math.round(RESIZER_SIZE / _classPrivateFieldGet(this, _aspectRatio))}px`; + } +} + +_defineProperty(InkEditor, "_defaultColor", null); + +_defineProperty(InkEditor, "_defaultOpacity", 1); + +_defineProperty(InkEditor, "_defaultThickness", 1); + +_defineProperty(InkEditor, "_l10nPromise", void 0); + +_defineProperty(InkEditor, "_type", "ink"); + +/***/ }), +/* 150 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.fitCurve = void 0; + +const fitCurve = __w_pdfjs_require__(151); + +exports.fitCurve = fitCurve; + +/***/ }), +/* 151 */ +/***/ ((module) => { + +"use strict"; + + +function fitCurve(points, maxError, progressCallback) { + if (!Array.isArray(points)) { + throw new TypeError("First argument should be an array"); + } + + points.forEach(point => { + if (!Array.isArray(point) || point.some(item => typeof item !== 'number') || point.length !== points[0].length) { + throw Error("Each point should be an array of numbers. Each point should have the same amount of numbers."); + } + }); + points = points.filter((point, i) => i === 0 || !point.every((val, j) => val === points[i - 1][j])); + + if (points.length < 2) { + return []; + } + + const len = points.length; + const leftTangent = createTangent(points[1], points[0]); + const rightTangent = createTangent(points[len - 2], points[len - 1]); + return fitCubic(points, leftTangent, rightTangent, maxError, progressCallback); +} + +function fitCubic(points, leftTangent, rightTangent, error, progressCallback) { + const MaxIterations = 20; + var bezCurve, u, uPrime, maxError, prevErr, splitPoint, prevSplit, centerVector, toCenterTangent, fromCenterTangent, beziers, dist, i; + + if (points.length === 2) { + dist = maths.vectorLen(maths.subtract(points[0], points[1])) / 3.0; + bezCurve = [points[0], maths.addArrays(points[0], maths.mulItems(leftTangent, dist)), maths.addArrays(points[1], maths.mulItems(rightTangent, dist)), points[1]]; + return [bezCurve]; + } + + u = chordLengthParameterize(points); + [bezCurve, maxError, splitPoint] = generateAndReport(points, u, u, leftTangent, rightTangent, progressCallback); + + if (maxError === 0 || maxError < error) { + return [bezCurve]; + } + + if (maxError < error * error) { + uPrime = u; + prevErr = maxError; + prevSplit = splitPoint; + + for (i = 0; i < MaxIterations; i++) { + uPrime = reparameterize(bezCurve, points, uPrime); + [bezCurve, maxError, splitPoint] = generateAndReport(points, u, uPrime, leftTangent, rightTangent, progressCallback); + + if (maxError < error) { + return [bezCurve]; + } else if (splitPoint === prevSplit) { + let errChange = maxError / prevErr; + + if (errChange > .9999 && errChange < 1.0001) { + break; + } + } + + prevErr = maxError; + prevSplit = splitPoint; + } + } + + beziers = []; + centerVector = maths.subtract(points[splitPoint - 1], points[splitPoint + 1]); + + if (centerVector.every(val => val === 0)) { + centerVector = maths.subtract(points[splitPoint - 1], points[splitPoint]); + [centerVector[0], centerVector[1]] = [-centerVector[1], centerVector[0]]; + } + + toCenterTangent = maths.normalize(centerVector); + fromCenterTangent = maths.mulItems(toCenterTangent, -1); + beziers = beziers.concat(fitCubic(points.slice(0, splitPoint + 1), leftTangent, toCenterTangent, error, progressCallback)); + beziers = beziers.concat(fitCubic(points.slice(splitPoint), fromCenterTangent, rightTangent, error, progressCallback)); + return beziers; +} + +; + +function generateAndReport(points, paramsOrig, paramsPrime, leftTangent, rightTangent, progressCallback) { + var bezCurve, maxError, splitPoint; + bezCurve = generateBezier(points, paramsPrime, leftTangent, rightTangent, progressCallback); + [maxError, splitPoint] = computeMaxError(points, bezCurve, paramsOrig); + + if (progressCallback) { + progressCallback({ + bez: bezCurve, + points: points, + params: paramsOrig, + maxErr: maxError, + maxPoint: splitPoint + }); + } + + return [bezCurve, maxError, splitPoint]; +} + +function generateBezier(points, parameters, leftTangent, rightTangent) { + var bezCurve, + A, + a, + C, + X, + det_C0_C1, + det_C0_X, + det_X_C1, + alpha_l, + alpha_r, + epsilon, + segLength, + i, + len, + tmp, + u, + ux, + firstPoint = points[0], + lastPoint = points[points.length - 1]; + bezCurve = [firstPoint, null, null, lastPoint]; + A = maths.zeros_Xx2x2(parameters.length); + + for (i = 0, len = parameters.length; i < len; i++) { + u = parameters[i]; + ux = 1 - u; + a = A[i]; + a[0] = maths.mulItems(leftTangent, 3 * u * (ux * ux)); + a[1] = maths.mulItems(rightTangent, 3 * ux * (u * u)); + } + + C = [[0, 0], [0, 0]]; + X = [0, 0]; + + for (i = 0, len = points.length; i < len; i++) { + u = parameters[i]; + a = A[i]; + C[0][0] += maths.dot(a[0], a[0]); + C[0][1] += maths.dot(a[0], a[1]); + C[1][0] += maths.dot(a[0], a[1]); + C[1][1] += maths.dot(a[1], a[1]); + tmp = maths.subtract(points[i], bezier.q([firstPoint, firstPoint, lastPoint, lastPoint], u)); + X[0] += maths.dot(a[0], tmp); + X[1] += maths.dot(a[1], tmp); + } + + det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1]; + det_C0_X = C[0][0] * X[1] - C[1][0] * X[0]; + det_X_C1 = X[0] * C[1][1] - X[1] * C[0][1]; + alpha_l = det_C0_C1 === 0 ? 0 : det_X_C1 / det_C0_C1; + alpha_r = det_C0_C1 === 0 ? 0 : det_C0_X / det_C0_C1; + segLength = maths.vectorLen(maths.subtract(firstPoint, lastPoint)); + epsilon = 1.0e-6 * segLength; + + if (alpha_l < epsilon || alpha_r < epsilon) { + bezCurve[1] = maths.addArrays(firstPoint, maths.mulItems(leftTangent, segLength / 3.0)); + bezCurve[2] = maths.addArrays(lastPoint, maths.mulItems(rightTangent, segLength / 3.0)); + } else { + bezCurve[1] = maths.addArrays(firstPoint, maths.mulItems(leftTangent, alpha_l)); + bezCurve[2] = maths.addArrays(lastPoint, maths.mulItems(rightTangent, alpha_r)); + } + + return bezCurve; +} + +; + +function reparameterize(bezier, points, parameters) { + return parameters.map((p, i) => newtonRaphsonRootFind(bezier, points[i], p)); +} + +; + +function newtonRaphsonRootFind(bez, point, u) { + var d = maths.subtract(bezier.q(bez, u), point), + qprime = bezier.qprime(bez, u), + numerator = maths.mulMatrix(d, qprime), + denominator = maths.sum(maths.squareItems(qprime)) + 2 * maths.mulMatrix(d, bezier.qprimeprime(bez, u)); + + if (denominator === 0) { + return u; + } else { + return u - numerator / denominator; + } +} + +; + +function chordLengthParameterize(points) { + var u = [], + currU, + prevU, + prevP; + points.forEach((p, i) => { + currU = i ? prevU + maths.vectorLen(maths.subtract(p, prevP)) : 0; + u.push(currU); + prevU = currU; + prevP = p; + }); + u = u.map(x => x / prevU); + return u; +} + +; + +function computeMaxError(points, bez, parameters) { + var dist, maxDist, splitPoint, v, i, count, point, t; + maxDist = 0; + splitPoint = Math.floor(points.length / 2); + const t_distMap = mapTtoRelativeDistances(bez, 10); + + for (i = 0, count = points.length; i < count; i++) { + point = points[i]; + t = find_t(bez, parameters[i], t_distMap, 10); + v = maths.subtract(bezier.q(bez, t), point); + dist = v[0] * v[0] + v[1] * v[1]; + + if (dist > maxDist) { + maxDist = dist; + splitPoint = i; + } + } + + return [maxDist, splitPoint]; +} + +; + +var mapTtoRelativeDistances = function (bez, B_parts) { + var B_t_curr; + var B_t_dist = [0]; + var B_t_prev = bez[0]; + var sumLen = 0; + + for (var i = 1; i <= B_parts; i++) { + B_t_curr = bezier.q(bez, i / B_parts); + sumLen += maths.vectorLen(maths.subtract(B_t_curr, B_t_prev)); + B_t_dist.push(sumLen); + B_t_prev = B_t_curr; + } + + B_t_dist = B_t_dist.map(x => x / sumLen); + return B_t_dist; +}; + +function find_t(bez, param, t_distMap, B_parts) { + if (param < 0) { + return 0; + } + + if (param > 1) { + return 1; + } + + var lenMax, lenMin, tMax, tMin, t; + + for (var i = 1; i <= B_parts; i++) { + if (param <= t_distMap[i]) { + tMin = (i - 1) / B_parts; + tMax = i / B_parts; + lenMin = t_distMap[i - 1]; + lenMax = t_distMap[i]; + t = (param - lenMin) / (lenMax - lenMin) * (tMax - tMin) + tMin; + break; + } + } + + return t; +} + +function createTangent(pointA, pointB) { + return maths.normalize(maths.subtract(pointA, pointB)); +} + +class maths { + static zeros_Xx2x2(x) { + var zs = []; + + while (x--) { + zs.push([0, 0]); + } + + return zs; + } + + static mulItems(items, multiplier) { + return items.map(x => x * multiplier); + } + + static mulMatrix(m1, m2) { + return m1.reduce((sum, x1, i) => sum + x1 * m2[i], 0); + } + + static subtract(arr1, arr2) { + return arr1.map((x1, i) => x1 - arr2[i]); + } + + static addArrays(arr1, arr2) { + return arr1.map((x1, i) => x1 + arr2[i]); + } + + static addItems(items, addition) { + return items.map(x => x + addition); + } + + static sum(items) { + return items.reduce((sum, x) => sum + x); + } + + static dot(m1, m2) { + return maths.mulMatrix(m1, m2); + } + + static vectorLen(v) { + return Math.hypot(...v); + } + + static divItems(items, divisor) { + return items.map(x => x / divisor); + } + + static squareItems(items) { + return items.map(x => x * x); + } + + static normalize(v) { + return this.divItems(v, this.vectorLen(v)); + } + +} + +class bezier { + static q(ctrlPoly, t) { + var tx = 1.0 - t; + var pA = maths.mulItems(ctrlPoly[0], tx * tx * tx), + pB = maths.mulItems(ctrlPoly[1], 3 * tx * tx * t), + pC = maths.mulItems(ctrlPoly[2], 3 * tx * t * t), + pD = maths.mulItems(ctrlPoly[3], t * t * t); + return maths.addArrays(maths.addArrays(pA, pB), maths.addArrays(pC, pD)); + } + + static qprime(ctrlPoly, t) { + var tx = 1.0 - t; + var pA = maths.mulItems(maths.subtract(ctrlPoly[1], ctrlPoly[0]), 3 * tx * tx), + pB = maths.mulItems(maths.subtract(ctrlPoly[2], ctrlPoly[1]), 6 * tx * t), + pC = maths.mulItems(maths.subtract(ctrlPoly[3], ctrlPoly[2]), 3 * t * t); + return maths.addArrays(maths.addArrays(pA, pB), pC); + } + + static qprimeprime(ctrlPoly, t) { + return maths.addArrays(maths.mulItems(maths.addArrays(maths.subtract(ctrlPoly[2], maths.mulItems(ctrlPoly[1], 2)), ctrlPoly[0]), 6 * (1.0 - t)), maths.mulItems(maths.addArrays(maths.subtract(ctrlPoly[3], maths.mulItems(ctrlPoly[2], 2)), ctrlPoly[1]), 6 * t)); + } + +} + +module.exports = fitCurve; +module.exports.fitCubic = fitCubic; +module.exports.createTangent = createTangent; + +/***/ }), +/* 152 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.AnnotationLayer = void 0; + +var _util = __w_pdfjs_require__(1); + +var _display_utils = __w_pdfjs_require__(133); + +var _annotation_storage = __w_pdfjs_require__(130); + +var _scripting_utils = __w_pdfjs_require__(153); + +var _xfa_layer = __w_pdfjs_require__(154); + +function _classStaticPrivateMethodGet(receiver, classConstructor, method) { _classCheckPrivateStaticAccess(receiver, classConstructor); return method; } + +function _classCheckPrivateStaticAccess(receiver, classConstructor) { if (receiver !== classConstructor) { throw new TypeError("Private static access of wrong provenance"); } } + +const DEFAULT_TAB_INDEX = 1000; +const DEFAULT_FONT_SIZE = 9; +const GetElementsByNameSet = new WeakSet(); + +function getRectDims(rect) { + return { + width: rect[2] - rect[0], + height: rect[3] - rect[1] + }; +} + +class AnnotationElementFactory { + static create(parameters) { + const subtype = parameters.data.annotationType; + + switch (subtype) { + case _util.AnnotationType.LINK: + return new LinkAnnotationElement(parameters); + + case _util.AnnotationType.TEXT: + return new TextAnnotationElement(parameters); + + case _util.AnnotationType.WIDGET: + const fieldType = parameters.data.fieldType; + + switch (fieldType) { + case "Tx": + return new TextWidgetAnnotationElement(parameters); + + case "Btn": + if (parameters.data.radioButton) { + return new RadioButtonWidgetAnnotationElement(parameters); + } else if (parameters.data.checkBox) { + return new CheckboxWidgetAnnotationElement(parameters); + } + + return new PushButtonWidgetAnnotationElement(parameters); + + case "Ch": + return new ChoiceWidgetAnnotationElement(parameters); + } + + return new WidgetAnnotationElement(parameters); + + case _util.AnnotationType.POPUP: + return new PopupAnnotationElement(parameters); + + case _util.AnnotationType.FREETEXT: + return new FreeTextAnnotationElement(parameters); + + case _util.AnnotationType.LINE: + return new LineAnnotationElement(parameters); + + case _util.AnnotationType.SQUARE: + return new SquareAnnotationElement(parameters); + + case _util.AnnotationType.CIRCLE: + return new CircleAnnotationElement(parameters); + + case _util.AnnotationType.POLYLINE: + return new PolylineAnnotationElement(parameters); + + case _util.AnnotationType.CARET: + return new CaretAnnotationElement(parameters); + + case _util.AnnotationType.INK: + return new InkAnnotationElement(parameters); + + case _util.AnnotationType.POLYGON: + return new PolygonAnnotationElement(parameters); + + case _util.AnnotationType.HIGHLIGHT: + return new HighlightAnnotationElement(parameters); + + case _util.AnnotationType.UNDERLINE: + return new UnderlineAnnotationElement(parameters); + + case _util.AnnotationType.SQUIGGLY: + return new SquigglyAnnotationElement(parameters); + + case _util.AnnotationType.STRIKEOUT: + return new StrikeOutAnnotationElement(parameters); + + case _util.AnnotationType.STAMP: + return new StampAnnotationElement(parameters); + + case _util.AnnotationType.FILEATTACHMENT: + return new FileAttachmentAnnotationElement(parameters); + + default: + return new AnnotationElement(parameters); + } + } + +} + +class AnnotationElement { + constructor(parameters) { + let { + isRenderable = false, + ignoreBorder = false, + createQuadrilaterals = false + } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + this.isRenderable = isRenderable; + this.data = parameters.data; + this.layer = parameters.layer; + this.page = parameters.page; + this.viewport = parameters.viewport; + this.linkService = parameters.linkService; + this.downloadManager = parameters.downloadManager; + this.imageResourcesPath = parameters.imageResourcesPath; + this.renderForms = parameters.renderForms; + this.svgFactory = parameters.svgFactory; + this.annotationStorage = parameters.annotationStorage; + this.enableScripting = parameters.enableScripting; + this.hasJSActions = parameters.hasJSActions; + this._fieldObjects = parameters.fieldObjects; + this._mouseState = parameters.mouseState; + + if (isRenderable) { + this.container = this._createContainer(ignoreBorder); + } + + if (createQuadrilaterals) { + this.quadrilaterals = this._createQuadrilaterals(ignoreBorder); + } + } + + _createContainer() { + let ignoreBorder = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + const data = this.data, + page = this.page, + viewport = this.viewport; + const container = document.createElement("section"); + const { + width, + height + } = getRectDims(data.rect); + const [pageLLx, pageLLy, pageURx, pageURy] = viewport.viewBox; + const pageWidth = pageURx - pageLLx; + const pageHeight = pageURy - pageLLy; + container.setAttribute("data-annotation-id", data.id); + + const rect = _util.Util.normalizeRect([data.rect[0], page.view[3] - data.rect[1] + page.view[1], data.rect[2], page.view[3] - data.rect[3] + page.view[1]]); + + if (!ignoreBorder && data.borderStyle.width > 0) { + container.style.borderWidth = `${data.borderStyle.width}px`; + const horizontalRadius = data.borderStyle.horizontalCornerRadius; + const verticalRadius = data.borderStyle.verticalCornerRadius; + + if (horizontalRadius > 0 || verticalRadius > 0) { + const radius = `calc(${horizontalRadius}px * var(--scale-factor)) / calc(${verticalRadius}px * var(--scale-factor))`; + container.style.borderRadius = radius; + } else if (this instanceof RadioButtonWidgetAnnotationElement) { + const radius = `calc(${width}px * var(--scale-factor)) / calc(${height}px * var(--scale-factor))`; + container.style.borderRadius = radius; + } + + switch (data.borderStyle.style) { + case _util.AnnotationBorderStyleType.SOLID: + container.style.borderStyle = "solid"; + break; + + case _util.AnnotationBorderStyleType.DASHED: + container.style.borderStyle = "dashed"; + break; + + case _util.AnnotationBorderStyleType.BEVELED: + (0, _util.warn)("Unimplemented border style: beveled"); + break; + + case _util.AnnotationBorderStyleType.INSET: + (0, _util.warn)("Unimplemented border style: inset"); + break; + + case _util.AnnotationBorderStyleType.UNDERLINE: + container.style.borderBottomStyle = "solid"; + break; + + default: + break; + } + + const borderColor = data.borderColor || null; + + if (borderColor) { + container.style.borderColor = _util.Util.makeHexColor(borderColor[0] | 0, borderColor[1] | 0, borderColor[2] | 0); + } else { + container.style.borderWidth = 0; + } + } + + container.style.left = `${100 * (rect[0] - pageLLx) / pageWidth}%`; + container.style.top = `${100 * (rect[1] - pageLLy) / pageHeight}%`; + const { + rotation + } = data; + + if (data.hasOwnCanvas || rotation === 0) { + container.style.width = `${100 * width / pageWidth}%`; + container.style.height = `${100 * height / pageHeight}%`; + } else { + this.setRotation(rotation, container); + } + + return container; + } + + setRotation(angle) { + let container = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.container; + const [pageLLx, pageLLy, pageURx, pageURy] = this.viewport.viewBox; + const pageWidth = pageURx - pageLLx; + const pageHeight = pageURy - pageLLy; + const { + width, + height + } = getRectDims(this.data.rect); + let elementWidth, elementHeight; + + if (angle % 180 === 0) { + elementWidth = 100 * width / pageWidth; + elementHeight = 100 * height / pageHeight; + } else { + elementWidth = 100 * height / pageWidth; + elementHeight = 100 * width / pageHeight; + } + + container.style.width = `${elementWidth}%`; + container.style.height = `${elementHeight}%`; + container.setAttribute("data-main-rotation", (360 - angle) % 360); + } + + get _commonActions() { + const setColor = (jsName, styleName, event) => { + const color = event.detail[jsName]; + event.target.style[styleName] = _scripting_utils.ColorConverters[`${color[0]}_HTML`](color.slice(1)); + }; + + return (0, _util.shadow)(this, "_commonActions", { + display: event => { + const hidden = event.detail.display % 2 === 1; + this.container.style.visibility = hidden ? "hidden" : "visible"; + this.annotationStorage.setValue(this.data.id, { + hidden, + print: event.detail.display === 0 || event.detail.display === 3 + }); + }, + print: event => { + this.annotationStorage.setValue(this.data.id, { + print: event.detail.print + }); + }, + hidden: event => { + this.container.style.visibility = event.detail.hidden ? "hidden" : "visible"; + this.annotationStorage.setValue(this.data.id, { + hidden: event.detail.hidden + }); + }, + focus: event => { + setTimeout(() => event.target.focus({ + preventScroll: false + }), 0); + }, + userName: event => { + event.target.title = event.detail.userName; + }, + readonly: event => { + if (event.detail.readonly) { + event.target.setAttribute("readonly", ""); + } else { + event.target.removeAttribute("readonly"); + } + }, + required: event => { + this._setRequired(event.target, event.detail.required); + }, + bgColor: event => { + setColor("bgColor", "backgroundColor", event); + }, + fillColor: event => { + setColor("fillColor", "backgroundColor", event); + }, + fgColor: event => { + setColor("fgColor", "color", event); + }, + textColor: event => { + setColor("textColor", "color", event); + }, + borderColor: event => { + setColor("borderColor", "borderColor", event); + }, + strokeColor: event => { + setColor("strokeColor", "borderColor", event); + }, + rotation: event => { + const angle = event.detail.rotation; + this.setRotation(angle); + this.annotationStorage.setValue(this.data.id, { + rotation: angle + }); + } + }); + } + + _dispatchEventFromSandbox(actions, jsEvent) { + const commonActions = this._commonActions; + + for (const name of Object.keys(jsEvent.detail)) { + const action = actions[name] || commonActions[name]; + + if (action) { + action(jsEvent); + } + } + } + + _setDefaultPropertiesFromJS(element) { + if (!this.enableScripting) { + return; + } + + const storedData = this.annotationStorage.getRawValue(this.data.id); + + if (!storedData) { + return; + } + + const commonActions = this._commonActions; + + for (const [actionName, detail] of Object.entries(storedData)) { + const action = commonActions[actionName]; + + if (action) { + const eventProxy = { + detail: { + [actionName]: detail + }, + target: element + }; + action(eventProxy); + delete storedData[actionName]; + } + } + } + + _createQuadrilaterals() { + let ignoreBorder = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + if (!this.data.quadPoints) { + return null; + } + + const quadrilaterals = []; + const savedRect = this.data.rect; + + for (const quadPoint of this.data.quadPoints) { + this.data.rect = [quadPoint[2].x, quadPoint[2].y, quadPoint[1].x, quadPoint[1].y]; + quadrilaterals.push(this._createContainer(ignoreBorder)); + } + + this.data.rect = savedRect; + return quadrilaterals; + } + + _createPopup(trigger, data) { + let container = this.container; + + if (this.quadrilaterals) { + trigger = trigger || this.quadrilaterals; + container = this.quadrilaterals[0]; + } + + if (!trigger) { + trigger = document.createElement("div"); + trigger.className = "popupTriggerArea"; + container.append(trigger); + } + + const popupElement = new PopupElement({ + container, + trigger, + color: data.color, + titleObj: data.titleObj, + modificationDate: data.modificationDate, + contentsObj: data.contentsObj, + richText: data.richText, + hideWrapper: true + }); + const popup = popupElement.render(); + popup.style.left = "100%"; + container.append(popup); + } + + _renderQuadrilaterals(className) { + for (const quadrilateral of this.quadrilaterals) { + quadrilateral.className = className; + } + + return this.quadrilaterals; + } + + render() { + (0, _util.unreachable)("Abstract method `AnnotationElement.render` called"); + } + + _getElementsByName(name) { + let skipId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + const fields = []; + + if (this._fieldObjects) { + const fieldObj = this._fieldObjects[name]; + + if (fieldObj) { + for (const { + page, + id, + exportValues + } of fieldObj) { + if (page === -1) { + continue; + } + + if (id === skipId) { + continue; + } + + const exportValue = typeof exportValues === "string" ? exportValues : null; + const domElement = document.querySelector(`[data-element-id="${id}"]`); + + if (domElement && !GetElementsByNameSet.has(domElement)) { + (0, _util.warn)(`_getElementsByName - element not allowed: ${id}`); + continue; + } + + fields.push({ + id, + exportValue, + domElement + }); + } + } + + return fields; + } + + for (const domElement of document.getElementsByName(name)) { + const { + id, + exportValue + } = domElement; + + if (id === skipId) { + continue; + } + + if (!GetElementsByNameSet.has(domElement)) { + continue; + } + + fields.push({ + id, + exportValue, + domElement + }); + } + + return fields; + } + + static get platform() { + const platform = typeof navigator !== "undefined" ? navigator.platform : ""; + return (0, _util.shadow)(this, "platform", { + isWin: platform.includes("Win"), + isMac: platform.includes("Mac") + }); + } + +} + +class LinkAnnotationElement extends AnnotationElement { + constructor(parameters) { + let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + super(parameters, { + isRenderable: true, + ignoreBorder: !!(options !== null && options !== void 0 && options.ignoreBorder), + createQuadrilaterals: true + }); + this.isTooltipOnly = parameters.data.isTooltipOnly; + } + + render() { + const { + data, + linkService + } = this; + const link = document.createElement("a"); + link.setAttribute("data-element-id", data.id); + let isBound = false; + + if (data.url) { + linkService.addLinkAttributes(link, data.url, data.newWindow); + isBound = true; + } else if (data.action) { + this._bindNamedAction(link, data.action); + + isBound = true; + } else if (data.dest) { + this._bindLink(link, data.dest); + + isBound = true; + } else { + if (data.actions && (data.actions.Action || data.actions["Mouse Up"] || data.actions["Mouse Down"]) && this.enableScripting && this.hasJSActions) { + this._bindJSAction(link, data); + + isBound = true; + } + + if (data.resetForm) { + this._bindResetFormAction(link, data.resetForm); + + isBound = true; + } else if (this.isTooltipOnly && !isBound) { + this._bindLink(link, ""); + + isBound = true; + } + } + + if (this.quadrilaterals) { + return this._renderQuadrilaterals("linkAnnotation").map((quadrilateral, index) => { + const linkElement = index === 0 ? link : link.cloneNode(); + quadrilateral.append(linkElement); + return quadrilateral; + }); + } + + this.container.className = "linkAnnotation"; + + if (isBound) { + this.container.append(link); + } + + return this.container; + } + + _bindLink(link, destination) { + link.href = this.linkService.getDestinationHash(destination); + + link.onclick = () => { + if (destination) { + this.linkService.goToDestination(destination); + } + + return false; + }; + + if (destination || destination === "") { + link.className = "internalLink"; + } + } + + _bindNamedAction(link, action) { + link.href = this.linkService.getAnchorUrl(""); + + link.onclick = () => { + this.linkService.executeNamedAction(action); + return false; + }; + + link.className = "internalLink"; + } + + _bindJSAction(link, data) { + link.href = this.linkService.getAnchorUrl(""); + const map = new Map([["Action", "onclick"], ["Mouse Up", "onmouseup"], ["Mouse Down", "onmousedown"]]); + + for (const name of Object.keys(data.actions)) { + const jsName = map.get(name); + + if (!jsName) { + continue; + } + + link[jsName] = () => { + var _this$linkService$eve; + + (_this$linkService$eve = this.linkService.eventBus) === null || _this$linkService$eve === void 0 ? void 0 : _this$linkService$eve.dispatch("dispatcheventinsandbox", { + source: this, + detail: { + id: data.id, + name + } + }); + return false; + }; + } + + if (!link.onclick) { + link.onclick = () => false; + } + + link.className = "internalLink"; + } + + _bindResetFormAction(link, resetForm) { + const otherClickAction = link.onclick; + + if (!otherClickAction) { + link.href = this.linkService.getAnchorUrl(""); + } + + link.className = "internalLink"; + + if (!this._fieldObjects) { + (0, _util.warn)(`_bindResetFormAction - "resetForm" action not supported, ` + "ensure that the `fieldObjects` parameter is provided."); + + if (!otherClickAction) { + link.onclick = () => false; + } + + return; + } + + link.onclick = () => { + if (otherClickAction) { + otherClickAction(); + } + + const { + fields: resetFormFields, + refs: resetFormRefs, + include + } = resetForm; + const allFields = []; + + if (resetFormFields.length !== 0 || resetFormRefs.length !== 0) { + const fieldIds = new Set(resetFormRefs); + + for (const fieldName of resetFormFields) { + const fields = this._fieldObjects[fieldName] || []; + + for (const { + id + } of fields) { + fieldIds.add(id); + } + } + + for (const fields of Object.values(this._fieldObjects)) { + for (const field of fields) { + if (fieldIds.has(field.id) === include) { + allFields.push(field); + } + } + } + } else { + for (const fields of Object.values(this._fieldObjects)) { + allFields.push(...fields); + } + } + + const storage = this.annotationStorage; + const allIds = []; + + for (const field of allFields) { + const { + id + } = field; + allIds.push(id); + + switch (field.type) { + case "text": + { + const value = field.defaultValue || ""; + storage.setValue(id, { + value + }); + break; + } + + case "checkbox": + case "radiobutton": + { + const value = field.defaultValue === field.exportValues; + storage.setValue(id, { + value + }); + break; + } + + case "combobox": + case "listbox": + { + const value = field.defaultValue || ""; + storage.setValue(id, { + value + }); + break; + } + + default: + continue; + } + + const domElement = document.querySelector(`[data-element-id="${id}"]`); + + if (!domElement) { + continue; + } else if (!GetElementsByNameSet.has(domElement)) { + (0, _util.warn)(`_bindResetFormAction - element not allowed: ${id}`); + continue; + } + + domElement.dispatchEvent(new Event("resetform")); + } + + if (this.enableScripting) { + var _this$linkService$eve2; + + (_this$linkService$eve2 = this.linkService.eventBus) === null || _this$linkService$eve2 === void 0 ? void 0 : _this$linkService$eve2.dispatch("dispatcheventinsandbox", { + source: this, + detail: { + id: "app", + ids: allIds, + name: "ResetForm" + } + }); + } + + return false; + }; + } + +} + +class TextAnnotationElement extends AnnotationElement { + constructor(parameters) { + var _parameters$data$titl, _parameters$data$cont, _parameters$data$rich; + + const isRenderable = !!(parameters.data.hasPopup || (_parameters$data$titl = parameters.data.titleObj) !== null && _parameters$data$titl !== void 0 && _parameters$data$titl.str || (_parameters$data$cont = parameters.data.contentsObj) !== null && _parameters$data$cont !== void 0 && _parameters$data$cont.str || (_parameters$data$rich = parameters.data.richText) !== null && _parameters$data$rich !== void 0 && _parameters$data$rich.str); + super(parameters, { + isRenderable + }); + } + + render() { + this.container.className = "textAnnotation"; + const image = document.createElement("img"); + image.src = this.imageResourcesPath + "annotation-" + this.data.name.toLowerCase() + ".svg"; + image.alt = "[{{type}} Annotation]"; + image.dataset.l10nId = "text_annotation_type"; + image.dataset.l10nArgs = JSON.stringify({ + type: this.data.name + }); + + if (!this.data.hasPopup) { + this._createPopup(image, this.data); + } + + this.container.append(image); + return this.container; + } + +} + +class WidgetAnnotationElement extends AnnotationElement { + render() { + if (this.data.alternativeText) { + this.container.title = this.data.alternativeText; + } + + return this.container; + } + + _getKeyModifier(event) { + const { + isWin, + isMac + } = AnnotationElement.platform; + return isWin && event.ctrlKey || isMac && event.metaKey; + } + + _setEventListener(element, baseName, eventName, valueGetter) { + if (baseName.includes("mouse")) { + element.addEventListener(baseName, event => { + var _this$linkService$eve3; + + (_this$linkService$eve3 = this.linkService.eventBus) === null || _this$linkService$eve3 === void 0 ? void 0 : _this$linkService$eve3.dispatch("dispatcheventinsandbox", { + source: this, + detail: { + id: this.data.id, + name: eventName, + value: valueGetter(event), + shift: event.shiftKey, + modifier: this._getKeyModifier(event) + } + }); + }); + } else { + element.addEventListener(baseName, event => { + var _this$linkService$eve4; + + (_this$linkService$eve4 = this.linkService.eventBus) === null || _this$linkService$eve4 === void 0 ? void 0 : _this$linkService$eve4.dispatch("dispatcheventinsandbox", { + source: this, + detail: { + id: this.data.id, + name: eventName, + value: valueGetter(event) + } + }); + }); + } + } + + _setEventListeners(element, names, getter) { + for (const [baseName, eventName] of names) { + var _this$data$actions; + + if (eventName === "Action" || (_this$data$actions = this.data.actions) !== null && _this$data$actions !== void 0 && _this$data$actions[eventName]) { + this._setEventListener(element, baseName, eventName, getter); + } + } + } + + _setBackgroundColor(element) { + const color = this.data.backgroundColor || null; + element.style.backgroundColor = color === null ? "transparent" : _util.Util.makeHexColor(color[0], color[1], color[2]); + } + + _setTextStyle(element) { + const TEXT_ALIGNMENT = ["left", "center", "right"]; + const { + fontColor + } = this.data.defaultAppearanceData; + const fontSize = this.data.defaultAppearanceData.fontSize || DEFAULT_FONT_SIZE; + const style = element.style; + let computedFontSize; + + if (this.data.multiLine) { + const height = Math.abs(this.data.rect[3] - this.data.rect[1]); + const numberOfLines = Math.round(height / (_util.LINE_FACTOR * fontSize)) || 1; + const lineHeight = height / numberOfLines; + computedFontSize = Math.min(fontSize, Math.round(lineHeight / _util.LINE_FACTOR)); + } else { + const height = Math.abs(this.data.rect[3] - this.data.rect[1]); + computedFontSize = Math.min(fontSize, Math.round(height / _util.LINE_FACTOR)); + } + + style.fontSize = `calc(${computedFontSize}px * var(--scale-factor))`; + style.color = _util.Util.makeHexColor(fontColor[0], fontColor[1], fontColor[2]); + + if (this.data.textAlignment !== null) { + style.textAlign = TEXT_ALIGNMENT[this.data.textAlignment]; + } + } + + _setRequired(element, isRequired) { + if (isRequired) { + element.setAttribute("required", true); + } else { + element.removeAttribute("required"); + } + + element.setAttribute("aria-required", isRequired); + } + +} + +class TextWidgetAnnotationElement extends WidgetAnnotationElement { + constructor(parameters) { + const isRenderable = parameters.renderForms || !parameters.data.hasAppearance && !!parameters.data.fieldValue; + super(parameters, { + isRenderable + }); + } + + setPropertyOnSiblings(base, key, value, keyInStorage) { + const storage = this.annotationStorage; + + for (const element of this._getElementsByName(base.name, base.id)) { + if (element.domElement) { + element.domElement[key] = value; + } + + storage.setValue(element.id, { + [keyInStorage]: value + }); + } + } + + render() { + const storage = this.annotationStorage; + const id = this.data.id; + this.container.className = "textWidgetAnnotation"; + let element = null; + + if (this.renderForms) { + const storedData = storage.getValue(id, { + value: this.data.fieldValue + }); + let textContent = storedData.formattedValue || storedData.value || ""; + const maxLen = storage.getValue(id, { + charLimit: this.data.maxLen + }).charLimit; + + if (maxLen && textContent.length > maxLen) { + textContent = textContent.slice(0, maxLen); + } + + const elementData = { + userValue: textContent, + formattedValue: null, + valueOnFocus: "" + }; + + if (this.data.multiLine) { + element = document.createElement("textarea"); + element.textContent = textContent; + + if (this.data.doNotScroll) { + element.style.overflowY = "hidden"; + } + } else { + element = document.createElement("input"); + element.type = "text"; + element.setAttribute("value", textContent); + + if (this.data.doNotScroll) { + element.style.overflowX = "hidden"; + } + } + + GetElementsByNameSet.add(element); + element.setAttribute("data-element-id", id); + element.disabled = this.data.readOnly; + element.name = this.data.fieldName; + element.tabIndex = DEFAULT_TAB_INDEX; + + this._setRequired(element, this.data.required); + + if (maxLen) { + element.maxLength = maxLen; + } + + element.addEventListener("input", event => { + storage.setValue(id, { + value: event.target.value + }); + this.setPropertyOnSiblings(element, "value", event.target.value, "value"); + }); + element.addEventListener("resetform", event => { + var _this$data$defaultFie; + + const defaultValue = (_this$data$defaultFie = this.data.defaultFieldValue) !== null && _this$data$defaultFie !== void 0 ? _this$data$defaultFie : ""; + element.value = elementData.userValue = defaultValue; + elementData.formattedValue = null; + }); + + let blurListener = event => { + const { + formattedValue + } = elementData; + + if (formattedValue !== null && formattedValue !== undefined) { + event.target.value = formattedValue; + } + + event.target.scrollLeft = 0; + }; + + if (this.enableScripting && this.hasJSActions) { + var _this$data$actions2; + + element.addEventListener("focus", event => { + if (elementData.userValue) { + event.target.value = elementData.userValue; + } + + elementData.valueOnFocus = event.target.value; + }); + element.addEventListener("updatefromsandbox", jsEvent => { + const actions = { + value(event) { + var _event$detail$value; + + elementData.userValue = (_event$detail$value = event.detail.value) !== null && _event$detail$value !== void 0 ? _event$detail$value : ""; + storage.setValue(id, { + value: elementData.userValue.toString() + }); + event.target.value = elementData.userValue; + }, + + formattedValue(event) { + const { + formattedValue + } = event.detail; + elementData.formattedValue = formattedValue; + + if (formattedValue !== null && formattedValue !== undefined && event.target !== document.activeElement) { + event.target.value = formattedValue; + } + + storage.setValue(id, { + formattedValue + }); + }, + + selRange(event) { + event.target.setSelectionRange(...event.detail.selRange); + }, + + charLimit: event => { + var _this$linkService$eve5; + + const { + charLimit + } = event.detail; + const { + target + } = event; + + if (charLimit === 0) { + target.removeAttribute("maxLength"); + return; + } + + target.setAttribute("maxLength", charLimit); + let value = elementData.userValue; + + if (!value || value.length <= charLimit) { + return; + } + + value = value.slice(0, charLimit); + target.value = elementData.userValue = value; + storage.setValue(id, { + value + }); + (_this$linkService$eve5 = this.linkService.eventBus) === null || _this$linkService$eve5 === void 0 ? void 0 : _this$linkService$eve5.dispatch("dispatcheventinsandbox", { + source: this, + detail: { + id, + name: "Keystroke", + value, + willCommit: true, + commitKey: 1, + selStart: target.selectionStart, + selEnd: target.selectionEnd + } + }); + } + }; + + this._dispatchEventFromSandbox(actions, jsEvent); + }); + element.addEventListener("keydown", event => { + var _this$linkService$eve6; + + let commitKey = -1; + + if (event.key === "Escape") { + commitKey = 0; + } else if (event.key === "Enter") { + commitKey = 2; + } else if (event.key === "Tab") { + commitKey = 3; + } + + if (commitKey === -1) { + return; + } + + const { + value + } = event.target; + + if (elementData.valueOnFocus === value) { + return; + } + + elementData.userValue = value; + (_this$linkService$eve6 = this.linkService.eventBus) === null || _this$linkService$eve6 === void 0 ? void 0 : _this$linkService$eve6.dispatch("dispatcheventinsandbox", { + source: this, + detail: { + id, + name: "Keystroke", + value, + willCommit: true, + commitKey, + selStart: event.target.selectionStart, + selEnd: event.target.selectionEnd + } + }); + }); + const _blurListener = blurListener; + blurListener = null; + element.addEventListener("blur", event => { + const { + value + } = event.target; + elementData.userValue = value; + + if (this._mouseState.isDown && elementData.valueOnFocus !== value) { + var _this$linkService$eve7; + + (_this$linkService$eve7 = this.linkService.eventBus) === null || _this$linkService$eve7 === void 0 ? void 0 : _this$linkService$eve7.dispatch("dispatcheventinsandbox", { + source: this, + detail: { + id, + name: "Keystroke", + value, + willCommit: true, + commitKey: 1, + selStart: event.target.selectionStart, + selEnd: event.target.selectionEnd + } + }); + } + + _blurListener(event); + }); + + if ((_this$data$actions2 = this.data.actions) !== null && _this$data$actions2 !== void 0 && _this$data$actions2.Keystroke) { + element.addEventListener("beforeinput", event => { + var _this$linkService$eve8; + + const { + data, + target + } = event; + const { + value, + selectionStart, + selectionEnd + } = target; + let selStart = selectionStart, + selEnd = selectionEnd; + + switch (event.inputType) { + case "deleteWordBackward": + { + const match = value.substring(0, selectionStart).match(/\w*[^\w]*$/); + + if (match) { + selStart -= match[0].length; + } + + break; + } + + case "deleteWordForward": + { + const match = value.substring(selectionStart).match(/^[^\w]*\w*/); + + if (match) { + selEnd += match[0].length; + } + + break; + } + + case "deleteContentBackward": + if (selectionStart === selectionEnd) { + selStart -= 1; + } + + break; + + case "deleteContentForward": + if (selectionStart === selectionEnd) { + selEnd += 1; + } + + break; + } + + event.preventDefault(); + (_this$linkService$eve8 = this.linkService.eventBus) === null || _this$linkService$eve8 === void 0 ? void 0 : _this$linkService$eve8.dispatch("dispatcheventinsandbox", { + source: this, + detail: { + id, + name: "Keystroke", + value, + change: data || "", + willCommit: false, + selStart, + selEnd + } + }); + }); + } + + this._setEventListeners(element, [["focus", "Focus"], ["blur", "Blur"], ["mousedown", "Mouse Down"], ["mouseenter", "Mouse Enter"], ["mouseleave", "Mouse Exit"], ["mouseup", "Mouse Up"]], event => event.target.value); + } + + if (blurListener) { + element.addEventListener("blur", blurListener); + } + + if (this.data.comb) { + const fieldWidth = this.data.rect[2] - this.data.rect[0]; + const combWidth = fieldWidth / maxLen; + element.classList.add("comb"); + element.style.letterSpacing = `calc(${combWidth}px * var(--scale-factor) - 1ch)`; + } + } else { + element = document.createElement("div"); + element.textContent = this.data.fieldValue; + element.style.verticalAlign = "middle"; + element.style.display = "table-cell"; + } + + this._setTextStyle(element); + + this._setBackgroundColor(element); + + this._setDefaultPropertiesFromJS(element); + + this.container.append(element); + return this.container; + } + +} + +class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement { + constructor(parameters) { + super(parameters, { + isRenderable: parameters.renderForms + }); + } + + render() { + const storage = this.annotationStorage; + const data = this.data; + const id = data.id; + let value = storage.getValue(id, { + value: data.exportValue === data.fieldValue + }).value; + + if (typeof value === "string") { + value = value !== "Off"; + storage.setValue(id, { + value + }); + } + + this.container.className = "buttonWidgetAnnotation checkBox"; + const element = document.createElement("input"); + GetElementsByNameSet.add(element); + element.setAttribute("data-element-id", id); + element.disabled = data.readOnly; + + this._setRequired(element, this.data.required); + + element.type = "checkbox"; + element.name = data.fieldName; + + if (value) { + element.setAttribute("checked", true); + } + + element.setAttribute("exportValue", data.exportValue); + element.tabIndex = DEFAULT_TAB_INDEX; + element.addEventListener("change", event => { + const { + name, + checked + } = event.target; + + for (const checkbox of this._getElementsByName(name, id)) { + const curChecked = checked && checkbox.exportValue === data.exportValue; + + if (checkbox.domElement) { + checkbox.domElement.checked = curChecked; + } + + storage.setValue(checkbox.id, { + value: curChecked + }); + } + + storage.setValue(id, { + value: checked + }); + }); + element.addEventListener("resetform", event => { + const defaultValue = data.defaultFieldValue || "Off"; + event.target.checked = defaultValue === data.exportValue; + }); + + if (this.enableScripting && this.hasJSActions) { + element.addEventListener("updatefromsandbox", jsEvent => { + const actions = { + value(event) { + event.target.checked = event.detail.value !== "Off"; + storage.setValue(id, { + value: event.target.checked + }); + } + + }; + + this._dispatchEventFromSandbox(actions, jsEvent); + }); + + this._setEventListeners(element, [["change", "Validate"], ["change", "Action"], ["focus", "Focus"], ["blur", "Blur"], ["mousedown", "Mouse Down"], ["mouseenter", "Mouse Enter"], ["mouseleave", "Mouse Exit"], ["mouseup", "Mouse Up"]], event => event.target.checked); + } + + this._setBackgroundColor(element); + + this._setDefaultPropertiesFromJS(element); + + this.container.append(element); + return this.container; + } + +} + +class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement { + constructor(parameters) { + super(parameters, { + isRenderable: parameters.renderForms + }); + } + + render() { + this.container.className = "buttonWidgetAnnotation radioButton"; + const storage = this.annotationStorage; + const data = this.data; + const id = data.id; + let value = storage.getValue(id, { + value: data.fieldValue === data.buttonValue + }).value; + + if (typeof value === "string") { + value = value !== data.buttonValue; + storage.setValue(id, { + value + }); + } + + const element = document.createElement("input"); + GetElementsByNameSet.add(element); + element.setAttribute("data-element-id", id); + element.disabled = data.readOnly; + + this._setRequired(element, this.data.required); + + element.type = "radio"; + element.name = data.fieldName; + + if (value) { + element.setAttribute("checked", true); + } + + element.tabIndex = DEFAULT_TAB_INDEX; + element.addEventListener("change", event => { + const { + name, + checked + } = event.target; + + for (const radio of this._getElementsByName(name, id)) { + storage.setValue(radio.id, { + value: false + }); + } + + storage.setValue(id, { + value: checked + }); + }); + element.addEventListener("resetform", event => { + const defaultValue = data.defaultFieldValue; + event.target.checked = defaultValue !== null && defaultValue !== undefined && defaultValue === data.buttonValue; + }); + + if (this.enableScripting && this.hasJSActions) { + const pdfButtonValue = data.buttonValue; + element.addEventListener("updatefromsandbox", jsEvent => { + const actions = { + value: event => { + const checked = pdfButtonValue === event.detail.value; + + for (const radio of this._getElementsByName(event.target.name)) { + const curChecked = checked && radio.id === id; + + if (radio.domElement) { + radio.domElement.checked = curChecked; + } + + storage.setValue(radio.id, { + value: curChecked + }); + } + } + }; + + this._dispatchEventFromSandbox(actions, jsEvent); + }); + + this._setEventListeners(element, [["change", "Validate"], ["change", "Action"], ["focus", "Focus"], ["blur", "Blur"], ["mousedown", "Mouse Down"], ["mouseenter", "Mouse Enter"], ["mouseleave", "Mouse Exit"], ["mouseup", "Mouse Up"]], event => event.target.checked); + } + + this._setBackgroundColor(element); + + this._setDefaultPropertiesFromJS(element); + + this.container.append(element); + return this.container; + } + +} + +class PushButtonWidgetAnnotationElement extends LinkAnnotationElement { + constructor(parameters) { + super(parameters, { + ignoreBorder: parameters.data.hasAppearance + }); + } + + render() { + const container = super.render(); + container.className = "buttonWidgetAnnotation pushButton"; + + if (this.data.alternativeText) { + container.title = this.data.alternativeText; + } + + const linkElement = container.lastChild; + + if (this.enableScripting && this.hasJSActions && linkElement) { + this._setDefaultPropertiesFromJS(linkElement); + + linkElement.addEventListener("updatefromsandbox", jsEvent => { + this._dispatchEventFromSandbox({}, jsEvent); + }); + } + + return container; + } + +} + +class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement { + constructor(parameters) { + super(parameters, { + isRenderable: parameters.renderForms + }); + } + + render() { + this.container.className = "choiceWidgetAnnotation"; + const storage = this.annotationStorage; + const id = this.data.id; + const storedData = storage.getValue(id, { + value: this.data.fieldValue + }); + const selectElement = document.createElement("select"); + GetElementsByNameSet.add(selectElement); + selectElement.setAttribute("data-element-id", id); + selectElement.disabled = this.data.readOnly; + + this._setRequired(selectElement, this.data.required); + + selectElement.name = this.data.fieldName; + selectElement.tabIndex = DEFAULT_TAB_INDEX; + let addAnEmptyEntry = this.data.combo && this.data.options.length > 0; + + if (!this.data.combo) { + selectElement.size = this.data.options.length; + + if (this.data.multiSelect) { + selectElement.multiple = true; + } + } + + selectElement.addEventListener("resetform", event => { + const defaultValue = this.data.defaultFieldValue; + + for (const option of selectElement.options) { + option.selected = option.value === defaultValue; + } + }); + + for (const option of this.data.options) { + const optionElement = document.createElement("option"); + optionElement.textContent = option.displayValue; + optionElement.value = option.exportValue; + + if (storedData.value.includes(option.exportValue)) { + optionElement.setAttribute("selected", true); + addAnEmptyEntry = false; + } + + selectElement.append(optionElement); + } + + let removeEmptyEntry = null; + + if (addAnEmptyEntry) { + const noneOptionElement = document.createElement("option"); + noneOptionElement.value = " "; + noneOptionElement.setAttribute("hidden", true); + noneOptionElement.setAttribute("selected", true); + selectElement.prepend(noneOptionElement); + + removeEmptyEntry = () => { + noneOptionElement.remove(); + selectElement.removeEventListener("input", removeEmptyEntry); + removeEmptyEntry = null; + }; + + selectElement.addEventListener("input", removeEmptyEntry); + } + + const getValue = (event, isExport) => { + const name = isExport ? "value" : "textContent"; + const options = event.target.options; + + if (!event.target.multiple) { + return options.selectedIndex === -1 ? null : options[options.selectedIndex][name]; + } + + return Array.prototype.filter.call(options, option => option.selected).map(option => option[name]); + }; + + const getItems = event => { + const options = event.target.options; + return Array.prototype.map.call(options, option => { + return { + displayValue: option.textContent, + exportValue: option.value + }; + }); + }; + + if (this.enableScripting && this.hasJSActions) { + selectElement.addEventListener("updatefromsandbox", jsEvent => { + const actions = { + value(event) { + var _removeEmptyEntry; + + (_removeEmptyEntry = removeEmptyEntry) === null || _removeEmptyEntry === void 0 ? void 0 : _removeEmptyEntry(); + const value = event.detail.value; + const values = new Set(Array.isArray(value) ? value : [value]); + + for (const option of selectElement.options) { + option.selected = values.has(option.value); + } + + storage.setValue(id, { + value: getValue(event, true) + }); + }, + + multipleSelection(event) { + selectElement.multiple = true; + }, + + remove(event) { + const options = selectElement.options; + const index = event.detail.remove; + options[index].selected = false; + selectElement.remove(index); + + if (options.length > 0) { + const i = Array.prototype.findIndex.call(options, option => option.selected); + + if (i === -1) { + options[0].selected = true; + } + } + + storage.setValue(id, { + value: getValue(event, true), + items: getItems(event) + }); + }, + + clear(event) { + while (selectElement.length !== 0) { + selectElement.remove(0); + } + + storage.setValue(id, { + value: null, + items: [] + }); + }, + + insert(event) { + const { + index, + displayValue, + exportValue + } = event.detail.insert; + const selectChild = selectElement.children[index]; + const optionElement = document.createElement("option"); + optionElement.textContent = displayValue; + optionElement.value = exportValue; + + if (selectChild) { + selectChild.before(optionElement); + } else { + selectElement.append(optionElement); + } + + storage.setValue(id, { + value: getValue(event, true), + items: getItems(event) + }); + }, + + items(event) { + const { + items + } = event.detail; + + while (selectElement.length !== 0) { + selectElement.remove(0); + } + + for (const item of items) { + const { + displayValue, + exportValue + } = item; + const optionElement = document.createElement("option"); + optionElement.textContent = displayValue; + optionElement.value = exportValue; + selectElement.append(optionElement); + } + + if (selectElement.options.length > 0) { + selectElement.options[0].selected = true; + } + + storage.setValue(id, { + value: getValue(event, true), + items: getItems(event) + }); + }, + + indices(event) { + const indices = new Set(event.detail.indices); + + for (const option of event.target.options) { + option.selected = indices.has(option.index); + } + + storage.setValue(id, { + value: getValue(event, true) + }); + }, + + editable(event) { + event.target.disabled = !event.detail.editable; + } + + }; + + this._dispatchEventFromSandbox(actions, jsEvent); + }); + selectElement.addEventListener("input", event => { + var _this$linkService$eve9; + + const exportValue = getValue(event, true); + const value = getValue(event, false); + storage.setValue(id, { + value: exportValue + }); + (_this$linkService$eve9 = this.linkService.eventBus) === null || _this$linkService$eve9 === void 0 ? void 0 : _this$linkService$eve9.dispatch("dispatcheventinsandbox", { + source: this, + detail: { + id, + name: "Keystroke", + value, + changeEx: exportValue, + willCommit: true, + commitKey: 1, + keyDown: false + } + }); + }); + + this._setEventListeners(selectElement, [["focus", "Focus"], ["blur", "Blur"], ["mousedown", "Mouse Down"], ["mouseenter", "Mouse Enter"], ["mouseleave", "Mouse Exit"], ["mouseup", "Mouse Up"], ["input", "Action"]], event => event.target.checked); + } else { + selectElement.addEventListener("input", function (event) { + storage.setValue(id, { + value: getValue(event, true) + }); + }); + } + + if (this.data.combo) { + this._setTextStyle(selectElement); + } else {} + + this._setBackgroundColor(selectElement); + + this._setDefaultPropertiesFromJS(selectElement); + + this.container.append(selectElement); + return this.container; + } + +} + +class PopupAnnotationElement extends AnnotationElement { + constructor(parameters) { + var _parameters$data$titl2, _parameters$data$cont2, _parameters$data$rich2; + + const isRenderable = !!((_parameters$data$titl2 = parameters.data.titleObj) !== null && _parameters$data$titl2 !== void 0 && _parameters$data$titl2.str || (_parameters$data$cont2 = parameters.data.contentsObj) !== null && _parameters$data$cont2 !== void 0 && _parameters$data$cont2.str || (_parameters$data$rich2 = parameters.data.richText) !== null && _parameters$data$rich2 !== void 0 && _parameters$data$rich2.str); + super(parameters, { + isRenderable + }); + } + + render() { + const IGNORE_TYPES = ["Line", "Square", "Circle", "PolyLine", "Polygon", "Ink"]; + this.container.className = "popupAnnotation"; + + if (IGNORE_TYPES.includes(this.data.parentType)) { + return this.container; + } + + const selector = `[data-annotation-id="${this.data.parentId}"]`; + const parentElements = this.layer.querySelectorAll(selector); + + if (parentElements.length === 0) { + return this.container; + } + + const popup = new PopupElement({ + container: this.container, + trigger: Array.from(parentElements), + color: this.data.color, + titleObj: this.data.titleObj, + modificationDate: this.data.modificationDate, + contentsObj: this.data.contentsObj, + richText: this.data.richText + }); + const page = this.page; + + const rect = _util.Util.normalizeRect([this.data.parentRect[0], page.view[3] - this.data.parentRect[1] + page.view[1], this.data.parentRect[2], page.view[3] - this.data.parentRect[3] + page.view[1]]); + + const popupLeft = rect[0] + this.data.parentRect[2] - this.data.parentRect[0]; + const popupTop = rect[1]; + const [pageLLx, pageLLy, pageURx, pageURy] = this.viewport.viewBox; + const pageWidth = pageURx - pageLLx; + const pageHeight = pageURy - pageLLy; + this.container.style.left = `${100 * (popupLeft - pageLLx) / pageWidth}%`; + this.container.style.top = `${100 * (popupTop - pageLLy) / pageHeight}%`; + this.container.append(popup.render()); + return this.container; + } + +} + +class PopupElement { + constructor(parameters) { + this.container = parameters.container; + this.trigger = parameters.trigger; + this.color = parameters.color; + this.titleObj = parameters.titleObj; + this.modificationDate = parameters.modificationDate; + this.contentsObj = parameters.contentsObj; + this.richText = parameters.richText; + this.hideWrapper = parameters.hideWrapper || false; + this.pinned = false; + } + + render() { + var _this$richText, _this$contentsObj; + + const BACKGROUND_ENLIGHT = 0.7; + const wrapper = document.createElement("div"); + wrapper.className = "popupWrapper"; + this.hideElement = this.hideWrapper ? wrapper : this.container; + this.hideElement.hidden = true; + const popup = document.createElement("div"); + popup.className = "popup"; + const color = this.color; + + if (color) { + const r = BACKGROUND_ENLIGHT * (255 - color[0]) + color[0]; + const g = BACKGROUND_ENLIGHT * (255 - color[1]) + color[1]; + const b = BACKGROUND_ENLIGHT * (255 - color[2]) + color[2]; + popup.style.backgroundColor = _util.Util.makeHexColor(r | 0, g | 0, b | 0); + } + + const title = document.createElement("h1"); + title.dir = this.titleObj.dir; + title.textContent = this.titleObj.str; + popup.append(title); + + const dateObject = _display_utils.PDFDateString.toDateObject(this.modificationDate); + + if (dateObject) { + const modificationDate = document.createElement("span"); + modificationDate.className = "popupDate"; + modificationDate.textContent = "{{date}}, {{time}}"; + modificationDate.dataset.l10nId = "annotation_date_string"; + modificationDate.dataset.l10nArgs = JSON.stringify({ + date: dateObject.toLocaleDateString(), + time: dateObject.toLocaleTimeString() + }); + popup.append(modificationDate); + } + + if ((_this$richText = this.richText) !== null && _this$richText !== void 0 && _this$richText.str && (!((_this$contentsObj = this.contentsObj) !== null && _this$contentsObj !== void 0 && _this$contentsObj.str) || this.contentsObj.str === this.richText.str)) { + _xfa_layer.XfaLayer.render({ + xfaHtml: this.richText.html, + intent: "richText", + div: popup + }); + + popup.lastChild.className = "richText popupContent"; + } else { + const contents = this._formatContents(this.contentsObj); + + popup.append(contents); + } + + if (!Array.isArray(this.trigger)) { + this.trigger = [this.trigger]; + } + + for (const element of this.trigger) { + element.addEventListener("click", this._toggle.bind(this)); + element.addEventListener("mouseover", this._show.bind(this, false)); + element.addEventListener("mouseout", this._hide.bind(this, false)); + } + + popup.addEventListener("click", this._hide.bind(this, true)); + wrapper.append(popup); + return wrapper; + } + + _formatContents(_ref) { + let { + str, + dir + } = _ref; + const p = document.createElement("p"); + p.className = "popupContent"; + p.dir = dir; + const lines = str.split(/(?:\r\n?|\n)/); + + for (let i = 0, ii = lines.length; i < ii; ++i) { + const line = lines[i]; + p.append(document.createTextNode(line)); + + if (i < ii - 1) { + p.append(document.createElement("br")); + } + } + + return p; + } + + _toggle() { + if (this.pinned) { + this._hide(true); + } else { + this._show(true); + } + } + + _show() { + let pin = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + if (pin) { + this.pinned = true; + } + + if (this.hideElement.hidden) { + this.hideElement.hidden = false; + this.container.style.zIndex = parseInt(this.container.style.zIndex) + 1000; + } + } + + _hide() { + let unpin = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; + + if (unpin) { + this.pinned = false; + } + + if (!this.hideElement.hidden && !this.pinned) { + this.hideElement.hidden = true; + this.container.style.zIndex = parseInt(this.container.style.zIndex) - 1000; + } + } + +} + +class FreeTextAnnotationElement extends AnnotationElement { + constructor(parameters) { + var _parameters$data$titl3, _parameters$data$cont3, _parameters$data$rich3; + + const isRenderable = !!(parameters.data.hasPopup || (_parameters$data$titl3 = parameters.data.titleObj) !== null && _parameters$data$titl3 !== void 0 && _parameters$data$titl3.str || (_parameters$data$cont3 = parameters.data.contentsObj) !== null && _parameters$data$cont3 !== void 0 && _parameters$data$cont3.str || (_parameters$data$rich3 = parameters.data.richText) !== null && _parameters$data$rich3 !== void 0 && _parameters$data$rich3.str); + super(parameters, { + isRenderable, + ignoreBorder: true + }); + this.textContent = parameters.data.textContent; + } + + render() { + this.container.className = "freeTextAnnotation"; + + if (this.textContent) { + const content = document.createElement("div"); + content.className = "annotationTextContent"; + content.setAttribute("role", "comment"); + + for (const line of this.textContent) { + const lineSpan = document.createElement("span"); + lineSpan.textContent = line; + content.append(lineSpan); + } + + this.container.append(content); + } + + if (!this.data.hasPopup) { + this._createPopup(null, this.data); + } + + return this.container; + } + +} + +class LineAnnotationElement extends AnnotationElement { + constructor(parameters) { + var _parameters$data$titl4, _parameters$data$cont4, _parameters$data$rich4; + + const isRenderable = !!(parameters.data.hasPopup || (_parameters$data$titl4 = parameters.data.titleObj) !== null && _parameters$data$titl4 !== void 0 && _parameters$data$titl4.str || (_parameters$data$cont4 = parameters.data.contentsObj) !== null && _parameters$data$cont4 !== void 0 && _parameters$data$cont4.str || (_parameters$data$rich4 = parameters.data.richText) !== null && _parameters$data$rich4 !== void 0 && _parameters$data$rich4.str); + super(parameters, { + isRenderable, + ignoreBorder: true + }); + } + + render() { + this.container.className = "lineAnnotation"; + const data = this.data; + const { + width, + height + } = getRectDims(data.rect); + const svg = this.svgFactory.create(width, height, true); + const line = this.svgFactory.createElement("svg:line"); + line.setAttribute("x1", data.rect[2] - data.lineCoordinates[0]); + line.setAttribute("y1", data.rect[3] - data.lineCoordinates[1]); + line.setAttribute("x2", data.rect[2] - data.lineCoordinates[2]); + line.setAttribute("y2", data.rect[3] - data.lineCoordinates[3]); + line.setAttribute("stroke-width", data.borderStyle.width || 1); + line.setAttribute("stroke", "transparent"); + line.setAttribute("fill", "transparent"); + svg.append(line); + this.container.append(svg); + + this._createPopup(line, data); + + return this.container; + } + +} + +class SquareAnnotationElement extends AnnotationElement { + constructor(parameters) { + var _parameters$data$titl5, _parameters$data$cont5, _parameters$data$rich5; + + const isRenderable = !!(parameters.data.hasPopup || (_parameters$data$titl5 = parameters.data.titleObj) !== null && _parameters$data$titl5 !== void 0 && _parameters$data$titl5.str || (_parameters$data$cont5 = parameters.data.contentsObj) !== null && _parameters$data$cont5 !== void 0 && _parameters$data$cont5.str || (_parameters$data$rich5 = parameters.data.richText) !== null && _parameters$data$rich5 !== void 0 && _parameters$data$rich5.str); + super(parameters, { + isRenderable, + ignoreBorder: true + }); + } + + render() { + this.container.className = "squareAnnotation"; + const data = this.data; + const { + width, + height + } = getRectDims(data.rect); + const svg = this.svgFactory.create(width, height, true); + const borderWidth = data.borderStyle.width; + const square = this.svgFactory.createElement("svg:rect"); + square.setAttribute("x", borderWidth / 2); + square.setAttribute("y", borderWidth / 2); + square.setAttribute("width", width - borderWidth); + square.setAttribute("height", height - borderWidth); + square.setAttribute("stroke-width", borderWidth || 1); + square.setAttribute("stroke", "transparent"); + square.setAttribute("fill", "transparent"); + svg.append(square); + this.container.append(svg); + + this._createPopup(square, data); + + return this.container; + } + +} + +class CircleAnnotationElement extends AnnotationElement { + constructor(parameters) { + var _parameters$data$titl6, _parameters$data$cont6, _parameters$data$rich6; + + const isRenderable = !!(parameters.data.hasPopup || (_parameters$data$titl6 = parameters.data.titleObj) !== null && _parameters$data$titl6 !== void 0 && _parameters$data$titl6.str || (_parameters$data$cont6 = parameters.data.contentsObj) !== null && _parameters$data$cont6 !== void 0 && _parameters$data$cont6.str || (_parameters$data$rich6 = parameters.data.richText) !== null && _parameters$data$rich6 !== void 0 && _parameters$data$rich6.str); + super(parameters, { + isRenderable, + ignoreBorder: true + }); + } + + render() { + this.container.className = "circleAnnotation"; + const data = this.data; + const { + width, + height + } = getRectDims(data.rect); + const svg = this.svgFactory.create(width, height, true); + const borderWidth = data.borderStyle.width; + const circle = this.svgFactory.createElement("svg:ellipse"); + circle.setAttribute("cx", width / 2); + circle.setAttribute("cy", height / 2); + circle.setAttribute("rx", width / 2 - borderWidth / 2); + circle.setAttribute("ry", height / 2 - borderWidth / 2); + circle.setAttribute("stroke-width", borderWidth || 1); + circle.setAttribute("stroke", "transparent"); + circle.setAttribute("fill", "transparent"); + svg.append(circle); + this.container.append(svg); + + this._createPopup(circle, data); + + return this.container; + } + +} + +class PolylineAnnotationElement extends AnnotationElement { + constructor(parameters) { + var _parameters$data$titl7, _parameters$data$cont7, _parameters$data$rich7; + + const isRenderable = !!(parameters.data.hasPopup || (_parameters$data$titl7 = parameters.data.titleObj) !== null && _parameters$data$titl7 !== void 0 && _parameters$data$titl7.str || (_parameters$data$cont7 = parameters.data.contentsObj) !== null && _parameters$data$cont7 !== void 0 && _parameters$data$cont7.str || (_parameters$data$rich7 = parameters.data.richText) !== null && _parameters$data$rich7 !== void 0 && _parameters$data$rich7.str); + super(parameters, { + isRenderable, + ignoreBorder: true + }); + this.containerClassName = "polylineAnnotation"; + this.svgElementName = "svg:polyline"; + } + + render() { + this.container.className = this.containerClassName; + const data = this.data; + const { + width, + height + } = getRectDims(data.rect); + const svg = this.svgFactory.create(width, height, true); + let points = []; + + for (const coordinate of data.vertices) { + const x = coordinate.x - data.rect[0]; + const y = data.rect[3] - coordinate.y; + points.push(x + "," + y); + } + + points = points.join(" "); + const polyline = this.svgFactory.createElement(this.svgElementName); + polyline.setAttribute("points", points); + polyline.setAttribute("stroke-width", data.borderStyle.width || 1); + polyline.setAttribute("stroke", "transparent"); + polyline.setAttribute("fill", "transparent"); + svg.append(polyline); + this.container.append(svg); + + this._createPopup(polyline, data); + + return this.container; + } + +} + +class PolygonAnnotationElement extends PolylineAnnotationElement { + constructor(parameters) { + super(parameters); + this.containerClassName = "polygonAnnotation"; + this.svgElementName = "svg:polygon"; + } + +} + +class CaretAnnotationElement extends AnnotationElement { + constructor(parameters) { + var _parameters$data$titl8, _parameters$data$cont8, _parameters$data$rich8; + + const isRenderable = !!(parameters.data.hasPopup || (_parameters$data$titl8 = parameters.data.titleObj) !== null && _parameters$data$titl8 !== void 0 && _parameters$data$titl8.str || (_parameters$data$cont8 = parameters.data.contentsObj) !== null && _parameters$data$cont8 !== void 0 && _parameters$data$cont8.str || (_parameters$data$rich8 = parameters.data.richText) !== null && _parameters$data$rich8 !== void 0 && _parameters$data$rich8.str); + super(parameters, { + isRenderable, + ignoreBorder: true + }); + } + + render() { + this.container.className = "caretAnnotation"; + + if (!this.data.hasPopup) { + this._createPopup(null, this.data); + } + + return this.container; + } + +} + +class InkAnnotationElement extends AnnotationElement { + constructor(parameters) { + var _parameters$data$titl9, _parameters$data$cont9, _parameters$data$rich9; + + const isRenderable = !!(parameters.data.hasPopup || (_parameters$data$titl9 = parameters.data.titleObj) !== null && _parameters$data$titl9 !== void 0 && _parameters$data$titl9.str || (_parameters$data$cont9 = parameters.data.contentsObj) !== null && _parameters$data$cont9 !== void 0 && _parameters$data$cont9.str || (_parameters$data$rich9 = parameters.data.richText) !== null && _parameters$data$rich9 !== void 0 && _parameters$data$rich9.str); + super(parameters, { + isRenderable, + ignoreBorder: true + }); + this.containerClassName = "inkAnnotation"; + this.svgElementName = "svg:polyline"; + } + + render() { + this.container.className = this.containerClassName; + const data = this.data; + const { + width, + height + } = getRectDims(data.rect); + const svg = this.svgFactory.create(width, height, true); + + for (const inkList of data.inkLists) { + let points = []; + + for (const coordinate of inkList) { + const x = coordinate.x - data.rect[0]; + const y = data.rect[3] - coordinate.y; + points.push(`${x},${y}`); + } + + points = points.join(" "); + const polyline = this.svgFactory.createElement(this.svgElementName); + polyline.setAttribute("points", points); + polyline.setAttribute("stroke-width", data.borderStyle.width || 1); + polyline.setAttribute("stroke", "transparent"); + polyline.setAttribute("fill", "transparent"); + + this._createPopup(polyline, data); + + svg.append(polyline); + } + + this.container.append(svg); + return this.container; + } + +} + +class HighlightAnnotationElement extends AnnotationElement { + constructor(parameters) { + var _parameters$data$titl10, _parameters$data$cont10, _parameters$data$rich10; + + const isRenderable = !!(parameters.data.hasPopup || (_parameters$data$titl10 = parameters.data.titleObj) !== null && _parameters$data$titl10 !== void 0 && _parameters$data$titl10.str || (_parameters$data$cont10 = parameters.data.contentsObj) !== null && _parameters$data$cont10 !== void 0 && _parameters$data$cont10.str || (_parameters$data$rich10 = parameters.data.richText) !== null && _parameters$data$rich10 !== void 0 && _parameters$data$rich10.str); + super(parameters, { + isRenderable, + ignoreBorder: true, + createQuadrilaterals: true + }); + } + + render() { + if (!this.data.hasPopup) { + this._createPopup(null, this.data); + } + + if (this.quadrilaterals) { + return this._renderQuadrilaterals("highlightAnnotation"); + } + + this.container.className = "highlightAnnotation"; + return this.container; + } + +} + +class UnderlineAnnotationElement extends AnnotationElement { + constructor(parameters) { + var _parameters$data$titl11, _parameters$data$cont11, _parameters$data$rich11; + + const isRenderable = !!(parameters.data.hasPopup || (_parameters$data$titl11 = parameters.data.titleObj) !== null && _parameters$data$titl11 !== void 0 && _parameters$data$titl11.str || (_parameters$data$cont11 = parameters.data.contentsObj) !== null && _parameters$data$cont11 !== void 0 && _parameters$data$cont11.str || (_parameters$data$rich11 = parameters.data.richText) !== null && _parameters$data$rich11 !== void 0 && _parameters$data$rich11.str); + super(parameters, { + isRenderable, + ignoreBorder: true, + createQuadrilaterals: true + }); + } + + render() { + if (!this.data.hasPopup) { + this._createPopup(null, this.data); + } + + if (this.quadrilaterals) { + return this._renderQuadrilaterals("underlineAnnotation"); + } + + this.container.className = "underlineAnnotation"; + return this.container; + } + +} + +class SquigglyAnnotationElement extends AnnotationElement { + constructor(parameters) { + var _parameters$data$titl12, _parameters$data$cont12, _parameters$data$rich12; + + const isRenderable = !!(parameters.data.hasPopup || (_parameters$data$titl12 = parameters.data.titleObj) !== null && _parameters$data$titl12 !== void 0 && _parameters$data$titl12.str || (_parameters$data$cont12 = parameters.data.contentsObj) !== null && _parameters$data$cont12 !== void 0 && _parameters$data$cont12.str || (_parameters$data$rich12 = parameters.data.richText) !== null && _parameters$data$rich12 !== void 0 && _parameters$data$rich12.str); + super(parameters, { + isRenderable, + ignoreBorder: true, + createQuadrilaterals: true + }); + } + + render() { + if (!this.data.hasPopup) { + this._createPopup(null, this.data); + } + + if (this.quadrilaterals) { + return this._renderQuadrilaterals("squigglyAnnotation"); + } + + this.container.className = "squigglyAnnotation"; + return this.container; + } + +} + +class StrikeOutAnnotationElement extends AnnotationElement { + constructor(parameters) { + var _parameters$data$titl13, _parameters$data$cont13, _parameters$data$rich13; + + const isRenderable = !!(parameters.data.hasPopup || (_parameters$data$titl13 = parameters.data.titleObj) !== null && _parameters$data$titl13 !== void 0 && _parameters$data$titl13.str || (_parameters$data$cont13 = parameters.data.contentsObj) !== null && _parameters$data$cont13 !== void 0 && _parameters$data$cont13.str || (_parameters$data$rich13 = parameters.data.richText) !== null && _parameters$data$rich13 !== void 0 && _parameters$data$rich13.str); + super(parameters, { + isRenderable, + ignoreBorder: true, + createQuadrilaterals: true + }); + } + + render() { + if (!this.data.hasPopup) { + this._createPopup(null, this.data); + } + + if (this.quadrilaterals) { + return this._renderQuadrilaterals("strikeoutAnnotation"); + } + + this.container.className = "strikeoutAnnotation"; + return this.container; + } + +} + +class StampAnnotationElement extends AnnotationElement { + constructor(parameters) { + var _parameters$data$titl14, _parameters$data$cont14, _parameters$data$rich14; + + const isRenderable = !!(parameters.data.hasPopup || (_parameters$data$titl14 = parameters.data.titleObj) !== null && _parameters$data$titl14 !== void 0 && _parameters$data$titl14.str || (_parameters$data$cont14 = parameters.data.contentsObj) !== null && _parameters$data$cont14 !== void 0 && _parameters$data$cont14.str || (_parameters$data$rich14 = parameters.data.richText) !== null && _parameters$data$rich14 !== void 0 && _parameters$data$rich14.str); + super(parameters, { + isRenderable, + ignoreBorder: true + }); + } + + render() { + this.container.className = "stampAnnotation"; + + if (!this.data.hasPopup) { + this._createPopup(null, this.data); + } + + return this.container; + } + +} + +class FileAttachmentAnnotationElement extends AnnotationElement { + constructor(parameters) { + var _this$linkService$eve10; + + super(parameters, { + isRenderable: true + }); + const { + filename, + content + } = this.data.file; + this.filename = (0, _display_utils.getFilenameFromUrl)(filename); + this.content = content; + (_this$linkService$eve10 = this.linkService.eventBus) === null || _this$linkService$eve10 === void 0 ? void 0 : _this$linkService$eve10.dispatch("fileattachmentannotation", { + source: this, + filename, + content + }); + } + + render() { + var _this$data$titleObj, _this$data$contentsOb; + + this.container.className = "fileAttachmentAnnotation"; + const trigger = document.createElement("div"); + trigger.className = "popupTriggerArea"; + trigger.addEventListener("dblclick", this._download.bind(this)); + + if (!this.data.hasPopup && ((_this$data$titleObj = this.data.titleObj) !== null && _this$data$titleObj !== void 0 && _this$data$titleObj.str || (_this$data$contentsOb = this.data.contentsObj) !== null && _this$data$contentsOb !== void 0 && _this$data$contentsOb.str || this.data.richText)) { + this._createPopup(trigger, this.data); + } + + this.container.append(trigger); + return this.container; + } + + _download() { + var _this$downloadManager; + + (_this$downloadManager = this.downloadManager) === null || _this$downloadManager === void 0 ? void 0 : _this$downloadManager.openOrDownloadData(this.container, this.content, this.filename); + } + +} + +class AnnotationLayer { + static render(parameters) { + const { + annotations, + div, + viewport, + accessibilityManager + } = parameters; + + _classStaticPrivateMethodGet(this, AnnotationLayer, _setDimensions).call(this, div, viewport); + + let zIndex = 0; + + for (const data of annotations) { + if (data.annotationType !== _util.AnnotationType.POPUP) { + const { + width, + height + } = getRectDims(data.rect); + + if (width <= 0 || height <= 0) { + continue; + } + } + + const element = AnnotationElementFactory.create({ + data, + layer: div, + page: parameters.page, + viewport, + linkService: parameters.linkService, + downloadManager: parameters.downloadManager, + imageResourcesPath: parameters.imageResourcesPath || "", + renderForms: parameters.renderForms !== false, + svgFactory: new _display_utils.DOMSVGFactory(), + annotationStorage: parameters.annotationStorage || new _annotation_storage.AnnotationStorage(), + enableScripting: parameters.enableScripting, + hasJSActions: parameters.hasJSActions, + fieldObjects: parameters.fieldObjects, + mouseState: parameters.mouseState || { + isDown: false + } + }); + + if (element.isRenderable) { + const rendered = element.render(); + + if (data.hidden) { + rendered.style.visibility = "hidden"; + } + + if (Array.isArray(rendered)) { + for (const renderedElement of rendered) { + renderedElement.style.zIndex = zIndex++; + + _classStaticPrivateMethodGet(AnnotationLayer, AnnotationLayer, _appendElement).call(AnnotationLayer, renderedElement, data.id, div, accessibilityManager); + } + } else { + rendered.style.zIndex = zIndex++; + + if (element instanceof PopupAnnotationElement) { + div.prepend(rendered); + } else { + _classStaticPrivateMethodGet(AnnotationLayer, AnnotationLayer, _appendElement).call(AnnotationLayer, rendered, data.id, div, accessibilityManager); + } + } + } + } + + _classStaticPrivateMethodGet(this, AnnotationLayer, _setAnnotationCanvasMap).call(this, div, parameters.annotationCanvasMap); + } + + static update(parameters) { + const { + annotationCanvasMap, + div, + viewport + } = parameters; + + _classStaticPrivateMethodGet(this, AnnotationLayer, _setDimensions).call(this, div, viewport); + + _classStaticPrivateMethodGet(this, AnnotationLayer, _setAnnotationCanvasMap).call(this, div, annotationCanvasMap); + + div.hidden = false; + } + +} + +exports.AnnotationLayer = AnnotationLayer; + +function _appendElement(element, id, div, accessibilityManager) { + const contentElement = element.firstChild || element; + contentElement.id = `${_display_utils.AnnotationPrefix}${id}`; + div.append(element); + accessibilityManager === null || accessibilityManager === void 0 ? void 0 : accessibilityManager.moveElementInDOM(div, element, contentElement, false); +} + +function _setDimensions(div, _ref2) { + let { + width, + height, + rotation + } = _ref2; + const { + style + } = div; + const flipOrientation = rotation % 180 !== 0, + widthStr = Math.floor(width) + "px", + heightStr = Math.floor(height) + "px"; + style.width = flipOrientation ? heightStr : widthStr; + style.height = flipOrientation ? widthStr : heightStr; + div.setAttribute("data-main-rotation", rotation); +} + +function _setAnnotationCanvasMap(div, annotationCanvasMap) { + if (!annotationCanvasMap) { + return; + } + + for (const [id, canvas] of annotationCanvasMap) { + const element = div.querySelector(`[data-annotation-id="${id}"]`); + + if (!element) { + continue; + } + + const { + firstChild + } = element; + + if (!firstChild) { + element.append(canvas); + } else if (firstChild.nodeName === "CANVAS") { + firstChild.replaceWith(canvas); + } else { + firstChild.before(canvas); + } + } + + annotationCanvasMap.clear(); +} + +/***/ }), +/* 153 */ +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.ColorConverters = void 0; + +function makeColorComp(n) { + return Math.floor(Math.max(0, Math.min(1, n)) * 255).toString(16).padStart(2, "0"); +} + +class ColorConverters { + static CMYK_G(_ref) { + let [c, y, m, k] = _ref; + return ["G", 1 - Math.min(1, 0.3 * c + 0.59 * m + 0.11 * y + k)]; + } + + static G_CMYK(_ref2) { + let [g] = _ref2; + return ["CMYK", 0, 0, 0, 1 - g]; + } + + static G_RGB(_ref3) { + let [g] = _ref3; + return ["RGB", g, g, g]; + } + + static G_HTML(_ref4) { + let [g] = _ref4; + const G = makeColorComp(g); + return `#${G}${G}${G}`; + } + + static RGB_G(_ref5) { + let [r, g, b] = _ref5; + return ["G", 0.3 * r + 0.59 * g + 0.11 * b]; + } + + static RGB_HTML(_ref6) { + let [r, g, b] = _ref6; + const R = makeColorComp(r); + const G = makeColorComp(g); + const B = makeColorComp(b); + return `#${R}${G}${B}`; + } + + static T_HTML() { + return "#00000000"; + } + + static CMYK_RGB(_ref7) { + let [c, y, m, k] = _ref7; + return ["RGB", 1 - Math.min(1, c + k), 1 - Math.min(1, m + k), 1 - Math.min(1, y + k)]; + } + + static CMYK_HTML(components) { + const rgb = this.CMYK_RGB(components).slice(1); + return this.RGB_HTML(rgb); + } + + static RGB_CMYK(_ref8) { + let [r, g, b] = _ref8; + const c = 1 - r; + const m = 1 - g; + const y = 1 - b; + const k = Math.min(c, m, y); + return ["CMYK", c, m, y, k]; + } + +} + +exports.ColorConverters = ColorConverters; + +/***/ }), +/* 154 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.XfaLayer = void 0; + +var _xfa_text = __w_pdfjs_require__(145); + +class XfaLayer { + static setupStorage(html, id, element, storage, intent) { + const storedData = storage.getValue(id, { + value: null + }); + + switch (element.name) { + case "textarea": + if (storedData.value !== null) { + html.textContent = storedData.value; + } + + if (intent === "print") { + break; + } + + html.addEventListener("input", event => { + storage.setValue(id, { + value: event.target.value + }); + }); + break; + + case "input": + if (element.attributes.type === "radio" || element.attributes.type === "checkbox") { + if (storedData.value === element.attributes.xfaOn) { + html.setAttribute("checked", true); + } else if (storedData.value === element.attributes.xfaOff) { + html.removeAttribute("checked"); + } + + if (intent === "print") { + break; + } + + html.addEventListener("change", event => { + storage.setValue(id, { + value: event.target.checked ? event.target.getAttribute("xfaOn") : event.target.getAttribute("xfaOff") + }); + }); + } else { + if (storedData.value !== null) { + html.setAttribute("value", storedData.value); + } + + if (intent === "print") { + break; + } + + html.addEventListener("input", event => { + storage.setValue(id, { + value: event.target.value + }); + }); + } + + break; + + case "select": + if (storedData.value !== null) { + for (const option of element.children) { + if (option.attributes.value === storedData.value) { + option.attributes.selected = true; + } + } + } + + html.addEventListener("input", event => { + const options = event.target.options; + const value = options.selectedIndex === -1 ? "" : options[options.selectedIndex].value; + storage.setValue(id, { + value + }); + }); + break; + } + } + + static setAttributes(_ref) { + let { + html, + element, + storage = null, + intent, + linkService + } = _ref; + const { + attributes + } = element; + const isHTMLAnchorElement = html instanceof HTMLAnchorElement; + + if (attributes.type === "radio") { + attributes.name = `${attributes.name}-${intent}`; + } + + for (const [key, value] of Object.entries(attributes)) { + if (value === null || value === undefined) { + continue; + } + + switch (key) { + case "class": + if (value.length) { + html.setAttribute(key, value.join(" ")); + } + + break; + + case "dataId": + break; + + case "id": + html.setAttribute("data-element-id", value); + break; + + case "style": + Object.assign(html.style, value); + break; + + case "textContent": + html.textContent = value; + break; + + default: + if (!isHTMLAnchorElement || key !== "href" && key !== "newWindow") { + html.setAttribute(key, value); + } + + } + } + + if (isHTMLAnchorElement) { + linkService.addLinkAttributes(html, attributes.href, attributes.newWindow); + } + + if (storage && attributes.dataId) { + this.setupStorage(html, attributes.dataId, element, storage); + } + } + + static render(parameters) { + const storage = parameters.annotationStorage; + const linkService = parameters.linkService; + const root = parameters.xfaHtml; + const intent = parameters.intent || "display"; + const rootHtml = document.createElement(root.name); + + if (root.attributes) { + this.setAttributes({ + html: rootHtml, + element: root, + intent, + linkService + }); + } + + const stack = [[root, -1, rootHtml]]; + const rootDiv = parameters.div; + rootDiv.append(rootHtml); + + if (parameters.viewport) { + const transform = `matrix(${parameters.viewport.transform.join(",")})`; + rootDiv.style.transform = transform; + } + + if (intent !== "richText") { + rootDiv.setAttribute("class", "xfaLayer xfaFont"); + } + + const textDivs = []; + + while (stack.length > 0) { + var _child$attributes; + + const [parent, i, html] = stack.at(-1); + + if (i + 1 === parent.children.length) { + stack.pop(); + continue; + } + + const child = parent.children[++stack.at(-1)[1]]; + + if (child === null) { + continue; + } + + const { + name + } = child; + + if (name === "#text") { + const node = document.createTextNode(child.value); + textDivs.push(node); + html.append(node); + continue; + } + + let childHtml; + + if (child !== null && child !== void 0 && (_child$attributes = child.attributes) !== null && _child$attributes !== void 0 && _child$attributes.xmlns) { + childHtml = document.createElementNS(child.attributes.xmlns, name); + } else { + childHtml = document.createElement(name); + } + + html.append(childHtml); + + if (child.attributes) { + this.setAttributes({ + html: childHtml, + element: child, + storage, + intent, + linkService + }); + } + + if (child.children && child.children.length > 0) { + stack.push([child, -1, childHtml]); + } else if (child.value) { + const node = document.createTextNode(child.value); + + if (_xfa_text.XfaText.shouldBuildText(name)) { + textDivs.push(node); + } + + childHtml.append(node); + } + } + + for (const el of rootDiv.querySelectorAll(".xfaNonInteractive input, .xfaNonInteractive textarea")) { + el.setAttribute("readOnly", true); + } + + return { + textDivs + }; + } + + static update(parameters) { + const transform = `matrix(${parameters.viewport.transform.join(",")})`; + parameters.div.style.transform = transform; + parameters.div.hidden = false; + } + +} + +exports.XfaLayer = XfaLayer; + +/***/ }), +/* 155 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.TextLayerRenderTask = void 0; +exports.renderTextLayer = renderTextLayer; + +var _util = __w_pdfjs_require__(1); + +var _display_utils = __w_pdfjs_require__(133); + +const MAX_TEXT_DIVS_TO_RENDER = 100000; +const DEFAULT_FONT_SIZE = 30; +const DEFAULT_FONT_ASCENT = 0.8; +const ascentCache = new Map(); +const AllWhitespaceRegexp = /^\s+$/g; + +function getAscent(fontFamily, ctx) { + const cachedAscent = ascentCache.get(fontFamily); + + if (cachedAscent) { + return cachedAscent; + } + + ctx.save(); + ctx.font = `${DEFAULT_FONT_SIZE}px ${fontFamily}`; + const metrics = ctx.measureText(""); + let ascent = metrics.fontBoundingBoxAscent; + let descent = Math.abs(metrics.fontBoundingBoxDescent); + + if (ascent) { + ctx.restore(); + const ratio = ascent / (ascent + descent); + ascentCache.set(fontFamily, ratio); + return ratio; + } + + ctx.strokeStyle = "red"; + ctx.clearRect(0, 0, DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE); + ctx.strokeText("g", 0, 0); + let pixels = ctx.getImageData(0, 0, DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE).data; + descent = 0; + + for (let i = pixels.length - 1 - 3; i >= 0; i -= 4) { + if (pixels[i] > 0) { + descent = Math.ceil(i / 4 / DEFAULT_FONT_SIZE); + break; + } + } + + ctx.clearRect(0, 0, DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE); + ctx.strokeText("A", 0, DEFAULT_FONT_SIZE); + pixels = ctx.getImageData(0, 0, DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE).data; + ascent = 0; + + for (let i = 0, ii = pixels.length; i < ii; i += 4) { + if (pixels[i] > 0) { + ascent = DEFAULT_FONT_SIZE - Math.floor(i / 4 / DEFAULT_FONT_SIZE); + break; + } + } + + ctx.restore(); + + if (ascent) { + const ratio = ascent / (ascent + descent); + ascentCache.set(fontFamily, ratio); + return ratio; + } + + ascentCache.set(fontFamily, DEFAULT_FONT_ASCENT); + return DEFAULT_FONT_ASCENT; +} + +function appendText(task, geom, styles, ctx) { + const textDiv = document.createElement("span"); + const textDivProperties = task._enhanceTextSelection ? { + angle: 0, + canvasWidth: 0, + hasText: geom.str !== "", + hasEOL: geom.hasEOL, + originalTransform: null, + paddingBottom: 0, + paddingLeft: 0, + paddingRight: 0, + paddingTop: 0, + scale: 1, + fontSize: 0 + } : { + angle: 0, + canvasWidth: 0, + hasText: geom.str !== "", + hasEOL: geom.hasEOL, + fontSize: 0 + }; + + task._textDivs.push(textDiv); + + const tx = _util.Util.transform(task._viewport.transform, geom.transform); + + let angle = Math.atan2(tx[1], tx[0]); + const style = styles[geom.fontName]; + + if (style.vertical) { + angle += Math.PI / 2; + } + + const fontHeight = Math.hypot(tx[2], tx[3]); + const fontAscent = fontHeight * getAscent(style.fontFamily, ctx); + let left, top; + + if (angle === 0) { + left = tx[4]; + top = tx[5] - fontAscent; + } else { + left = tx[4] + fontAscent * Math.sin(angle); + top = tx[5] - fontAscent * Math.cos(angle); + } + + textDiv.style.left = `${left}px`; + textDiv.style.top = `${top}px`; + textDiv.style.fontSize = `${fontHeight}px`; + textDiv.style.fontFamily = style.fontFamily; + textDivProperties.fontSize = fontHeight; + textDiv.setAttribute("role", "presentation"); + textDiv.textContent = geom.str; + textDiv.dir = geom.dir; + + if (task._fontInspectorEnabled) { + textDiv.dataset.fontName = geom.fontName; + } + + if (angle !== 0) { + textDivProperties.angle = angle * (180 / Math.PI); + } + + let shouldScaleText = false; + + if (geom.str.length > 1 || task._enhanceTextSelection && AllWhitespaceRegexp.test(geom.str)) { + shouldScaleText = true; + } else if (geom.str !== " " && geom.transform[0] !== geom.transform[3]) { + const absScaleX = Math.abs(geom.transform[0]), + absScaleY = Math.abs(geom.transform[3]); + + if (absScaleX !== absScaleY && Math.max(absScaleX, absScaleY) / Math.min(absScaleX, absScaleY) > 1.5) { + shouldScaleText = true; + } + } + + if (shouldScaleText) { + if (style.vertical) { + textDivProperties.canvasWidth = geom.height * task._viewport.scale; + } else { + textDivProperties.canvasWidth = geom.width * task._viewport.scale; + } + } + + task._textDivProperties.set(textDiv, textDivProperties); + + if (task._textContentStream) { + task._layoutText(textDiv); + } + + if (task._enhanceTextSelection && textDivProperties.hasText) { + let angleCos = 1, + angleSin = 0; + + if (angle !== 0) { + angleCos = Math.cos(angle); + angleSin = Math.sin(angle); + } + + const divWidth = (style.vertical ? geom.height : geom.width) * task._viewport.scale; + const divHeight = fontHeight; + let m, b; + + if (angle !== 0) { + m = [angleCos, angleSin, -angleSin, angleCos, left, top]; + b = _util.Util.getAxialAlignedBoundingBox([0, 0, divWidth, divHeight], m); + } else { + b = [left, top, left + divWidth, top + divHeight]; + } + + task._bounds.push({ + left: b[0], + top: b[1], + right: b[2], + bottom: b[3], + div: textDiv, + size: [divWidth, divHeight], + m + }); + } +} + +function render(task) { + if (task._canceled) { + return; + } + + const textDivs = task._textDivs; + const capability = task._capability; + const textDivsLength = textDivs.length; + + if (textDivsLength > MAX_TEXT_DIVS_TO_RENDER) { + task._renderingDone = true; + capability.resolve(); + return; + } + + if (!task._textContentStream) { + for (let i = 0; i < textDivsLength; i++) { + task._layoutText(textDivs[i]); + } + } + + task._renderingDone = true; + capability.resolve(); +} + +function findPositiveMin(ts, offset, count) { + let result = 0; + + for (let i = 0; i < count; i++) { + const t = ts[offset++]; + + if (t > 0) { + result = result ? Math.min(t, result) : t; + } + } + + return result; +} + +function expand(task) { + const bounds = task._bounds; + const viewport = task._viewport; + const expanded = expandBounds(viewport.width, viewport.height, bounds); + + for (let i = 0; i < expanded.length; i++) { + const div = bounds[i].div; + + const divProperties = task._textDivProperties.get(div); + + if (divProperties.angle === 0) { + divProperties.paddingLeft = bounds[i].left - expanded[i].left; + divProperties.paddingTop = bounds[i].top - expanded[i].top; + divProperties.paddingRight = expanded[i].right - bounds[i].right; + divProperties.paddingBottom = expanded[i].bottom - bounds[i].bottom; + + task._textDivProperties.set(div, divProperties); + + continue; + } + + const e = expanded[i], + b = bounds[i]; + const m = b.m, + c = m[0], + s = m[1]; + const points = [[0, 0], [0, b.size[1]], [b.size[0], 0], b.size]; + const ts = new Float64Array(64); + + for (let j = 0, jj = points.length; j < jj; j++) { + const t = _util.Util.applyTransform(points[j], m); + + ts[j + 0] = c && (e.left - t[0]) / c; + ts[j + 4] = s && (e.top - t[1]) / s; + ts[j + 8] = c && (e.right - t[0]) / c; + ts[j + 12] = s && (e.bottom - t[1]) / s; + ts[j + 16] = s && (e.left - t[0]) / -s; + ts[j + 20] = c && (e.top - t[1]) / c; + ts[j + 24] = s && (e.right - t[0]) / -s; + ts[j + 28] = c && (e.bottom - t[1]) / c; + ts[j + 32] = c && (e.left - t[0]) / -c; + ts[j + 36] = s && (e.top - t[1]) / -s; + ts[j + 40] = c && (e.right - t[0]) / -c; + ts[j + 44] = s && (e.bottom - t[1]) / -s; + ts[j + 48] = s && (e.left - t[0]) / s; + ts[j + 52] = c && (e.top - t[1]) / -c; + ts[j + 56] = s && (e.right - t[0]) / s; + ts[j + 60] = c && (e.bottom - t[1]) / -c; + } + + const boxScale = 1 + Math.min(Math.abs(c), Math.abs(s)); + divProperties.paddingLeft = findPositiveMin(ts, 32, 16) / boxScale; + divProperties.paddingTop = findPositiveMin(ts, 48, 16) / boxScale; + divProperties.paddingRight = findPositiveMin(ts, 0, 16) / boxScale; + divProperties.paddingBottom = findPositiveMin(ts, 16, 16) / boxScale; + + task._textDivProperties.set(div, divProperties); + } +} + +function expandBounds(width, height, boxes) { + const bounds = boxes.map(function (box, i) { + return { + x1: box.left, + y1: box.top, + x2: box.right, + y2: box.bottom, + index: i, + x1New: undefined, + x2New: undefined + }; + }); + expandBoundsLTR(width, bounds); + const expanded = new Array(boxes.length); + + for (const b of bounds) { + const i = b.index; + expanded[i] = { + left: b.x1New, + top: 0, + right: b.x2New, + bottom: 0 + }; + } + + boxes.map(function (box, i) { + const e = expanded[i], + b = bounds[i]; + b.x1 = box.top; + b.y1 = width - e.right; + b.x2 = box.bottom; + b.y2 = width - e.left; + b.index = i; + b.x1New = undefined; + b.x2New = undefined; + }); + expandBoundsLTR(height, bounds); + + for (const b of bounds) { + const i = b.index; + expanded[i].top = b.x1New; + expanded[i].bottom = b.x2New; + } + + return expanded; +} + +function expandBoundsLTR(width, bounds) { + bounds.sort(function (a, b) { + return a.x1 - b.x1 || a.index - b.index; + }); + const fakeBoundary = { + x1: -Infinity, + y1: -Infinity, + x2: 0, + y2: Infinity, + index: -1, + x1New: 0, + x2New: 0 + }; + const horizon = [{ + start: -Infinity, + end: Infinity, + boundary: fakeBoundary + }]; + + for (const boundary of bounds) { + let i = 0; + + while (i < horizon.length && horizon[i].end <= boundary.y1) { + i++; + } + + let j = horizon.length - 1; + + while (j >= 0 && horizon[j].start >= boundary.y2) { + j--; + } + + let horizonPart, affectedBoundary; + let q, + k, + maxXNew = -Infinity; + + for (q = i; q <= j; q++) { + horizonPart = horizon[q]; + affectedBoundary = horizonPart.boundary; + let xNew; + + if (affectedBoundary.x2 > boundary.x1) { + xNew = affectedBoundary.index > boundary.index ? affectedBoundary.x1New : boundary.x1; + } else if (affectedBoundary.x2New === undefined) { + xNew = (affectedBoundary.x2 + boundary.x1) / 2; + } else { + xNew = affectedBoundary.x2New; + } + + if (xNew > maxXNew) { + maxXNew = xNew; + } + } + + boundary.x1New = maxXNew; + + for (q = i; q <= j; q++) { + horizonPart = horizon[q]; + affectedBoundary = horizonPart.boundary; + + if (affectedBoundary.x2New === undefined) { + if (affectedBoundary.x2 > boundary.x1) { + if (affectedBoundary.index > boundary.index) { + affectedBoundary.x2New = affectedBoundary.x2; + } + } else { + affectedBoundary.x2New = maxXNew; + } + } else if (affectedBoundary.x2New > maxXNew) { + affectedBoundary.x2New = Math.max(maxXNew, affectedBoundary.x2); + } + } + + const changedHorizon = []; + let lastBoundary = null; + + for (q = i; q <= j; q++) { + horizonPart = horizon[q]; + affectedBoundary = horizonPart.boundary; + const useBoundary = affectedBoundary.x2 > boundary.x2 ? affectedBoundary : boundary; + + if (lastBoundary === useBoundary) { + changedHorizon.at(-1).end = horizonPart.end; + } else { + changedHorizon.push({ + start: horizonPart.start, + end: horizonPart.end, + boundary: useBoundary + }); + lastBoundary = useBoundary; + } + } + + if (horizon[i].start < boundary.y1) { + changedHorizon[0].start = boundary.y1; + changedHorizon.unshift({ + start: horizon[i].start, + end: boundary.y1, + boundary: horizon[i].boundary + }); + } + + if (boundary.y2 < horizon[j].end) { + changedHorizon.at(-1).end = boundary.y2; + changedHorizon.push({ + start: boundary.y2, + end: horizon[j].end, + boundary: horizon[j].boundary + }); + } + + for (q = i; q <= j; q++) { + horizonPart = horizon[q]; + affectedBoundary = horizonPart.boundary; + + if (affectedBoundary.x2New !== undefined) { + continue; + } + + let used = false; + + for (k = i - 1; !used && k >= 0 && horizon[k].start >= affectedBoundary.y1; k--) { + used = horizon[k].boundary === affectedBoundary; + } + + for (k = j + 1; !used && k < horizon.length && horizon[k].end <= affectedBoundary.y2; k++) { + used = horizon[k].boundary === affectedBoundary; + } + + for (k = 0; !used && k < changedHorizon.length; k++) { + used = changedHorizon[k].boundary === affectedBoundary; + } + + if (!used) { + affectedBoundary.x2New = maxXNew; + } + } + + Array.prototype.splice.apply(horizon, [i, j - i + 1, ...changedHorizon]); + } + + for (const horizonPart of horizon) { + const affectedBoundary = horizonPart.boundary; + + if (affectedBoundary.x2New === undefined) { + affectedBoundary.x2New = Math.max(width, affectedBoundary.x2); + } + } +} + +class TextLayerRenderTask { + constructor(_ref) { + var _globalThis$FontInspe; + + let { + textContent, + textContentStream, + container, + viewport, + textDivs, + textContentItemsStr, + enhanceTextSelection + } = _ref; + + if (enhanceTextSelection) { + (0, _display_utils.deprecated)("The `enhanceTextSelection` functionality will be removed in the future."); + } + + this._textContent = textContent; + this._textContentStream = textContentStream; + this._container = container; + this._document = container.ownerDocument; + this._viewport = viewport; + this._textDivs = textDivs || []; + this._textContentItemsStr = textContentItemsStr || []; + this._enhanceTextSelection = !!enhanceTextSelection; + this._fontInspectorEnabled = !!((_globalThis$FontInspe = globalThis.FontInspector) !== null && _globalThis$FontInspe !== void 0 && _globalThis$FontInspe.enabled); + this._reader = null; + this._layoutTextLastFontSize = null; + this._layoutTextLastFontFamily = null; + this._layoutTextCtx = null; + this._textDivProperties = new WeakMap(); + this._renderingDone = false; + this._canceled = false; + this._capability = (0, _util.createPromiseCapability)(); + this._renderTimer = null; + this._bounds = []; + this._devicePixelRatio = globalThis.devicePixelRatio || 1; + + this._capability.promise.finally(() => { + if (!this._enhanceTextSelection) { + this._textDivProperties = null; + } + + if (this._layoutTextCtx) { + this._layoutTextCtx.canvas.width = 0; + this._layoutTextCtx.canvas.height = 0; + this._layoutTextCtx = null; + } + }).catch(() => {}); + } + + get promise() { + return this._capability.promise; + } + + cancel() { + this._canceled = true; + + if (this._reader) { + this._reader.cancel(new _util.AbortException("TextLayer task cancelled.")).catch(() => {}); + + this._reader = null; + } + + if (this._renderTimer !== null) { + clearTimeout(this._renderTimer); + this._renderTimer = null; + } + + this._capability.reject(new Error("TextLayer task cancelled.")); + } + + _processItems(items, styleCache) { + for (let i = 0, len = items.length; i < len; i++) { + if (items[i].str === undefined) { + if (items[i].type === "beginMarkedContentProps" || items[i].type === "beginMarkedContent") { + const parent = this._container; + this._container = document.createElement("span"); + + this._container.classList.add("markedContent"); + + if (items[i].id !== null) { + this._container.setAttribute("id", `${items[i].id}`); + } + + parent.append(this._container); + } else if (items[i].type === "endMarkedContent") { + this._container = this._container.parentNode; + } + + continue; + } + + this._textContentItemsStr.push(items[i].str); + + appendText(this, items[i], styleCache, this._layoutTextCtx); + } + } + + _layoutText(textDiv) { + const textDivProperties = this._textDivProperties.get(textDiv); + + let transform = ""; + + if (textDivProperties.canvasWidth !== 0 && textDivProperties.hasText) { + const { + fontFamily + } = textDiv.style; + const { + fontSize + } = textDivProperties; + + if (fontSize !== this._layoutTextLastFontSize || fontFamily !== this._layoutTextLastFontFamily) { + this._layoutTextCtx.font = `${fontSize * this._devicePixelRatio}px ${fontFamily}`; + this._layoutTextLastFontSize = fontSize; + this._layoutTextLastFontFamily = fontFamily; + } + + const { + width + } = this._layoutTextCtx.measureText(textDiv.textContent); + + if (width > 0) { + const scale = this._devicePixelRatio * textDivProperties.canvasWidth / width; + + if (this._enhanceTextSelection) { + textDivProperties.scale = scale; + } + + transform = `scaleX(${scale})`; + } + } + + if (textDivProperties.angle !== 0) { + transform = `rotate(${textDivProperties.angle}deg) ${transform}`; + } + + if (transform.length > 0) { + if (this._enhanceTextSelection) { + textDivProperties.originalTransform = transform; + } + + textDiv.style.transform = transform; + } + + if (textDivProperties.hasText) { + this._container.append(textDiv); + } + + if (textDivProperties.hasEOL) { + const br = document.createElement("br"); + br.setAttribute("role", "presentation"); + + this._container.append(br); + } + } + + _render() { + let timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + const capability = (0, _util.createPromiseCapability)(); + let styleCache = Object.create(null); + + const canvas = this._document.createElement("canvas"); + + canvas.height = canvas.width = DEFAULT_FONT_SIZE; + this._layoutTextCtx = canvas.getContext("2d", { + alpha: false + }); + + if (this._textContent) { + const textItems = this._textContent.items; + const textStyles = this._textContent.styles; + + this._processItems(textItems, textStyles); + + capability.resolve(); + } else if (this._textContentStream) { + const pump = () => { + this._reader.read().then(_ref2 => { + let { + value, + done + } = _ref2; + + if (done) { + capability.resolve(); + return; + } + + Object.assign(styleCache, value.styles); + + this._processItems(value.items, styleCache); + + pump(); + }, capability.reject); + }; + + this._reader = this._textContentStream.getReader(); + pump(); + } else { + throw new Error('Neither "textContent" nor "textContentStream" parameters specified.'); + } + + capability.promise.then(() => { + styleCache = null; + + if (!timeout) { + render(this); + } else { + this._renderTimer = setTimeout(() => { + render(this); + this._renderTimer = null; + }, timeout); + } + }, this._capability.reject); + } + + expandTextDivs() { + let expandDivs = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + if (!this._enhanceTextSelection || !this._renderingDone) { + return; + } + + if (this._bounds !== null) { + expand(this); + this._bounds = null; + } + + const transformBuf = [], + paddingBuf = []; + + for (let i = 0, ii = this._textDivs.length; i < ii; i++) { + const div = this._textDivs[i]; + + const divProps = this._textDivProperties.get(div); + + if (!divProps.hasText) { + continue; + } + + if (expandDivs) { + transformBuf.length = 0; + paddingBuf.length = 0; + + if (divProps.originalTransform) { + transformBuf.push(divProps.originalTransform); + } + + if (divProps.paddingTop > 0) { + paddingBuf.push(`${divProps.paddingTop}px`); + transformBuf.push(`translateY(${-divProps.paddingTop}px)`); + } else { + paddingBuf.push(0); + } + + if (divProps.paddingRight > 0) { + paddingBuf.push(`${divProps.paddingRight / divProps.scale}px`); + } else { + paddingBuf.push(0); + } + + if (divProps.paddingBottom > 0) { + paddingBuf.push(`${divProps.paddingBottom}px`); + } else { + paddingBuf.push(0); + } + + if (divProps.paddingLeft > 0) { + paddingBuf.push(`${divProps.paddingLeft / divProps.scale}px`); + transformBuf.push(`translateX(${-divProps.paddingLeft / divProps.scale}px)`); + } else { + paddingBuf.push(0); + } + + div.style.padding = paddingBuf.join(" "); + + if (transformBuf.length) { + div.style.transform = transformBuf.join(" "); + } + } else { + div.style.padding = null; + div.style.transform = divProps.originalTransform; + } + } + } + +} + +exports.TextLayerRenderTask = TextLayerRenderTask; + +function renderTextLayer(renderParameters) { + const task = new TextLayerRenderTask({ + textContent: renderParameters.textContent, + textContentStream: renderParameters.textContentStream, + container: renderParameters.container, + viewport: renderParameters.viewport, + textDivs: renderParameters.textDivs, + textContentItemsStr: renderParameters.textContentItemsStr, + enhanceTextSelection: renderParameters.enhanceTextSelection + }); + + task._render(renderParameters.timeout); + + return task; +} + +/***/ }), +/* 156 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.SVGGraphics = void 0; + +var _display_utils = __w_pdfjs_require__(133); + +var _util = __w_pdfjs_require__(1); + +var _is_node = __w_pdfjs_require__(3); + +let SVGGraphics = class { + constructor() { + (0, _util.unreachable)("Not implemented: SVGGraphics"); + } + +}; +exports.SVGGraphics = SVGGraphics; +{ + const SVG_DEFAULTS = { + fontStyle: "normal", + fontWeight: "normal", + fillColor: "#000000" + }; + const XML_NS = "http://www.w3.org/XML/1998/namespace"; + const XLINK_NS = "http://www.w3.org/1999/xlink"; + const LINE_CAP_STYLES = ["butt", "round", "square"]; + const LINE_JOIN_STYLES = ["miter", "round", "bevel"]; + + const createObjectURL = function (data) { + let contentType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ""; + let forceDataSchema = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + + if (URL.createObjectURL && typeof Blob !== "undefined" && !forceDataSchema) { + return URL.createObjectURL(new Blob([data], { + type: contentType + })); + } + + const digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + let buffer = `data:${contentType};base64,`; + + for (let i = 0, ii = data.length; i < ii; i += 3) { + const b1 = data[i] & 0xff; + const b2 = data[i + 1] & 0xff; + const b3 = data[i + 2] & 0xff; + const d1 = b1 >> 2, + d2 = (b1 & 3) << 4 | b2 >> 4; + const d3 = i + 1 < ii ? (b2 & 0xf) << 2 | b3 >> 6 : 64; + const d4 = i + 2 < ii ? b3 & 0x3f : 64; + buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4]; + } + + return buffer; + }; + + const convertImgDataToPng = function () { + const PNG_HEADER = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]); + const CHUNK_WRAPPER_SIZE = 12; + const crcTable = new Int32Array(256); + + for (let i = 0; i < 256; i++) { + let c = i; + + for (let h = 0; h < 8; h++) { + if (c & 1) { + c = 0xedb88320 ^ c >> 1 & 0x7fffffff; + } else { + c = c >> 1 & 0x7fffffff; + } + } + + crcTable[i] = c; + } + + function crc32(data, start, end) { + let crc = -1; + + for (let i = start; i < end; i++) { + const a = (crc ^ data[i]) & 0xff; + const b = crcTable[a]; + crc = crc >>> 8 ^ b; + } + + return crc ^ -1; + } + + function writePngChunk(type, body, data, offset) { + let p = offset; + const len = body.length; + data[p] = len >> 24 & 0xff; + data[p + 1] = len >> 16 & 0xff; + data[p + 2] = len >> 8 & 0xff; + data[p + 3] = len & 0xff; + p += 4; + data[p] = type.charCodeAt(0) & 0xff; + data[p + 1] = type.charCodeAt(1) & 0xff; + data[p + 2] = type.charCodeAt(2) & 0xff; + data[p + 3] = type.charCodeAt(3) & 0xff; + p += 4; + data.set(body, p); + p += body.length; + const crc = crc32(data, offset + 4, p); + data[p] = crc >> 24 & 0xff; + data[p + 1] = crc >> 16 & 0xff; + data[p + 2] = crc >> 8 & 0xff; + data[p + 3] = crc & 0xff; + } + + function adler32(data, start, end) { + let a = 1; + let b = 0; + + for (let i = start; i < end; ++i) { + a = (a + (data[i] & 0xff)) % 65521; + b = (b + a) % 65521; + } + + return b << 16 | a; + } + + function deflateSync(literals) { + if (!_is_node.isNodeJS) { + return deflateSyncUncompressed(literals); + } + + try { + let input; + + if (parseInt(process.versions.node) >= 8) { + input = literals; + } else { + input = Buffer.from(literals); + } + + const output = require("zlib").deflateSync(input, { + level: 9 + }); + + return output instanceof Uint8Array ? output : new Uint8Array(output); + } catch (e) { + (0, _util.warn)("Not compressing PNG because zlib.deflateSync is unavailable: " + e); + } + + return deflateSyncUncompressed(literals); + } + + function deflateSyncUncompressed(literals) { + let len = literals.length; + const maxBlockLength = 0xffff; + const deflateBlocks = Math.ceil(len / maxBlockLength); + const idat = new Uint8Array(2 + len + deflateBlocks * 5 + 4); + let pi = 0; + idat[pi++] = 0x78; + idat[pi++] = 0x9c; + let pos = 0; + + while (len > maxBlockLength) { + idat[pi++] = 0x00; + idat[pi++] = 0xff; + idat[pi++] = 0xff; + idat[pi++] = 0x00; + idat[pi++] = 0x00; + idat.set(literals.subarray(pos, pos + maxBlockLength), pi); + pi += maxBlockLength; + pos += maxBlockLength; + len -= maxBlockLength; + } + + idat[pi++] = 0x01; + idat[pi++] = len & 0xff; + idat[pi++] = len >> 8 & 0xff; + idat[pi++] = ~len & 0xffff & 0xff; + idat[pi++] = (~len & 0xffff) >> 8 & 0xff; + idat.set(literals.subarray(pos), pi); + pi += literals.length - pos; + const adler = adler32(literals, 0, literals.length); + idat[pi++] = adler >> 24 & 0xff; + idat[pi++] = adler >> 16 & 0xff; + idat[pi++] = adler >> 8 & 0xff; + idat[pi++] = adler & 0xff; + return idat; + } + + function encode(imgData, kind, forceDataSchema, isMask) { + const width = imgData.width; + const height = imgData.height; + let bitDepth, colorType, lineSize; + const bytes = imgData.data; + + switch (kind) { + case _util.ImageKind.GRAYSCALE_1BPP: + colorType = 0; + bitDepth = 1; + lineSize = width + 7 >> 3; + break; + + case _util.ImageKind.RGB_24BPP: + colorType = 2; + bitDepth = 8; + lineSize = width * 3; + break; + + case _util.ImageKind.RGBA_32BPP: + colorType = 6; + bitDepth = 8; + lineSize = width * 4; + break; + + default: + throw new Error("invalid format"); + } + + const literals = new Uint8Array((1 + lineSize) * height); + let offsetLiterals = 0, + offsetBytes = 0; + + for (let y = 0; y < height; ++y) { + literals[offsetLiterals++] = 0; + literals.set(bytes.subarray(offsetBytes, offsetBytes + lineSize), offsetLiterals); + offsetBytes += lineSize; + offsetLiterals += lineSize; + } + + if (kind === _util.ImageKind.GRAYSCALE_1BPP && isMask) { + offsetLiterals = 0; + + for (let y = 0; y < height; y++) { + offsetLiterals++; + + for (let i = 0; i < lineSize; i++) { + literals[offsetLiterals++] ^= 0xff; + } + } + } + + const ihdr = new Uint8Array([width >> 24 & 0xff, width >> 16 & 0xff, width >> 8 & 0xff, width & 0xff, height >> 24 & 0xff, height >> 16 & 0xff, height >> 8 & 0xff, height & 0xff, bitDepth, colorType, 0x00, 0x00, 0x00]); + const idat = deflateSync(literals); + const pngLength = PNG_HEADER.length + CHUNK_WRAPPER_SIZE * 3 + ihdr.length + idat.length; + const data = new Uint8Array(pngLength); + let offset = 0; + data.set(PNG_HEADER, offset); + offset += PNG_HEADER.length; + writePngChunk("IHDR", ihdr, data, offset); + offset += CHUNK_WRAPPER_SIZE + ihdr.length; + writePngChunk("IDATA", idat, data, offset); + offset += CHUNK_WRAPPER_SIZE + idat.length; + writePngChunk("IEND", new Uint8Array(0), data, offset); + return createObjectURL(data, "image/png", forceDataSchema); + } + + return function convertImgDataToPng(imgData, forceDataSchema, isMask) { + const kind = imgData.kind === undefined ? _util.ImageKind.GRAYSCALE_1BPP : imgData.kind; + return encode(imgData, kind, forceDataSchema, isMask); + }; + }(); + + class SVGExtraState { + constructor() { + this.fontSizeScale = 1; + this.fontWeight = SVG_DEFAULTS.fontWeight; + this.fontSize = 0; + this.textMatrix = _util.IDENTITY_MATRIX; + this.fontMatrix = _util.FONT_IDENTITY_MATRIX; + this.leading = 0; + this.textRenderingMode = _util.TextRenderingMode.FILL; + this.textMatrixScale = 1; + this.x = 0; + this.y = 0; + this.lineX = 0; + this.lineY = 0; + this.charSpacing = 0; + this.wordSpacing = 0; + this.textHScale = 1; + this.textRise = 0; + this.fillColor = SVG_DEFAULTS.fillColor; + this.strokeColor = "#000000"; + this.fillAlpha = 1; + this.strokeAlpha = 1; + this.lineWidth = 1; + this.lineJoin = ""; + this.lineCap = ""; + this.miterLimit = 0; + this.dashArray = []; + this.dashPhase = 0; + this.dependencies = []; + this.activeClipUrl = null; + this.clipGroup = null; + this.maskId = ""; + } + + clone() { + return Object.create(this); + } + + setCurrentPoint(x, y) { + this.x = x; + this.y = y; + } + + } + + function opListToTree(opList) { + let opTree = []; + const tmp = []; + + for (const opListElement of opList) { + if (opListElement.fn === "save") { + opTree.push({ + fnId: 92, + fn: "group", + items: [] + }); + tmp.push(opTree); + opTree = opTree.at(-1).items; + continue; + } + + if (opListElement.fn === "restore") { + opTree = tmp.pop(); + } else { + opTree.push(opListElement); + } + } + + return opTree; + } + + function pf(value) { + if (Number.isInteger(value)) { + return value.toString(); + } + + const s = value.toFixed(10); + let i = s.length - 1; + + if (s[i] !== "0") { + return s; + } + + do { + i--; + } while (s[i] === "0"); + + return s.substring(0, s[i] === "." ? i : i + 1); + } + + function pm(m) { + if (m[4] === 0 && m[5] === 0) { + if (m[1] === 0 && m[2] === 0) { + if (m[0] === 1 && m[3] === 1) { + return ""; + } + + return `scale(${pf(m[0])} ${pf(m[3])})`; + } + + if (m[0] === m[3] && m[1] === -m[2]) { + const a = Math.acos(m[0]) * 180 / Math.PI; + return `rotate(${pf(a)})`; + } + } else { + if (m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1) { + return `translate(${pf(m[4])} ${pf(m[5])})`; + } + } + + return `matrix(${pf(m[0])} ${pf(m[1])} ${pf(m[2])} ${pf(m[3])} ${pf(m[4])} ` + `${pf(m[5])})`; + } + + let clipCount = 0; + let maskCount = 0; + let shadingCount = 0; + exports.SVGGraphics = SVGGraphics = class { + constructor(commonObjs, objs) { + let forceDataSchema = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + (0, _display_utils.deprecated)("The SVG back-end is no longer maintained and *may* be removed in the future."); + this.svgFactory = new _display_utils.DOMSVGFactory(); + this.current = new SVGExtraState(); + this.transformMatrix = _util.IDENTITY_MATRIX; + this.transformStack = []; + this.extraStack = []; + this.commonObjs = commonObjs; + this.objs = objs; + this.pendingClip = null; + this.pendingEOFill = false; + this.embedFonts = false; + this.embeddedFonts = Object.create(null); + this.cssStyle = null; + this.forceDataSchema = !!forceDataSchema; + this._operatorIdMapping = []; + + for (const op in _util.OPS) { + this._operatorIdMapping[_util.OPS[op]] = op; + } + } + + save() { + this.transformStack.push(this.transformMatrix); + const old = this.current; + this.extraStack.push(old); + this.current = old.clone(); + } + + restore() { + this.transformMatrix = this.transformStack.pop(); + this.current = this.extraStack.pop(); + this.pendingClip = null; + this.tgrp = null; + } + + group(items) { + this.save(); + this.executeOpTree(items); + this.restore(); + } + + loadDependencies(operatorList) { + const fnArray = operatorList.fnArray; + const argsArray = operatorList.argsArray; + + for (let i = 0, ii = fnArray.length; i < ii; i++) { + if (fnArray[i] !== _util.OPS.dependency) { + continue; + } + + for (const obj of argsArray[i]) { + const objsPool = obj.startsWith("g_") ? this.commonObjs : this.objs; + const promise = new Promise(resolve => { + objsPool.get(obj, resolve); + }); + this.current.dependencies.push(promise); + } + } + + return Promise.all(this.current.dependencies); + } + + transform(a, b, c, d, e, f) { + const transformMatrix = [a, b, c, d, e, f]; + this.transformMatrix = _util.Util.transform(this.transformMatrix, transformMatrix); + this.tgrp = null; + } + + getSVG(operatorList, viewport) { + this.viewport = viewport; + + const svgElement = this._initialize(viewport); + + return this.loadDependencies(operatorList).then(() => { + this.transformMatrix = _util.IDENTITY_MATRIX; + this.executeOpTree(this.convertOpList(operatorList)); + return svgElement; + }); + } + + convertOpList(operatorList) { + const operatorIdMapping = this._operatorIdMapping; + const argsArray = operatorList.argsArray; + const fnArray = operatorList.fnArray; + const opList = []; + + for (let i = 0, ii = fnArray.length; i < ii; i++) { + const fnId = fnArray[i]; + opList.push({ + fnId, + fn: operatorIdMapping[fnId], + args: argsArray[i] + }); + } + + return opListToTree(opList); + } + + executeOpTree(opTree) { + for (const opTreeElement of opTree) { + const fn = opTreeElement.fn; + const fnId = opTreeElement.fnId; + const args = opTreeElement.args; + + switch (fnId | 0) { + case _util.OPS.beginText: + this.beginText(); + break; + + case _util.OPS.dependency: + break; + + case _util.OPS.setLeading: + this.setLeading(args); + break; + + case _util.OPS.setLeadingMoveText: + this.setLeadingMoveText(args[0], args[1]); + break; + + case _util.OPS.setFont: + this.setFont(args); + break; + + case _util.OPS.showText: + this.showText(args[0]); + break; + + case _util.OPS.showSpacedText: + this.showText(args[0]); + break; + + case _util.OPS.endText: + this.endText(); + break; + + case _util.OPS.moveText: + this.moveText(args[0], args[1]); + break; + + case _util.OPS.setCharSpacing: + this.setCharSpacing(args[0]); + break; + + case _util.OPS.setWordSpacing: + this.setWordSpacing(args[0]); + break; + + case _util.OPS.setHScale: + this.setHScale(args[0]); + break; + + case _util.OPS.setTextMatrix: + this.setTextMatrix(args[0], args[1], args[2], args[3], args[4], args[5]); + break; + + case _util.OPS.setTextRise: + this.setTextRise(args[0]); + break; + + case _util.OPS.setTextRenderingMode: + this.setTextRenderingMode(args[0]); + break; + + case _util.OPS.setLineWidth: + this.setLineWidth(args[0]); + break; + + case _util.OPS.setLineJoin: + this.setLineJoin(args[0]); + break; + + case _util.OPS.setLineCap: + this.setLineCap(args[0]); + break; + + case _util.OPS.setMiterLimit: + this.setMiterLimit(args[0]); + break; + + case _util.OPS.setFillRGBColor: + this.setFillRGBColor(args[0], args[1], args[2]); + break; + + case _util.OPS.setStrokeRGBColor: + this.setStrokeRGBColor(args[0], args[1], args[2]); + break; + + case _util.OPS.setStrokeColorN: + this.setStrokeColorN(args); + break; + + case _util.OPS.setFillColorN: + this.setFillColorN(args); + break; + + case _util.OPS.shadingFill: + this.shadingFill(args[0]); + break; + + case _util.OPS.setDash: + this.setDash(args[0], args[1]); + break; + + case _util.OPS.setRenderingIntent: + this.setRenderingIntent(args[0]); + break; + + case _util.OPS.setFlatness: + this.setFlatness(args[0]); + break; + + case _util.OPS.setGState: + this.setGState(args[0]); + break; + + case _util.OPS.fill: + this.fill(); + break; + + case _util.OPS.eoFill: + this.eoFill(); + break; + + case _util.OPS.stroke: + this.stroke(); + break; + + case _util.OPS.fillStroke: + this.fillStroke(); + break; + + case _util.OPS.eoFillStroke: + this.eoFillStroke(); + break; + + case _util.OPS.clip: + this.clip("nonzero"); + break; + + case _util.OPS.eoClip: + this.clip("evenodd"); + break; + + case _util.OPS.paintSolidColorImageMask: + this.paintSolidColorImageMask(); + break; + + case _util.OPS.paintImageXObject: + this.paintImageXObject(args[0]); + break; + + case _util.OPS.paintInlineImageXObject: + this.paintInlineImageXObject(args[0]); + break; + + case _util.OPS.paintImageMaskXObject: + this.paintImageMaskXObject(args[0]); + break; + + case _util.OPS.paintFormXObjectBegin: + this.paintFormXObjectBegin(args[0], args[1]); + break; + + case _util.OPS.paintFormXObjectEnd: + this.paintFormXObjectEnd(); + break; + + case _util.OPS.closePath: + this.closePath(); + break; + + case _util.OPS.closeStroke: + this.closeStroke(); + break; + + case _util.OPS.closeFillStroke: + this.closeFillStroke(); + break; + + case _util.OPS.closeEOFillStroke: + this.closeEOFillStroke(); + break; + + case _util.OPS.nextLine: + this.nextLine(); + break; + + case _util.OPS.transform: + this.transform(args[0], args[1], args[2], args[3], args[4], args[5]); + break; + + case _util.OPS.constructPath: + this.constructPath(args[0], args[1]); + break; + + case _util.OPS.endPath: + this.endPath(); + break; + + case 92: + this.group(opTreeElement.items); + break; + + default: + (0, _util.warn)(`Unimplemented operator ${fn}`); + break; + } + } + } + + setWordSpacing(wordSpacing) { + this.current.wordSpacing = wordSpacing; + } + + setCharSpacing(charSpacing) { + this.current.charSpacing = charSpacing; + } + + nextLine() { + this.moveText(0, this.current.leading); + } + + setTextMatrix(a, b, c, d, e, f) { + const current = this.current; + current.textMatrix = current.lineMatrix = [a, b, c, d, e, f]; + current.textMatrixScale = Math.hypot(a, b); + current.x = current.lineX = 0; + current.y = current.lineY = 0; + current.xcoords = []; + current.ycoords = []; + current.tspan = this.svgFactory.createElement("svg:tspan"); + current.tspan.setAttributeNS(null, "font-family", current.fontFamily); + current.tspan.setAttributeNS(null, "font-size", `${pf(current.fontSize)}px`); + current.tspan.setAttributeNS(null, "y", pf(-current.y)); + current.txtElement = this.svgFactory.createElement("svg:text"); + current.txtElement.append(current.tspan); + } + + beginText() { + const current = this.current; + current.x = current.lineX = 0; + current.y = current.lineY = 0; + current.textMatrix = _util.IDENTITY_MATRIX; + current.lineMatrix = _util.IDENTITY_MATRIX; + current.textMatrixScale = 1; + current.tspan = this.svgFactory.createElement("svg:tspan"); + current.txtElement = this.svgFactory.createElement("svg:text"); + current.txtgrp = this.svgFactory.createElement("svg:g"); + current.xcoords = []; + current.ycoords = []; + } + + moveText(x, y) { + const current = this.current; + current.x = current.lineX += x; + current.y = current.lineY += y; + current.xcoords = []; + current.ycoords = []; + current.tspan = this.svgFactory.createElement("svg:tspan"); + current.tspan.setAttributeNS(null, "font-family", current.fontFamily); + current.tspan.setAttributeNS(null, "font-size", `${pf(current.fontSize)}px`); + current.tspan.setAttributeNS(null, "y", pf(-current.y)); + } + + showText(glyphs) { + const current = this.current; + const font = current.font; + const fontSize = current.fontSize; + + if (fontSize === 0) { + return; + } + + const fontSizeScale = current.fontSizeScale; + const charSpacing = current.charSpacing; + const wordSpacing = current.wordSpacing; + const fontDirection = current.fontDirection; + const textHScale = current.textHScale * fontDirection; + const vertical = font.vertical; + const spacingDir = vertical ? 1 : -1; + const defaultVMetrics = font.defaultVMetrics; + const widthAdvanceScale = fontSize * current.fontMatrix[0]; + let x = 0; + + for (const glyph of glyphs) { + if (glyph === null) { + x += fontDirection * wordSpacing; + continue; + } else if (typeof glyph === "number") { + x += spacingDir * glyph * fontSize / 1000; + continue; + } + + const spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing; + const character = glyph.fontChar; + let scaledX, scaledY; + let width = glyph.width; + + if (vertical) { + let vx; + const vmetric = glyph.vmetric || defaultVMetrics; + vx = glyph.vmetric ? vmetric[1] : width * 0.5; + vx = -vx * widthAdvanceScale; + const vy = vmetric[2] * widthAdvanceScale; + width = vmetric ? -vmetric[0] : width; + scaledX = vx / fontSizeScale; + scaledY = (x + vy) / fontSizeScale; + } else { + scaledX = x / fontSizeScale; + scaledY = 0; + } + + if (glyph.isInFont || font.missingFile) { + current.xcoords.push(current.x + scaledX); + + if (vertical) { + current.ycoords.push(-current.y + scaledY); + } + + current.tspan.textContent += character; + } else {} + + let charWidth; + + if (vertical) { + charWidth = width * widthAdvanceScale - spacing * fontDirection; + } else { + charWidth = width * widthAdvanceScale + spacing * fontDirection; + } + + x += charWidth; + } + + current.tspan.setAttributeNS(null, "x", current.xcoords.map(pf).join(" ")); + + if (vertical) { + current.tspan.setAttributeNS(null, "y", current.ycoords.map(pf).join(" ")); + } else { + current.tspan.setAttributeNS(null, "y", pf(-current.y)); + } + + if (vertical) { + current.y -= x; + } else { + current.x += x * textHScale; + } + + current.tspan.setAttributeNS(null, "font-family", current.fontFamily); + current.tspan.setAttributeNS(null, "font-size", `${pf(current.fontSize)}px`); + + if (current.fontStyle !== SVG_DEFAULTS.fontStyle) { + current.tspan.setAttributeNS(null, "font-style", current.fontStyle); + } + + if (current.fontWeight !== SVG_DEFAULTS.fontWeight) { + current.tspan.setAttributeNS(null, "font-weight", current.fontWeight); + } + + const fillStrokeMode = current.textRenderingMode & _util.TextRenderingMode.FILL_STROKE_MASK; + + if (fillStrokeMode === _util.TextRenderingMode.FILL || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) { + if (current.fillColor !== SVG_DEFAULTS.fillColor) { + current.tspan.setAttributeNS(null, "fill", current.fillColor); + } + + if (current.fillAlpha < 1) { + current.tspan.setAttributeNS(null, "fill-opacity", current.fillAlpha); + } + } else if (current.textRenderingMode === _util.TextRenderingMode.ADD_TO_PATH) { + current.tspan.setAttributeNS(null, "fill", "transparent"); + } else { + current.tspan.setAttributeNS(null, "fill", "none"); + } + + if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) { + const lineWidthScale = 1 / (current.textMatrixScale || 1); + + this._setStrokeAttributes(current.tspan, lineWidthScale); + } + + let textMatrix = current.textMatrix; + + if (current.textRise !== 0) { + textMatrix = textMatrix.slice(); + textMatrix[5] += current.textRise; + } + + current.txtElement.setAttributeNS(null, "transform", `${pm(textMatrix)} scale(${pf(textHScale)}, -1)`); + current.txtElement.setAttributeNS(XML_NS, "xml:space", "preserve"); + current.txtElement.append(current.tspan); + current.txtgrp.append(current.txtElement); + + this._ensureTransformGroup().append(current.txtElement); + } + + setLeadingMoveText(x, y) { + this.setLeading(-y); + this.moveText(x, y); + } + + addFontStyle(fontObj) { + if (!fontObj.data) { + throw new Error("addFontStyle: No font data available, " + 'ensure that the "fontExtraProperties" API parameter is set.'); + } + + if (!this.cssStyle) { + this.cssStyle = this.svgFactory.createElement("svg:style"); + this.cssStyle.setAttributeNS(null, "type", "text/css"); + this.defs.append(this.cssStyle); + } + + const url = createObjectURL(fontObj.data, fontObj.mimetype, this.forceDataSchema); + this.cssStyle.textContent += `@font-face { font-family: "${fontObj.loadedName}";` + ` src: url(${url}); }\n`; + } + + setFont(details) { + const current = this.current; + const fontObj = this.commonObjs.get(details[0]); + let size = details[1]; + current.font = fontObj; + + if (this.embedFonts && !fontObj.missingFile && !this.embeddedFonts[fontObj.loadedName]) { + this.addFontStyle(fontObj); + this.embeddedFonts[fontObj.loadedName] = fontObj; + } + + current.fontMatrix = fontObj.fontMatrix || _util.FONT_IDENTITY_MATRIX; + let bold = "normal"; + + if (fontObj.black) { + bold = "900"; + } else if (fontObj.bold) { + bold = "bold"; + } + + const italic = fontObj.italic ? "italic" : "normal"; + + if (size < 0) { + size = -size; + current.fontDirection = -1; + } else { + current.fontDirection = 1; + } + + current.fontSize = size; + current.fontFamily = fontObj.loadedName; + current.fontWeight = bold; + current.fontStyle = italic; + current.tspan = this.svgFactory.createElement("svg:tspan"); + current.tspan.setAttributeNS(null, "y", pf(-current.y)); + current.xcoords = []; + current.ycoords = []; + } + + endText() { + var _current$txtElement; + + const current = this.current; + + if (current.textRenderingMode & _util.TextRenderingMode.ADD_TO_PATH_FLAG && (_current$txtElement = current.txtElement) !== null && _current$txtElement !== void 0 && _current$txtElement.hasChildNodes()) { + current.element = current.txtElement; + this.clip("nonzero"); + this.endPath(); + } + } + + setLineWidth(width) { + if (width > 0) { + this.current.lineWidth = width; + } + } + + setLineCap(style) { + this.current.lineCap = LINE_CAP_STYLES[style]; + } + + setLineJoin(style) { + this.current.lineJoin = LINE_JOIN_STYLES[style]; + } + + setMiterLimit(limit) { + this.current.miterLimit = limit; + } + + setStrokeAlpha(strokeAlpha) { + this.current.strokeAlpha = strokeAlpha; + } + + setStrokeRGBColor(r, g, b) { + this.current.strokeColor = _util.Util.makeHexColor(r, g, b); + } + + setFillAlpha(fillAlpha) { + this.current.fillAlpha = fillAlpha; + } + + setFillRGBColor(r, g, b) { + this.current.fillColor = _util.Util.makeHexColor(r, g, b); + this.current.tspan = this.svgFactory.createElement("svg:tspan"); + this.current.xcoords = []; + this.current.ycoords = []; + } + + setStrokeColorN(args) { + this.current.strokeColor = this._makeColorN_Pattern(args); + } + + setFillColorN(args) { + this.current.fillColor = this._makeColorN_Pattern(args); + } + + shadingFill(args) { + const width = this.viewport.width; + const height = this.viewport.height; + + const inv = _util.Util.inverseTransform(this.transformMatrix); + + const bl = _util.Util.applyTransform([0, 0], inv); + + const br = _util.Util.applyTransform([0, height], inv); + + const ul = _util.Util.applyTransform([width, 0], inv); + + const ur = _util.Util.applyTransform([width, height], inv); + + const x0 = Math.min(bl[0], br[0], ul[0], ur[0]); + const y0 = Math.min(bl[1], br[1], ul[1], ur[1]); + const x1 = Math.max(bl[0], br[0], ul[0], ur[0]); + const y1 = Math.max(bl[1], br[1], ul[1], ur[1]); + const rect = this.svgFactory.createElement("svg:rect"); + rect.setAttributeNS(null, "x", x0); + rect.setAttributeNS(null, "y", y0); + rect.setAttributeNS(null, "width", x1 - x0); + rect.setAttributeNS(null, "height", y1 - y0); + rect.setAttributeNS(null, "fill", this._makeShadingPattern(args)); + + if (this.current.fillAlpha < 1) { + rect.setAttributeNS(null, "fill-opacity", this.current.fillAlpha); + } + + this._ensureTransformGroup().append(rect); + } + + _makeColorN_Pattern(args) { + if (args[0] === "TilingPattern") { + return this._makeTilingPattern(args); + } + + return this._makeShadingPattern(args); + } + + _makeTilingPattern(args) { + const color = args[1]; + const operatorList = args[2]; + const matrix = args[3] || _util.IDENTITY_MATRIX; + const [x0, y0, x1, y1] = args[4]; + const xstep = args[5]; + const ystep = args[6]; + const paintType = args[7]; + const tilingId = `shading${shadingCount++}`; + + const [tx0, ty0, tx1, ty1] = _util.Util.normalizeRect([..._util.Util.applyTransform([x0, y0], matrix), ..._util.Util.applyTransform([x1, y1], matrix)]); + + const [xscale, yscale] = _util.Util.singularValueDecompose2dScale(matrix); + + const txstep = xstep * xscale; + const tystep = ystep * yscale; + const tiling = this.svgFactory.createElement("svg:pattern"); + tiling.setAttributeNS(null, "id", tilingId); + tiling.setAttributeNS(null, "patternUnits", "userSpaceOnUse"); + tiling.setAttributeNS(null, "width", txstep); + tiling.setAttributeNS(null, "height", tystep); + tiling.setAttributeNS(null, "x", `${tx0}`); + tiling.setAttributeNS(null, "y", `${ty0}`); + const svg = this.svg; + const transformMatrix = this.transformMatrix; + const fillColor = this.current.fillColor; + const strokeColor = this.current.strokeColor; + const bbox = this.svgFactory.create(tx1 - tx0, ty1 - ty0); + this.svg = bbox; + this.transformMatrix = matrix; + + if (paintType === 2) { + const cssColor = _util.Util.makeHexColor(...color); + + this.current.fillColor = cssColor; + this.current.strokeColor = cssColor; + } + + this.executeOpTree(this.convertOpList(operatorList)); + this.svg = svg; + this.transformMatrix = transformMatrix; + this.current.fillColor = fillColor; + this.current.strokeColor = strokeColor; + tiling.append(bbox.childNodes[0]); + this.defs.append(tiling); + return `url(#${tilingId})`; + } + + _makeShadingPattern(args) { + if (typeof args === "string") { + args = this.objs.get(args); + } + + switch (args[0]) { + case "RadialAxial": + const shadingId = `shading${shadingCount++}`; + const colorStops = args[3]; + let gradient; + + switch (args[1]) { + case "axial": + const point0 = args[4]; + const point1 = args[5]; + gradient = this.svgFactory.createElement("svg:linearGradient"); + gradient.setAttributeNS(null, "id", shadingId); + gradient.setAttributeNS(null, "gradientUnits", "userSpaceOnUse"); + gradient.setAttributeNS(null, "x1", point0[0]); + gradient.setAttributeNS(null, "y1", point0[1]); + gradient.setAttributeNS(null, "x2", point1[0]); + gradient.setAttributeNS(null, "y2", point1[1]); + break; + + case "radial": + const focalPoint = args[4]; + const circlePoint = args[5]; + const focalRadius = args[6]; + const circleRadius = args[7]; + gradient = this.svgFactory.createElement("svg:radialGradient"); + gradient.setAttributeNS(null, "id", shadingId); + gradient.setAttributeNS(null, "gradientUnits", "userSpaceOnUse"); + gradient.setAttributeNS(null, "cx", circlePoint[0]); + gradient.setAttributeNS(null, "cy", circlePoint[1]); + gradient.setAttributeNS(null, "r", circleRadius); + gradient.setAttributeNS(null, "fx", focalPoint[0]); + gradient.setAttributeNS(null, "fy", focalPoint[1]); + gradient.setAttributeNS(null, "fr", focalRadius); + break; + + default: + throw new Error(`Unknown RadialAxial type: ${args[1]}`); + } + + for (const colorStop of colorStops) { + const stop = this.svgFactory.createElement("svg:stop"); + stop.setAttributeNS(null, "offset", colorStop[0]); + stop.setAttributeNS(null, "stop-color", colorStop[1]); + gradient.append(stop); + } + + this.defs.append(gradient); + return `url(#${shadingId})`; + + case "Mesh": + (0, _util.warn)("Unimplemented pattern Mesh"); + return null; + + case "Dummy": + return "hotpink"; + + default: + throw new Error(`Unknown IR type: ${args[0]}`); + } + } + + setDash(dashArray, dashPhase) { + this.current.dashArray = dashArray; + this.current.dashPhase = dashPhase; + } + + constructPath(ops, args) { + const current = this.current; + let x = current.x, + y = current.y; + let d = []; + let j = 0; + + for (const op of ops) { + switch (op | 0) { + case _util.OPS.rectangle: + x = args[j++]; + y = args[j++]; + const width = args[j++]; + const height = args[j++]; + const xw = x + width; + const yh = y + height; + d.push("M", pf(x), pf(y), "L", pf(xw), pf(y), "L", pf(xw), pf(yh), "L", pf(x), pf(yh), "Z"); + break; + + case _util.OPS.moveTo: + x = args[j++]; + y = args[j++]; + d.push("M", pf(x), pf(y)); + break; + + case _util.OPS.lineTo: + x = args[j++]; + y = args[j++]; + d.push("L", pf(x), pf(y)); + break; + + case _util.OPS.curveTo: + x = args[j + 4]; + y = args[j + 5]; + d.push("C", pf(args[j]), pf(args[j + 1]), pf(args[j + 2]), pf(args[j + 3]), pf(x), pf(y)); + j += 6; + break; + + case _util.OPS.curveTo2: + d.push("C", pf(x), pf(y), pf(args[j]), pf(args[j + 1]), pf(args[j + 2]), pf(args[j + 3])); + x = args[j + 2]; + y = args[j + 3]; + j += 4; + break; + + case _util.OPS.curveTo3: + x = args[j + 2]; + y = args[j + 3]; + d.push("C", pf(args[j]), pf(args[j + 1]), pf(x), pf(y), pf(x), pf(y)); + j += 4; + break; + + case _util.OPS.closePath: + d.push("Z"); + break; + } + } + + d = d.join(" "); + + if (current.path && ops.length > 0 && ops[0] !== _util.OPS.rectangle && ops[0] !== _util.OPS.moveTo) { + d = current.path.getAttributeNS(null, "d") + d; + } else { + current.path = this.svgFactory.createElement("svg:path"); + + this._ensureTransformGroup().append(current.path); + } + + current.path.setAttributeNS(null, "d", d); + current.path.setAttributeNS(null, "fill", "none"); + current.element = current.path; + current.setCurrentPoint(x, y); + } + + endPath() { + const current = this.current; + current.path = null; + + if (!this.pendingClip) { + return; + } + + if (!current.element) { + this.pendingClip = null; + return; + } + + const clipId = `clippath${clipCount++}`; + const clipPath = this.svgFactory.createElement("svg:clipPath"); + clipPath.setAttributeNS(null, "id", clipId); + clipPath.setAttributeNS(null, "transform", pm(this.transformMatrix)); + const clipElement = current.element.cloneNode(true); + + if (this.pendingClip === "evenodd") { + clipElement.setAttributeNS(null, "clip-rule", "evenodd"); + } else { + clipElement.setAttributeNS(null, "clip-rule", "nonzero"); + } + + this.pendingClip = null; + clipPath.append(clipElement); + this.defs.append(clipPath); + + if (current.activeClipUrl) { + current.clipGroup = null; + + for (const prev of this.extraStack) { + prev.clipGroup = null; + } + + clipPath.setAttributeNS(null, "clip-path", current.activeClipUrl); + } + + current.activeClipUrl = `url(#${clipId})`; + this.tgrp = null; + } + + clip(type) { + this.pendingClip = type; + } + + closePath() { + const current = this.current; + + if (current.path) { + const d = `${current.path.getAttributeNS(null, "d")}Z`; + current.path.setAttributeNS(null, "d", d); + } + } + + setLeading(leading) { + this.current.leading = -leading; + } + + setTextRise(textRise) { + this.current.textRise = textRise; + } + + setTextRenderingMode(textRenderingMode) { + this.current.textRenderingMode = textRenderingMode; + } + + setHScale(scale) { + this.current.textHScale = scale / 100; + } + + setRenderingIntent(intent) {} + + setFlatness(flatness) {} + + setGState(states) { + for (const [key, value] of states) { + switch (key) { + case "LW": + this.setLineWidth(value); + break; + + case "LC": + this.setLineCap(value); + break; + + case "LJ": + this.setLineJoin(value); + break; + + case "ML": + this.setMiterLimit(value); + break; + + case "D": + this.setDash(value[0], value[1]); + break; + + case "RI": + this.setRenderingIntent(value); + break; + + case "FL": + this.setFlatness(value); + break; + + case "Font": + this.setFont(value); + break; + + case "CA": + this.setStrokeAlpha(value); + break; + + case "ca": + this.setFillAlpha(value); + break; + + default: + (0, _util.warn)(`Unimplemented graphic state operator ${key}`); + break; + } + } + } + + fill() { + const current = this.current; + + if (current.element) { + current.element.setAttributeNS(null, "fill", current.fillColor); + current.element.setAttributeNS(null, "fill-opacity", current.fillAlpha); + this.endPath(); + } + } + + stroke() { + const current = this.current; + + if (current.element) { + this._setStrokeAttributes(current.element); + + current.element.setAttributeNS(null, "fill", "none"); + this.endPath(); + } + } + + _setStrokeAttributes(element) { + let lineWidthScale = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1; + const current = this.current; + let dashArray = current.dashArray; + + if (lineWidthScale !== 1 && dashArray.length > 0) { + dashArray = dashArray.map(function (value) { + return lineWidthScale * value; + }); + } + + element.setAttributeNS(null, "stroke", current.strokeColor); + element.setAttributeNS(null, "stroke-opacity", current.strokeAlpha); + element.setAttributeNS(null, "stroke-miterlimit", pf(current.miterLimit)); + element.setAttributeNS(null, "stroke-linecap", current.lineCap); + element.setAttributeNS(null, "stroke-linejoin", current.lineJoin); + element.setAttributeNS(null, "stroke-width", pf(lineWidthScale * current.lineWidth) + "px"); + element.setAttributeNS(null, "stroke-dasharray", dashArray.map(pf).join(" ")); + element.setAttributeNS(null, "stroke-dashoffset", pf(lineWidthScale * current.dashPhase) + "px"); + } + + eoFill() { + if (this.current.element) { + this.current.element.setAttributeNS(null, "fill-rule", "evenodd"); + } + + this.fill(); + } + + fillStroke() { + this.stroke(); + this.fill(); + } + + eoFillStroke() { + if (this.current.element) { + this.current.element.setAttributeNS(null, "fill-rule", "evenodd"); + } + + this.fillStroke(); + } + + closeStroke() { + this.closePath(); + this.stroke(); + } + + closeFillStroke() { + this.closePath(); + this.fillStroke(); + } + + closeEOFillStroke() { + this.closePath(); + this.eoFillStroke(); + } + + paintSolidColorImageMask() { + const rect = this.svgFactory.createElement("svg:rect"); + rect.setAttributeNS(null, "x", "0"); + rect.setAttributeNS(null, "y", "0"); + rect.setAttributeNS(null, "width", "1px"); + rect.setAttributeNS(null, "height", "1px"); + rect.setAttributeNS(null, "fill", this.current.fillColor); + + this._ensureTransformGroup().append(rect); + } + + paintImageXObject(objId) { + const imgData = objId.startsWith("g_") ? this.commonObjs.get(objId) : this.objs.get(objId); + + if (!imgData) { + (0, _util.warn)(`Dependent image with object ID ${objId} is not ready yet`); + return; + } + + this.paintInlineImageXObject(imgData); + } + + paintInlineImageXObject(imgData, mask) { + const width = imgData.width; + const height = imgData.height; + const imgSrc = convertImgDataToPng(imgData, this.forceDataSchema, !!mask); + const cliprect = this.svgFactory.createElement("svg:rect"); + cliprect.setAttributeNS(null, "x", "0"); + cliprect.setAttributeNS(null, "y", "0"); + cliprect.setAttributeNS(null, "width", pf(width)); + cliprect.setAttributeNS(null, "height", pf(height)); + this.current.element = cliprect; + this.clip("nonzero"); + const imgEl = this.svgFactory.createElement("svg:image"); + imgEl.setAttributeNS(XLINK_NS, "xlink:href", imgSrc); + imgEl.setAttributeNS(null, "x", "0"); + imgEl.setAttributeNS(null, "y", pf(-height)); + imgEl.setAttributeNS(null, "width", pf(width) + "px"); + imgEl.setAttributeNS(null, "height", pf(height) + "px"); + imgEl.setAttributeNS(null, "transform", `scale(${pf(1 / width)} ${pf(-1 / height)})`); + + if (mask) { + mask.append(imgEl); + } else { + this._ensureTransformGroup().append(imgEl); + } + } + + paintImageMaskXObject(imgData) { + const current = this.current; + const width = imgData.width; + const height = imgData.height; + const fillColor = current.fillColor; + current.maskId = `mask${maskCount++}`; + const mask = this.svgFactory.createElement("svg:mask"); + mask.setAttributeNS(null, "id", current.maskId); + const rect = this.svgFactory.createElement("svg:rect"); + rect.setAttributeNS(null, "x", "0"); + rect.setAttributeNS(null, "y", "0"); + rect.setAttributeNS(null, "width", pf(width)); + rect.setAttributeNS(null, "height", pf(height)); + rect.setAttributeNS(null, "fill", fillColor); + rect.setAttributeNS(null, "mask", `url(#${current.maskId})`); + this.defs.append(mask); + + this._ensureTransformGroup().append(rect); + + this.paintInlineImageXObject(imgData, mask); + } + + paintFormXObjectBegin(matrix, bbox) { + if (Array.isArray(matrix) && matrix.length === 6) { + this.transform(matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); + } + + if (bbox) { + const width = bbox[2] - bbox[0]; + const height = bbox[3] - bbox[1]; + const cliprect = this.svgFactory.createElement("svg:rect"); + cliprect.setAttributeNS(null, "x", bbox[0]); + cliprect.setAttributeNS(null, "y", bbox[1]); + cliprect.setAttributeNS(null, "width", pf(width)); + cliprect.setAttributeNS(null, "height", pf(height)); + this.current.element = cliprect; + this.clip("nonzero"); + this.endPath(); + } + } + + paintFormXObjectEnd() {} + + _initialize(viewport) { + const svg = this.svgFactory.create(viewport.width, viewport.height); + const definitions = this.svgFactory.createElement("svg:defs"); + svg.append(definitions); + this.defs = definitions; + const rootGroup = this.svgFactory.createElement("svg:g"); + rootGroup.setAttributeNS(null, "transform", pm(viewport.transform)); + svg.append(rootGroup); + this.svg = rootGroup; + return svg; + } + + _ensureClipGroup() { + if (!this.current.clipGroup) { + const clipGroup = this.svgFactory.createElement("svg:g"); + clipGroup.setAttributeNS(null, "clip-path", this.current.activeClipUrl); + this.svg.append(clipGroup); + this.current.clipGroup = clipGroup; + } + + return this.current.clipGroup; + } + + _ensureTransformGroup() { + if (!this.tgrp) { + this.tgrp = this.svgFactory.createElement("svg:g"); + this.tgrp.setAttributeNS(null, "transform", pm(this.transformMatrix)); + + if (this.current.activeClipUrl) { + this._ensureClipGroup().append(this.tgrp); + } else { + this.svg.append(this.tgrp); + } + } + + return this.tgrp; + } + + }; +} + +/***/ }), +/* 157 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFNodeStream = void 0; + +var _util = __w_pdfjs_require__(1); + +var _network_utils = __w_pdfjs_require__(158); + +; + +const fs = require("fs"); + +const http = require("http"); + +const https = require("https"); + +const url = require("url"); + +const fileUriRegex = /^file:\/\/\/[a-zA-Z]:\//; + +function parseUrl(sourceUrl) { + const parsedUrl = url.parse(sourceUrl); + + if (parsedUrl.protocol === "file:" || parsedUrl.host) { + return parsedUrl; + } + + if (/^[a-z]:[/\\]/i.test(sourceUrl)) { + return url.parse(`file:///${sourceUrl}`); + } + + if (!parsedUrl.host) { + parsedUrl.protocol = "file:"; + } + + return parsedUrl; +} + +class PDFNodeStream { + constructor(source) { + this.source = source; + this.url = parseUrl(source.url); + this.isHttp = this.url.protocol === "http:" || this.url.protocol === "https:"; + this.isFsUrl = this.url.protocol === "file:"; + this.httpHeaders = this.isHttp && source.httpHeaders || {}; + this._fullRequestReader = null; + this._rangeRequestReaders = []; + } + + get _progressiveDataLength() { + var _this$_fullRequestRea, _this$_fullRequestRea2; + + return (_this$_fullRequestRea = (_this$_fullRequestRea2 = this._fullRequestReader) === null || _this$_fullRequestRea2 === void 0 ? void 0 : _this$_fullRequestRea2._loaded) !== null && _this$_fullRequestRea !== void 0 ? _this$_fullRequestRea : 0; + } + + getFullReader() { + (0, _util.assert)(!this._fullRequestReader, "PDFNodeStream.getFullReader can only be called once."); + this._fullRequestReader = this.isFsUrl ? new PDFNodeStreamFsFullReader(this) : new PDFNodeStreamFullReader(this); + return this._fullRequestReader; + } + + getRangeReader(start, end) { + if (end <= this._progressiveDataLength) { + return null; + } + + const rangeReader = this.isFsUrl ? new PDFNodeStreamFsRangeReader(this, start, end) : new PDFNodeStreamRangeReader(this, start, end); + + this._rangeRequestReaders.push(rangeReader); + + return rangeReader; + } + + cancelAllRequests(reason) { + if (this._fullRequestReader) { + this._fullRequestReader.cancel(reason); + } + + for (const reader of this._rangeRequestReaders.slice(0)) { + reader.cancel(reason); + } + } + +} + +exports.PDFNodeStream = PDFNodeStream; + +class BaseFullReader { + constructor(stream) { + this._url = stream.url; + this._done = false; + this._storedError = null; + this.onProgress = null; + const source = stream.source; + this._contentLength = source.length; + this._loaded = 0; + this._filename = null; + this._disableRange = source.disableRange || false; + this._rangeChunkSize = source.rangeChunkSize; + + if (!this._rangeChunkSize && !this._disableRange) { + this._disableRange = true; + } + + this._isStreamingSupported = !source.disableStream; + this._isRangeSupported = !source.disableRange; + this._readableStream = null; + this._readCapability = (0, _util.createPromiseCapability)(); + this._headersCapability = (0, _util.createPromiseCapability)(); + } + + get headersReady() { + return this._headersCapability.promise; + } + + get filename() { + return this._filename; + } + + get contentLength() { + return this._contentLength; + } + + get isRangeSupported() { + return this._isRangeSupported; + } + + get isStreamingSupported() { + return this._isStreamingSupported; + } + + async read() { + await this._readCapability.promise; + + if (this._done) { + return { + value: undefined, + done: true + }; + } + + if (this._storedError) { + throw this._storedError; + } + + const chunk = this._readableStream.read(); + + if (chunk === null) { + this._readCapability = (0, _util.createPromiseCapability)(); + return this.read(); + } + + this._loaded += chunk.length; + + if (this.onProgress) { + this.onProgress({ + loaded: this._loaded, + total: this._contentLength + }); + } + + const buffer = new Uint8Array(chunk).buffer; + return { + value: buffer, + done: false + }; + } + + cancel(reason) { + if (!this._readableStream) { + this._error(reason); + + return; + } + + this._readableStream.destroy(reason); + } + + _error(reason) { + this._storedError = reason; + + this._readCapability.resolve(); + } + + _setReadableStream(readableStream) { + this._readableStream = readableStream; + readableStream.on("readable", () => { + this._readCapability.resolve(); + }); + readableStream.on("end", () => { + readableStream.destroy(); + this._done = true; + + this._readCapability.resolve(); + }); + readableStream.on("error", reason => { + this._error(reason); + }); + + if (!this._isStreamingSupported && this._isRangeSupported) { + this._error(new _util.AbortException("streaming is disabled")); + } + + if (this._storedError) { + this._readableStream.destroy(this._storedError); + } + } + +} + +class BaseRangeReader { + constructor(stream) { + this._url = stream.url; + this._done = false; + this._storedError = null; + this.onProgress = null; + this._loaded = 0; + this._readableStream = null; + this._readCapability = (0, _util.createPromiseCapability)(); + const source = stream.source; + this._isStreamingSupported = !source.disableStream; + } + + get isStreamingSupported() { + return this._isStreamingSupported; + } + + async read() { + await this._readCapability.promise; + + if (this._done) { + return { + value: undefined, + done: true + }; + } + + if (this._storedError) { + throw this._storedError; + } + + const chunk = this._readableStream.read(); + + if (chunk === null) { + this._readCapability = (0, _util.createPromiseCapability)(); + return this.read(); + } + + this._loaded += chunk.length; + + if (this.onProgress) { + this.onProgress({ + loaded: this._loaded + }); + } + + const buffer = new Uint8Array(chunk).buffer; + return { + value: buffer, + done: false + }; + } + + cancel(reason) { + if (!this._readableStream) { + this._error(reason); + + return; + } + + this._readableStream.destroy(reason); + } + + _error(reason) { + this._storedError = reason; + + this._readCapability.resolve(); + } + + _setReadableStream(readableStream) { + this._readableStream = readableStream; + readableStream.on("readable", () => { + this._readCapability.resolve(); + }); + readableStream.on("end", () => { + readableStream.destroy(); + this._done = true; + + this._readCapability.resolve(); + }); + readableStream.on("error", reason => { + this._error(reason); + }); + + if (this._storedError) { + this._readableStream.destroy(this._storedError); + } + } + +} + +function createRequestOptions(parsedUrl, headers) { + return { + protocol: parsedUrl.protocol, + auth: parsedUrl.auth, + host: parsedUrl.hostname, + port: parsedUrl.port, + path: parsedUrl.path, + method: "GET", + headers + }; +} + +class PDFNodeStreamFullReader extends BaseFullReader { + constructor(stream) { + super(stream); + + const handleResponse = response => { + if (response.statusCode === 404) { + const error = new _util.MissingPDFException(`Missing PDF "${this._url}".`); + this._storedError = error; + + this._headersCapability.reject(error); + + return; + } + + this._headersCapability.resolve(); + + this._setReadableStream(response); + + const getResponseHeader = name => { + return this._readableStream.headers[name.toLowerCase()]; + }; + + const { + allowRangeRequests, + suggestedLength + } = (0, _network_utils.validateRangeRequestCapabilities)({ + getResponseHeader, + isHttp: stream.isHttp, + rangeChunkSize: this._rangeChunkSize, + disableRange: this._disableRange + }); + this._isRangeSupported = allowRangeRequests; + this._contentLength = suggestedLength || this._contentLength; + this._filename = (0, _network_utils.extractFilenameFromHeader)(getResponseHeader); + }; + + this._request = null; + + if (this._url.protocol === "http:") { + this._request = http.request(createRequestOptions(this._url, stream.httpHeaders), handleResponse); + } else { + this._request = https.request(createRequestOptions(this._url, stream.httpHeaders), handleResponse); + } + + this._request.on("error", reason => { + this._storedError = reason; + + this._headersCapability.reject(reason); + }); + + this._request.end(); + } + +} + +class PDFNodeStreamRangeReader extends BaseRangeReader { + constructor(stream, start, end) { + super(stream); + this._httpHeaders = {}; + + for (const property in stream.httpHeaders) { + const value = stream.httpHeaders[property]; + + if (typeof value === "undefined") { + continue; + } + + this._httpHeaders[property] = value; + } + + this._httpHeaders.Range = `bytes=${start}-${end - 1}`; + + const handleResponse = response => { + if (response.statusCode === 404) { + const error = new _util.MissingPDFException(`Missing PDF "${this._url}".`); + this._storedError = error; + return; + } + + this._setReadableStream(response); + }; + + this._request = null; + + if (this._url.protocol === "http:") { + this._request = http.request(createRequestOptions(this._url, this._httpHeaders), handleResponse); + } else { + this._request = https.request(createRequestOptions(this._url, this._httpHeaders), handleResponse); + } + + this._request.on("error", reason => { + this._storedError = reason; + }); + + this._request.end(); + } + +} + +class PDFNodeStreamFsFullReader extends BaseFullReader { + constructor(stream) { + super(stream); + let path = decodeURIComponent(this._url.path); + + if (fileUriRegex.test(this._url.href)) { + path = path.replace(/^\//, ""); + } + + fs.lstat(path, (error, stat) => { + if (error) { + if (error.code === "ENOENT") { + error = new _util.MissingPDFException(`Missing PDF "${path}".`); + } + + this._storedError = error; + + this._headersCapability.reject(error); + + return; + } + + this._contentLength = stat.size; + + this._setReadableStream(fs.createReadStream(path)); + + this._headersCapability.resolve(); + }); + } + +} + +class PDFNodeStreamFsRangeReader extends BaseRangeReader { + constructor(stream, start, end) { + super(stream); + let path = decodeURIComponent(this._url.path); + + if (fileUriRegex.test(this._url.href)) { + path = path.replace(/^\//, ""); + } + + this._setReadableStream(fs.createReadStream(path, { + start, + end: end - 1 + })); + } + +} + +/***/ }), +/* 158 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.createResponseStatusError = createResponseStatusError; +exports.extractFilenameFromHeader = extractFilenameFromHeader; +exports.validateRangeRequestCapabilities = validateRangeRequestCapabilities; +exports.validateResponseStatus = validateResponseStatus; + +var _util = __w_pdfjs_require__(1); + +var _content_disposition = __w_pdfjs_require__(159); + +var _display_utils = __w_pdfjs_require__(133); + +function validateRangeRequestCapabilities(_ref) { + let { + getResponseHeader, + isHttp, + rangeChunkSize, + disableRange + } = _ref; + const returnValues = { + allowRangeRequests: false, + suggestedLength: undefined + }; + const length = parseInt(getResponseHeader("Content-Length"), 10); + + if (!Number.isInteger(length)) { + return returnValues; + } + + returnValues.suggestedLength = length; + + if (length <= 2 * rangeChunkSize) { + return returnValues; + } + + if (disableRange || !isHttp) { + return returnValues; + } + + if (getResponseHeader("Accept-Ranges") !== "bytes") { + return returnValues; + } + + const contentEncoding = getResponseHeader("Content-Encoding") || "identity"; + + if (contentEncoding !== "identity") { + return returnValues; + } + + returnValues.allowRangeRequests = true; + return returnValues; +} + +function extractFilenameFromHeader(getResponseHeader) { + const contentDisposition = getResponseHeader("Content-Disposition"); + + if (contentDisposition) { + let filename = (0, _content_disposition.getFilenameFromContentDispositionHeader)(contentDisposition); + + if (filename.includes("%")) { + try { + filename = decodeURIComponent(filename); + } catch (ex) {} + } + + if ((0, _display_utils.isPdfFile)(filename)) { + return filename; + } + } + + return null; +} + +function createResponseStatusError(status, url) { + if (status === 404 || status === 0 && url.startsWith("file:")) { + return new _util.MissingPDFException('Missing PDF "' + url + '".'); + } + + return new _util.UnexpectedResponseException(`Unexpected server response (${status}) while retrieving PDF "${url}".`, status); +} + +function validateResponseStatus(status) { + return status === 200 || status === 206; +} + +/***/ }), +/* 159 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.getFilenameFromContentDispositionHeader = getFilenameFromContentDispositionHeader; + +var _util = __w_pdfjs_require__(1); + +function getFilenameFromContentDispositionHeader(contentDisposition) { + let needsEncodingFixup = true; + let tmp = toParamRegExp("filename\\*", "i").exec(contentDisposition); + + if (tmp) { + tmp = tmp[1]; + let filename = rfc2616unquote(tmp); + filename = unescape(filename); + filename = rfc5987decode(filename); + filename = rfc2047decode(filename); + return fixupEncoding(filename); + } + + tmp = rfc2231getparam(contentDisposition); + + if (tmp) { + const filename = rfc2047decode(tmp); + return fixupEncoding(filename); + } + + tmp = toParamRegExp("filename", "i").exec(contentDisposition); + + if (tmp) { + tmp = tmp[1]; + let filename = rfc2616unquote(tmp); + filename = rfc2047decode(filename); + return fixupEncoding(filename); + } + + function toParamRegExp(attributePattern, flags) { + return new RegExp("(?:^|;)\\s*" + attributePattern + "\\s*=\\s*" + "(" + '[^";\\s][^;\\s]*' + "|" + '"(?:[^"\\\\]|\\\\"?)+"?' + ")", flags); + } + + function textdecode(encoding, value) { + if (encoding) { + if (!/^[\x00-\xFF]+$/.test(value)) { + return value; + } + + try { + const decoder = new TextDecoder(encoding, { + fatal: true + }); + const buffer = (0, _util.stringToBytes)(value); + value = decoder.decode(buffer); + needsEncodingFixup = false; + } catch (e) {} + } + + return value; + } + + function fixupEncoding(value) { + if (needsEncodingFixup && /[\x80-\xff]/.test(value)) { + value = textdecode("utf-8", value); + + if (needsEncodingFixup) { + value = textdecode("iso-8859-1", value); + } + } + + return value; + } + + function rfc2231getparam(contentDispositionStr) { + const matches = []; + let match; + const iter = toParamRegExp("filename\\*((?!0\\d)\\d+)(\\*?)", "ig"); + + while ((match = iter.exec(contentDispositionStr)) !== null) { + let [, n, quot, part] = match; + n = parseInt(n, 10); + + if (n in matches) { + if (n === 0) { + break; + } + + continue; + } + + matches[n] = [quot, part]; + } + + const parts = []; + + for (let n = 0; n < matches.length; ++n) { + if (!(n in matches)) { + break; + } + + let [quot, part] = matches[n]; + part = rfc2616unquote(part); + + if (quot) { + part = unescape(part); + + if (n === 0) { + part = rfc5987decode(part); + } + } + + parts.push(part); + } + + return parts.join(""); + } + + function rfc2616unquote(value) { + if (value.startsWith('"')) { + const parts = value.slice(1).split('\\"'); + + for (let i = 0; i < parts.length; ++i) { + const quotindex = parts[i].indexOf('"'); + + if (quotindex !== -1) { + parts[i] = parts[i].slice(0, quotindex); + parts.length = i + 1; + } + + parts[i] = parts[i].replace(/\\(.)/g, "$1"); + } + + value = parts.join('"'); + } + + return value; + } + + function rfc5987decode(extvalue) { + const encodingend = extvalue.indexOf("'"); + + if (encodingend === -1) { + return extvalue; + } + + const encoding = extvalue.slice(0, encodingend); + const langvalue = extvalue.slice(encodingend + 1); + const value = langvalue.replace(/^[^']*'/, ""); + return textdecode(encoding, value); + } + + function rfc2047decode(value) { + if (!value.startsWith("=?") || /[\x00-\x19\x80-\xff]/.test(value)) { + return value; + } + + return value.replace(/=\?([\w-]*)\?([QqBb])\?((?:[^?]|\?(?!=))*)\?=/g, function (matches, charset, encoding, text) { + if (encoding === "q" || encoding === "Q") { + text = text.replace(/_/g, " "); + text = text.replace(/=([0-9a-fA-F]{2})/g, function (match, hex) { + return String.fromCharCode(parseInt(hex, 16)); + }); + return textdecode(charset, text); + } + + try { + text = atob(text); + } catch (e) {} + + return textdecode(charset, text); + }); + } + + return ""; +} + +/***/ }), +/* 160 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFNetworkStream = void 0; + +var _util = __w_pdfjs_require__(1); + +var _network_utils = __w_pdfjs_require__(158); + +; +const OK_RESPONSE = 200; +const PARTIAL_CONTENT_RESPONSE = 206; + +function getArrayBuffer(xhr) { + const data = xhr.response; + + if (typeof data !== "string") { + return data; + } + + const array = (0, _util.stringToBytes)(data); + return array.buffer; +} + +class NetworkManager { + constructor(url) { + let args = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + this.url = url; + this.isHttp = /^https?:/i.test(url); + this.httpHeaders = this.isHttp && args.httpHeaders || Object.create(null); + this.withCredentials = args.withCredentials || false; + + this.getXhr = args.getXhr || function NetworkManager_getXhr() { + return new XMLHttpRequest(); + }; + + this.currXhrId = 0; + this.pendingRequests = Object.create(null); + } + + requestRange(begin, end, listeners) { + const args = { + begin, + end + }; + + for (const prop in listeners) { + args[prop] = listeners[prop]; + } + + return this.request(args); + } + + requestFull(listeners) { + return this.request(listeners); + } + + request(args) { + const xhr = this.getXhr(); + const xhrId = this.currXhrId++; + const pendingRequest = this.pendingRequests[xhrId] = { + xhr + }; + xhr.open("GET", this.url); + xhr.withCredentials = this.withCredentials; + + for (const property in this.httpHeaders) { + const value = this.httpHeaders[property]; + + if (typeof value === "undefined") { + continue; + } + + xhr.setRequestHeader(property, value); + } + + if (this.isHttp && "begin" in args && "end" in args) { + xhr.setRequestHeader("Range", `bytes=${args.begin}-${args.end - 1}`); + pendingRequest.expectedStatus = PARTIAL_CONTENT_RESPONSE; + } else { + pendingRequest.expectedStatus = OK_RESPONSE; + } + + xhr.responseType = "arraybuffer"; + + if (args.onError) { + xhr.onerror = function (evt) { + args.onError(xhr.status); + }; + } + + xhr.onreadystatechange = this.onStateChange.bind(this, xhrId); + xhr.onprogress = this.onProgress.bind(this, xhrId); + pendingRequest.onHeadersReceived = args.onHeadersReceived; + pendingRequest.onDone = args.onDone; + pendingRequest.onError = args.onError; + pendingRequest.onProgress = args.onProgress; + xhr.send(null); + return xhrId; + } + + onProgress(xhrId, evt) { + var _pendingRequest$onPro; + + const pendingRequest = this.pendingRequests[xhrId]; + + if (!pendingRequest) { + return; + } + + (_pendingRequest$onPro = pendingRequest.onProgress) === null || _pendingRequest$onPro === void 0 ? void 0 : _pendingRequest$onPro.call(pendingRequest, evt); + } + + onStateChange(xhrId, evt) { + const pendingRequest = this.pendingRequests[xhrId]; + + if (!pendingRequest) { + return; + } + + const xhr = pendingRequest.xhr; + + if (xhr.readyState >= 2 && pendingRequest.onHeadersReceived) { + pendingRequest.onHeadersReceived(); + delete pendingRequest.onHeadersReceived; + } + + if (xhr.readyState !== 4) { + return; + } + + if (!(xhrId in this.pendingRequests)) { + return; + } + + delete this.pendingRequests[xhrId]; + + if (xhr.status === 0 && this.isHttp) { + var _pendingRequest$onErr; + + (_pendingRequest$onErr = pendingRequest.onError) === null || _pendingRequest$onErr === void 0 ? void 0 : _pendingRequest$onErr.call(pendingRequest, xhr.status); + return; + } + + const xhrStatus = xhr.status || OK_RESPONSE; + const ok_response_on_range_request = xhrStatus === OK_RESPONSE && pendingRequest.expectedStatus === PARTIAL_CONTENT_RESPONSE; + + if (!ok_response_on_range_request && xhrStatus !== pendingRequest.expectedStatus) { + var _pendingRequest$onErr2; + + (_pendingRequest$onErr2 = pendingRequest.onError) === null || _pendingRequest$onErr2 === void 0 ? void 0 : _pendingRequest$onErr2.call(pendingRequest, xhr.status); + return; + } + + const chunk = getArrayBuffer(xhr); + + if (xhrStatus === PARTIAL_CONTENT_RESPONSE) { + const rangeHeader = xhr.getResponseHeader("Content-Range"); + const matches = /bytes (\d+)-(\d+)\/(\d+)/.exec(rangeHeader); + pendingRequest.onDone({ + begin: parseInt(matches[1], 10), + chunk + }); + } else if (chunk) { + pendingRequest.onDone({ + begin: 0, + chunk + }); + } else { + var _pendingRequest$onErr3; + + (_pendingRequest$onErr3 = pendingRequest.onError) === null || _pendingRequest$onErr3 === void 0 ? void 0 : _pendingRequest$onErr3.call(pendingRequest, xhr.status); + } + } + + getRequestXhr(xhrId) { + return this.pendingRequests[xhrId].xhr; + } + + isPendingRequest(xhrId) { + return xhrId in this.pendingRequests; + } + + abortRequest(xhrId) { + const xhr = this.pendingRequests[xhrId].xhr; + delete this.pendingRequests[xhrId]; + xhr.abort(); + } + +} + +class PDFNetworkStream { + constructor(source) { + this._source = source; + this._manager = new NetworkManager(source.url, { + httpHeaders: source.httpHeaders, + withCredentials: source.withCredentials + }); + this._rangeChunkSize = source.rangeChunkSize; + this._fullRequestReader = null; + this._rangeRequestReaders = []; + } + + _onRangeRequestReaderClosed(reader) { + const i = this._rangeRequestReaders.indexOf(reader); + + if (i >= 0) { + this._rangeRequestReaders.splice(i, 1); + } + } + + getFullReader() { + (0, _util.assert)(!this._fullRequestReader, "PDFNetworkStream.getFullReader can only be called once."); + this._fullRequestReader = new PDFNetworkStreamFullRequestReader(this._manager, this._source); + return this._fullRequestReader; + } + + getRangeReader(begin, end) { + const reader = new PDFNetworkStreamRangeRequestReader(this._manager, begin, end); + reader.onClosed = this._onRangeRequestReaderClosed.bind(this); + + this._rangeRequestReaders.push(reader); + + return reader; + } + + cancelAllRequests(reason) { + var _this$_fullRequestRea; + + (_this$_fullRequestRea = this._fullRequestReader) === null || _this$_fullRequestRea === void 0 ? void 0 : _this$_fullRequestRea.cancel(reason); + + for (const reader of this._rangeRequestReaders.slice(0)) { + reader.cancel(reason); + } + } + +} + +exports.PDFNetworkStream = PDFNetworkStream; + +class PDFNetworkStreamFullRequestReader { + constructor(manager, source) { + this._manager = manager; + const args = { + onHeadersReceived: this._onHeadersReceived.bind(this), + onDone: this._onDone.bind(this), + onError: this._onError.bind(this), + onProgress: this._onProgress.bind(this) + }; + this._url = source.url; + this._fullRequestId = manager.requestFull(args); + this._headersReceivedCapability = (0, _util.createPromiseCapability)(); + this._disableRange = source.disableRange || false; + this._contentLength = source.length; + this._rangeChunkSize = source.rangeChunkSize; + + if (!this._rangeChunkSize && !this._disableRange) { + this._disableRange = true; + } + + this._isStreamingSupported = false; + this._isRangeSupported = false; + this._cachedChunks = []; + this._requests = []; + this._done = false; + this._storedError = undefined; + this._filename = null; + this.onProgress = null; + } + + _onHeadersReceived() { + const fullRequestXhrId = this._fullRequestId; + + const fullRequestXhr = this._manager.getRequestXhr(fullRequestXhrId); + + const getResponseHeader = name => { + return fullRequestXhr.getResponseHeader(name); + }; + + const { + allowRangeRequests, + suggestedLength + } = (0, _network_utils.validateRangeRequestCapabilities)({ + getResponseHeader, + isHttp: this._manager.isHttp, + rangeChunkSize: this._rangeChunkSize, + disableRange: this._disableRange + }); + + if (allowRangeRequests) { + this._isRangeSupported = true; + } + + this._contentLength = suggestedLength || this._contentLength; + this._filename = (0, _network_utils.extractFilenameFromHeader)(getResponseHeader); + + if (this._isRangeSupported) { + this._manager.abortRequest(fullRequestXhrId); + } + + this._headersReceivedCapability.resolve(); + } + + _onDone(data) { + if (data) { + if (this._requests.length > 0) { + const requestCapability = this._requests.shift(); + + requestCapability.resolve({ + value: data.chunk, + done: false + }); + } else { + this._cachedChunks.push(data.chunk); + } + } + + this._done = true; + + if (this._cachedChunks.length > 0) { + return; + } + + for (const requestCapability of this._requests) { + requestCapability.resolve({ + value: undefined, + done: true + }); + } + + this._requests.length = 0; + } + + _onError(status) { + this._storedError = (0, _network_utils.createResponseStatusError)(status, this._url); + + this._headersReceivedCapability.reject(this._storedError); + + for (const requestCapability of this._requests) { + requestCapability.reject(this._storedError); + } + + this._requests.length = 0; + this._cachedChunks.length = 0; + } + + _onProgress(evt) { + var _this$onProgress; + + (_this$onProgress = this.onProgress) === null || _this$onProgress === void 0 ? void 0 : _this$onProgress.call(this, { + loaded: evt.loaded, + total: evt.lengthComputable ? evt.total : this._contentLength + }); + } + + get filename() { + return this._filename; + } + + get isRangeSupported() { + return this._isRangeSupported; + } + + get isStreamingSupported() { + return this._isStreamingSupported; + } + + get contentLength() { + return this._contentLength; + } + + get headersReady() { + return this._headersReceivedCapability.promise; + } + + async read() { + if (this._storedError) { + throw this._storedError; + } + + if (this._cachedChunks.length > 0) { + const chunk = this._cachedChunks.shift(); + + return { + value: chunk, + done: false + }; + } + + if (this._done) { + return { + value: undefined, + done: true + }; + } + + const requestCapability = (0, _util.createPromiseCapability)(); + + this._requests.push(requestCapability); + + return requestCapability.promise; + } + + cancel(reason) { + this._done = true; + + this._headersReceivedCapability.reject(reason); + + for (const requestCapability of this._requests) { + requestCapability.resolve({ + value: undefined, + done: true + }); + } + + this._requests.length = 0; + + if (this._manager.isPendingRequest(this._fullRequestId)) { + this._manager.abortRequest(this._fullRequestId); + } + + this._fullRequestReader = null; + } + +} + +class PDFNetworkStreamRangeRequestReader { + constructor(manager, begin, end) { + this._manager = manager; + const args = { + onDone: this._onDone.bind(this), + onError: this._onError.bind(this), + onProgress: this._onProgress.bind(this) + }; + this._url = manager.url; + this._requestId = manager.requestRange(begin, end, args); + this._requests = []; + this._queuedChunk = null; + this._done = false; + this._storedError = undefined; + this.onProgress = null; + this.onClosed = null; + } + + _close() { + var _this$onClosed; + + (_this$onClosed = this.onClosed) === null || _this$onClosed === void 0 ? void 0 : _this$onClosed.call(this, this); + } + + _onDone(data) { + const chunk = data.chunk; + + if (this._requests.length > 0) { + const requestCapability = this._requests.shift(); + + requestCapability.resolve({ + value: chunk, + done: false + }); + } else { + this._queuedChunk = chunk; + } + + this._done = true; + + for (const requestCapability of this._requests) { + requestCapability.resolve({ + value: undefined, + done: true + }); + } + + this._requests.length = 0; + + this._close(); + } + + _onError(status) { + this._storedError = (0, _network_utils.createResponseStatusError)(status, this._url); + + for (const requestCapability of this._requests) { + requestCapability.reject(this._storedError); + } + + this._requests.length = 0; + this._queuedChunk = null; + } + + _onProgress(evt) { + if (!this.isStreamingSupported) { + var _this$onProgress2; + + (_this$onProgress2 = this.onProgress) === null || _this$onProgress2 === void 0 ? void 0 : _this$onProgress2.call(this, { + loaded: evt.loaded + }); + } + } + + get isStreamingSupported() { + return false; + } + + async read() { + if (this._storedError) { + throw this._storedError; + } + + if (this._queuedChunk !== null) { + const chunk = this._queuedChunk; + this._queuedChunk = null; + return { + value: chunk, + done: false + }; + } + + if (this._done) { + return { + value: undefined, + done: true + }; + } + + const requestCapability = (0, _util.createPromiseCapability)(); + + this._requests.push(requestCapability); + + return requestCapability.promise; + } + + cancel(reason) { + this._done = true; + + for (const requestCapability of this._requests) { + requestCapability.resolve({ + value: undefined, + done: true + }); + } + + this._requests.length = 0; + + if (this._manager.isPendingRequest(this._requestId)) { + this._manager.abortRequest(this._requestId); + } + + this._close(); + } + +} + +/***/ }), +/* 161 */ +/***/ ((__unused_webpack_module, exports, __w_pdfjs_require__) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFFetchStream = void 0; + +var _util = __w_pdfjs_require__(1); + +var _network_utils = __w_pdfjs_require__(158); + +; + +function createFetchOptions(headers, withCredentials, abortController) { + return { + method: "GET", + headers, + signal: abortController.signal, + mode: "cors", + credentials: withCredentials ? "include" : "same-origin", + redirect: "follow" + }; +} + +function createHeaders(httpHeaders) { + const headers = new Headers(); + + for (const property in httpHeaders) { + const value = httpHeaders[property]; + + if (typeof value === "undefined") { + continue; + } + + headers.append(property, value); + } + + return headers; +} + +class PDFFetchStream { + constructor(source) { + this.source = source; + this.isHttp = /^https?:/i.test(source.url); + this.httpHeaders = this.isHttp && source.httpHeaders || {}; + this._fullRequestReader = null; + this._rangeRequestReaders = []; + } + + get _progressiveDataLength() { + var _this$_fullRequestRea, _this$_fullRequestRea2; + + return (_this$_fullRequestRea = (_this$_fullRequestRea2 = this._fullRequestReader) === null || _this$_fullRequestRea2 === void 0 ? void 0 : _this$_fullRequestRea2._loaded) !== null && _this$_fullRequestRea !== void 0 ? _this$_fullRequestRea : 0; + } + + getFullReader() { + (0, _util.assert)(!this._fullRequestReader, "PDFFetchStream.getFullReader can only be called once."); + this._fullRequestReader = new PDFFetchStreamReader(this); + return this._fullRequestReader; + } + + getRangeReader(begin, end) { + if (end <= this._progressiveDataLength) { + return null; + } + + const reader = new PDFFetchStreamRangeReader(this, begin, end); + + this._rangeRequestReaders.push(reader); + + return reader; + } + + cancelAllRequests(reason) { + if (this._fullRequestReader) { + this._fullRequestReader.cancel(reason); + } + + for (const reader of this._rangeRequestReaders.slice(0)) { + reader.cancel(reason); + } + } + +} + +exports.PDFFetchStream = PDFFetchStream; + +class PDFFetchStreamReader { + constructor(stream) { + this._stream = stream; + this._reader = null; + this._loaded = 0; + this._filename = null; + const source = stream.source; + this._withCredentials = source.withCredentials || false; + this._contentLength = source.length; + this._headersCapability = (0, _util.createPromiseCapability)(); + this._disableRange = source.disableRange || false; + this._rangeChunkSize = source.rangeChunkSize; + + if (!this._rangeChunkSize && !this._disableRange) { + this._disableRange = true; + } + + this._abortController = new AbortController(); + this._isStreamingSupported = !source.disableStream; + this._isRangeSupported = !source.disableRange; + this._headers = createHeaders(this._stream.httpHeaders); + const url = source.url; + fetch(url, createFetchOptions(this._headers, this._withCredentials, this._abortController)).then(response => { + if (!(0, _network_utils.validateResponseStatus)(response.status)) { + throw (0, _network_utils.createResponseStatusError)(response.status, url); + } + + this._reader = response.body.getReader(); + + this._headersCapability.resolve(); + + const getResponseHeader = name => { + return response.headers.get(name); + }; + + const { + allowRangeRequests, + suggestedLength + } = (0, _network_utils.validateRangeRequestCapabilities)({ + getResponseHeader, + isHttp: this._stream.isHttp, + rangeChunkSize: this._rangeChunkSize, + disableRange: this._disableRange + }); + this._isRangeSupported = allowRangeRequests; + this._contentLength = suggestedLength || this._contentLength; + this._filename = (0, _network_utils.extractFilenameFromHeader)(getResponseHeader); + + if (!this._isStreamingSupported && this._isRangeSupported) { + this.cancel(new _util.AbortException("Streaming is disabled.")); + } + }).catch(this._headersCapability.reject); + this.onProgress = null; + } + + get headersReady() { + return this._headersCapability.promise; + } + + get filename() { + return this._filename; + } + + get contentLength() { + return this._contentLength; + } + + get isRangeSupported() { + return this._isRangeSupported; + } + + get isStreamingSupported() { + return this._isStreamingSupported; + } + + async read() { + await this._headersCapability.promise; + const { + value, + done + } = await this._reader.read(); + + if (done) { + return { + value, + done + }; + } + + this._loaded += value.byteLength; + + if (this.onProgress) { + this.onProgress({ + loaded: this._loaded, + total: this._contentLength + }); + } + + const buffer = new Uint8Array(value).buffer; + return { + value: buffer, + done: false + }; + } + + cancel(reason) { + if (this._reader) { + this._reader.cancel(reason); + } + + this._abortController.abort(); + } + +} + +class PDFFetchStreamRangeReader { + constructor(stream, begin, end) { + this._stream = stream; + this._reader = null; + this._loaded = 0; + const source = stream.source; + this._withCredentials = source.withCredentials || false; + this._readCapability = (0, _util.createPromiseCapability)(); + this._isStreamingSupported = !source.disableStream; + this._abortController = new AbortController(); + this._headers = createHeaders(this._stream.httpHeaders); + + this._headers.append("Range", `bytes=${begin}-${end - 1}`); + + const url = source.url; + fetch(url, createFetchOptions(this._headers, this._withCredentials, this._abortController)).then(response => { + if (!(0, _network_utils.validateResponseStatus)(response.status)) { + throw (0, _network_utils.createResponseStatusError)(response.status, url); + } + + this._readCapability.resolve(); + + this._reader = response.body.getReader(); + }).catch(this._readCapability.reject); + this.onProgress = null; + } + + get isStreamingSupported() { + return this._isStreamingSupported; + } + + async read() { + await this._readCapability.promise; + const { + value, + done + } = await this._reader.read(); + + if (done) { + return { + value, + done + }; + } + + this._loaded += value.byteLength; + + if (this.onProgress) { + this.onProgress({ + loaded: this._loaded + }); + } + + const buffer = new Uint8Array(value).buffer; + return { + value: buffer, + done: false + }; + } + + cancel(reason) { + if (this._reader) { + this._reader.cancel(reason); + } + + this._abortController.abort(); + } + +} + +/***/ }) +/******/ ]); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __w_pdfjs_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __w_pdfjs_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be in strict mode. +(() => { +"use strict"; +var exports = __webpack_exports__; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +Object.defineProperty(exports, "AnnotationEditorLayer", ({ + enumerable: true, + get: function () { + return _annotation_editor_layer.AnnotationEditorLayer; + } +})); +Object.defineProperty(exports, "AnnotationEditorParamsType", ({ + enumerable: true, + get: function () { + return _util.AnnotationEditorParamsType; + } +})); +Object.defineProperty(exports, "AnnotationEditorType", ({ + enumerable: true, + get: function () { + return _util.AnnotationEditorType; + } +})); +Object.defineProperty(exports, "AnnotationEditorUIManager", ({ + enumerable: true, + get: function () { + return _tools.AnnotationEditorUIManager; + } +})); +Object.defineProperty(exports, "AnnotationLayer", ({ + enumerable: true, + get: function () { + return _annotation_layer.AnnotationLayer; + } +})); +Object.defineProperty(exports, "AnnotationMode", ({ + enumerable: true, + get: function () { + return _util.AnnotationMode; + } +})); +Object.defineProperty(exports, "CMapCompressionType", ({ + enumerable: true, + get: function () { + return _util.CMapCompressionType; + } +})); +Object.defineProperty(exports, "GlobalWorkerOptions", ({ + enumerable: true, + get: function () { + return _worker_options.GlobalWorkerOptions; + } +})); +Object.defineProperty(exports, "InvalidPDFException", ({ + enumerable: true, + get: function () { + return _util.InvalidPDFException; + } +})); +Object.defineProperty(exports, "LoopbackPort", ({ + enumerable: true, + get: function () { + return _api.LoopbackPort; + } +})); +Object.defineProperty(exports, "MissingPDFException", ({ + enumerable: true, + get: function () { + return _util.MissingPDFException; + } +})); +Object.defineProperty(exports, "OPS", ({ + enumerable: true, + get: function () { + return _util.OPS; + } +})); +Object.defineProperty(exports, "PDFDataRangeTransport", ({ + enumerable: true, + get: function () { + return _api.PDFDataRangeTransport; + } +})); +Object.defineProperty(exports, "PDFDateString", ({ + enumerable: true, + get: function () { + return _display_utils.PDFDateString; + } +})); +Object.defineProperty(exports, "PDFWorker", ({ + enumerable: true, + get: function () { + return _api.PDFWorker; + } +})); +Object.defineProperty(exports, "PasswordResponses", ({ + enumerable: true, + get: function () { + return _util.PasswordResponses; + } +})); +Object.defineProperty(exports, "PermissionFlag", ({ + enumerable: true, + get: function () { + return _util.PermissionFlag; + } +})); +Object.defineProperty(exports, "PixelsPerInch", ({ + enumerable: true, + get: function () { + return _display_utils.PixelsPerInch; + } +})); +Object.defineProperty(exports, "RenderingCancelledException", ({ + enumerable: true, + get: function () { + return _display_utils.RenderingCancelledException; + } +})); +Object.defineProperty(exports, "SVGGraphics", ({ + enumerable: true, + get: function () { + return _svg.SVGGraphics; + } +})); +Object.defineProperty(exports, "UNSUPPORTED_FEATURES", ({ + enumerable: true, + get: function () { + return _util.UNSUPPORTED_FEATURES; + } +})); +Object.defineProperty(exports, "UnexpectedResponseException", ({ + enumerable: true, + get: function () { + return _util.UnexpectedResponseException; + } +})); +Object.defineProperty(exports, "Util", ({ + enumerable: true, + get: function () { + return _util.Util; + } +})); +Object.defineProperty(exports, "VerbosityLevel", ({ + enumerable: true, + get: function () { + return _util.VerbosityLevel; + } +})); +Object.defineProperty(exports, "XfaLayer", ({ + enumerable: true, + get: function () { + return _xfa_layer.XfaLayer; + } +})); +Object.defineProperty(exports, "build", ({ + enumerable: true, + get: function () { + return _api.build; + } +})); +Object.defineProperty(exports, "createPromiseCapability", ({ + enumerable: true, + get: function () { + return _util.createPromiseCapability; + } +})); +Object.defineProperty(exports, "createValidAbsoluteUrl", ({ + enumerable: true, + get: function () { + return _util.createValidAbsoluteUrl; + } +})); +Object.defineProperty(exports, "getDocument", ({ + enumerable: true, + get: function () { + return _api.getDocument; + } +})); +Object.defineProperty(exports, "getFilenameFromUrl", ({ + enumerable: true, + get: function () { + return _display_utils.getFilenameFromUrl; + } +})); +Object.defineProperty(exports, "getPdfFilenameFromUrl", ({ + enumerable: true, + get: function () { + return _display_utils.getPdfFilenameFromUrl; + } +})); +Object.defineProperty(exports, "getXfaPageViewport", ({ + enumerable: true, + get: function () { + return _display_utils.getXfaPageViewport; + } +})); +Object.defineProperty(exports, "isPdfFile", ({ + enumerable: true, + get: function () { + return _display_utils.isPdfFile; + } +})); +Object.defineProperty(exports, "loadScript", ({ + enumerable: true, + get: function () { + return _display_utils.loadScript; + } +})); +Object.defineProperty(exports, "renderTextLayer", ({ + enumerable: true, + get: function () { + return _text_layer.renderTextLayer; + } +})); +Object.defineProperty(exports, "shadow", ({ + enumerable: true, + get: function () { + return _util.shadow; + } +})); +Object.defineProperty(exports, "version", ({ + enumerable: true, + get: function () { + return _api.version; + } +})); + +var _util = __w_pdfjs_require__(1); + +var _api = __w_pdfjs_require__(129); + +var _display_utils = __w_pdfjs_require__(133); + +var _annotation_editor_layer = __w_pdfjs_require__(147); + +var _tools = __w_pdfjs_require__(132); + +var _annotation_layer = __w_pdfjs_require__(152); + +var _worker_options = __w_pdfjs_require__(140); + +var _is_node = __w_pdfjs_require__(3); + +var _text_layer = __w_pdfjs_require__(155); + +var _svg = __w_pdfjs_require__(156); + +var _xfa_layer = __w_pdfjs_require__(154); + +const pdfjsVersion = '2.16.105'; +const pdfjsBuild = '172ccdbe5'; +{ + if (_is_node.isNodeJS) { + const { + PDFNodeStream + } = __w_pdfjs_require__(157); + + (0, _api.setPDFNetworkStreamFactory)(params => { + return new PDFNodeStream(params); + }); + } else { + const { + PDFNetworkStream + } = __w_pdfjs_require__(160); + + const { + PDFFetchStream + } = __w_pdfjs_require__(161); + + (0, _api.setPDFNetworkStreamFactory)(params => { + if ((0, _display_utils.isValidFetchUrl)(params.url)) { + return new PDFFetchStream(params); + } + + return new PDFNetworkStream(params); + }); + } +} +})(); + +/******/ return __webpack_exports__; +/******/ })() +; +}); +//# sourceMappingURL=pdf.js.map \ No newline at end of file diff --git a/frontend/public/pdfjs/build/pdf.js.map b/frontend/public/pdfjs/build/pdf.js.map new file mode 100644 index 0000000..a97c603 --- /dev/null +++ b/frontend/public/pdfjs/build/pdf.js.map @@ -0,0 +1 @@ +{"version":3,"file":"pdf.js","mappings":"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","sources":["webpack://pdfjs-dist/build/pdf/webpack/universalModuleDefinition","webpack://pdfjs-dist/build/pdf/src/shared/util.js","webpack://pdfjs-dist/build/pdf/src/shared/compatibility.js","webpack://pdfjs-dist/build/pdf/src/shared/is_node.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/es/array/at.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/modules/es.array.at.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/export.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/global.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/object-get-own-property-descriptor.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/descriptors.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/fails.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/function-call.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/function-bind-native.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/object-property-is-enumerable.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/create-property-descriptor.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/to-indexed-object.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/indexed-object.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/function-uncurry-this.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/classof-raw.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/require-object-coercible.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/to-property-key.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/to-primitive.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/is-object.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/is-callable.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/is-symbol.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/get-built-in.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/object-is-prototype-of.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/use-symbol-as-uid.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/native-symbol.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/engine-v8-version.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/engine-user-agent.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/get-method.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/a-callable.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/try-to-string.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/ordinary-to-primitive.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/well-known-symbol.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/shared.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/is-pure.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/shared-store.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/define-global-property.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/has-own-property.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/to-object.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/uid.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/ie8-dom-define.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/document-create-element.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/create-non-enumerable-property.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/object-define-property.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/v8-prototype-define-bug.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/an-object.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/define-built-in.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/make-built-in.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/function-name.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/inspect-source.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/internal-state.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/native-weak-map.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/shared-key.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/hidden-keys.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/copy-constructor-properties.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/own-keys.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/object-get-own-property-names.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/object-keys-internal.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/array-includes.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/to-absolute-index.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/to-integer-or-infinity.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/math-trunc.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/length-of-array-like.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/to-length.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/enum-bug-keys.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/object-get-own-property-symbols.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/is-forced.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/add-to-unscopables.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/object-create.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/object-define-properties.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/object-keys.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/html.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/entry-unbind.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/es/typed-array/at.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/modules/es.typed-array.at.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/array-buffer-view-core.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/array-buffer-native.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/classof.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/to-string-tag-support.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/object-get-prototype-of.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/correct-prototype-getter.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/object-set-prototype-of.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/a-possible-prototype.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/web/structured-clone.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/modules/es.array.iterator.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/iterators.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/define-iterator.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/create-iterator-constructor.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/iterators-core.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/set-to-string-tag.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/modules/es.object.to-string.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/object-to-string.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/modules/es.map.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/modules/es.map.constructor.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/collection.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/internal-metadata.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/object-get-own-property-names-external.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/array-slice-simple.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/create-property.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/object-is-extensible.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/array-buffer-non-extensible.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/freezing.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/iterate.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/function-bind-context.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/is-array-iterator-method.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/get-iterator.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/get-iterator-method.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/iterator-close.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/an-instance.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/check-correctness-of-iteration.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/inherit-if-required.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/collection-strong.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/define-built-ins.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/set-species.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/modules/es.set.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/modules/es.set.constructor.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/modules/web.structured-clone.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/is-constructor.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/validate-arguments-length.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/regexp-get-flags.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/regexp-flags.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/error-stack-installable.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/engine-is-browser.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/engine-is-deno.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/engine-is-node.js","webpack://pdfjs-dist/build/pdf/node_modules/core-js/internals/path.js","webpack://pdfjs-dist/build/pdf/src/display/api.js","webpack://pdfjs-dist/build/pdf/src/display/annotation_storage.js","webpack://pdfjs-dist/build/pdf/src/display/editor/editor.js","webpack://pdfjs-dist/build/pdf/src/display/editor/tools.js","webpack://pdfjs-dist/build/pdf/src/display/display_utils.js","webpack://pdfjs-dist/build/pdf/src/display/base_factory.js","webpack://pdfjs-dist/build/pdf/src/shared/murmurhash3.js","webpack://pdfjs-dist/build/pdf/src/display/font_loader.js","webpack://pdfjs-dist/build/pdf/src/display/canvas.js","webpack://pdfjs-dist/build/pdf/src/display/pattern_helper.js","webpack://pdfjs-dist/build/pdf/src/shared/image_utils.js","webpack://pdfjs-dist/build/pdf/src/display/worker_options.js","webpack://pdfjs-dist/build/pdf/src/shared/message_handler.js","webpack://pdfjs-dist/build/pdf/src/display/metadata.js","webpack://pdfjs-dist/build/pdf/src/display/optional_content_config.js","webpack://pdfjs-dist/build/pdf/src/display/transport_stream.js","webpack://pdfjs-dist/build/pdf/src/display/xfa_text.js","webpack://pdfjs-dist/build/pdf/src/display/node_utils.js","webpack://pdfjs-dist/build/pdf/src/display/editor/annotation_editor_layer.js","webpack://pdfjs-dist/build/pdf/src/display/editor/freetext.js","webpack://pdfjs-dist/build/pdf/src/display/editor/ink.js","webpack://pdfjs-dist/build/pdf/src/display/editor/fit_curve.js","webpack://pdfjs-dist/build/pdf/node_modules/fit-curve/src/fit-curve.js","webpack://pdfjs-dist/build/pdf/src/display/annotation_layer.js","webpack://pdfjs-dist/build/pdf/src/shared/scripting_utils.js","webpack://pdfjs-dist/build/pdf/src/display/xfa_layer.js","webpack://pdfjs-dist/build/pdf/src/display/text_layer.js","webpack://pdfjs-dist/build/pdf/src/display/svg.js","webpack://pdfjs-dist/build/pdf/src/display/node_stream.js","webpack://pdfjs-dist/build/pdf/src/display/network_utils.js","webpack://pdfjs-dist/build/pdf/src/display/content_disposition.js","webpack://pdfjs-dist/build/pdf/src/display/network.js","webpack://pdfjs-dist/build/pdf/src/display/fetch_stream.js","webpack://pdfjs-dist/build/pdf/webpack/bootstrap","webpack://pdfjs-dist/build/pdf/src/pdf.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"pdfjs-dist/build/pdf\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"pdfjs-dist/build/pdf\"] = factory();\n\telse\n\t\troot[\"pdfjs-dist/build/pdf\"] = factory();\n})(globalThis, () => {\nreturn ","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport \"./compatibility.js\";\n\nconst IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];\nconst FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];\n\n// Represent the percentage of the height of a single-line field over\n// the font size. Acrobat seems to use this value.\nconst LINE_FACTOR = 1.35;\nconst LINE_DESCENT_FACTOR = 0.35;\n\n/**\n * Refer to the `WorkerTransport.getRenderingIntent`-method in the API, to see\n * how these flags are being used:\n * - ANY, DISPLAY, and PRINT are the normal rendering intents, note the\n * `PDFPageProxy.{render, getOperatorList, getAnnotations}`-methods.\n * - ANNOTATIONS_FORMS, ANNOTATIONS_STORAGE, ANNOTATIONS_DISABLE control which\n * annotations are rendered onto the canvas (i.e. by being included in the\n * operatorList), note the `PDFPageProxy.{render, getOperatorList}`-methods\n * and their `annotationMode`-option.\n * - OPLIST is used with the `PDFPageProxy.getOperatorList`-method, note the\n * `OperatorList`-constructor (on the worker-thread).\n */\nconst RenderingIntentFlag = {\n ANY: 0x01,\n DISPLAY: 0x02,\n PRINT: 0x04,\n ANNOTATIONS_FORMS: 0x10,\n ANNOTATIONS_STORAGE: 0x20,\n ANNOTATIONS_DISABLE: 0x40,\n OPLIST: 0x100,\n};\n\nconst AnnotationMode = {\n DISABLE: 0,\n ENABLE: 1,\n ENABLE_FORMS: 2,\n ENABLE_STORAGE: 3,\n};\n\nconst AnnotationEditorPrefix = \"pdfjs_internal_editor_\";\n\nconst AnnotationEditorType = {\n DISABLE: -1,\n NONE: 0,\n FREETEXT: 3,\n INK: 15,\n};\n\nconst AnnotationEditorParamsType = {\n FREETEXT_SIZE: 1,\n FREETEXT_COLOR: 2,\n FREETEXT_OPACITY: 3,\n INK_COLOR: 11,\n INK_THICKNESS: 12,\n INK_OPACITY: 13,\n};\n\n// Permission flags from Table 22, Section 7.6.3.2 of the PDF specification.\nconst PermissionFlag = {\n PRINT: 0x04,\n MODIFY_CONTENTS: 0x08,\n COPY: 0x10,\n MODIFY_ANNOTATIONS: 0x20,\n FILL_INTERACTIVE_FORMS: 0x100,\n COPY_FOR_ACCESSIBILITY: 0x200,\n ASSEMBLE: 0x400,\n PRINT_HIGH_QUALITY: 0x800,\n};\n\nconst TextRenderingMode = {\n FILL: 0,\n STROKE: 1,\n FILL_STROKE: 2,\n INVISIBLE: 3,\n FILL_ADD_TO_PATH: 4,\n STROKE_ADD_TO_PATH: 5,\n FILL_STROKE_ADD_TO_PATH: 6,\n ADD_TO_PATH: 7,\n FILL_STROKE_MASK: 3,\n ADD_TO_PATH_FLAG: 4,\n};\n\nconst ImageKind = {\n GRAYSCALE_1BPP: 1,\n RGB_24BPP: 2,\n RGBA_32BPP: 3,\n};\n\nconst AnnotationType = {\n TEXT: 1,\n LINK: 2,\n FREETEXT: 3,\n LINE: 4,\n SQUARE: 5,\n CIRCLE: 6,\n POLYGON: 7,\n POLYLINE: 8,\n HIGHLIGHT: 9,\n UNDERLINE: 10,\n SQUIGGLY: 11,\n STRIKEOUT: 12,\n STAMP: 13,\n CARET: 14,\n INK: 15,\n POPUP: 16,\n FILEATTACHMENT: 17,\n SOUND: 18,\n MOVIE: 19,\n WIDGET: 20,\n SCREEN: 21,\n PRINTERMARK: 22,\n TRAPNET: 23,\n WATERMARK: 24,\n THREED: 25,\n REDACT: 26,\n};\n\nconst AnnotationStateModelType = {\n MARKED: \"Marked\",\n REVIEW: \"Review\",\n};\n\nconst AnnotationMarkedState = {\n MARKED: \"Marked\",\n UNMARKED: \"Unmarked\",\n};\n\nconst AnnotationReviewState = {\n ACCEPTED: \"Accepted\",\n REJECTED: \"Rejected\",\n CANCELLED: \"Cancelled\",\n COMPLETED: \"Completed\",\n NONE: \"None\",\n};\n\nconst AnnotationReplyType = {\n GROUP: \"Group\",\n REPLY: \"R\",\n};\n\nconst AnnotationFlag = {\n INVISIBLE: 0x01,\n HIDDEN: 0x02,\n PRINT: 0x04,\n NOZOOM: 0x08,\n NOROTATE: 0x10,\n NOVIEW: 0x20,\n READONLY: 0x40,\n LOCKED: 0x80,\n TOGGLENOVIEW: 0x100,\n LOCKEDCONTENTS: 0x200,\n};\n\nconst AnnotationFieldFlag = {\n READONLY: 0x0000001,\n REQUIRED: 0x0000002,\n NOEXPORT: 0x0000004,\n MULTILINE: 0x0001000,\n PASSWORD: 0x0002000,\n NOTOGGLETOOFF: 0x0004000,\n RADIO: 0x0008000,\n PUSHBUTTON: 0x0010000,\n COMBO: 0x0020000,\n EDIT: 0x0040000,\n SORT: 0x0080000,\n FILESELECT: 0x0100000,\n MULTISELECT: 0x0200000,\n DONOTSPELLCHECK: 0x0400000,\n DONOTSCROLL: 0x0800000,\n COMB: 0x1000000,\n RICHTEXT: 0x2000000,\n RADIOSINUNISON: 0x2000000,\n COMMITONSELCHANGE: 0x4000000,\n};\n\nconst AnnotationBorderStyleType = {\n SOLID: 1,\n DASHED: 2,\n BEVELED: 3,\n INSET: 4,\n UNDERLINE: 5,\n};\n\nconst AnnotationActionEventType = {\n E: \"Mouse Enter\",\n X: \"Mouse Exit\",\n D: \"Mouse Down\",\n U: \"Mouse Up\",\n Fo: \"Focus\",\n Bl: \"Blur\",\n PO: \"PageOpen\",\n PC: \"PageClose\",\n PV: \"PageVisible\",\n PI: \"PageInvisible\",\n K: \"Keystroke\",\n F: \"Format\",\n V: \"Validate\",\n C: \"Calculate\",\n};\n\nconst DocumentActionEventType = {\n WC: \"WillClose\",\n WS: \"WillSave\",\n DS: \"DidSave\",\n WP: \"WillPrint\",\n DP: \"DidPrint\",\n};\n\nconst PageActionEventType = {\n O: \"PageOpen\",\n C: \"PageClose\",\n};\n\nconst StreamType = {\n UNKNOWN: \"UNKNOWN\",\n FLATE: \"FLATE\",\n LZW: \"LZW\",\n DCT: \"DCT\",\n JPX: \"JPX\",\n JBIG: \"JBIG\",\n A85: \"A85\",\n AHX: \"AHX\",\n CCF: \"CCF\",\n RLX: \"RLX\", // PDF short name is 'RL', but telemetry requires three chars.\n};\n\nconst FontType = {\n UNKNOWN: \"UNKNOWN\",\n TYPE1: \"TYPE1\",\n TYPE1STANDARD: \"TYPE1STANDARD\",\n TYPE1C: \"TYPE1C\",\n CIDFONTTYPE0: \"CIDFONTTYPE0\",\n CIDFONTTYPE0C: \"CIDFONTTYPE0C\",\n TRUETYPE: \"TRUETYPE\",\n CIDFONTTYPE2: \"CIDFONTTYPE2\",\n TYPE3: \"TYPE3\",\n OPENTYPE: \"OPENTYPE\",\n TYPE0: \"TYPE0\",\n MMTYPE1: \"MMTYPE1\",\n};\n\nconst VerbosityLevel = {\n ERRORS: 0,\n WARNINGS: 1,\n INFOS: 5,\n};\n\nconst CMapCompressionType = {\n NONE: 0,\n BINARY: 1,\n STREAM: 2,\n};\n\n// All the possible operations for an operator list.\nconst OPS = {\n // Intentionally start from 1 so it is easy to spot bad operators that will be\n // 0's.\n dependency: 1,\n setLineWidth: 2,\n setLineCap: 3,\n setLineJoin: 4,\n setMiterLimit: 5,\n setDash: 6,\n setRenderingIntent: 7,\n setFlatness: 8,\n setGState: 9,\n save: 10,\n restore: 11,\n transform: 12,\n moveTo: 13,\n lineTo: 14,\n curveTo: 15,\n curveTo2: 16,\n curveTo3: 17,\n closePath: 18,\n rectangle: 19,\n stroke: 20,\n closeStroke: 21,\n fill: 22,\n eoFill: 23,\n fillStroke: 24,\n eoFillStroke: 25,\n closeFillStroke: 26,\n closeEOFillStroke: 27,\n endPath: 28,\n clip: 29,\n eoClip: 30,\n beginText: 31,\n endText: 32,\n setCharSpacing: 33,\n setWordSpacing: 34,\n setHScale: 35,\n setLeading: 36,\n setFont: 37,\n setTextRenderingMode: 38,\n setTextRise: 39,\n moveText: 40,\n setLeadingMoveText: 41,\n setTextMatrix: 42,\n nextLine: 43,\n showText: 44,\n showSpacedText: 45,\n nextLineShowText: 46,\n nextLineSetSpacingShowText: 47,\n setCharWidth: 48,\n setCharWidthAndBounds: 49,\n setStrokeColorSpace: 50,\n setFillColorSpace: 51,\n setStrokeColor: 52,\n setStrokeColorN: 53,\n setFillColor: 54,\n setFillColorN: 55,\n setStrokeGray: 56,\n setFillGray: 57,\n setStrokeRGBColor: 58,\n setFillRGBColor: 59,\n setStrokeCMYKColor: 60,\n setFillCMYKColor: 61,\n shadingFill: 62,\n beginInlineImage: 63,\n beginImageData: 64,\n endInlineImage: 65,\n paintXObject: 66,\n markPoint: 67,\n markPointProps: 68,\n beginMarkedContent: 69,\n beginMarkedContentProps: 70,\n endMarkedContent: 71,\n beginCompat: 72,\n endCompat: 73,\n paintFormXObjectBegin: 74,\n paintFormXObjectEnd: 75,\n beginGroup: 76,\n endGroup: 77,\n /** @deprecated unused */\n beginAnnotations: 78,\n /** @deprecated unused */\n endAnnotations: 79,\n beginAnnotation: 80,\n endAnnotation: 81,\n /** @deprecated unused */\n paintJpegXObject: 82,\n paintImageMaskXObject: 83,\n paintImageMaskXObjectGroup: 84,\n paintImageXObject: 85,\n paintInlineImageXObject: 86,\n paintInlineImageXObjectGroup: 87,\n paintImageXObjectRepeat: 88,\n paintImageMaskXObjectRepeat: 89,\n paintSolidColorImageMask: 90,\n constructPath: 91,\n};\n\nconst UNSUPPORTED_FEATURES = {\n /** @deprecated unused */\n unknown: \"unknown\",\n forms: \"forms\",\n javaScript: \"javaScript\",\n signatures: \"signatures\",\n smask: \"smask\",\n shadingPattern: \"shadingPattern\",\n /** @deprecated unused */\n font: \"font\",\n errorTilingPattern: \"errorTilingPattern\",\n errorExtGState: \"errorExtGState\",\n errorXObject: \"errorXObject\",\n errorFontLoadType3: \"errorFontLoadType3\",\n errorFontState: \"errorFontState\",\n errorFontMissing: \"errorFontMissing\",\n errorFontTranslate: \"errorFontTranslate\",\n errorColorSpace: \"errorColorSpace\",\n errorOperatorList: \"errorOperatorList\",\n errorFontToUnicode: \"errorFontToUnicode\",\n errorFontLoadNative: \"errorFontLoadNative\",\n errorFontBuildPath: \"errorFontBuildPath\",\n errorFontGetPath: \"errorFontGetPath\",\n errorMarkedContent: \"errorMarkedContent\",\n errorContentSubStream: \"errorContentSubStream\",\n};\n\nconst PasswordResponses = {\n NEED_PASSWORD: 1,\n INCORRECT_PASSWORD: 2,\n};\n\nlet verbosity = VerbosityLevel.WARNINGS;\n\nfunction setVerbosityLevel(level) {\n if (Number.isInteger(level)) {\n verbosity = level;\n }\n}\n\nfunction getVerbosityLevel() {\n return verbosity;\n}\n\n// A notice for devs. These are good for things that are helpful to devs, such\n// as warning that Workers were disabled, which is important to devs but not\n// end users.\nfunction info(msg) {\n if (verbosity >= VerbosityLevel.INFOS) {\n console.log(`Info: ${msg}`);\n }\n}\n\n// Non-fatal warnings.\nfunction warn(msg) {\n if (verbosity >= VerbosityLevel.WARNINGS) {\n console.log(`Warning: ${msg}`);\n }\n}\n\nfunction unreachable(msg) {\n throw new Error(msg);\n}\n\nfunction assert(cond, msg) {\n if (!cond) {\n unreachable(msg);\n }\n}\n\n// Checks if URLs use one of the allowed protocols, e.g. to avoid XSS.\nfunction _isValidProtocol(url) {\n if (!url) {\n return false;\n }\n switch (url.protocol) {\n case \"http:\":\n case \"https:\":\n case \"ftp:\":\n case \"mailto:\":\n case \"tel:\":\n return true;\n default:\n return false;\n }\n}\n\n/**\n * Attempts to create a valid absolute URL.\n *\n * @param {URL|string} url - An absolute, or relative, URL.\n * @param {URL|string} [baseUrl] - An absolute URL.\n * @param {Object} [options]\n * @returns Either a valid {URL}, or `null` otherwise.\n */\nfunction createValidAbsoluteUrl(url, baseUrl = null, options = null) {\n if (!url) {\n return null;\n }\n try {\n if (options && typeof url === \"string\") {\n // Let URLs beginning with \"www.\" default to using the \"http://\" protocol.\n if (options.addDefaultProtocol && url.startsWith(\"www.\")) {\n const dots = url.match(/\\./g);\n // Avoid accidentally matching a *relative* URL pointing to a file named\n // e.g. \"www.pdf\" or similar.\n if (dots && dots.length >= 2) {\n url = `http://${url}`;\n }\n }\n\n // According to ISO 32000-1:2008, section 12.6.4.7, URIs should be encoded\n // in 7-bit ASCII. Some bad PDFs use UTF-8 encoding; see bug 1122280.\n if (options.tryConvertEncoding) {\n try {\n url = stringToUTF8String(url);\n } catch (ex) {}\n }\n }\n\n const absoluteUrl = baseUrl ? new URL(url, baseUrl) : new URL(url);\n if (_isValidProtocol(absoluteUrl)) {\n return absoluteUrl;\n }\n } catch (ex) {\n /* `new URL()` will throw on incorrect data. */\n }\n return null;\n}\n\nfunction shadow(obj, prop, value) {\n if (\n typeof PDFJSDev === \"undefined\" ||\n PDFJSDev.test(\"!PRODUCTION || TESTING\")\n ) {\n assert(\n prop in obj,\n `shadow: Property \"${prop && prop.toString()}\" not found in object.`\n );\n }\n Object.defineProperty(obj, prop, {\n value,\n enumerable: true,\n configurable: true,\n writable: false,\n });\n return value;\n}\n\n/**\n * @type {any}\n */\nconst BaseException = (function BaseExceptionClosure() {\n // eslint-disable-next-line no-shadow\n function BaseException(message, name) {\n if (this.constructor === BaseException) {\n unreachable(\"Cannot initialize BaseException.\");\n }\n this.message = message;\n this.name = name;\n }\n BaseException.prototype = new Error();\n BaseException.constructor = BaseException;\n\n return BaseException;\n})();\n\nclass PasswordException extends BaseException {\n constructor(msg, code) {\n super(msg, \"PasswordException\");\n this.code = code;\n }\n}\n\nclass UnknownErrorException extends BaseException {\n constructor(msg, details) {\n super(msg, \"UnknownErrorException\");\n this.details = details;\n }\n}\n\nclass InvalidPDFException extends BaseException {\n constructor(msg) {\n super(msg, \"InvalidPDFException\");\n }\n}\n\nclass MissingPDFException extends BaseException {\n constructor(msg) {\n super(msg, \"MissingPDFException\");\n }\n}\n\nclass UnexpectedResponseException extends BaseException {\n constructor(msg, status) {\n super(msg, \"UnexpectedResponseException\");\n this.status = status;\n }\n}\n\n/**\n * Error caused during parsing PDF data.\n */\nclass FormatError extends BaseException {\n constructor(msg) {\n super(msg, \"FormatError\");\n }\n}\n\n/**\n * Error used to indicate task cancellation.\n */\nclass AbortException extends BaseException {\n constructor(msg) {\n super(msg, \"AbortException\");\n }\n}\n\nfunction bytesToString(bytes) {\n if (\n typeof bytes !== \"object\" ||\n bytes === null ||\n bytes.length === undefined\n ) {\n unreachable(\"Invalid argument for bytesToString\");\n }\n const length = bytes.length;\n const MAX_ARGUMENT_COUNT = 8192;\n if (length < MAX_ARGUMENT_COUNT) {\n return String.fromCharCode.apply(null, bytes);\n }\n const strBuf = [];\n for (let i = 0; i < length; i += MAX_ARGUMENT_COUNT) {\n const chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length);\n const chunk = bytes.subarray(i, chunkEnd);\n strBuf.push(String.fromCharCode.apply(null, chunk));\n }\n return strBuf.join(\"\");\n}\n\nfunction stringToBytes(str) {\n if (typeof str !== \"string\") {\n unreachable(\"Invalid argument for stringToBytes\");\n }\n const length = str.length;\n const bytes = new Uint8Array(length);\n for (let i = 0; i < length; ++i) {\n bytes[i] = str.charCodeAt(i) & 0xff;\n }\n return bytes;\n}\n\n/**\n * Gets length of the array (Array, Uint8Array, or string) in bytes.\n * @param {Array|Uint8Array|string} arr\n * @returns {number}\n */\n// eslint-disable-next-line consistent-return\nfunction arrayByteLength(arr) {\n if (arr.length !== undefined) {\n return arr.length;\n }\n if (arr.byteLength !== undefined) {\n return arr.byteLength;\n }\n unreachable(\"Invalid argument for arrayByteLength\");\n}\n\n/**\n * Combines array items (arrays) into single Uint8Array object.\n * @param {Array|Uint8Array|string>} arr - the array of the arrays\n * (Array, Uint8Array, or string).\n * @returns {Uint8Array}\n */\nfunction arraysToBytes(arr) {\n const length = arr.length;\n // Shortcut: if first and only item is Uint8Array, return it.\n if (length === 1 && arr[0] instanceof Uint8Array) {\n return arr[0];\n }\n let resultLength = 0;\n for (let i = 0; i < length; i++) {\n resultLength += arrayByteLength(arr[i]);\n }\n let pos = 0;\n const data = new Uint8Array(resultLength);\n for (let i = 0; i < length; i++) {\n let item = arr[i];\n if (!(item instanceof Uint8Array)) {\n if (typeof item === \"string\") {\n item = stringToBytes(item);\n } else {\n item = new Uint8Array(item);\n }\n }\n const itemLength = item.byteLength;\n data.set(item, pos);\n pos += itemLength;\n }\n return data;\n}\n\nfunction string32(value) {\n if (\n typeof PDFJSDev === \"undefined\" ||\n PDFJSDev.test(\"!PRODUCTION || TESTING\")\n ) {\n assert(\n typeof value === \"number\" && Math.abs(value) < 2 ** 32,\n `string32: Unexpected input \"${value}\".`\n );\n }\n return String.fromCharCode(\n (value >> 24) & 0xff,\n (value >> 16) & 0xff,\n (value >> 8) & 0xff,\n value & 0xff\n );\n}\n\nfunction objectSize(obj) {\n return Object.keys(obj).length;\n}\n\n// Ensure that the returned Object has a `null` prototype; hence why\n// `Object.fromEntries(...)` is not used.\nfunction objectFromMap(map) {\n const obj = Object.create(null);\n for (const [key, value] of map) {\n obj[key] = value;\n }\n return obj;\n}\n\n// Checks the endianness of the platform.\nfunction isLittleEndian() {\n const buffer8 = new Uint8Array(4);\n buffer8[0] = 1;\n const view32 = new Uint32Array(buffer8.buffer, 0, 1);\n return view32[0] === 1;\n}\n\n// Checks if it's possible to eval JS expressions.\nfunction isEvalSupported() {\n try {\n new Function(\"\"); // eslint-disable-line no-new, no-new-func\n return true;\n } catch (e) {\n return false;\n }\n}\n\nclass FeatureTest {\n static get isLittleEndian() {\n return shadow(this, \"isLittleEndian\", isLittleEndian());\n }\n\n static get isEvalSupported() {\n return shadow(this, \"isEvalSupported\", isEvalSupported());\n }\n\n static get isOffscreenCanvasSupported() {\n return shadow(\n this,\n \"isOffscreenCanvasSupported\",\n typeof OffscreenCanvas !== \"undefined\"\n );\n }\n}\n\nconst hexNumbers = [...Array(256).keys()].map(n =>\n n.toString(16).padStart(2, \"0\")\n);\n\nclass Util {\n static makeHexColor(r, g, b) {\n return `#${hexNumbers[r]}${hexNumbers[g]}${hexNumbers[b]}`;\n }\n\n // Apply a scaling matrix to some min/max values.\n // If a scaling factor is negative then min and max must be\n // swaped.\n static scaleMinMax(transform, minMax) {\n let temp;\n if (transform[0]) {\n if (transform[0] < 0) {\n temp = minMax[0];\n minMax[0] = minMax[1];\n minMax[1] = temp;\n }\n minMax[0] *= transform[0];\n minMax[1] *= transform[0];\n\n if (transform[3] < 0) {\n temp = minMax[2];\n minMax[2] = minMax[3];\n minMax[3] = temp;\n }\n minMax[2] *= transform[3];\n minMax[3] *= transform[3];\n } else {\n temp = minMax[0];\n minMax[0] = minMax[2];\n minMax[2] = temp;\n temp = minMax[1];\n minMax[1] = minMax[3];\n minMax[3] = temp;\n\n if (transform[1] < 0) {\n temp = minMax[2];\n minMax[2] = minMax[3];\n minMax[3] = temp;\n }\n minMax[2] *= transform[1];\n minMax[3] *= transform[1];\n\n if (transform[2] < 0) {\n temp = minMax[0];\n minMax[0] = minMax[1];\n minMax[1] = temp;\n }\n minMax[0] *= transform[2];\n minMax[1] *= transform[2];\n }\n minMax[0] += transform[4];\n minMax[1] += transform[4];\n minMax[2] += transform[5];\n minMax[3] += transform[5];\n }\n\n // Concatenates two transformation matrices together and returns the result.\n static transform(m1, m2) {\n return [\n m1[0] * m2[0] + m1[2] * m2[1],\n m1[1] * m2[0] + m1[3] * m2[1],\n m1[0] * m2[2] + m1[2] * m2[3],\n m1[1] * m2[2] + m1[3] * m2[3],\n m1[0] * m2[4] + m1[2] * m2[5] + m1[4],\n m1[1] * m2[4] + m1[3] * m2[5] + m1[5],\n ];\n }\n\n // For 2d affine transforms\n static applyTransform(p, m) {\n const xt = p[0] * m[0] + p[1] * m[2] + m[4];\n const yt = p[0] * m[1] + p[1] * m[3] + m[5];\n return [xt, yt];\n }\n\n static applyInverseTransform(p, m) {\n const d = m[0] * m[3] - m[1] * m[2];\n const xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d;\n const yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d;\n return [xt, yt];\n }\n\n // Applies the transform to the rectangle and finds the minimum axially\n // aligned bounding box.\n static getAxialAlignedBoundingBox(r, m) {\n const p1 = Util.applyTransform(r, m);\n const p2 = Util.applyTransform(r.slice(2, 4), m);\n const p3 = Util.applyTransform([r[0], r[3]], m);\n const p4 = Util.applyTransform([r[2], r[1]], m);\n return [\n Math.min(p1[0], p2[0], p3[0], p4[0]),\n Math.min(p1[1], p2[1], p3[1], p4[1]),\n Math.max(p1[0], p2[0], p3[0], p4[0]),\n Math.max(p1[1], p2[1], p3[1], p4[1]),\n ];\n }\n\n static inverseTransform(m) {\n const d = m[0] * m[3] - m[1] * m[2];\n return [\n m[3] / d,\n -m[1] / d,\n -m[2] / d,\n m[0] / d,\n (m[2] * m[5] - m[4] * m[3]) / d,\n (m[4] * m[1] - m[5] * m[0]) / d,\n ];\n }\n\n // Apply a generic 3d matrix M on a 3-vector v:\n // | a b c | | X |\n // | d e f | x | Y |\n // | g h i | | Z |\n // M is assumed to be serialized as [a,b,c,d,e,f,g,h,i],\n // with v as [X,Y,Z]\n static apply3dTransform(m, v) {\n return [\n m[0] * v[0] + m[1] * v[1] + m[2] * v[2],\n m[3] * v[0] + m[4] * v[1] + m[5] * v[2],\n m[6] * v[0] + m[7] * v[1] + m[8] * v[2],\n ];\n }\n\n // This calculation uses Singular Value Decomposition.\n // The SVD can be represented with formula A = USV. We are interested in the\n // matrix S here because it represents the scale values.\n static singularValueDecompose2dScale(m) {\n const transpose = [m[0], m[2], m[1], m[3]];\n\n // Multiply matrix m with its transpose.\n const a = m[0] * transpose[0] + m[1] * transpose[2];\n const b = m[0] * transpose[1] + m[1] * transpose[3];\n const c = m[2] * transpose[0] + m[3] * transpose[2];\n const d = m[2] * transpose[1] + m[3] * transpose[3];\n\n // Solve the second degree polynomial to get roots.\n const first = (a + d) / 2;\n const second = Math.sqrt((a + d) ** 2 - 4 * (a * d - c * b)) / 2;\n const sx = first + second || 1;\n const sy = first - second || 1;\n\n // Scale values are the square roots of the eigenvalues.\n return [Math.sqrt(sx), Math.sqrt(sy)];\n }\n\n // Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2)\n // For coordinate systems whose origin lies in the bottom-left, this\n // means normalization to (BL,TR) ordering. For systems with origin in the\n // top-left, this means (TL,BR) ordering.\n static normalizeRect(rect) {\n const r = rect.slice(0); // clone rect\n if (rect[0] > rect[2]) {\n r[0] = rect[2];\n r[2] = rect[0];\n }\n if (rect[1] > rect[3]) {\n r[1] = rect[3];\n r[3] = rect[1];\n }\n return r;\n }\n\n // Returns a rectangle [x1, y1, x2, y2] corresponding to the\n // intersection of rect1 and rect2. If no intersection, returns 'null'\n // The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2]\n static intersect(rect1, rect2) {\n const xLow = Math.max(\n Math.min(rect1[0], rect1[2]),\n Math.min(rect2[0], rect2[2])\n );\n const xHigh = Math.min(\n Math.max(rect1[0], rect1[2]),\n Math.max(rect2[0], rect2[2])\n );\n if (xLow > xHigh) {\n return null;\n }\n const yLow = Math.max(\n Math.min(rect1[1], rect1[3]),\n Math.min(rect2[1], rect2[3])\n );\n const yHigh = Math.min(\n Math.max(rect1[1], rect1[3]),\n Math.max(rect2[1], rect2[3])\n );\n if (yLow > yHigh) {\n return null;\n }\n\n return [xLow, yLow, xHigh, yHigh];\n }\n\n // From https://github.com/adobe-webplatform/Snap.svg/blob/b365287722a72526000ac4bfcf0ce4cac2faa015/src/path.js#L852\n static bezierBoundingBox(x0, y0, x1, y1, x2, y2, x3, y3) {\n const tvalues = [],\n bounds = [[], []];\n let a, b, c, t, t1, t2, b2ac, sqrtb2ac;\n for (let i = 0; i < 2; ++i) {\n if (i === 0) {\n b = 6 * x0 - 12 * x1 + 6 * x2;\n a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3;\n c = 3 * x1 - 3 * x0;\n } else {\n b = 6 * y0 - 12 * y1 + 6 * y2;\n a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;\n c = 3 * y1 - 3 * y0;\n }\n if (Math.abs(a) < 1e-12) {\n if (Math.abs(b) < 1e-12) {\n continue;\n }\n t = -c / b;\n if (0 < t && t < 1) {\n tvalues.push(t);\n }\n continue;\n }\n b2ac = b * b - 4 * c * a;\n sqrtb2ac = Math.sqrt(b2ac);\n if (b2ac < 0) {\n continue;\n }\n t1 = (-b + sqrtb2ac) / (2 * a);\n if (0 < t1 && t1 < 1) {\n tvalues.push(t1);\n }\n t2 = (-b - sqrtb2ac) / (2 * a);\n if (0 < t2 && t2 < 1) {\n tvalues.push(t2);\n }\n }\n\n let j = tvalues.length,\n mt;\n const jlen = j;\n while (j--) {\n t = tvalues[j];\n mt = 1 - t;\n bounds[0][j] =\n mt * mt * mt * x0 +\n 3 * mt * mt * t * x1 +\n 3 * mt * t * t * x2 +\n t * t * t * x3;\n bounds[1][j] =\n mt * mt * mt * y0 +\n 3 * mt * mt * t * y1 +\n 3 * mt * t * t * y2 +\n t * t * t * y3;\n }\n\n bounds[0][jlen] = x0;\n bounds[1][jlen] = y0;\n bounds[0][jlen + 1] = x3;\n bounds[1][jlen + 1] = y3;\n bounds[0].length = bounds[1].length = jlen + 2;\n\n return [\n Math.min(...bounds[0]),\n Math.min(...bounds[1]),\n Math.max(...bounds[0]),\n Math.max(...bounds[1]),\n ];\n }\n}\n\nconst PDFStringTranslateTable = [\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2d8,\n 0x2c7, 0x2c6, 0x2d9, 0x2dd, 0x2db, 0x2da, 0x2dc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x192,\n 0x2044, 0x2039, 0x203a, 0x2212, 0x2030, 0x201e, 0x201c, 0x201d, 0x2018,\n 0x2019, 0x201a, 0x2122, 0xfb01, 0xfb02, 0x141, 0x152, 0x160, 0x178, 0x17d,\n 0x131, 0x142, 0x153, 0x161, 0x17e, 0, 0x20ac,\n];\n\nfunction stringToPDFString(str) {\n if (str[0] >= \"\\xEF\") {\n let encoding;\n if (str[0] === \"\\xFE\" && str[1] === \"\\xFF\") {\n encoding = \"utf-16be\";\n } else if (str[0] === \"\\xFF\" && str[1] === \"\\xFE\") {\n encoding = \"utf-16le\";\n } else if (str[0] === \"\\xEF\" && str[1] === \"\\xBB\" && str[2] === \"\\xBF\") {\n encoding = \"utf-8\";\n }\n\n if (encoding) {\n try {\n const decoder = new TextDecoder(encoding, { fatal: true });\n const buffer = stringToBytes(str);\n return decoder.decode(buffer);\n } catch (ex) {\n warn(`stringToPDFString: \"${ex}\".`);\n }\n }\n }\n // ISO Latin 1\n const strBuf = [];\n for (let i = 0, ii = str.length; i < ii; i++) {\n const code = PDFStringTranslateTable[str.charCodeAt(i)];\n strBuf.push(code ? String.fromCharCode(code) : str.charAt(i));\n }\n return strBuf.join(\"\");\n}\n\nfunction escapeString(str) {\n // replace \"(\", \")\", \"\\n\", \"\\r\" and \"\\\"\n // by \"\\(\", \"\\)\", \"\\\\n\", \"\\\\r\" and \"\\\\\"\n // in order to write it in a PDF file.\n return str.replace(/([()\\\\\\n\\r])/g, match => {\n if (match === \"\\n\") {\n return \"\\\\n\";\n } else if (match === \"\\r\") {\n return \"\\\\r\";\n }\n return `\\\\${match}`;\n });\n}\n\nfunction isAscii(str) {\n return /^[\\x00-\\x7F]*$/.test(str);\n}\n\nfunction stringToUTF16BEString(str) {\n const buf = [\"\\xFE\\xFF\"];\n for (let i = 0, ii = str.length; i < ii; i++) {\n const char = str.charCodeAt(i);\n buf.push(\n String.fromCharCode((char >> 8) & 0xff),\n String.fromCharCode(char & 0xff)\n );\n }\n return buf.join(\"\");\n}\n\nfunction stringToUTF8String(str) {\n return decodeURIComponent(escape(str));\n}\n\nfunction utf8StringToString(str) {\n return unescape(encodeURIComponent(str));\n}\n\nfunction isArrayBuffer(v) {\n return typeof v === \"object\" && v !== null && v.byteLength !== undefined;\n}\n\nfunction isArrayEqual(arr1, arr2) {\n if (arr1.length !== arr2.length) {\n return false;\n }\n for (let i = 0, ii = arr1.length; i < ii; i++) {\n if (arr1[i] !== arr2[i]) {\n return false;\n }\n }\n return true;\n}\n\nfunction getModificationDate(date = new Date()) {\n const buffer = [\n date.getUTCFullYear().toString(),\n (date.getUTCMonth() + 1).toString().padStart(2, \"0\"),\n date.getUTCDate().toString().padStart(2, \"0\"),\n date.getUTCHours().toString().padStart(2, \"0\"),\n date.getUTCMinutes().toString().padStart(2, \"0\"),\n date.getUTCSeconds().toString().padStart(2, \"0\"),\n ];\n\n return buffer.join(\"\");\n}\n\n/**\n * Promise Capability object.\n *\n * @typedef {Object} PromiseCapability\n * @property {Promise} promise - A Promise object.\n * @property {boolean} settled - If the Promise has been fulfilled/rejected.\n * @property {function} resolve - Fulfills the Promise.\n * @property {function} reject - Rejects the Promise.\n */\n\n/**\n * Creates a promise capability object.\n * @alias createPromiseCapability\n *\n * @returns {PromiseCapability}\n */\nfunction createPromiseCapability() {\n const capability = Object.create(null);\n let isSettled = false;\n\n Object.defineProperty(capability, \"settled\", {\n get() {\n return isSettled;\n },\n });\n capability.promise = new Promise(function (resolve, reject) {\n capability.resolve = function (data) {\n isSettled = true;\n resolve(data);\n };\n capability.reject = function (reason) {\n isSettled = true;\n reject(reason);\n };\n });\n return capability;\n}\n\nexport {\n AbortException,\n AnnotationActionEventType,\n AnnotationBorderStyleType,\n AnnotationEditorParamsType,\n AnnotationEditorPrefix,\n AnnotationEditorType,\n AnnotationFieldFlag,\n AnnotationFlag,\n AnnotationMarkedState,\n AnnotationMode,\n AnnotationReplyType,\n AnnotationReviewState,\n AnnotationStateModelType,\n AnnotationType,\n arrayByteLength,\n arraysToBytes,\n assert,\n BaseException,\n bytesToString,\n CMapCompressionType,\n createPromiseCapability,\n createValidAbsoluteUrl,\n DocumentActionEventType,\n escapeString,\n FeatureTest,\n FONT_IDENTITY_MATRIX,\n FontType,\n FormatError,\n getModificationDate,\n getVerbosityLevel,\n IDENTITY_MATRIX,\n ImageKind,\n info,\n InvalidPDFException,\n isArrayBuffer,\n isArrayEqual,\n isAscii,\n LINE_DESCENT_FACTOR,\n LINE_FACTOR,\n MissingPDFException,\n objectFromMap,\n objectSize,\n OPS,\n PageActionEventType,\n PasswordException,\n PasswordResponses,\n PermissionFlag,\n RenderingIntentFlag,\n setVerbosityLevel,\n shadow,\n StreamType,\n string32,\n stringToBytes,\n stringToPDFString,\n stringToUTF16BEString,\n stringToUTF8String,\n TextRenderingMode,\n UnexpectedResponseException,\n UnknownErrorException,\n unreachable,\n UNSUPPORTED_FEATURES,\n utf8StringToString,\n Util,\n VerbosityLevel,\n warn,\n};\n","/* Copyright 2017 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/* globals __non_webpack_require__ */\n\nimport { isNodeJS } from \"./is_node.js\";\n\n// Skip compatibility checks for modern builds and if we already ran the module.\nif (\n (typeof PDFJSDev === \"undefined\" || !PDFJSDev.test(\"SKIP_BABEL\")) &&\n !globalThis._pdfjsCompatibilityChecked\n) {\n globalThis._pdfjsCompatibilityChecked = true;\n\n // Support: Node.js<16.0.0\n (function checkNodeBtoa() {\n if (globalThis.btoa || !isNodeJS) {\n return;\n }\n globalThis.btoa = function (chars) {\n // eslint-disable-next-line no-undef\n return Buffer.from(chars, \"binary\").toString(\"base64\");\n };\n })();\n\n // Support: Node.js<16.0.0\n (function checkNodeAtob() {\n if (globalThis.atob || !isNodeJS) {\n return;\n }\n globalThis.atob = function (input) {\n // eslint-disable-next-line no-undef\n return Buffer.from(input, \"base64\").toString(\"binary\");\n };\n })();\n\n // Support: Node.js\n (function checkDOMMatrix() {\n if (globalThis.DOMMatrix || !isNodeJS) {\n return;\n }\n globalThis.DOMMatrix = __non_webpack_require__(\n \"dommatrix/dist/dommatrix.js\"\n );\n })();\n\n // Support: Node.js\n (function checkReadableStream() {\n if (globalThis.ReadableStream || !isNodeJS) {\n return;\n }\n globalThis.ReadableStream = __non_webpack_require__(\n \"web-streams-polyfill/dist/ponyfill.js\"\n ).ReadableStream;\n })();\n\n // Support: Firefox<90, Chrome<92, Safari<15.4, Node.js<16.6.0\n (function checkArrayAt() {\n if (Array.prototype.at) {\n return;\n }\n require(\"core-js/es/array/at.js\");\n })();\n\n // Support: Firefox<90, Chrome<92, Safari<15.4, Node.js<16.6.0\n (function checkTypedArrayAt() {\n if (Uint8Array.prototype.at) {\n return;\n }\n require(\"core-js/es/typed-array/at.js\");\n })();\n\n // Support: Firefox<94, Chrome<98, Safari<15.4, Node.js<17.0.0\n (function checkStructuredClone() {\n if (typeof PDFJSDev !== \"undefined\" && PDFJSDev.test(\"IMAGE_DECODERS\")) {\n // The current image decoders are synchronous, hence `structuredClone`\n // shouldn't need to be polyfilled for the IMAGE_DECODERS build target.\n return;\n }\n if (globalThis.structuredClone) {\n return;\n }\n require(\"core-js/web/structured-clone.js\");\n })();\n}\n","/* Copyright 2018 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/* globals process */\n\n// NW.js / Electron is a browser context, but copies some Node.js objects; see\n// http://docs.nwjs.io/en/latest/For%20Users/Advanced/JavaScript%20Contexts%20in%20NW.js/#access-nodejs-and-nwjs-api-in-browser-context\n// https://www.electronjs.org/docs/api/process#processversionselectron-readonly\n// https://www.electronjs.org/docs/api/process#processtype-readonly\nconst isNodeJS =\n (typeof PDFJSDev === \"undefined\" || PDFJSDev.test(\"GENERIC\")) &&\n typeof process === \"object\" &&\n process + \"\" === \"[object process]\" &&\n !process.versions.nw &&\n !(process.versions.electron && process.type && process.type !== \"browser\");\n\nexport { isNodeJS };\n","require('../../modules/es.array.at');\nvar entryUnbind = require('../../internals/entry-unbind');\n\nmodule.exports = entryUnbind('Array', 'at');\n","'use strict';\nvar $ = require('../internals/export');\nvar toObject = require('../internals/to-object');\nvar lengthOfArrayLike = require('../internals/length-of-array-like');\nvar toIntegerOrInfinity = require('../internals/to-integer-or-infinity');\nvar addToUnscopables = require('../internals/add-to-unscopables');\n\n// `Array.prototype.at` method\n// https://github.com/tc39/proposal-relative-indexing-method\n$({ target: 'Array', proto: true }, {\n at: function at(index) {\n var O = toObject(this);\n var len = lengthOfArrayLike(O);\n var relativeIndex = toIntegerOrInfinity(index);\n var k = relativeIndex >= 0 ? relativeIndex : len + relativeIndex;\n return (k < 0 || k >= len) ? undefined : O[k];\n }\n});\n\naddToUnscopables('at');\n","var global = require('../internals/global');\nvar getOwnPropertyDescriptor = require('../internals/object-get-own-property-descriptor').f;\nvar createNonEnumerableProperty = require('../internals/create-non-enumerable-property');\nvar defineBuiltIn = require('../internals/define-built-in');\nvar defineGlobalProperty = require('../internals/define-global-property');\nvar copyConstructorProperties = require('../internals/copy-constructor-properties');\nvar isForced = require('../internals/is-forced');\n\n/*\n options.target - name of the target object\n options.global - target is the global object\n options.stat - export as static methods of target\n options.proto - export as prototype methods of target\n options.real - real prototype method for the `pure` version\n options.forced - export even if the native feature is available\n options.bind - bind methods to the target, required for the `pure` version\n options.wrap - wrap constructors to preventing global pollution, required for the `pure` version\n options.unsafe - use the simple assignment of property instead of delete + defineProperty\n options.sham - add a flag to not completely full polyfills\n options.enumerable - export as enumerable property\n options.dontCallGetSet - prevent calling a getter on target\n options.name - the .name of the function if it does not match the key\n*/\nmodule.exports = function (options, source) {\n var TARGET = options.target;\n var GLOBAL = options.global;\n var STATIC = options.stat;\n var FORCED, target, key, targetProperty, sourceProperty, descriptor;\n if (GLOBAL) {\n target = global;\n } else if (STATIC) {\n target = global[TARGET] || defineGlobalProperty(TARGET, {});\n } else {\n target = (global[TARGET] || {}).prototype;\n }\n if (target) for (key in source) {\n sourceProperty = source[key];\n if (options.dontCallGetSet) {\n descriptor = getOwnPropertyDescriptor(target, key);\n targetProperty = descriptor && descriptor.value;\n } else targetProperty = target[key];\n FORCED = isForced(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced);\n // contained in target\n if (!FORCED && targetProperty !== undefined) {\n if (typeof sourceProperty == typeof targetProperty) continue;\n copyConstructorProperties(sourceProperty, targetProperty);\n }\n // add a flag to not completely full polyfills\n if (options.sham || (targetProperty && targetProperty.sham)) {\n createNonEnumerableProperty(sourceProperty, 'sham', true);\n }\n defineBuiltIn(target, key, sourceProperty, options);\n }\n};\n","var check = function (it) {\n return it && it.Math == Math && it;\n};\n\n// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028\nmodule.exports =\n // eslint-disable-next-line es-x/no-global-this -- safe\n check(typeof globalThis == 'object' && globalThis) ||\n check(typeof window == 'object' && window) ||\n // eslint-disable-next-line no-restricted-globals -- safe\n check(typeof self == 'object' && self) ||\n check(typeof global == 'object' && global) ||\n // eslint-disable-next-line no-new-func -- fallback\n (function () { return this; })() || Function('return this')();\n","var DESCRIPTORS = require('../internals/descriptors');\nvar call = require('../internals/function-call');\nvar propertyIsEnumerableModule = require('../internals/object-property-is-enumerable');\nvar createPropertyDescriptor = require('../internals/create-property-descriptor');\nvar toIndexedObject = require('../internals/to-indexed-object');\nvar toPropertyKey = require('../internals/to-property-key');\nvar hasOwn = require('../internals/has-own-property');\nvar IE8_DOM_DEFINE = require('../internals/ie8-dom-define');\n\n// eslint-disable-next-line es-x/no-object-getownpropertydescriptor -- safe\nvar $getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;\n\n// `Object.getOwnPropertyDescriptor` method\n// https://tc39.es/ecma262/#sec-object.getownpropertydescriptor\nexports.f = DESCRIPTORS ? $getOwnPropertyDescriptor : function getOwnPropertyDescriptor(O, P) {\n O = toIndexedObject(O);\n P = toPropertyKey(P);\n if (IE8_DOM_DEFINE) try {\n return $getOwnPropertyDescriptor(O, P);\n } catch (error) { /* empty */ }\n if (hasOwn(O, P)) return createPropertyDescriptor(!call(propertyIsEnumerableModule.f, O, P), O[P]);\n};\n","var fails = require('../internals/fails');\n\n// Detect IE8's incomplete defineProperty implementation\nmodule.exports = !fails(function () {\n // eslint-disable-next-line es-x/no-object-defineproperty -- required for testing\n return Object.defineProperty({}, 1, { get: function () { return 7; } })[1] != 7;\n});\n","module.exports = function (exec) {\n try {\n return !!exec();\n } catch (error) {\n return true;\n }\n};\n","var NATIVE_BIND = require('../internals/function-bind-native');\n\nvar call = Function.prototype.call;\n\nmodule.exports = NATIVE_BIND ? call.bind(call) : function () {\n return call.apply(call, arguments);\n};\n","var fails = require('../internals/fails');\n\nmodule.exports = !fails(function () {\n // eslint-disable-next-line es-x/no-function-prototype-bind -- safe\n var test = (function () { /* empty */ }).bind();\n // eslint-disable-next-line no-prototype-builtins -- safe\n return typeof test != 'function' || test.hasOwnProperty('prototype');\n});\n","'use strict';\nvar $propertyIsEnumerable = {}.propertyIsEnumerable;\n// eslint-disable-next-line es-x/no-object-getownpropertydescriptor -- safe\nvar getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;\n\n// Nashorn ~ JDK8 bug\nvar NASHORN_BUG = getOwnPropertyDescriptor && !$propertyIsEnumerable.call({ 1: 2 }, 1);\n\n// `Object.prototype.propertyIsEnumerable` method implementation\n// https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable\nexports.f = NASHORN_BUG ? function propertyIsEnumerable(V) {\n var descriptor = getOwnPropertyDescriptor(this, V);\n return !!descriptor && descriptor.enumerable;\n} : $propertyIsEnumerable;\n","module.exports = function (bitmap, value) {\n return {\n enumerable: !(bitmap & 1),\n configurable: !(bitmap & 2),\n writable: !(bitmap & 4),\n value: value\n };\n};\n","// toObject with fallback for non-array-like ES3 strings\nvar IndexedObject = require('../internals/indexed-object');\nvar requireObjectCoercible = require('../internals/require-object-coercible');\n\nmodule.exports = function (it) {\n return IndexedObject(requireObjectCoercible(it));\n};\n","var uncurryThis = require('../internals/function-uncurry-this');\nvar fails = require('../internals/fails');\nvar classof = require('../internals/classof-raw');\n\nvar $Object = Object;\nvar split = uncurryThis(''.split);\n\n// fallback for non-array-like ES3 and non-enumerable old V8 strings\nmodule.exports = fails(function () {\n // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346\n // eslint-disable-next-line no-prototype-builtins -- safe\n return !$Object('z').propertyIsEnumerable(0);\n}) ? function (it) {\n return classof(it) == 'String' ? split(it, '') : $Object(it);\n} : $Object;\n","var NATIVE_BIND = require('../internals/function-bind-native');\n\nvar FunctionPrototype = Function.prototype;\nvar bind = FunctionPrototype.bind;\nvar call = FunctionPrototype.call;\nvar uncurryThis = NATIVE_BIND && bind.bind(call, call);\n\nmodule.exports = NATIVE_BIND ? function (fn) {\n return fn && uncurryThis(fn);\n} : function (fn) {\n return fn && function () {\n return call.apply(fn, arguments);\n };\n};\n","var uncurryThis = require('../internals/function-uncurry-this');\n\nvar toString = uncurryThis({}.toString);\nvar stringSlice = uncurryThis(''.slice);\n\nmodule.exports = function (it) {\n return stringSlice(toString(it), 8, -1);\n};\n","var $TypeError = TypeError;\n\n// `RequireObjectCoercible` abstract operation\n// https://tc39.es/ecma262/#sec-requireobjectcoercible\nmodule.exports = function (it) {\n if (it == undefined) throw $TypeError(\"Can't call method on \" + it);\n return it;\n};\n","var toPrimitive = require('../internals/to-primitive');\nvar isSymbol = require('../internals/is-symbol');\n\n// `ToPropertyKey` abstract operation\n// https://tc39.es/ecma262/#sec-topropertykey\nmodule.exports = function (argument) {\n var key = toPrimitive(argument, 'string');\n return isSymbol(key) ? key : key + '';\n};\n","var call = require('../internals/function-call');\nvar isObject = require('../internals/is-object');\nvar isSymbol = require('../internals/is-symbol');\nvar getMethod = require('../internals/get-method');\nvar ordinaryToPrimitive = require('../internals/ordinary-to-primitive');\nvar wellKnownSymbol = require('../internals/well-known-symbol');\n\nvar $TypeError = TypeError;\nvar TO_PRIMITIVE = wellKnownSymbol('toPrimitive');\n\n// `ToPrimitive` abstract operation\n// https://tc39.es/ecma262/#sec-toprimitive\nmodule.exports = function (input, pref) {\n if (!isObject(input) || isSymbol(input)) return input;\n var exoticToPrim = getMethod(input, TO_PRIMITIVE);\n var result;\n if (exoticToPrim) {\n if (pref === undefined) pref = 'default';\n result = call(exoticToPrim, input, pref);\n if (!isObject(result) || isSymbol(result)) return result;\n throw $TypeError(\"Can't convert object to primitive value\");\n }\n if (pref === undefined) pref = 'number';\n return ordinaryToPrimitive(input, pref);\n};\n","var isCallable = require('../internals/is-callable');\n\nmodule.exports = function (it) {\n return typeof it == 'object' ? it !== null : isCallable(it);\n};\n","// `IsCallable` abstract operation\n// https://tc39.es/ecma262/#sec-iscallable\nmodule.exports = function (argument) {\n return typeof argument == 'function';\n};\n","var getBuiltIn = require('../internals/get-built-in');\nvar isCallable = require('../internals/is-callable');\nvar isPrototypeOf = require('../internals/object-is-prototype-of');\nvar USE_SYMBOL_AS_UID = require('../internals/use-symbol-as-uid');\n\nvar $Object = Object;\n\nmodule.exports = USE_SYMBOL_AS_UID ? function (it) {\n return typeof it == 'symbol';\n} : function (it) {\n var $Symbol = getBuiltIn('Symbol');\n return isCallable($Symbol) && isPrototypeOf($Symbol.prototype, $Object(it));\n};\n","var global = require('../internals/global');\nvar isCallable = require('../internals/is-callable');\n\nvar aFunction = function (argument) {\n return isCallable(argument) ? argument : undefined;\n};\n\nmodule.exports = function (namespace, method) {\n return arguments.length < 2 ? aFunction(global[namespace]) : global[namespace] && global[namespace][method];\n};\n","var uncurryThis = require('../internals/function-uncurry-this');\n\nmodule.exports = uncurryThis({}.isPrototypeOf);\n","/* eslint-disable es-x/no-symbol -- required for testing */\nvar NATIVE_SYMBOL = require('../internals/native-symbol');\n\nmodule.exports = NATIVE_SYMBOL\n && !Symbol.sham\n && typeof Symbol.iterator == 'symbol';\n","/* eslint-disable es-x/no-symbol -- required for testing */\nvar V8_VERSION = require('../internals/engine-v8-version');\nvar fails = require('../internals/fails');\n\n// eslint-disable-next-line es-x/no-object-getownpropertysymbols -- required for testing\nmodule.exports = !!Object.getOwnPropertySymbols && !fails(function () {\n var symbol = Symbol();\n // Chrome 38 Symbol has incorrect toString conversion\n // `get-own-property-symbols` polyfill symbols converted to object are not Symbol instances\n return !String(symbol) || !(Object(symbol) instanceof Symbol) ||\n // Chrome 38-40 symbols are not inherited from DOM collections prototypes to instances\n !Symbol.sham && V8_VERSION && V8_VERSION < 41;\n});\n","var global = require('../internals/global');\nvar userAgent = require('../internals/engine-user-agent');\n\nvar process = global.process;\nvar Deno = global.Deno;\nvar versions = process && process.versions || Deno && Deno.version;\nvar v8 = versions && versions.v8;\nvar match, version;\n\nif (v8) {\n match = v8.split('.');\n // in old Chrome, versions of V8 isn't V8 = Chrome / 10\n // but their correct versions are not interesting for us\n version = match[0] > 0 && match[0] < 4 ? 1 : +(match[0] + match[1]);\n}\n\n// BrowserFS NodeJS `process` polyfill incorrectly set `.v8` to `0.0`\n// so check `userAgent` even if `.v8` exists, but 0\nif (!version && userAgent) {\n match = userAgent.match(/Edge\\/(\\d+)/);\n if (!match || match[1] >= 74) {\n match = userAgent.match(/Chrome\\/(\\d+)/);\n if (match) version = +match[1];\n }\n}\n\nmodule.exports = version;\n","var getBuiltIn = require('../internals/get-built-in');\n\nmodule.exports = getBuiltIn('navigator', 'userAgent') || '';\n","var aCallable = require('../internals/a-callable');\n\n// `GetMethod` abstract operation\n// https://tc39.es/ecma262/#sec-getmethod\nmodule.exports = function (V, P) {\n var func = V[P];\n return func == null ? undefined : aCallable(func);\n};\n","var isCallable = require('../internals/is-callable');\nvar tryToString = require('../internals/try-to-string');\n\nvar $TypeError = TypeError;\n\n// `Assert: IsCallable(argument) is true`\nmodule.exports = function (argument) {\n if (isCallable(argument)) return argument;\n throw $TypeError(tryToString(argument) + ' is not a function');\n};\n","var $String = String;\n\nmodule.exports = function (argument) {\n try {\n return $String(argument);\n } catch (error) {\n return 'Object';\n }\n};\n","var call = require('../internals/function-call');\nvar isCallable = require('../internals/is-callable');\nvar isObject = require('../internals/is-object');\n\nvar $TypeError = TypeError;\n\n// `OrdinaryToPrimitive` abstract operation\n// https://tc39.es/ecma262/#sec-ordinarytoprimitive\nmodule.exports = function (input, pref) {\n var fn, val;\n if (pref === 'string' && isCallable(fn = input.toString) && !isObject(val = call(fn, input))) return val;\n if (isCallable(fn = input.valueOf) && !isObject(val = call(fn, input))) return val;\n if (pref !== 'string' && isCallable(fn = input.toString) && !isObject(val = call(fn, input))) return val;\n throw $TypeError(\"Can't convert object to primitive value\");\n};\n","var global = require('../internals/global');\nvar shared = require('../internals/shared');\nvar hasOwn = require('../internals/has-own-property');\nvar uid = require('../internals/uid');\nvar NATIVE_SYMBOL = require('../internals/native-symbol');\nvar USE_SYMBOL_AS_UID = require('../internals/use-symbol-as-uid');\n\nvar WellKnownSymbolsStore = shared('wks');\nvar Symbol = global.Symbol;\nvar symbolFor = Symbol && Symbol['for'];\nvar createWellKnownSymbol = USE_SYMBOL_AS_UID ? Symbol : Symbol && Symbol.withoutSetter || uid;\n\nmodule.exports = function (name) {\n if (!hasOwn(WellKnownSymbolsStore, name) || !(NATIVE_SYMBOL || typeof WellKnownSymbolsStore[name] == 'string')) {\n var description = 'Symbol.' + name;\n if (NATIVE_SYMBOL && hasOwn(Symbol, name)) {\n WellKnownSymbolsStore[name] = Symbol[name];\n } else if (USE_SYMBOL_AS_UID && symbolFor) {\n WellKnownSymbolsStore[name] = symbolFor(description);\n } else {\n WellKnownSymbolsStore[name] = createWellKnownSymbol(description);\n }\n } return WellKnownSymbolsStore[name];\n};\n","var IS_PURE = require('../internals/is-pure');\nvar store = require('../internals/shared-store');\n\n(module.exports = function (key, value) {\n return store[key] || (store[key] = value !== undefined ? value : {});\n})('versions', []).push({\n version: '3.24.1',\n mode: IS_PURE ? 'pure' : 'global',\n copyright: '© 2014-2022 Denis Pushkarev (zloirock.ru)',\n license: 'https://github.com/zloirock/core-js/blob/v3.24.1/LICENSE',\n source: 'https://github.com/zloirock/core-js'\n});\n","module.exports = false;\n","var global = require('../internals/global');\nvar defineGlobalProperty = require('../internals/define-global-property');\n\nvar SHARED = '__core-js_shared__';\nvar store = global[SHARED] || defineGlobalProperty(SHARED, {});\n\nmodule.exports = store;\n","var global = require('../internals/global');\n\n// eslint-disable-next-line es-x/no-object-defineproperty -- safe\nvar defineProperty = Object.defineProperty;\n\nmodule.exports = function (key, value) {\n try {\n defineProperty(global, key, { value: value, configurable: true, writable: true });\n } catch (error) {\n global[key] = value;\n } return value;\n};\n","var uncurryThis = require('../internals/function-uncurry-this');\nvar toObject = require('../internals/to-object');\n\nvar hasOwnProperty = uncurryThis({}.hasOwnProperty);\n\n// `HasOwnProperty` abstract operation\n// https://tc39.es/ecma262/#sec-hasownproperty\n// eslint-disable-next-line es-x/no-object-hasown -- safe\nmodule.exports = Object.hasOwn || function hasOwn(it, key) {\n return hasOwnProperty(toObject(it), key);\n};\n","var requireObjectCoercible = require('../internals/require-object-coercible');\n\nvar $Object = Object;\n\n// `ToObject` abstract operation\n// https://tc39.es/ecma262/#sec-toobject\nmodule.exports = function (argument) {\n return $Object(requireObjectCoercible(argument));\n};\n","var uncurryThis = require('../internals/function-uncurry-this');\n\nvar id = 0;\nvar postfix = Math.random();\nvar toString = uncurryThis(1.0.toString);\n\nmodule.exports = function (key) {\n return 'Symbol(' + (key === undefined ? '' : key) + ')_' + toString(++id + postfix, 36);\n};\n","var DESCRIPTORS = require('../internals/descriptors');\nvar fails = require('../internals/fails');\nvar createElement = require('../internals/document-create-element');\n\n// Thanks to IE8 for its funny defineProperty\nmodule.exports = !DESCRIPTORS && !fails(function () {\n // eslint-disable-next-line es-x/no-object-defineproperty -- required for testing\n return Object.defineProperty(createElement('div'), 'a', {\n get: function () { return 7; }\n }).a != 7;\n});\n","var global = require('../internals/global');\nvar isObject = require('../internals/is-object');\n\nvar document = global.document;\n// typeof document.createElement is 'object' in old IE\nvar EXISTS = isObject(document) && isObject(document.createElement);\n\nmodule.exports = function (it) {\n return EXISTS ? document.createElement(it) : {};\n};\n","var DESCRIPTORS = require('../internals/descriptors');\nvar definePropertyModule = require('../internals/object-define-property');\nvar createPropertyDescriptor = require('../internals/create-property-descriptor');\n\nmodule.exports = DESCRIPTORS ? function (object, key, value) {\n return definePropertyModule.f(object, key, createPropertyDescriptor(1, value));\n} : function (object, key, value) {\n object[key] = value;\n return object;\n};\n","var DESCRIPTORS = require('../internals/descriptors');\nvar IE8_DOM_DEFINE = require('../internals/ie8-dom-define');\nvar V8_PROTOTYPE_DEFINE_BUG = require('../internals/v8-prototype-define-bug');\nvar anObject = require('../internals/an-object');\nvar toPropertyKey = require('../internals/to-property-key');\n\nvar $TypeError = TypeError;\n// eslint-disable-next-line es-x/no-object-defineproperty -- safe\nvar $defineProperty = Object.defineProperty;\n// eslint-disable-next-line es-x/no-object-getownpropertydescriptor -- safe\nvar $getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;\nvar ENUMERABLE = 'enumerable';\nvar CONFIGURABLE = 'configurable';\nvar WRITABLE = 'writable';\n\n// `Object.defineProperty` method\n// https://tc39.es/ecma262/#sec-object.defineproperty\nexports.f = DESCRIPTORS ? V8_PROTOTYPE_DEFINE_BUG ? function defineProperty(O, P, Attributes) {\n anObject(O);\n P = toPropertyKey(P);\n anObject(Attributes);\n if (typeof O === 'function' && P === 'prototype' && 'value' in Attributes && WRITABLE in Attributes && !Attributes[WRITABLE]) {\n var current = $getOwnPropertyDescriptor(O, P);\n if (current && current[WRITABLE]) {\n O[P] = Attributes.value;\n Attributes = {\n configurable: CONFIGURABLE in Attributes ? Attributes[CONFIGURABLE] : current[CONFIGURABLE],\n enumerable: ENUMERABLE in Attributes ? Attributes[ENUMERABLE] : current[ENUMERABLE],\n writable: false\n };\n }\n } return $defineProperty(O, P, Attributes);\n} : $defineProperty : function defineProperty(O, P, Attributes) {\n anObject(O);\n P = toPropertyKey(P);\n anObject(Attributes);\n if (IE8_DOM_DEFINE) try {\n return $defineProperty(O, P, Attributes);\n } catch (error) { /* empty */ }\n if ('get' in Attributes || 'set' in Attributes) throw $TypeError('Accessors not supported');\n if ('value' in Attributes) O[P] = Attributes.value;\n return O;\n};\n","var DESCRIPTORS = require('../internals/descriptors');\nvar fails = require('../internals/fails');\n\n// V8 ~ Chrome 36-\n// https://bugs.chromium.org/p/v8/issues/detail?id=3334\nmodule.exports = DESCRIPTORS && fails(function () {\n // eslint-disable-next-line es-x/no-object-defineproperty -- required for testing\n return Object.defineProperty(function () { /* empty */ }, 'prototype', {\n value: 42,\n writable: false\n }).prototype != 42;\n});\n","var isObject = require('../internals/is-object');\n\nvar $String = String;\nvar $TypeError = TypeError;\n\n// `Assert: Type(argument) is Object`\nmodule.exports = function (argument) {\n if (isObject(argument)) return argument;\n throw $TypeError($String(argument) + ' is not an object');\n};\n","var isCallable = require('../internals/is-callable');\nvar definePropertyModule = require('../internals/object-define-property');\nvar makeBuiltIn = require('../internals/make-built-in');\nvar defineGlobalProperty = require('../internals/define-global-property');\n\nmodule.exports = function (O, key, value, options) {\n if (!options) options = {};\n var simple = options.enumerable;\n var name = options.name !== undefined ? options.name : key;\n if (isCallable(value)) makeBuiltIn(value, name, options);\n if (options.global) {\n if (simple) O[key] = value;\n else defineGlobalProperty(key, value);\n } else {\n try {\n if (!options.unsafe) delete O[key];\n else if (O[key]) simple = true;\n } catch (error) { /* empty */ }\n if (simple) O[key] = value;\n else definePropertyModule.f(O, key, {\n value: value,\n enumerable: false,\n configurable: !options.nonConfigurable,\n writable: !options.nonWritable\n });\n } return O;\n};\n","var fails = require('../internals/fails');\nvar isCallable = require('../internals/is-callable');\nvar hasOwn = require('../internals/has-own-property');\nvar DESCRIPTORS = require('../internals/descriptors');\nvar CONFIGURABLE_FUNCTION_NAME = require('../internals/function-name').CONFIGURABLE;\nvar inspectSource = require('../internals/inspect-source');\nvar InternalStateModule = require('../internals/internal-state');\n\nvar enforceInternalState = InternalStateModule.enforce;\nvar getInternalState = InternalStateModule.get;\n// eslint-disable-next-line es-x/no-object-defineproperty -- safe\nvar defineProperty = Object.defineProperty;\n\nvar CONFIGURABLE_LENGTH = DESCRIPTORS && !fails(function () {\n return defineProperty(function () { /* empty */ }, 'length', { value: 8 }).length !== 8;\n});\n\nvar TEMPLATE = String(String).split('String');\n\nvar makeBuiltIn = module.exports = function (value, name, options) {\n if (String(name).slice(0, 7) === 'Symbol(') {\n name = '[' + String(name).replace(/^Symbol\\(([^)]*)\\)/, '$1') + ']';\n }\n if (options && options.getter) name = 'get ' + name;\n if (options && options.setter) name = 'set ' + name;\n if (!hasOwn(value, 'name') || (CONFIGURABLE_FUNCTION_NAME && value.name !== name)) {\n if (DESCRIPTORS) defineProperty(value, 'name', { value: name, configurable: true });\n else value.name = name;\n }\n if (CONFIGURABLE_LENGTH && options && hasOwn(options, 'arity') && value.length !== options.arity) {\n defineProperty(value, 'length', { value: options.arity });\n }\n try {\n if (options && hasOwn(options, 'constructor') && options.constructor) {\n if (DESCRIPTORS) defineProperty(value, 'prototype', { writable: false });\n // in V8 ~ Chrome 53, prototypes of some methods, like `Array.prototype.values`, are non-writable\n } else if (value.prototype) value.prototype = undefined;\n } catch (error) { /* empty */ }\n var state = enforceInternalState(value);\n if (!hasOwn(state, 'source')) {\n state.source = TEMPLATE.join(typeof name == 'string' ? name : '');\n } return value;\n};\n\n// add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative\n// eslint-disable-next-line no-extend-native -- required\nFunction.prototype.toString = makeBuiltIn(function toString() {\n return isCallable(this) && getInternalState(this).source || inspectSource(this);\n}, 'toString');\n","var DESCRIPTORS = require('../internals/descriptors');\nvar hasOwn = require('../internals/has-own-property');\n\nvar FunctionPrototype = Function.prototype;\n// eslint-disable-next-line es-x/no-object-getownpropertydescriptor -- safe\nvar getDescriptor = DESCRIPTORS && Object.getOwnPropertyDescriptor;\n\nvar EXISTS = hasOwn(FunctionPrototype, 'name');\n// additional protection from minified / mangled / dropped function names\nvar PROPER = EXISTS && (function something() { /* empty */ }).name === 'something';\nvar CONFIGURABLE = EXISTS && (!DESCRIPTORS || (DESCRIPTORS && getDescriptor(FunctionPrototype, 'name').configurable));\n\nmodule.exports = {\n EXISTS: EXISTS,\n PROPER: PROPER,\n CONFIGURABLE: CONFIGURABLE\n};\n","var uncurryThis = require('../internals/function-uncurry-this');\nvar isCallable = require('../internals/is-callable');\nvar store = require('../internals/shared-store');\n\nvar functionToString = uncurryThis(Function.toString);\n\n// this helper broken in `core-js@3.4.1-3.4.4`, so we can't use `shared` helper\nif (!isCallable(store.inspectSource)) {\n store.inspectSource = function (it) {\n return functionToString(it);\n };\n}\n\nmodule.exports = store.inspectSource;\n","var NATIVE_WEAK_MAP = require('../internals/native-weak-map');\nvar global = require('../internals/global');\nvar uncurryThis = require('../internals/function-uncurry-this');\nvar isObject = require('../internals/is-object');\nvar createNonEnumerableProperty = require('../internals/create-non-enumerable-property');\nvar hasOwn = require('../internals/has-own-property');\nvar shared = require('../internals/shared-store');\nvar sharedKey = require('../internals/shared-key');\nvar hiddenKeys = require('../internals/hidden-keys');\n\nvar OBJECT_ALREADY_INITIALIZED = 'Object already initialized';\nvar TypeError = global.TypeError;\nvar WeakMap = global.WeakMap;\nvar set, get, has;\n\nvar enforce = function (it) {\n return has(it) ? get(it) : set(it, {});\n};\n\nvar getterFor = function (TYPE) {\n return function (it) {\n var state;\n if (!isObject(it) || (state = get(it)).type !== TYPE) {\n throw TypeError('Incompatible receiver, ' + TYPE + ' required');\n } return state;\n };\n};\n\nif (NATIVE_WEAK_MAP || shared.state) {\n var store = shared.state || (shared.state = new WeakMap());\n var wmget = uncurryThis(store.get);\n var wmhas = uncurryThis(store.has);\n var wmset = uncurryThis(store.set);\n set = function (it, metadata) {\n if (wmhas(store, it)) throw new TypeError(OBJECT_ALREADY_INITIALIZED);\n metadata.facade = it;\n wmset(store, it, metadata);\n return metadata;\n };\n get = function (it) {\n return wmget(store, it) || {};\n };\n has = function (it) {\n return wmhas(store, it);\n };\n} else {\n var STATE = sharedKey('state');\n hiddenKeys[STATE] = true;\n set = function (it, metadata) {\n if (hasOwn(it, STATE)) throw new TypeError(OBJECT_ALREADY_INITIALIZED);\n metadata.facade = it;\n createNonEnumerableProperty(it, STATE, metadata);\n return metadata;\n };\n get = function (it) {\n return hasOwn(it, STATE) ? it[STATE] : {};\n };\n has = function (it) {\n return hasOwn(it, STATE);\n };\n}\n\nmodule.exports = {\n set: set,\n get: get,\n has: has,\n enforce: enforce,\n getterFor: getterFor\n};\n","var global = require('../internals/global');\nvar isCallable = require('../internals/is-callable');\nvar inspectSource = require('../internals/inspect-source');\n\nvar WeakMap = global.WeakMap;\n\nmodule.exports = isCallable(WeakMap) && /native code/.test(inspectSource(WeakMap));\n","var shared = require('../internals/shared');\nvar uid = require('../internals/uid');\n\nvar keys = shared('keys');\n\nmodule.exports = function (key) {\n return keys[key] || (keys[key] = uid(key));\n};\n","module.exports = {};\n","var hasOwn = require('../internals/has-own-property');\nvar ownKeys = require('../internals/own-keys');\nvar getOwnPropertyDescriptorModule = require('../internals/object-get-own-property-descriptor');\nvar definePropertyModule = require('../internals/object-define-property');\n\nmodule.exports = function (target, source, exceptions) {\n var keys = ownKeys(source);\n var defineProperty = definePropertyModule.f;\n var getOwnPropertyDescriptor = getOwnPropertyDescriptorModule.f;\n for (var i = 0; i < keys.length; i++) {\n var key = keys[i];\n if (!hasOwn(target, key) && !(exceptions && hasOwn(exceptions, key))) {\n defineProperty(target, key, getOwnPropertyDescriptor(source, key));\n }\n }\n};\n","var getBuiltIn = require('../internals/get-built-in');\nvar uncurryThis = require('../internals/function-uncurry-this');\nvar getOwnPropertyNamesModule = require('../internals/object-get-own-property-names');\nvar getOwnPropertySymbolsModule = require('../internals/object-get-own-property-symbols');\nvar anObject = require('../internals/an-object');\n\nvar concat = uncurryThis([].concat);\n\n// all object keys, includes non-enumerable and symbols\nmodule.exports = getBuiltIn('Reflect', 'ownKeys') || function ownKeys(it) {\n var keys = getOwnPropertyNamesModule.f(anObject(it));\n var getOwnPropertySymbols = getOwnPropertySymbolsModule.f;\n return getOwnPropertySymbols ? concat(keys, getOwnPropertySymbols(it)) : keys;\n};\n","var internalObjectKeys = require('../internals/object-keys-internal');\nvar enumBugKeys = require('../internals/enum-bug-keys');\n\nvar hiddenKeys = enumBugKeys.concat('length', 'prototype');\n\n// `Object.getOwnPropertyNames` method\n// https://tc39.es/ecma262/#sec-object.getownpropertynames\n// eslint-disable-next-line es-x/no-object-getownpropertynames -- safe\nexports.f = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {\n return internalObjectKeys(O, hiddenKeys);\n};\n","var uncurryThis = require('../internals/function-uncurry-this');\nvar hasOwn = require('../internals/has-own-property');\nvar toIndexedObject = require('../internals/to-indexed-object');\nvar indexOf = require('../internals/array-includes').indexOf;\nvar hiddenKeys = require('../internals/hidden-keys');\n\nvar push = uncurryThis([].push);\n\nmodule.exports = function (object, names) {\n var O = toIndexedObject(object);\n var i = 0;\n var result = [];\n var key;\n for (key in O) !hasOwn(hiddenKeys, key) && hasOwn(O, key) && push(result, key);\n // Don't enum bug & hidden keys\n while (names.length > i) if (hasOwn(O, key = names[i++])) {\n ~indexOf(result, key) || push(result, key);\n }\n return result;\n};\n","var toIndexedObject = require('../internals/to-indexed-object');\nvar toAbsoluteIndex = require('../internals/to-absolute-index');\nvar lengthOfArrayLike = require('../internals/length-of-array-like');\n\n// `Array.prototype.{ indexOf, includes }` methods implementation\nvar createMethod = function (IS_INCLUDES) {\n return function ($this, el, fromIndex) {\n var O = toIndexedObject($this);\n var length = lengthOfArrayLike(O);\n var index = toAbsoluteIndex(fromIndex, length);\n var value;\n // Array#includes uses SameValueZero equality algorithm\n // eslint-disable-next-line no-self-compare -- NaN check\n if (IS_INCLUDES && el != el) while (length > index) {\n value = O[index++];\n // eslint-disable-next-line no-self-compare -- NaN check\n if (value != value) return true;\n // Array#indexOf ignores holes, Array#includes - not\n } else for (;length > index; index++) {\n if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;\n } return !IS_INCLUDES && -1;\n };\n};\n\nmodule.exports = {\n // `Array.prototype.includes` method\n // https://tc39.es/ecma262/#sec-array.prototype.includes\n includes: createMethod(true),\n // `Array.prototype.indexOf` method\n // https://tc39.es/ecma262/#sec-array.prototype.indexof\n indexOf: createMethod(false)\n};\n","var toIntegerOrInfinity = require('../internals/to-integer-or-infinity');\n\nvar max = Math.max;\nvar min = Math.min;\n\n// Helper for a popular repeating case of the spec:\n// Let integer be ? ToInteger(index).\n// If integer < 0, let result be max((length + integer), 0); else let result be min(integer, length).\nmodule.exports = function (index, length) {\n var integer = toIntegerOrInfinity(index);\n return integer < 0 ? max(integer + length, 0) : min(integer, length);\n};\n","var trunc = require('../internals/math-trunc');\n\n// `ToIntegerOrInfinity` abstract operation\n// https://tc39.es/ecma262/#sec-tointegerorinfinity\nmodule.exports = function (argument) {\n var number = +argument;\n // eslint-disable-next-line no-self-compare -- NaN check\n return number !== number || number === 0 ? 0 : trunc(number);\n};\n","var ceil = Math.ceil;\nvar floor = Math.floor;\n\n// `Math.trunc` method\n// https://tc39.es/ecma262/#sec-math.trunc\n// eslint-disable-next-line es-x/no-math-trunc -- safe\nmodule.exports = Math.trunc || function trunc(x) {\n var n = +x;\n return (n > 0 ? floor : ceil)(n);\n};\n","var toLength = require('../internals/to-length');\n\n// `LengthOfArrayLike` abstract operation\n// https://tc39.es/ecma262/#sec-lengthofarraylike\nmodule.exports = function (obj) {\n return toLength(obj.length);\n};\n","var toIntegerOrInfinity = require('../internals/to-integer-or-infinity');\n\nvar min = Math.min;\n\n// `ToLength` abstract operation\n// https://tc39.es/ecma262/#sec-tolength\nmodule.exports = function (argument) {\n return argument > 0 ? min(toIntegerOrInfinity(argument), 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991\n};\n","// IE8- don't enum bug keys\nmodule.exports = [\n 'constructor',\n 'hasOwnProperty',\n 'isPrototypeOf',\n 'propertyIsEnumerable',\n 'toLocaleString',\n 'toString',\n 'valueOf'\n];\n","// eslint-disable-next-line es-x/no-object-getownpropertysymbols -- safe\nexports.f = Object.getOwnPropertySymbols;\n","var fails = require('../internals/fails');\nvar isCallable = require('../internals/is-callable');\n\nvar replacement = /#|\\.prototype\\./;\n\nvar isForced = function (feature, detection) {\n var value = data[normalize(feature)];\n return value == POLYFILL ? true\n : value == NATIVE ? false\n : isCallable(detection) ? fails(detection)\n : !!detection;\n};\n\nvar normalize = isForced.normalize = function (string) {\n return String(string).replace(replacement, '.').toLowerCase();\n};\n\nvar data = isForced.data = {};\nvar NATIVE = isForced.NATIVE = 'N';\nvar POLYFILL = isForced.POLYFILL = 'P';\n\nmodule.exports = isForced;\n","var wellKnownSymbol = require('../internals/well-known-symbol');\nvar create = require('../internals/object-create');\nvar defineProperty = require('../internals/object-define-property').f;\n\nvar UNSCOPABLES = wellKnownSymbol('unscopables');\nvar ArrayPrototype = Array.prototype;\n\n// Array.prototype[@@unscopables]\n// https://tc39.es/ecma262/#sec-array.prototype-@@unscopables\nif (ArrayPrototype[UNSCOPABLES] == undefined) {\n defineProperty(ArrayPrototype, UNSCOPABLES, {\n configurable: true,\n value: create(null)\n });\n}\n\n// add a key to Array.prototype[@@unscopables]\nmodule.exports = function (key) {\n ArrayPrototype[UNSCOPABLES][key] = true;\n};\n","/* global ActiveXObject -- old IE, WSH */\nvar anObject = require('../internals/an-object');\nvar definePropertiesModule = require('../internals/object-define-properties');\nvar enumBugKeys = require('../internals/enum-bug-keys');\nvar hiddenKeys = require('../internals/hidden-keys');\nvar html = require('../internals/html');\nvar documentCreateElement = require('../internals/document-create-element');\nvar sharedKey = require('../internals/shared-key');\n\nvar GT = '>';\nvar LT = '<';\nvar PROTOTYPE = 'prototype';\nvar SCRIPT = 'script';\nvar IE_PROTO = sharedKey('IE_PROTO');\n\nvar EmptyConstructor = function () { /* empty */ };\n\nvar scriptTag = function (content) {\n return LT + SCRIPT + GT + content + LT + '/' + SCRIPT + GT;\n};\n\n// Create object with fake `null` prototype: use ActiveX Object with cleared prototype\nvar NullProtoObjectViaActiveX = function (activeXDocument) {\n activeXDocument.write(scriptTag(''));\n activeXDocument.close();\n var temp = activeXDocument.parentWindow.Object;\n activeXDocument = null; // avoid memory leak\n return temp;\n};\n\n// Create object with fake `null` prototype: use iframe Object with cleared prototype\nvar NullProtoObjectViaIFrame = function () {\n // Thrash, waste and sodomy: IE GC bug\n var iframe = documentCreateElement('iframe');\n var JS = 'java' + SCRIPT + ':';\n var iframeDocument;\n iframe.style.display = 'none';\n html.appendChild(iframe);\n // https://github.com/zloirock/core-js/issues/475\n iframe.src = String(JS);\n iframeDocument = iframe.contentWindow.document;\n iframeDocument.open();\n iframeDocument.write(scriptTag('document.F=Object'));\n iframeDocument.close();\n return iframeDocument.F;\n};\n\n// Check for document.domain and active x support\n// No need to use active x approach when document.domain is not set\n// see https://github.com/es-shims/es5-shim/issues/150\n// variation of https://github.com/kitcambridge/es5-shim/commit/4f738ac066346\n// avoid IE GC bug\nvar activeXDocument;\nvar NullProtoObject = function () {\n try {\n activeXDocument = new ActiveXObject('htmlfile');\n } catch (error) { /* ignore */ }\n NullProtoObject = typeof document != 'undefined'\n ? document.domain && activeXDocument\n ? NullProtoObjectViaActiveX(activeXDocument) // old IE\n : NullProtoObjectViaIFrame()\n : NullProtoObjectViaActiveX(activeXDocument); // WSH\n var length = enumBugKeys.length;\n while (length--) delete NullProtoObject[PROTOTYPE][enumBugKeys[length]];\n return NullProtoObject();\n};\n\nhiddenKeys[IE_PROTO] = true;\n\n// `Object.create` method\n// https://tc39.es/ecma262/#sec-object.create\n// eslint-disable-next-line es-x/no-object-create -- safe\nmodule.exports = Object.create || function create(O, Properties) {\n var result;\n if (O !== null) {\n EmptyConstructor[PROTOTYPE] = anObject(O);\n result = new EmptyConstructor();\n EmptyConstructor[PROTOTYPE] = null;\n // add \"__proto__\" for Object.getPrototypeOf polyfill\n result[IE_PROTO] = O;\n } else result = NullProtoObject();\n return Properties === undefined ? result : definePropertiesModule.f(result, Properties);\n};\n","var DESCRIPTORS = require('../internals/descriptors');\nvar V8_PROTOTYPE_DEFINE_BUG = require('../internals/v8-prototype-define-bug');\nvar definePropertyModule = require('../internals/object-define-property');\nvar anObject = require('../internals/an-object');\nvar toIndexedObject = require('../internals/to-indexed-object');\nvar objectKeys = require('../internals/object-keys');\n\n// `Object.defineProperties` method\n// https://tc39.es/ecma262/#sec-object.defineproperties\n// eslint-disable-next-line es-x/no-object-defineproperties -- safe\nexports.f = DESCRIPTORS && !V8_PROTOTYPE_DEFINE_BUG ? Object.defineProperties : function defineProperties(O, Properties) {\n anObject(O);\n var props = toIndexedObject(Properties);\n var keys = objectKeys(Properties);\n var length = keys.length;\n var index = 0;\n var key;\n while (length > index) definePropertyModule.f(O, key = keys[index++], props[key]);\n return O;\n};\n","var internalObjectKeys = require('../internals/object-keys-internal');\nvar enumBugKeys = require('../internals/enum-bug-keys');\n\n// `Object.keys` method\n// https://tc39.es/ecma262/#sec-object.keys\n// eslint-disable-next-line es-x/no-object-keys -- safe\nmodule.exports = Object.keys || function keys(O) {\n return internalObjectKeys(O, enumBugKeys);\n};\n","var getBuiltIn = require('../internals/get-built-in');\n\nmodule.exports = getBuiltIn('document', 'documentElement');\n","var global = require('../internals/global');\nvar uncurryThis = require('../internals/function-uncurry-this');\n\nmodule.exports = function (CONSTRUCTOR, METHOD) {\n return uncurryThis(global[CONSTRUCTOR].prototype[METHOD]);\n};\n","require('../../modules/es.typed-array.at');\n","'use strict';\nvar ArrayBufferViewCore = require('../internals/array-buffer-view-core');\nvar lengthOfArrayLike = require('../internals/length-of-array-like');\nvar toIntegerOrInfinity = require('../internals/to-integer-or-infinity');\n\nvar aTypedArray = ArrayBufferViewCore.aTypedArray;\nvar exportTypedArrayMethod = ArrayBufferViewCore.exportTypedArrayMethod;\n\n// `%TypedArray%.prototype.at` method\n// https://github.com/tc39/proposal-relative-indexing-method\nexportTypedArrayMethod('at', function at(index) {\n var O = aTypedArray(this);\n var len = lengthOfArrayLike(O);\n var relativeIndex = toIntegerOrInfinity(index);\n var k = relativeIndex >= 0 ? relativeIndex : len + relativeIndex;\n return (k < 0 || k >= len) ? undefined : O[k];\n});\n","'use strict';\nvar NATIVE_ARRAY_BUFFER = require('../internals/array-buffer-native');\nvar DESCRIPTORS = require('../internals/descriptors');\nvar global = require('../internals/global');\nvar isCallable = require('../internals/is-callable');\nvar isObject = require('../internals/is-object');\nvar hasOwn = require('../internals/has-own-property');\nvar classof = require('../internals/classof');\nvar tryToString = require('../internals/try-to-string');\nvar createNonEnumerableProperty = require('../internals/create-non-enumerable-property');\nvar defineBuiltIn = require('../internals/define-built-in');\nvar defineProperty = require('../internals/object-define-property').f;\nvar isPrototypeOf = require('../internals/object-is-prototype-of');\nvar getPrototypeOf = require('../internals/object-get-prototype-of');\nvar setPrototypeOf = require('../internals/object-set-prototype-of');\nvar wellKnownSymbol = require('../internals/well-known-symbol');\nvar uid = require('../internals/uid');\nvar InternalStateModule = require('../internals/internal-state');\n\nvar enforceInternalState = InternalStateModule.enforce;\nvar getInternalState = InternalStateModule.get;\nvar Int8Array = global.Int8Array;\nvar Int8ArrayPrototype = Int8Array && Int8Array.prototype;\nvar Uint8ClampedArray = global.Uint8ClampedArray;\nvar Uint8ClampedArrayPrototype = Uint8ClampedArray && Uint8ClampedArray.prototype;\nvar TypedArray = Int8Array && getPrototypeOf(Int8Array);\nvar TypedArrayPrototype = Int8ArrayPrototype && getPrototypeOf(Int8ArrayPrototype);\nvar ObjectPrototype = Object.prototype;\nvar TypeError = global.TypeError;\n\nvar TO_STRING_TAG = wellKnownSymbol('toStringTag');\nvar TYPED_ARRAY_TAG = uid('TYPED_ARRAY_TAG');\nvar TYPED_ARRAY_CONSTRUCTOR = 'TypedArrayConstructor';\n// Fixing native typed arrays in Opera Presto crashes the browser, see #595\nvar NATIVE_ARRAY_BUFFER_VIEWS = NATIVE_ARRAY_BUFFER && !!setPrototypeOf && classof(global.opera) !== 'Opera';\nvar TYPED_ARRAY_TAG_REQUIRED = false;\nvar NAME, Constructor, Prototype;\n\nvar TypedArrayConstructorsList = {\n Int8Array: 1,\n Uint8Array: 1,\n Uint8ClampedArray: 1,\n Int16Array: 2,\n Uint16Array: 2,\n Int32Array: 4,\n Uint32Array: 4,\n Float32Array: 4,\n Float64Array: 8\n};\n\nvar BigIntArrayConstructorsList = {\n BigInt64Array: 8,\n BigUint64Array: 8\n};\n\nvar isView = function isView(it) {\n if (!isObject(it)) return false;\n var klass = classof(it);\n return klass === 'DataView'\n || hasOwn(TypedArrayConstructorsList, klass)\n || hasOwn(BigIntArrayConstructorsList, klass);\n};\n\nvar getTypedArrayConstructor = function (it) {\n var proto = getPrototypeOf(it);\n if (!isObject(proto)) return;\n var state = getInternalState(proto);\n return (state && hasOwn(state, TYPED_ARRAY_CONSTRUCTOR)) ? state[TYPED_ARRAY_CONSTRUCTOR] : getTypedArrayConstructor(proto);\n};\n\nvar isTypedArray = function (it) {\n if (!isObject(it)) return false;\n var klass = classof(it);\n return hasOwn(TypedArrayConstructorsList, klass)\n || hasOwn(BigIntArrayConstructorsList, klass);\n};\n\nvar aTypedArray = function (it) {\n if (isTypedArray(it)) return it;\n throw TypeError('Target is not a typed array');\n};\n\nvar aTypedArrayConstructor = function (C) {\n if (isCallable(C) && (!setPrototypeOf || isPrototypeOf(TypedArray, C))) return C;\n throw TypeError(tryToString(C) + ' is not a typed array constructor');\n};\n\nvar exportTypedArrayMethod = function (KEY, property, forced, options) {\n if (!DESCRIPTORS) return;\n if (forced) for (var ARRAY in TypedArrayConstructorsList) {\n var TypedArrayConstructor = global[ARRAY];\n if (TypedArrayConstructor && hasOwn(TypedArrayConstructor.prototype, KEY)) try {\n delete TypedArrayConstructor.prototype[KEY];\n } catch (error) {\n // old WebKit bug - some methods are non-configurable\n try {\n TypedArrayConstructor.prototype[KEY] = property;\n } catch (error2) { /* empty */ }\n }\n }\n if (!TypedArrayPrototype[KEY] || forced) {\n defineBuiltIn(TypedArrayPrototype, KEY, forced ? property\n : NATIVE_ARRAY_BUFFER_VIEWS && Int8ArrayPrototype[KEY] || property, options);\n }\n};\n\nvar exportTypedArrayStaticMethod = function (KEY, property, forced) {\n var ARRAY, TypedArrayConstructor;\n if (!DESCRIPTORS) return;\n if (setPrototypeOf) {\n if (forced) for (ARRAY in TypedArrayConstructorsList) {\n TypedArrayConstructor = global[ARRAY];\n if (TypedArrayConstructor && hasOwn(TypedArrayConstructor, KEY)) try {\n delete TypedArrayConstructor[KEY];\n } catch (error) { /* empty */ }\n }\n if (!TypedArray[KEY] || forced) {\n // V8 ~ Chrome 49-50 `%TypedArray%` methods are non-writable non-configurable\n try {\n return defineBuiltIn(TypedArray, KEY, forced ? property : NATIVE_ARRAY_BUFFER_VIEWS && TypedArray[KEY] || property);\n } catch (error) { /* empty */ }\n } else return;\n }\n for (ARRAY in TypedArrayConstructorsList) {\n TypedArrayConstructor = global[ARRAY];\n if (TypedArrayConstructor && (!TypedArrayConstructor[KEY] || forced)) {\n defineBuiltIn(TypedArrayConstructor, KEY, property);\n }\n }\n};\n\nfor (NAME in TypedArrayConstructorsList) {\n Constructor = global[NAME];\n Prototype = Constructor && Constructor.prototype;\n if (Prototype) enforceInternalState(Prototype)[TYPED_ARRAY_CONSTRUCTOR] = Constructor;\n else NATIVE_ARRAY_BUFFER_VIEWS = false;\n}\n\nfor (NAME in BigIntArrayConstructorsList) {\n Constructor = global[NAME];\n Prototype = Constructor && Constructor.prototype;\n if (Prototype) enforceInternalState(Prototype)[TYPED_ARRAY_CONSTRUCTOR] = Constructor;\n}\n\n// WebKit bug - typed arrays constructors prototype is Object.prototype\nif (!NATIVE_ARRAY_BUFFER_VIEWS || !isCallable(TypedArray) || TypedArray === Function.prototype) {\n // eslint-disable-next-line no-shadow -- safe\n TypedArray = function TypedArray() {\n throw TypeError('Incorrect invocation');\n };\n if (NATIVE_ARRAY_BUFFER_VIEWS) for (NAME in TypedArrayConstructorsList) {\n if (global[NAME]) setPrototypeOf(global[NAME], TypedArray);\n }\n}\n\nif (!NATIVE_ARRAY_BUFFER_VIEWS || !TypedArrayPrototype || TypedArrayPrototype === ObjectPrototype) {\n TypedArrayPrototype = TypedArray.prototype;\n if (NATIVE_ARRAY_BUFFER_VIEWS) for (NAME in TypedArrayConstructorsList) {\n if (global[NAME]) setPrototypeOf(global[NAME].prototype, TypedArrayPrototype);\n }\n}\n\n// WebKit bug - one more object in Uint8ClampedArray prototype chain\nif (NATIVE_ARRAY_BUFFER_VIEWS && getPrototypeOf(Uint8ClampedArrayPrototype) !== TypedArrayPrototype) {\n setPrototypeOf(Uint8ClampedArrayPrototype, TypedArrayPrototype);\n}\n\nif (DESCRIPTORS && !hasOwn(TypedArrayPrototype, TO_STRING_TAG)) {\n TYPED_ARRAY_TAG_REQUIRED = true;\n defineProperty(TypedArrayPrototype, TO_STRING_TAG, { get: function () {\n return isObject(this) ? this[TYPED_ARRAY_TAG] : undefined;\n } });\n for (NAME in TypedArrayConstructorsList) if (global[NAME]) {\n createNonEnumerableProperty(global[NAME], TYPED_ARRAY_TAG, NAME);\n }\n}\n\nmodule.exports = {\n NATIVE_ARRAY_BUFFER_VIEWS: NATIVE_ARRAY_BUFFER_VIEWS,\n TYPED_ARRAY_TAG: TYPED_ARRAY_TAG_REQUIRED && TYPED_ARRAY_TAG,\n aTypedArray: aTypedArray,\n aTypedArrayConstructor: aTypedArrayConstructor,\n exportTypedArrayMethod: exportTypedArrayMethod,\n exportTypedArrayStaticMethod: exportTypedArrayStaticMethod,\n getTypedArrayConstructor: getTypedArrayConstructor,\n isView: isView,\n isTypedArray: isTypedArray,\n TypedArray: TypedArray,\n TypedArrayPrototype: TypedArrayPrototype\n};\n","// eslint-disable-next-line es-x/no-typed-arrays -- safe\nmodule.exports = typeof ArrayBuffer != 'undefined' && typeof DataView != 'undefined';\n","var TO_STRING_TAG_SUPPORT = require('../internals/to-string-tag-support');\nvar isCallable = require('../internals/is-callable');\nvar classofRaw = require('../internals/classof-raw');\nvar wellKnownSymbol = require('../internals/well-known-symbol');\n\nvar TO_STRING_TAG = wellKnownSymbol('toStringTag');\nvar $Object = Object;\n\n// ES3 wrong here\nvar CORRECT_ARGUMENTS = classofRaw(function () { return arguments; }()) == 'Arguments';\n\n// fallback for IE11 Script Access Denied error\nvar tryGet = function (it, key) {\n try {\n return it[key];\n } catch (error) { /* empty */ }\n};\n\n// getting tag from ES6+ `Object.prototype.toString`\nmodule.exports = TO_STRING_TAG_SUPPORT ? classofRaw : function (it) {\n var O, tag, result;\n return it === undefined ? 'Undefined' : it === null ? 'Null'\n // @@toStringTag case\n : typeof (tag = tryGet(O = $Object(it), TO_STRING_TAG)) == 'string' ? tag\n // builtinTag case\n : CORRECT_ARGUMENTS ? classofRaw(O)\n // ES3 arguments fallback\n : (result = classofRaw(O)) == 'Object' && isCallable(O.callee) ? 'Arguments' : result;\n};\n","var wellKnownSymbol = require('../internals/well-known-symbol');\n\nvar TO_STRING_TAG = wellKnownSymbol('toStringTag');\nvar test = {};\n\ntest[TO_STRING_TAG] = 'z';\n\nmodule.exports = String(test) === '[object z]';\n","var hasOwn = require('../internals/has-own-property');\nvar isCallable = require('../internals/is-callable');\nvar toObject = require('../internals/to-object');\nvar sharedKey = require('../internals/shared-key');\nvar CORRECT_PROTOTYPE_GETTER = require('../internals/correct-prototype-getter');\n\nvar IE_PROTO = sharedKey('IE_PROTO');\nvar $Object = Object;\nvar ObjectPrototype = $Object.prototype;\n\n// `Object.getPrototypeOf` method\n// https://tc39.es/ecma262/#sec-object.getprototypeof\n// eslint-disable-next-line es-x/no-object-getprototypeof -- safe\nmodule.exports = CORRECT_PROTOTYPE_GETTER ? $Object.getPrototypeOf : function (O) {\n var object = toObject(O);\n if (hasOwn(object, IE_PROTO)) return object[IE_PROTO];\n var constructor = object.constructor;\n if (isCallable(constructor) && object instanceof constructor) {\n return constructor.prototype;\n } return object instanceof $Object ? ObjectPrototype : null;\n};\n","var fails = require('../internals/fails');\n\nmodule.exports = !fails(function () {\n function F() { /* empty */ }\n F.prototype.constructor = null;\n // eslint-disable-next-line es-x/no-object-getprototypeof -- required for testing\n return Object.getPrototypeOf(new F()) !== F.prototype;\n});\n","/* eslint-disable no-proto -- safe */\nvar uncurryThis = require('../internals/function-uncurry-this');\nvar anObject = require('../internals/an-object');\nvar aPossiblePrototype = require('../internals/a-possible-prototype');\n\n// `Object.setPrototypeOf` method\n// https://tc39.es/ecma262/#sec-object.setprototypeof\n// Works with __proto__ only. Old v8 can't work with null proto objects.\n// eslint-disable-next-line es-x/no-object-setprototypeof -- safe\nmodule.exports = Object.setPrototypeOf || ('__proto__' in {} ? function () {\n var CORRECT_SETTER = false;\n var test = {};\n var setter;\n try {\n // eslint-disable-next-line es-x/no-object-getownpropertydescriptor -- safe\n setter = uncurryThis(Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set);\n setter(test, []);\n CORRECT_SETTER = test instanceof Array;\n } catch (error) { /* empty */ }\n return function setPrototypeOf(O, proto) {\n anObject(O);\n aPossiblePrototype(proto);\n if (CORRECT_SETTER) setter(O, proto);\n else O.__proto__ = proto;\n return O;\n };\n}() : undefined);\n","var isCallable = require('../internals/is-callable');\n\nvar $String = String;\nvar $TypeError = TypeError;\n\nmodule.exports = function (argument) {\n if (typeof argument == 'object' || isCallable(argument)) return argument;\n throw $TypeError(\"Can't set \" + $String(argument) + ' as a prototype');\n};\n","require('../modules/es.array.iterator');\nrequire('../modules/es.object.to-string');\nrequire('../modules/es.map');\nrequire('../modules/es.set');\nrequire('../modules/web.structured-clone');\nvar path = require('../internals/path');\n\nmodule.exports = path.structuredClone;\n","'use strict';\nvar toIndexedObject = require('../internals/to-indexed-object');\nvar addToUnscopables = require('../internals/add-to-unscopables');\nvar Iterators = require('../internals/iterators');\nvar InternalStateModule = require('../internals/internal-state');\nvar defineProperty = require('../internals/object-define-property').f;\nvar defineIterator = require('../internals/define-iterator');\nvar IS_PURE = require('../internals/is-pure');\nvar DESCRIPTORS = require('../internals/descriptors');\n\nvar ARRAY_ITERATOR = 'Array Iterator';\nvar setInternalState = InternalStateModule.set;\nvar getInternalState = InternalStateModule.getterFor(ARRAY_ITERATOR);\n\n// `Array.prototype.entries` method\n// https://tc39.es/ecma262/#sec-array.prototype.entries\n// `Array.prototype.keys` method\n// https://tc39.es/ecma262/#sec-array.prototype.keys\n// `Array.prototype.values` method\n// https://tc39.es/ecma262/#sec-array.prototype.values\n// `Array.prototype[@@iterator]` method\n// https://tc39.es/ecma262/#sec-array.prototype-@@iterator\n// `CreateArrayIterator` internal method\n// https://tc39.es/ecma262/#sec-createarrayiterator\nmodule.exports = defineIterator(Array, 'Array', function (iterated, kind) {\n setInternalState(this, {\n type: ARRAY_ITERATOR,\n target: toIndexedObject(iterated), // target\n index: 0, // next index\n kind: kind // kind\n });\n// `%ArrayIteratorPrototype%.next` method\n// https://tc39.es/ecma262/#sec-%arrayiteratorprototype%.next\n}, function () {\n var state = getInternalState(this);\n var target = state.target;\n var kind = state.kind;\n var index = state.index++;\n if (!target || index >= target.length) {\n state.target = undefined;\n return { value: undefined, done: true };\n }\n if (kind == 'keys') return { value: index, done: false };\n if (kind == 'values') return { value: target[index], done: false };\n return { value: [index, target[index]], done: false };\n}, 'values');\n\n// argumentsList[@@iterator] is %ArrayProto_values%\n// https://tc39.es/ecma262/#sec-createunmappedargumentsobject\n// https://tc39.es/ecma262/#sec-createmappedargumentsobject\nvar values = Iterators.Arguments = Iterators.Array;\n\n// https://tc39.es/ecma262/#sec-array.prototype-@@unscopables\naddToUnscopables('keys');\naddToUnscopables('values');\naddToUnscopables('entries');\n\n// V8 ~ Chrome 45- bug\nif (!IS_PURE && DESCRIPTORS && values.name !== 'values') try {\n defineProperty(values, 'name', { value: 'values' });\n} catch (error) { /* empty */ }\n","module.exports = {};\n","'use strict';\nvar $ = require('../internals/export');\nvar call = require('../internals/function-call');\nvar IS_PURE = require('../internals/is-pure');\nvar FunctionName = require('../internals/function-name');\nvar isCallable = require('../internals/is-callable');\nvar createIteratorConstructor = require('../internals/create-iterator-constructor');\nvar getPrototypeOf = require('../internals/object-get-prototype-of');\nvar setPrototypeOf = require('../internals/object-set-prototype-of');\nvar setToStringTag = require('../internals/set-to-string-tag');\nvar createNonEnumerableProperty = require('../internals/create-non-enumerable-property');\nvar defineBuiltIn = require('../internals/define-built-in');\nvar wellKnownSymbol = require('../internals/well-known-symbol');\nvar Iterators = require('../internals/iterators');\nvar IteratorsCore = require('../internals/iterators-core');\n\nvar PROPER_FUNCTION_NAME = FunctionName.PROPER;\nvar CONFIGURABLE_FUNCTION_NAME = FunctionName.CONFIGURABLE;\nvar IteratorPrototype = IteratorsCore.IteratorPrototype;\nvar BUGGY_SAFARI_ITERATORS = IteratorsCore.BUGGY_SAFARI_ITERATORS;\nvar ITERATOR = wellKnownSymbol('iterator');\nvar KEYS = 'keys';\nvar VALUES = 'values';\nvar ENTRIES = 'entries';\n\nvar returnThis = function () { return this; };\n\nmodule.exports = function (Iterable, NAME, IteratorConstructor, next, DEFAULT, IS_SET, FORCED) {\n createIteratorConstructor(IteratorConstructor, NAME, next);\n\n var getIterationMethod = function (KIND) {\n if (KIND === DEFAULT && defaultIterator) return defaultIterator;\n if (!BUGGY_SAFARI_ITERATORS && KIND in IterablePrototype) return IterablePrototype[KIND];\n switch (KIND) {\n case KEYS: return function keys() { return new IteratorConstructor(this, KIND); };\n case VALUES: return function values() { return new IteratorConstructor(this, KIND); };\n case ENTRIES: return function entries() { return new IteratorConstructor(this, KIND); };\n } return function () { return new IteratorConstructor(this); };\n };\n\n var TO_STRING_TAG = NAME + ' Iterator';\n var INCORRECT_VALUES_NAME = false;\n var IterablePrototype = Iterable.prototype;\n var nativeIterator = IterablePrototype[ITERATOR]\n || IterablePrototype['@@iterator']\n || DEFAULT && IterablePrototype[DEFAULT];\n var defaultIterator = !BUGGY_SAFARI_ITERATORS && nativeIterator || getIterationMethod(DEFAULT);\n var anyNativeIterator = NAME == 'Array' ? IterablePrototype.entries || nativeIterator : nativeIterator;\n var CurrentIteratorPrototype, methods, KEY;\n\n // fix native\n if (anyNativeIterator) {\n CurrentIteratorPrototype = getPrototypeOf(anyNativeIterator.call(new Iterable()));\n if (CurrentIteratorPrototype !== Object.prototype && CurrentIteratorPrototype.next) {\n if (!IS_PURE && getPrototypeOf(CurrentIteratorPrototype) !== IteratorPrototype) {\n if (setPrototypeOf) {\n setPrototypeOf(CurrentIteratorPrototype, IteratorPrototype);\n } else if (!isCallable(CurrentIteratorPrototype[ITERATOR])) {\n defineBuiltIn(CurrentIteratorPrototype, ITERATOR, returnThis);\n }\n }\n // Set @@toStringTag to native iterators\n setToStringTag(CurrentIteratorPrototype, TO_STRING_TAG, true, true);\n if (IS_PURE) Iterators[TO_STRING_TAG] = returnThis;\n }\n }\n\n // fix Array.prototype.{ values, @@iterator }.name in V8 / FF\n if (PROPER_FUNCTION_NAME && DEFAULT == VALUES && nativeIterator && nativeIterator.name !== VALUES) {\n if (!IS_PURE && CONFIGURABLE_FUNCTION_NAME) {\n createNonEnumerableProperty(IterablePrototype, 'name', VALUES);\n } else {\n INCORRECT_VALUES_NAME = true;\n defaultIterator = function values() { return call(nativeIterator, this); };\n }\n }\n\n // export additional methods\n if (DEFAULT) {\n methods = {\n values: getIterationMethod(VALUES),\n keys: IS_SET ? defaultIterator : getIterationMethod(KEYS),\n entries: getIterationMethod(ENTRIES)\n };\n if (FORCED) for (KEY in methods) {\n if (BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME || !(KEY in IterablePrototype)) {\n defineBuiltIn(IterablePrototype, KEY, methods[KEY]);\n }\n } else $({ target: NAME, proto: true, forced: BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME }, methods);\n }\n\n // define iterator\n if ((!IS_PURE || FORCED) && IterablePrototype[ITERATOR] !== defaultIterator) {\n defineBuiltIn(IterablePrototype, ITERATOR, defaultIterator, { name: DEFAULT });\n }\n Iterators[NAME] = defaultIterator;\n\n return methods;\n};\n","'use strict';\nvar IteratorPrototype = require('../internals/iterators-core').IteratorPrototype;\nvar create = require('../internals/object-create');\nvar createPropertyDescriptor = require('../internals/create-property-descriptor');\nvar setToStringTag = require('../internals/set-to-string-tag');\nvar Iterators = require('../internals/iterators');\n\nvar returnThis = function () { return this; };\n\nmodule.exports = function (IteratorConstructor, NAME, next, ENUMERABLE_NEXT) {\n var TO_STRING_TAG = NAME + ' Iterator';\n IteratorConstructor.prototype = create(IteratorPrototype, { next: createPropertyDescriptor(+!ENUMERABLE_NEXT, next) });\n setToStringTag(IteratorConstructor, TO_STRING_TAG, false, true);\n Iterators[TO_STRING_TAG] = returnThis;\n return IteratorConstructor;\n};\n","'use strict';\nvar fails = require('../internals/fails');\nvar isCallable = require('../internals/is-callable');\nvar create = require('../internals/object-create');\nvar getPrototypeOf = require('../internals/object-get-prototype-of');\nvar defineBuiltIn = require('../internals/define-built-in');\nvar wellKnownSymbol = require('../internals/well-known-symbol');\nvar IS_PURE = require('../internals/is-pure');\n\nvar ITERATOR = wellKnownSymbol('iterator');\nvar BUGGY_SAFARI_ITERATORS = false;\n\n// `%IteratorPrototype%` object\n// https://tc39.es/ecma262/#sec-%iteratorprototype%-object\nvar IteratorPrototype, PrototypeOfArrayIteratorPrototype, arrayIterator;\n\n/* eslint-disable es-x/no-array-prototype-keys -- safe */\nif ([].keys) {\n arrayIterator = [].keys();\n // Safari 8 has buggy iterators w/o `next`\n if (!('next' in arrayIterator)) BUGGY_SAFARI_ITERATORS = true;\n else {\n PrototypeOfArrayIteratorPrototype = getPrototypeOf(getPrototypeOf(arrayIterator));\n if (PrototypeOfArrayIteratorPrototype !== Object.prototype) IteratorPrototype = PrototypeOfArrayIteratorPrototype;\n }\n}\n\nvar NEW_ITERATOR_PROTOTYPE = IteratorPrototype == undefined || fails(function () {\n var test = {};\n // FF44- legacy iterators case\n return IteratorPrototype[ITERATOR].call(test) !== test;\n});\n\nif (NEW_ITERATOR_PROTOTYPE) IteratorPrototype = {};\nelse if (IS_PURE) IteratorPrototype = create(IteratorPrototype);\n\n// `%IteratorPrototype%[@@iterator]()` method\n// https://tc39.es/ecma262/#sec-%iteratorprototype%-@@iterator\nif (!isCallable(IteratorPrototype[ITERATOR])) {\n defineBuiltIn(IteratorPrototype, ITERATOR, function () {\n return this;\n });\n}\n\nmodule.exports = {\n IteratorPrototype: IteratorPrototype,\n BUGGY_SAFARI_ITERATORS: BUGGY_SAFARI_ITERATORS\n};\n","var defineProperty = require('../internals/object-define-property').f;\nvar hasOwn = require('../internals/has-own-property');\nvar wellKnownSymbol = require('../internals/well-known-symbol');\n\nvar TO_STRING_TAG = wellKnownSymbol('toStringTag');\n\nmodule.exports = function (target, TAG, STATIC) {\n if (target && !STATIC) target = target.prototype;\n if (target && !hasOwn(target, TO_STRING_TAG)) {\n defineProperty(target, TO_STRING_TAG, { configurable: true, value: TAG });\n }\n};\n","var TO_STRING_TAG_SUPPORT = require('../internals/to-string-tag-support');\nvar defineBuiltIn = require('../internals/define-built-in');\nvar toString = require('../internals/object-to-string');\n\n// `Object.prototype.toString` method\n// https://tc39.es/ecma262/#sec-object.prototype.tostring\nif (!TO_STRING_TAG_SUPPORT) {\n defineBuiltIn(Object.prototype, 'toString', toString, { unsafe: true });\n}\n","'use strict';\nvar TO_STRING_TAG_SUPPORT = require('../internals/to-string-tag-support');\nvar classof = require('../internals/classof');\n\n// `Object.prototype.toString` method implementation\n// https://tc39.es/ecma262/#sec-object.prototype.tostring\nmodule.exports = TO_STRING_TAG_SUPPORT ? {}.toString : function toString() {\n return '[object ' + classof(this) + ']';\n};\n","// TODO: Remove this module from `core-js@4` since it's replaced to module below\nrequire('../modules/es.map.constructor');\n","'use strict';\nvar collection = require('../internals/collection');\nvar collectionStrong = require('../internals/collection-strong');\n\n// `Map` constructor\n// https://tc39.es/ecma262/#sec-map-objects\ncollection('Map', function (init) {\n return function Map() { return init(this, arguments.length ? arguments[0] : undefined); };\n}, collectionStrong);\n","'use strict';\nvar $ = require('../internals/export');\nvar global = require('../internals/global');\nvar uncurryThis = require('../internals/function-uncurry-this');\nvar isForced = require('../internals/is-forced');\nvar defineBuiltIn = require('../internals/define-built-in');\nvar InternalMetadataModule = require('../internals/internal-metadata');\nvar iterate = require('../internals/iterate');\nvar anInstance = require('../internals/an-instance');\nvar isCallable = require('../internals/is-callable');\nvar isObject = require('../internals/is-object');\nvar fails = require('../internals/fails');\nvar checkCorrectnessOfIteration = require('../internals/check-correctness-of-iteration');\nvar setToStringTag = require('../internals/set-to-string-tag');\nvar inheritIfRequired = require('../internals/inherit-if-required');\n\nmodule.exports = function (CONSTRUCTOR_NAME, wrapper, common) {\n var IS_MAP = CONSTRUCTOR_NAME.indexOf('Map') !== -1;\n var IS_WEAK = CONSTRUCTOR_NAME.indexOf('Weak') !== -1;\n var ADDER = IS_MAP ? 'set' : 'add';\n var NativeConstructor = global[CONSTRUCTOR_NAME];\n var NativePrototype = NativeConstructor && NativeConstructor.prototype;\n var Constructor = NativeConstructor;\n var exported = {};\n\n var fixMethod = function (KEY) {\n var uncurriedNativeMethod = uncurryThis(NativePrototype[KEY]);\n defineBuiltIn(NativePrototype, KEY,\n KEY == 'add' ? function add(value) {\n uncurriedNativeMethod(this, value === 0 ? 0 : value);\n return this;\n } : KEY == 'delete' ? function (key) {\n return IS_WEAK && !isObject(key) ? false : uncurriedNativeMethod(this, key === 0 ? 0 : key);\n } : KEY == 'get' ? function get(key) {\n return IS_WEAK && !isObject(key) ? undefined : uncurriedNativeMethod(this, key === 0 ? 0 : key);\n } : KEY == 'has' ? function has(key) {\n return IS_WEAK && !isObject(key) ? false : uncurriedNativeMethod(this, key === 0 ? 0 : key);\n } : function set(key, value) {\n uncurriedNativeMethod(this, key === 0 ? 0 : key, value);\n return this;\n }\n );\n };\n\n var REPLACE = isForced(\n CONSTRUCTOR_NAME,\n !isCallable(NativeConstructor) || !(IS_WEAK || NativePrototype.forEach && !fails(function () {\n new NativeConstructor().entries().next();\n }))\n );\n\n if (REPLACE) {\n // create collection constructor\n Constructor = common.getConstructor(wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER);\n InternalMetadataModule.enable();\n } else if (isForced(CONSTRUCTOR_NAME, true)) {\n var instance = new Constructor();\n // early implementations not supports chaining\n var HASNT_CHAINING = instance[ADDER](IS_WEAK ? {} : -0, 1) != instance;\n // V8 ~ Chromium 40- weak-collections throws on primitives, but should return false\n var THROWS_ON_PRIMITIVES = fails(function () { instance.has(1); });\n // most early implementations doesn't supports iterables, most modern - not close it correctly\n // eslint-disable-next-line no-new -- required for testing\n var ACCEPT_ITERABLES = checkCorrectnessOfIteration(function (iterable) { new NativeConstructor(iterable); });\n // for early implementations -0 and +0 not the same\n var BUGGY_ZERO = !IS_WEAK && fails(function () {\n // V8 ~ Chromium 42- fails only with 5+ elements\n var $instance = new NativeConstructor();\n var index = 5;\n while (index--) $instance[ADDER](index, index);\n return !$instance.has(-0);\n });\n\n if (!ACCEPT_ITERABLES) {\n Constructor = wrapper(function (dummy, iterable) {\n anInstance(dummy, NativePrototype);\n var that = inheritIfRequired(new NativeConstructor(), dummy, Constructor);\n if (iterable != undefined) iterate(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });\n return that;\n });\n Constructor.prototype = NativePrototype;\n NativePrototype.constructor = Constructor;\n }\n\n if (THROWS_ON_PRIMITIVES || BUGGY_ZERO) {\n fixMethod('delete');\n fixMethod('has');\n IS_MAP && fixMethod('get');\n }\n\n if (BUGGY_ZERO || HASNT_CHAINING) fixMethod(ADDER);\n\n // weak collections should not contains .clear method\n if (IS_WEAK && NativePrototype.clear) delete NativePrototype.clear;\n }\n\n exported[CONSTRUCTOR_NAME] = Constructor;\n $({ global: true, constructor: true, forced: Constructor != NativeConstructor }, exported);\n\n setToStringTag(Constructor, CONSTRUCTOR_NAME);\n\n if (!IS_WEAK) common.setStrong(Constructor, CONSTRUCTOR_NAME, IS_MAP);\n\n return Constructor;\n};\n","var $ = require('../internals/export');\nvar uncurryThis = require('../internals/function-uncurry-this');\nvar hiddenKeys = require('../internals/hidden-keys');\nvar isObject = require('../internals/is-object');\nvar hasOwn = require('../internals/has-own-property');\nvar defineProperty = require('../internals/object-define-property').f;\nvar getOwnPropertyNamesModule = require('../internals/object-get-own-property-names');\nvar getOwnPropertyNamesExternalModule = require('../internals/object-get-own-property-names-external');\nvar isExtensible = require('../internals/object-is-extensible');\nvar uid = require('../internals/uid');\nvar FREEZING = require('../internals/freezing');\n\nvar REQUIRED = false;\nvar METADATA = uid('meta');\nvar id = 0;\n\nvar setMetadata = function (it) {\n defineProperty(it, METADATA, { value: {\n objectID: 'O' + id++, // object ID\n weakData: {} // weak collections IDs\n } });\n};\n\nvar fastKey = function (it, create) {\n // return a primitive with prefix\n if (!isObject(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;\n if (!hasOwn(it, METADATA)) {\n // can't set metadata to uncaught frozen object\n if (!isExtensible(it)) return 'F';\n // not necessary to add metadata\n if (!create) return 'E';\n // add missing metadata\n setMetadata(it);\n // return object ID\n } return it[METADATA].objectID;\n};\n\nvar getWeakData = function (it, create) {\n if (!hasOwn(it, METADATA)) {\n // can't set metadata to uncaught frozen object\n if (!isExtensible(it)) return true;\n // not necessary to add metadata\n if (!create) return false;\n // add missing metadata\n setMetadata(it);\n // return the store of weak collections IDs\n } return it[METADATA].weakData;\n};\n\n// add metadata on freeze-family methods calling\nvar onFreeze = function (it) {\n if (FREEZING && REQUIRED && isExtensible(it) && !hasOwn(it, METADATA)) setMetadata(it);\n return it;\n};\n\nvar enable = function () {\n meta.enable = function () { /* empty */ };\n REQUIRED = true;\n var getOwnPropertyNames = getOwnPropertyNamesModule.f;\n var splice = uncurryThis([].splice);\n var test = {};\n test[METADATA] = 1;\n\n // prevent exposing of metadata key\n if (getOwnPropertyNames(test).length) {\n getOwnPropertyNamesModule.f = function (it) {\n var result = getOwnPropertyNames(it);\n for (var i = 0, length = result.length; i < length; i++) {\n if (result[i] === METADATA) {\n splice(result, i, 1);\n break;\n }\n } return result;\n };\n\n $({ target: 'Object', stat: true, forced: true }, {\n getOwnPropertyNames: getOwnPropertyNamesExternalModule.f\n });\n }\n};\n\nvar meta = module.exports = {\n enable: enable,\n fastKey: fastKey,\n getWeakData: getWeakData,\n onFreeze: onFreeze\n};\n\nhiddenKeys[METADATA] = true;\n","/* eslint-disable es-x/no-object-getownpropertynames -- safe */\nvar classof = require('../internals/classof-raw');\nvar toIndexedObject = require('../internals/to-indexed-object');\nvar $getOwnPropertyNames = require('../internals/object-get-own-property-names').f;\nvar arraySlice = require('../internals/array-slice-simple');\n\nvar windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames\n ? Object.getOwnPropertyNames(window) : [];\n\nvar getWindowNames = function (it) {\n try {\n return $getOwnPropertyNames(it);\n } catch (error) {\n return arraySlice(windowNames);\n }\n};\n\n// fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window\nmodule.exports.f = function getOwnPropertyNames(it) {\n return windowNames && classof(it) == 'Window'\n ? getWindowNames(it)\n : $getOwnPropertyNames(toIndexedObject(it));\n};\n","var toAbsoluteIndex = require('../internals/to-absolute-index');\nvar lengthOfArrayLike = require('../internals/length-of-array-like');\nvar createProperty = require('../internals/create-property');\n\nvar $Array = Array;\nvar max = Math.max;\n\nmodule.exports = function (O, start, end) {\n var length = lengthOfArrayLike(O);\n var k = toAbsoluteIndex(start, length);\n var fin = toAbsoluteIndex(end === undefined ? length : end, length);\n var result = $Array(max(fin - k, 0));\n for (var n = 0; k < fin; k++, n++) createProperty(result, n, O[k]);\n result.length = n;\n return result;\n};\n","'use strict';\nvar toPropertyKey = require('../internals/to-property-key');\nvar definePropertyModule = require('../internals/object-define-property');\nvar createPropertyDescriptor = require('../internals/create-property-descriptor');\n\nmodule.exports = function (object, key, value) {\n var propertyKey = toPropertyKey(key);\n if (propertyKey in object) definePropertyModule.f(object, propertyKey, createPropertyDescriptor(0, value));\n else object[propertyKey] = value;\n};\n","var fails = require('../internals/fails');\nvar isObject = require('../internals/is-object');\nvar classof = require('../internals/classof-raw');\nvar ARRAY_BUFFER_NON_EXTENSIBLE = require('../internals/array-buffer-non-extensible');\n\n// eslint-disable-next-line es-x/no-object-isextensible -- safe\nvar $isExtensible = Object.isExtensible;\nvar FAILS_ON_PRIMITIVES = fails(function () { $isExtensible(1); });\n\n// `Object.isExtensible` method\n// https://tc39.es/ecma262/#sec-object.isextensible\nmodule.exports = (FAILS_ON_PRIMITIVES || ARRAY_BUFFER_NON_EXTENSIBLE) ? function isExtensible(it) {\n if (!isObject(it)) return false;\n if (ARRAY_BUFFER_NON_EXTENSIBLE && classof(it) == 'ArrayBuffer') return false;\n return $isExtensible ? $isExtensible(it) : true;\n} : $isExtensible;\n","// FF26- bug: ArrayBuffers are non-extensible, but Object.isExtensible does not report it\nvar fails = require('../internals/fails');\n\nmodule.exports = fails(function () {\n if (typeof ArrayBuffer == 'function') {\n var buffer = new ArrayBuffer(8);\n // eslint-disable-next-line es-x/no-object-isextensible, es-x/no-object-defineproperty -- safe\n if (Object.isExtensible(buffer)) Object.defineProperty(buffer, 'a', { value: 8 });\n }\n});\n","var fails = require('../internals/fails');\n\nmodule.exports = !fails(function () {\n // eslint-disable-next-line es-x/no-object-isextensible, es-x/no-object-preventextensions -- required for testing\n return Object.isExtensible(Object.preventExtensions({}));\n});\n","var bind = require('../internals/function-bind-context');\nvar call = require('../internals/function-call');\nvar anObject = require('../internals/an-object');\nvar tryToString = require('../internals/try-to-string');\nvar isArrayIteratorMethod = require('../internals/is-array-iterator-method');\nvar lengthOfArrayLike = require('../internals/length-of-array-like');\nvar isPrototypeOf = require('../internals/object-is-prototype-of');\nvar getIterator = require('../internals/get-iterator');\nvar getIteratorMethod = require('../internals/get-iterator-method');\nvar iteratorClose = require('../internals/iterator-close');\n\nvar $TypeError = TypeError;\n\nvar Result = function (stopped, result) {\n this.stopped = stopped;\n this.result = result;\n};\n\nvar ResultPrototype = Result.prototype;\n\nmodule.exports = function (iterable, unboundFunction, options) {\n var that = options && options.that;\n var AS_ENTRIES = !!(options && options.AS_ENTRIES);\n var IS_RECORD = !!(options && options.IS_RECORD);\n var IS_ITERATOR = !!(options && options.IS_ITERATOR);\n var INTERRUPTED = !!(options && options.INTERRUPTED);\n var fn = bind(unboundFunction, that);\n var iterator, iterFn, index, length, result, next, step;\n\n var stop = function (condition) {\n if (iterator) iteratorClose(iterator, 'normal', condition);\n return new Result(true, condition);\n };\n\n var callFn = function (value) {\n if (AS_ENTRIES) {\n anObject(value);\n return INTERRUPTED ? fn(value[0], value[1], stop) : fn(value[0], value[1]);\n } return INTERRUPTED ? fn(value, stop) : fn(value);\n };\n\n if (IS_RECORD) {\n iterator = iterable.iterator;\n } else if (IS_ITERATOR) {\n iterator = iterable;\n } else {\n iterFn = getIteratorMethod(iterable);\n if (!iterFn) throw $TypeError(tryToString(iterable) + ' is not iterable');\n // optimisation for array iterators\n if (isArrayIteratorMethod(iterFn)) {\n for (index = 0, length = lengthOfArrayLike(iterable); length > index; index++) {\n result = callFn(iterable[index]);\n if (result && isPrototypeOf(ResultPrototype, result)) return result;\n } return new Result(false);\n }\n iterator = getIterator(iterable, iterFn);\n }\n\n next = IS_RECORD ? iterable.next : iterator.next;\n while (!(step = call(next, iterator)).done) {\n try {\n result = callFn(step.value);\n } catch (error) {\n iteratorClose(iterator, 'throw', error);\n }\n if (typeof result == 'object' && result && isPrototypeOf(ResultPrototype, result)) return result;\n } return new Result(false);\n};\n","var uncurryThis = require('../internals/function-uncurry-this');\nvar aCallable = require('../internals/a-callable');\nvar NATIVE_BIND = require('../internals/function-bind-native');\n\nvar bind = uncurryThis(uncurryThis.bind);\n\n// optional / simple context binding\nmodule.exports = function (fn, that) {\n aCallable(fn);\n return that === undefined ? fn : NATIVE_BIND ? bind(fn, that) : function (/* ...args */) {\n return fn.apply(that, arguments);\n };\n};\n","var wellKnownSymbol = require('../internals/well-known-symbol');\nvar Iterators = require('../internals/iterators');\n\nvar ITERATOR = wellKnownSymbol('iterator');\nvar ArrayPrototype = Array.prototype;\n\n// check on default Array iterator\nmodule.exports = function (it) {\n return it !== undefined && (Iterators.Array === it || ArrayPrototype[ITERATOR] === it);\n};\n","var call = require('../internals/function-call');\nvar aCallable = require('../internals/a-callable');\nvar anObject = require('../internals/an-object');\nvar tryToString = require('../internals/try-to-string');\nvar getIteratorMethod = require('../internals/get-iterator-method');\n\nvar $TypeError = TypeError;\n\nmodule.exports = function (argument, usingIterator) {\n var iteratorMethod = arguments.length < 2 ? getIteratorMethod(argument) : usingIterator;\n if (aCallable(iteratorMethod)) return anObject(call(iteratorMethod, argument));\n throw $TypeError(tryToString(argument) + ' is not iterable');\n};\n","var classof = require('../internals/classof');\nvar getMethod = require('../internals/get-method');\nvar Iterators = require('../internals/iterators');\nvar wellKnownSymbol = require('../internals/well-known-symbol');\n\nvar ITERATOR = wellKnownSymbol('iterator');\n\nmodule.exports = function (it) {\n if (it != undefined) return getMethod(it, ITERATOR)\n || getMethod(it, '@@iterator')\n || Iterators[classof(it)];\n};\n","var call = require('../internals/function-call');\nvar anObject = require('../internals/an-object');\nvar getMethod = require('../internals/get-method');\n\nmodule.exports = function (iterator, kind, value) {\n var innerResult, innerError;\n anObject(iterator);\n try {\n innerResult = getMethod(iterator, 'return');\n if (!innerResult) {\n if (kind === 'throw') throw value;\n return value;\n }\n innerResult = call(innerResult, iterator);\n } catch (error) {\n innerError = true;\n innerResult = error;\n }\n if (kind === 'throw') throw value;\n if (innerError) throw innerResult;\n anObject(innerResult);\n return value;\n};\n","var isPrototypeOf = require('../internals/object-is-prototype-of');\n\nvar $TypeError = TypeError;\n\nmodule.exports = function (it, Prototype) {\n if (isPrototypeOf(Prototype, it)) return it;\n throw $TypeError('Incorrect invocation');\n};\n","var wellKnownSymbol = require('../internals/well-known-symbol');\n\nvar ITERATOR = wellKnownSymbol('iterator');\nvar SAFE_CLOSING = false;\n\ntry {\n var called = 0;\n var iteratorWithReturn = {\n next: function () {\n return { done: !!called++ };\n },\n 'return': function () {\n SAFE_CLOSING = true;\n }\n };\n iteratorWithReturn[ITERATOR] = function () {\n return this;\n };\n // eslint-disable-next-line es-x/no-array-from, no-throw-literal -- required for testing\n Array.from(iteratorWithReturn, function () { throw 2; });\n} catch (error) { /* empty */ }\n\nmodule.exports = function (exec, SKIP_CLOSING) {\n if (!SKIP_CLOSING && !SAFE_CLOSING) return false;\n var ITERATION_SUPPORT = false;\n try {\n var object = {};\n object[ITERATOR] = function () {\n return {\n next: function () {\n return { done: ITERATION_SUPPORT = true };\n }\n };\n };\n exec(object);\n } catch (error) { /* empty */ }\n return ITERATION_SUPPORT;\n};\n","var isCallable = require('../internals/is-callable');\nvar isObject = require('../internals/is-object');\nvar setPrototypeOf = require('../internals/object-set-prototype-of');\n\n// makes subclassing work correct for wrapped built-ins\nmodule.exports = function ($this, dummy, Wrapper) {\n var NewTarget, NewTargetPrototype;\n if (\n // it can work only with native `setPrototypeOf`\n setPrototypeOf &&\n // we haven't completely correct pre-ES6 way for getting `new.target`, so use this\n isCallable(NewTarget = dummy.constructor) &&\n NewTarget !== Wrapper &&\n isObject(NewTargetPrototype = NewTarget.prototype) &&\n NewTargetPrototype !== Wrapper.prototype\n ) setPrototypeOf($this, NewTargetPrototype);\n return $this;\n};\n","'use strict';\nvar defineProperty = require('../internals/object-define-property').f;\nvar create = require('../internals/object-create');\nvar defineBuiltIns = require('../internals/define-built-ins');\nvar bind = require('../internals/function-bind-context');\nvar anInstance = require('../internals/an-instance');\nvar iterate = require('../internals/iterate');\nvar defineIterator = require('../internals/define-iterator');\nvar setSpecies = require('../internals/set-species');\nvar DESCRIPTORS = require('../internals/descriptors');\nvar fastKey = require('../internals/internal-metadata').fastKey;\nvar InternalStateModule = require('../internals/internal-state');\n\nvar setInternalState = InternalStateModule.set;\nvar internalStateGetterFor = InternalStateModule.getterFor;\n\nmodule.exports = {\n getConstructor: function (wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) {\n var Constructor = wrapper(function (that, iterable) {\n anInstance(that, Prototype);\n setInternalState(that, {\n type: CONSTRUCTOR_NAME,\n index: create(null),\n first: undefined,\n last: undefined,\n size: 0\n });\n if (!DESCRIPTORS) that.size = 0;\n if (iterable != undefined) iterate(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });\n });\n\n var Prototype = Constructor.prototype;\n\n var getInternalState = internalStateGetterFor(CONSTRUCTOR_NAME);\n\n var define = function (that, key, value) {\n var state = getInternalState(that);\n var entry = getEntry(that, key);\n var previous, index;\n // change existing entry\n if (entry) {\n entry.value = value;\n // create new entry\n } else {\n state.last = entry = {\n index: index = fastKey(key, true),\n key: key,\n value: value,\n previous: previous = state.last,\n next: undefined,\n removed: false\n };\n if (!state.first) state.first = entry;\n if (previous) previous.next = entry;\n if (DESCRIPTORS) state.size++;\n else that.size++;\n // add to index\n if (index !== 'F') state.index[index] = entry;\n } return that;\n };\n\n var getEntry = function (that, key) {\n var state = getInternalState(that);\n // fast case\n var index = fastKey(key);\n var entry;\n if (index !== 'F') return state.index[index];\n // frozen object case\n for (entry = state.first; entry; entry = entry.next) {\n if (entry.key == key) return entry;\n }\n };\n\n defineBuiltIns(Prototype, {\n // `{ Map, Set }.prototype.clear()` methods\n // https://tc39.es/ecma262/#sec-map.prototype.clear\n // https://tc39.es/ecma262/#sec-set.prototype.clear\n clear: function clear() {\n var that = this;\n var state = getInternalState(that);\n var data = state.index;\n var entry = state.first;\n while (entry) {\n entry.removed = true;\n if (entry.previous) entry.previous = entry.previous.next = undefined;\n delete data[entry.index];\n entry = entry.next;\n }\n state.first = state.last = undefined;\n if (DESCRIPTORS) state.size = 0;\n else that.size = 0;\n },\n // `{ Map, Set }.prototype.delete(key)` methods\n // https://tc39.es/ecma262/#sec-map.prototype.delete\n // https://tc39.es/ecma262/#sec-set.prototype.delete\n 'delete': function (key) {\n var that = this;\n var state = getInternalState(that);\n var entry = getEntry(that, key);\n if (entry) {\n var next = entry.next;\n var prev = entry.previous;\n delete state.index[entry.index];\n entry.removed = true;\n if (prev) prev.next = next;\n if (next) next.previous = prev;\n if (state.first == entry) state.first = next;\n if (state.last == entry) state.last = prev;\n if (DESCRIPTORS) state.size--;\n else that.size--;\n } return !!entry;\n },\n // `{ Map, Set }.prototype.forEach(callbackfn, thisArg = undefined)` methods\n // https://tc39.es/ecma262/#sec-map.prototype.foreach\n // https://tc39.es/ecma262/#sec-set.prototype.foreach\n forEach: function forEach(callbackfn /* , that = undefined */) {\n var state = getInternalState(this);\n var boundFunction = bind(callbackfn, arguments.length > 1 ? arguments[1] : undefined);\n var entry;\n while (entry = entry ? entry.next : state.first) {\n boundFunction(entry.value, entry.key, this);\n // revert to the last existing entry\n while (entry && entry.removed) entry = entry.previous;\n }\n },\n // `{ Map, Set}.prototype.has(key)` methods\n // https://tc39.es/ecma262/#sec-map.prototype.has\n // https://tc39.es/ecma262/#sec-set.prototype.has\n has: function has(key) {\n return !!getEntry(this, key);\n }\n });\n\n defineBuiltIns(Prototype, IS_MAP ? {\n // `Map.prototype.get(key)` method\n // https://tc39.es/ecma262/#sec-map.prototype.get\n get: function get(key) {\n var entry = getEntry(this, key);\n return entry && entry.value;\n },\n // `Map.prototype.set(key, value)` method\n // https://tc39.es/ecma262/#sec-map.prototype.set\n set: function set(key, value) {\n return define(this, key === 0 ? 0 : key, value);\n }\n } : {\n // `Set.prototype.add(value)` method\n // https://tc39.es/ecma262/#sec-set.prototype.add\n add: function add(value) {\n return define(this, value = value === 0 ? 0 : value, value);\n }\n });\n if (DESCRIPTORS) defineProperty(Prototype, 'size', {\n get: function () {\n return getInternalState(this).size;\n }\n });\n return Constructor;\n },\n setStrong: function (Constructor, CONSTRUCTOR_NAME, IS_MAP) {\n var ITERATOR_NAME = CONSTRUCTOR_NAME + ' Iterator';\n var getInternalCollectionState = internalStateGetterFor(CONSTRUCTOR_NAME);\n var getInternalIteratorState = internalStateGetterFor(ITERATOR_NAME);\n // `{ Map, Set }.prototype.{ keys, values, entries, @@iterator }()` methods\n // https://tc39.es/ecma262/#sec-map.prototype.entries\n // https://tc39.es/ecma262/#sec-map.prototype.keys\n // https://tc39.es/ecma262/#sec-map.prototype.values\n // https://tc39.es/ecma262/#sec-map.prototype-@@iterator\n // https://tc39.es/ecma262/#sec-set.prototype.entries\n // https://tc39.es/ecma262/#sec-set.prototype.keys\n // https://tc39.es/ecma262/#sec-set.prototype.values\n // https://tc39.es/ecma262/#sec-set.prototype-@@iterator\n defineIterator(Constructor, CONSTRUCTOR_NAME, function (iterated, kind) {\n setInternalState(this, {\n type: ITERATOR_NAME,\n target: iterated,\n state: getInternalCollectionState(iterated),\n kind: kind,\n last: undefined\n });\n }, function () {\n var state = getInternalIteratorState(this);\n var kind = state.kind;\n var entry = state.last;\n // revert to the last existing entry\n while (entry && entry.removed) entry = entry.previous;\n // get next entry\n if (!state.target || !(state.last = entry = entry ? entry.next : state.state.first)) {\n // or finish the iteration\n state.target = undefined;\n return { value: undefined, done: true };\n }\n // return step by kind\n if (kind == 'keys') return { value: entry.key, done: false };\n if (kind == 'values') return { value: entry.value, done: false };\n return { value: [entry.key, entry.value], done: false };\n }, IS_MAP ? 'entries' : 'values', !IS_MAP, true);\n\n // `{ Map, Set }.prototype[@@species]` accessors\n // https://tc39.es/ecma262/#sec-get-map-@@species\n // https://tc39.es/ecma262/#sec-get-set-@@species\n setSpecies(CONSTRUCTOR_NAME);\n }\n};\n","var defineBuiltIn = require('../internals/define-built-in');\n\nmodule.exports = function (target, src, options) {\n for (var key in src) defineBuiltIn(target, key, src[key], options);\n return target;\n};\n","'use strict';\nvar getBuiltIn = require('../internals/get-built-in');\nvar definePropertyModule = require('../internals/object-define-property');\nvar wellKnownSymbol = require('../internals/well-known-symbol');\nvar DESCRIPTORS = require('../internals/descriptors');\n\nvar SPECIES = wellKnownSymbol('species');\n\nmodule.exports = function (CONSTRUCTOR_NAME) {\n var Constructor = getBuiltIn(CONSTRUCTOR_NAME);\n var defineProperty = definePropertyModule.f;\n\n if (DESCRIPTORS && Constructor && !Constructor[SPECIES]) {\n defineProperty(Constructor, SPECIES, {\n configurable: true,\n get: function () { return this; }\n });\n }\n};\n","// TODO: Remove this module from `core-js@4` since it's replaced to module below\nrequire('../modules/es.set.constructor');\n","'use strict';\nvar collection = require('../internals/collection');\nvar collectionStrong = require('../internals/collection-strong');\n\n// `Set` constructor\n// https://tc39.es/ecma262/#sec-set-objects\ncollection('Set', function (init) {\n return function Set() { return init(this, arguments.length ? arguments[0] : undefined); };\n}, collectionStrong);\n","var IS_PURE = require('../internals/is-pure');\nvar $ = require('../internals/export');\nvar global = require('../internals/global');\nvar getBuiltin = require('../internals/get-built-in');\nvar uncurryThis = require('../internals/function-uncurry-this');\nvar fails = require('../internals/fails');\nvar uid = require('../internals/uid');\nvar isCallable = require('../internals/is-callable');\nvar isConstructor = require('../internals/is-constructor');\nvar isObject = require('../internals/is-object');\nvar isSymbol = require('../internals/is-symbol');\nvar iterate = require('../internals/iterate');\nvar anObject = require('../internals/an-object');\nvar classof = require('../internals/classof');\nvar hasOwn = require('../internals/has-own-property');\nvar createProperty = require('../internals/create-property');\nvar createNonEnumerableProperty = require('../internals/create-non-enumerable-property');\nvar lengthOfArrayLike = require('../internals/length-of-array-like');\nvar validateArgumentsLength = require('../internals/validate-arguments-length');\nvar getRegExpFlags = require('../internals/regexp-get-flags');\nvar ERROR_STACK_INSTALLABLE = require('../internals/error-stack-installable');\nvar V8 = require('../internals/engine-v8-version');\nvar IS_BROWSER = require('../internals/engine-is-browser');\nvar IS_DENO = require('../internals/engine-is-deno');\nvar IS_NODE = require('../internals/engine-is-node');\n\nvar Object = global.Object;\nvar Date = global.Date;\nvar Error = global.Error;\nvar EvalError = global.EvalError;\nvar RangeError = global.RangeError;\nvar ReferenceError = global.ReferenceError;\nvar SyntaxError = global.SyntaxError;\nvar TypeError = global.TypeError;\nvar URIError = global.URIError;\nvar PerformanceMark = global.PerformanceMark;\nvar WebAssembly = global.WebAssembly;\nvar CompileError = WebAssembly && WebAssembly.CompileError || Error;\nvar LinkError = WebAssembly && WebAssembly.LinkError || Error;\nvar RuntimeError = WebAssembly && WebAssembly.RuntimeError || Error;\nvar DOMException = getBuiltin('DOMException');\nvar Set = getBuiltin('Set');\nvar Map = getBuiltin('Map');\nvar MapPrototype = Map.prototype;\nvar mapHas = uncurryThis(MapPrototype.has);\nvar mapGet = uncurryThis(MapPrototype.get);\nvar mapSet = uncurryThis(MapPrototype.set);\nvar setAdd = uncurryThis(Set.prototype.add);\nvar objectKeys = getBuiltin('Object', 'keys');\nvar push = uncurryThis([].push);\nvar booleanValueOf = uncurryThis(true.valueOf);\nvar numberValueOf = uncurryThis(1.0.valueOf);\nvar stringValueOf = uncurryThis(''.valueOf);\nvar getTime = uncurryThis(Date.prototype.getTime);\nvar PERFORMANCE_MARK = uid('structuredClone');\nvar DATA_CLONE_ERROR = 'DataCloneError';\nvar TRANSFERRING = 'Transferring';\n\nvar checkBasicSemantic = function (structuredCloneImplementation) {\n return !fails(function () {\n var set1 = new global.Set([7]);\n var set2 = structuredCloneImplementation(set1);\n var number = structuredCloneImplementation(Object(7));\n return set2 == set1 || !set2.has(7) || typeof number != 'object' || number != 7;\n }) && structuredCloneImplementation;\n};\n\nvar checkErrorsCloning = function (structuredCloneImplementation, $Error) {\n return !fails(function () {\n var error = new $Error();\n var test = structuredCloneImplementation({ a: error, b: error });\n return !(test && test.a === test.b && test.a instanceof $Error && test.a.stack === error.stack);\n });\n};\n\n// https://github.com/whatwg/html/pull/5749\nvar checkNewErrorsCloningSemantic = function (structuredCloneImplementation) {\n return !fails(function () {\n var test = structuredCloneImplementation(new global.AggregateError([1], PERFORMANCE_MARK, { cause: 3 }));\n return test.name != 'AggregateError' || test.errors[0] != 1 || test.message != PERFORMANCE_MARK || test.cause != 3;\n });\n};\n\n// FF94+, Safari 15.4+, Chrome 98+, NodeJS 17.0+, Deno 1.13+\n// FF<103 and Safari implementations can't clone errors\n// https://bugzilla.mozilla.org/show_bug.cgi?id=1556604\n// FF103 can clone errors, but `.stack` of clone is an empty string\n// https://bugzilla.mozilla.org/show_bug.cgi?id=1778762\n// FF104+ fixed it on usual errors, but not on DOMExceptions\n// https://bugzilla.mozilla.org/show_bug.cgi?id=1777321\n// Chrome <102 returns `null` if cloned object contains multiple references to one error\n// https://bugs.chromium.org/p/v8/issues/detail?id=12542\n// NodeJS implementation can't clone DOMExceptions\n// https://github.com/nodejs/node/issues/41038\n// only FF103+ supports new (html/5749) error cloning semantic\nvar nativeStructuredClone = global.structuredClone;\n\nvar FORCED_REPLACEMENT = IS_PURE\n || !checkErrorsCloning(nativeStructuredClone, Error)\n || !checkErrorsCloning(nativeStructuredClone, DOMException)\n || !checkNewErrorsCloningSemantic(nativeStructuredClone);\n\n// Chrome 82+, Safari 14.1+, Deno 1.11+\n// Chrome 78-81 implementation swaps `.name` and `.message` of cloned `DOMException`\n// Chrome returns `null` if cloned object contains multiple references to one error\n// Safari 14.1 implementation doesn't clone some `RegExp` flags, so requires a workaround\n// Safari implementation can't clone errors\n// Deno 1.2-1.10 implementations too naive\n// NodeJS 16.0+ does not have `PerformanceMark` constructor\n// NodeJS <17.2 structured cloning implementation from `performance.mark` is too naive\n// and can't clone, for example, `RegExp` or some boxed primitives\n// https://github.com/nodejs/node/issues/40840\n// no one of those implementations supports new (html/5749) error cloning semantic\nvar structuredCloneFromMark = !nativeStructuredClone && checkBasicSemantic(function (value) {\n return new PerformanceMark(PERFORMANCE_MARK, { detail: value }).detail;\n});\n\nvar nativeRestrictedStructuredClone = checkBasicSemantic(nativeStructuredClone) || structuredCloneFromMark;\n\nvar throwUncloneable = function (type) {\n throw new DOMException('Uncloneable type: ' + type, DATA_CLONE_ERROR);\n};\n\nvar throwUnpolyfillable = function (type, kind) {\n throw new DOMException((kind || 'Cloning') + ' of ' + type + ' cannot be properly polyfilled in this engine', DATA_CLONE_ERROR);\n};\n\nvar structuredCloneInternal = function (value, map) {\n if (isSymbol(value)) throwUncloneable('Symbol');\n if (!isObject(value)) return value;\n // effectively preserves circular references\n if (map) {\n if (mapHas(map, value)) return mapGet(map, value);\n } else map = new Map();\n\n var type = classof(value);\n var deep = false;\n var C, name, cloned, dataTransfer, i, length, keys, key, source, target;\n\n switch (type) {\n case 'Array':\n cloned = [];\n deep = true;\n break;\n case 'Object':\n cloned = {};\n deep = true;\n break;\n case 'Map':\n cloned = new Map();\n deep = true;\n break;\n case 'Set':\n cloned = new Set();\n deep = true;\n break;\n case 'RegExp':\n // in this block because of a Safari 14.1 bug\n // old FF does not clone regexes passed to the constructor, so get the source and flags directly\n cloned = new RegExp(value.source, getRegExpFlags(value));\n break;\n case 'Error':\n name = value.name;\n switch (name) {\n case 'AggregateError':\n cloned = getBuiltin('AggregateError')([]);\n break;\n case 'EvalError':\n cloned = EvalError();\n break;\n case 'RangeError':\n cloned = RangeError();\n break;\n case 'ReferenceError':\n cloned = ReferenceError();\n break;\n case 'SyntaxError':\n cloned = SyntaxError();\n break;\n case 'TypeError':\n cloned = TypeError();\n break;\n case 'URIError':\n cloned = URIError();\n break;\n case 'CompileError':\n cloned = CompileError();\n break;\n case 'LinkError':\n cloned = LinkError();\n break;\n case 'RuntimeError':\n cloned = RuntimeError();\n break;\n default:\n cloned = Error();\n }\n deep = true;\n break;\n case 'DOMException':\n cloned = new DOMException(value.message, value.name);\n deep = true;\n break;\n case 'DataView':\n case 'Int8Array':\n case 'Uint8Array':\n case 'Uint8ClampedArray':\n case 'Int16Array':\n case 'Uint16Array':\n case 'Int32Array':\n case 'Uint32Array':\n case 'Float32Array':\n case 'Float64Array':\n case 'BigInt64Array':\n case 'BigUint64Array':\n C = global[type];\n // in some old engines like Safari 9, typeof C is 'object'\n // on Uint8ClampedArray or some other constructors\n if (!isObject(C)) throwUnpolyfillable(type);\n cloned = new C(\n // this is safe, since arraybuffer cannot have circular references\n structuredCloneInternal(value.buffer, map),\n value.byteOffset,\n type === 'DataView' ? value.byteLength : value.length\n );\n break;\n case 'DOMQuad':\n try {\n cloned = new DOMQuad(\n structuredCloneInternal(value.p1, map),\n structuredCloneInternal(value.p2, map),\n structuredCloneInternal(value.p3, map),\n structuredCloneInternal(value.p4, map)\n );\n } catch (error) {\n if (nativeRestrictedStructuredClone) {\n cloned = nativeRestrictedStructuredClone(value);\n } else throwUnpolyfillable(type);\n }\n break;\n case 'FileList':\n C = global.DataTransfer;\n if (isConstructor(C)) {\n dataTransfer = new C();\n for (i = 0, length = lengthOfArrayLike(value); i < length; i++) {\n dataTransfer.items.add(structuredCloneInternal(value[i], map));\n }\n cloned = dataTransfer.files;\n } else if (nativeRestrictedStructuredClone) {\n cloned = nativeRestrictedStructuredClone(value);\n } else throwUnpolyfillable(type);\n break;\n case 'ImageData':\n // Safari 9 ImageData is a constructor, but typeof ImageData is 'object'\n try {\n cloned = new ImageData(\n structuredCloneInternal(value.data, map),\n value.width,\n value.height,\n { colorSpace: value.colorSpace }\n );\n } catch (error) {\n if (nativeRestrictedStructuredClone) {\n cloned = nativeRestrictedStructuredClone(value);\n } else throwUnpolyfillable(type);\n } break;\n default:\n if (nativeRestrictedStructuredClone) {\n cloned = nativeRestrictedStructuredClone(value);\n } else switch (type) {\n case 'BigInt':\n // can be a 3rd party polyfill\n cloned = Object(value.valueOf());\n break;\n case 'Boolean':\n cloned = Object(booleanValueOf(value));\n break;\n case 'Number':\n cloned = Object(numberValueOf(value));\n break;\n case 'String':\n cloned = Object(stringValueOf(value));\n break;\n case 'Date':\n cloned = new Date(getTime(value));\n break;\n case 'ArrayBuffer':\n C = global.DataView;\n // `ArrayBuffer#slice` is not available in IE10\n // `ArrayBuffer#slice` and `DataView` are not available in old FF\n if (!C && typeof value.slice != 'function') throwUnpolyfillable(type);\n // detached buffers throws in `DataView` and `.slice`\n try {\n if (typeof value.slice == 'function') {\n cloned = value.slice(0);\n } else {\n length = value.byteLength;\n cloned = new ArrayBuffer(length);\n source = new C(value);\n target = new C(cloned);\n for (i = 0; i < length; i++) {\n target.setUint8(i, source.getUint8(i));\n }\n }\n } catch (error) {\n throw new DOMException('ArrayBuffer is detached', DATA_CLONE_ERROR);\n } break;\n case 'SharedArrayBuffer':\n // SharedArrayBuffer should use shared memory, we can't polyfill it, so return the original\n cloned = value;\n break;\n case 'Blob':\n try {\n cloned = value.slice(0, value.size, value.type);\n } catch (error) {\n throwUnpolyfillable(type);\n } break;\n case 'DOMPoint':\n case 'DOMPointReadOnly':\n C = global[type];\n try {\n cloned = C.fromPoint\n ? C.fromPoint(value)\n : new C(value.x, value.y, value.z, value.w);\n } catch (error) {\n throwUnpolyfillable(type);\n } break;\n case 'DOMRect':\n case 'DOMRectReadOnly':\n C = global[type];\n try {\n cloned = C.fromRect\n ? C.fromRect(value)\n : new C(value.x, value.y, value.width, value.height);\n } catch (error) {\n throwUnpolyfillable(type);\n } break;\n case 'DOMMatrix':\n case 'DOMMatrixReadOnly':\n C = global[type];\n try {\n cloned = C.fromMatrix\n ? C.fromMatrix(value)\n : new C(value);\n } catch (error) {\n throwUnpolyfillable(type);\n } break;\n case 'AudioData':\n case 'VideoFrame':\n if (!isCallable(value.clone)) throwUnpolyfillable(type);\n try {\n cloned = value.clone();\n } catch (error) {\n throwUncloneable(type);\n } break;\n case 'File':\n try {\n cloned = new File([value], value.name, value);\n } catch (error) {\n throwUnpolyfillable(type);\n } break;\n case 'CryptoKey':\n case 'GPUCompilationMessage':\n case 'GPUCompilationInfo':\n case 'ImageBitmap':\n case 'RTCCertificate':\n case 'WebAssembly.Module':\n throwUnpolyfillable(type);\n // break omitted\n default:\n throwUncloneable(type);\n }\n }\n\n mapSet(map, value, cloned);\n\n if (deep) switch (type) {\n case 'Array':\n case 'Object':\n keys = objectKeys(value);\n for (i = 0, length = lengthOfArrayLike(keys); i < length; i++) {\n key = keys[i];\n createProperty(cloned, key, structuredCloneInternal(value[key], map));\n } break;\n case 'Map':\n value.forEach(function (v, k) {\n mapSet(cloned, structuredCloneInternal(k, map), structuredCloneInternal(v, map));\n });\n break;\n case 'Set':\n value.forEach(function (v) {\n setAdd(cloned, structuredCloneInternal(v, map));\n });\n break;\n case 'Error':\n createNonEnumerableProperty(cloned, 'message', structuredCloneInternal(value.message, map));\n if (hasOwn(value, 'cause')) {\n createNonEnumerableProperty(cloned, 'cause', structuredCloneInternal(value.cause, map));\n }\n if (name == 'AggregateError') {\n cloned.errors = structuredCloneInternal(value.errors, map);\n } // break omitted\n case 'DOMException':\n if (ERROR_STACK_INSTALLABLE) {\n createNonEnumerableProperty(cloned, 'stack', structuredCloneInternal(value.stack, map));\n }\n }\n\n return cloned;\n};\n\nvar PROPER_TRANSFER = nativeStructuredClone && !fails(function () {\n // prevent V8 ArrayBufferDetaching protector cell invalidation and performance degradation\n // https://github.com/zloirock/core-js/issues/679\n if ((IS_DENO && V8 > 92) || (IS_NODE && V8 > 94) || (IS_BROWSER && V8 > 97)) return false;\n var buffer = new ArrayBuffer(8);\n var clone = nativeStructuredClone(buffer, { transfer: [buffer] });\n return buffer.byteLength != 0 || clone.byteLength != 8;\n});\n\nvar tryToTransfer = function (rawTransfer, map) {\n if (!isObject(rawTransfer)) throw TypeError('Transfer option cannot be converted to a sequence');\n\n var transfer = [];\n\n iterate(rawTransfer, function (value) {\n push(transfer, anObject(value));\n });\n\n var i = 0;\n var length = lengthOfArrayLike(transfer);\n var value, type, C, transferredArray, transferred, canvas, context;\n\n if (PROPER_TRANSFER) {\n transferredArray = nativeStructuredClone(transfer, { transfer: transfer });\n while (i < length) mapSet(map, transfer[i], transferredArray[i++]);\n } else while (i < length) {\n value = transfer[i++];\n if (mapHas(map, value)) throw new DOMException('Duplicate transferable', DATA_CLONE_ERROR);\n\n type = classof(value);\n\n switch (type) {\n case 'ImageBitmap':\n C = global.OffscreenCanvas;\n if (!isConstructor(C)) throwUnpolyfillable(type, TRANSFERRING);\n try {\n canvas = new C(value.width, value.height);\n context = canvas.getContext('bitmaprenderer');\n context.transferFromImageBitmap(value);\n transferred = canvas.transferToImageBitmap();\n } catch (error) { /* empty */ }\n break;\n case 'AudioData':\n case 'VideoFrame':\n if (!isCallable(value.clone) || !isCallable(value.close)) throwUnpolyfillable(type, TRANSFERRING);\n try {\n transferred = value.clone();\n value.close();\n } catch (error) { /* empty */ }\n break;\n case 'ArrayBuffer':\n case 'MessagePort':\n case 'OffscreenCanvas':\n case 'ReadableStream':\n case 'TransformStream':\n case 'WritableStream':\n throwUnpolyfillable(type, TRANSFERRING);\n }\n\n if (transferred === undefined) throw new DOMException('This object cannot be transferred: ' + type, DATA_CLONE_ERROR);\n mapSet(map, value, transferred);\n }\n};\n\n$({ global: true, enumerable: true, sham: !PROPER_TRANSFER, forced: FORCED_REPLACEMENT }, {\n structuredClone: function structuredClone(value /* , { transfer } */) {\n var options = validateArgumentsLength(arguments.length, 1) > 1 && arguments[1] != null ? anObject(arguments[1]) : undefined;\n var transfer = options ? options.transfer : undefined;\n var map;\n\n if (transfer !== undefined) {\n map = new Map();\n tryToTransfer(transfer, map);\n }\n\n return structuredCloneInternal(value, map);\n }\n});\n","var uncurryThis = require('../internals/function-uncurry-this');\nvar fails = require('../internals/fails');\nvar isCallable = require('../internals/is-callable');\nvar classof = require('../internals/classof');\nvar getBuiltIn = require('../internals/get-built-in');\nvar inspectSource = require('../internals/inspect-source');\n\nvar noop = function () { /* empty */ };\nvar empty = [];\nvar construct = getBuiltIn('Reflect', 'construct');\nvar constructorRegExp = /^\\s*(?:class|function)\\b/;\nvar exec = uncurryThis(constructorRegExp.exec);\nvar INCORRECT_TO_STRING = !constructorRegExp.exec(noop);\n\nvar isConstructorModern = function isConstructor(argument) {\n if (!isCallable(argument)) return false;\n try {\n construct(noop, empty, argument);\n return true;\n } catch (error) {\n return false;\n }\n};\n\nvar isConstructorLegacy = function isConstructor(argument) {\n if (!isCallable(argument)) return false;\n switch (classof(argument)) {\n case 'AsyncFunction':\n case 'GeneratorFunction':\n case 'AsyncGeneratorFunction': return false;\n }\n try {\n // we can't check .prototype since constructors produced by .bind haven't it\n // `Function#toString` throws on some built-it function in some legacy engines\n // (for example, `DOMQuad` and similar in FF41-)\n return INCORRECT_TO_STRING || !!exec(constructorRegExp, inspectSource(argument));\n } catch (error) {\n return true;\n }\n};\n\nisConstructorLegacy.sham = true;\n\n// `IsConstructor` abstract operation\n// https://tc39.es/ecma262/#sec-isconstructor\nmodule.exports = !construct || fails(function () {\n var called;\n return isConstructorModern(isConstructorModern.call)\n || !isConstructorModern(Object)\n || !isConstructorModern(function () { called = true; })\n || called;\n}) ? isConstructorLegacy : isConstructorModern;\n","var $TypeError = TypeError;\n\nmodule.exports = function (passed, required) {\n if (passed < required) throw $TypeError('Not enough arguments');\n return passed;\n};\n","var call = require('../internals/function-call');\nvar hasOwn = require('../internals/has-own-property');\nvar isPrototypeOf = require('../internals/object-is-prototype-of');\nvar regExpFlags = require('../internals/regexp-flags');\n\nvar RegExpPrototype = RegExp.prototype;\n\nmodule.exports = function (R) {\n var flags = R.flags;\n return flags === undefined && !('flags' in RegExpPrototype) && !hasOwn(R, 'flags') && isPrototypeOf(RegExpPrototype, R)\n ? call(regExpFlags, R) : flags;\n};\n","'use strict';\nvar anObject = require('../internals/an-object');\n\n// `RegExp.prototype.flags` getter implementation\n// https://tc39.es/ecma262/#sec-get-regexp.prototype.flags\nmodule.exports = function () {\n var that = anObject(this);\n var result = '';\n if (that.hasIndices) result += 'd';\n if (that.global) result += 'g';\n if (that.ignoreCase) result += 'i';\n if (that.multiline) result += 'm';\n if (that.dotAll) result += 's';\n if (that.unicode) result += 'u';\n if (that.unicodeSets) result += 'v';\n if (that.sticky) result += 'y';\n return result;\n};\n","var fails = require('../internals/fails');\nvar createPropertyDescriptor = require('../internals/create-property-descriptor');\n\nmodule.exports = !fails(function () {\n var error = Error('a');\n if (!('stack' in error)) return true;\n // eslint-disable-next-line es-x/no-object-defineproperty -- safe\n Object.defineProperty(error, 'stack', createPropertyDescriptor(1, 7));\n return error.stack !== 7;\n});\n","var IS_DENO = require('../internals/engine-is-deno');\nvar IS_NODE = require('../internals/engine-is-node');\n\nmodule.exports = !IS_DENO && !IS_NODE\n && typeof window == 'object'\n && typeof document == 'object';\n","/* global Deno -- Deno case */\nmodule.exports = typeof Deno == 'object' && Deno && typeof Deno.version == 'object';\n","var classof = require('../internals/classof-raw');\nvar global = require('../internals/global');\n\nmodule.exports = classof(global.process) == 'process';\n","var global = require('../internals/global');\n\nmodule.exports = global;\n","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * @module pdfjsLib\n */\n\nimport {\n AbortException,\n AnnotationMode,\n assert,\n createPromiseCapability,\n getVerbosityLevel,\n info,\n InvalidPDFException,\n isArrayBuffer,\n MissingPDFException,\n PasswordException,\n RenderingIntentFlag,\n setVerbosityLevel,\n shadow,\n stringToBytes,\n UnexpectedResponseException,\n UnknownErrorException,\n unreachable,\n warn,\n} from \"../shared/util.js\";\nimport {\n AnnotationStorage,\n PrintAnnotationStorage,\n} from \"./annotation_storage.js\";\nimport {\n deprecated,\n DOMCanvasFactory,\n DOMCMapReaderFactory,\n DOMStandardFontDataFactory,\n isDataScheme,\n loadScript,\n PageViewport,\n RenderingCancelledException,\n StatTimer,\n} from \"./display_utils.js\";\nimport { FontFaceObject, FontLoader } from \"./font_loader.js\";\nimport { CanvasGraphics } from \"./canvas.js\";\nimport { GlobalWorkerOptions } from \"./worker_options.js\";\nimport { isNodeJS } from \"../shared/is_node.js\";\nimport { MessageHandler } from \"../shared/message_handler.js\";\nimport { Metadata } from \"./metadata.js\";\nimport { OptionalContentConfig } from \"./optional_content_config.js\";\nimport { PDFDataTransportStream } from \"./transport_stream.js\";\nimport { XfaText } from \"./xfa_text.js\";\n\nconst DEFAULT_RANGE_CHUNK_SIZE = 65536; // 2^16 = 65536\nconst RENDERING_CANCELLED_TIMEOUT = 100; // ms\n\nlet DefaultCanvasFactory = DOMCanvasFactory;\nlet DefaultCMapReaderFactory = DOMCMapReaderFactory;\nlet DefaultStandardFontDataFactory = DOMStandardFontDataFactory;\n\nif (typeof PDFJSDev !== \"undefined\" && PDFJSDev.test(\"GENERIC\") && isNodeJS) {\n const {\n NodeCanvasFactory,\n NodeCMapReaderFactory,\n NodeStandardFontDataFactory,\n } = require(\"./node_utils.js\");\n\n DefaultCanvasFactory = NodeCanvasFactory;\n DefaultCMapReaderFactory = NodeCMapReaderFactory;\n DefaultStandardFontDataFactory = NodeStandardFontDataFactory;\n}\n\n/**\n * @typedef {function} IPDFStreamFactory\n * @param {DocumentInitParameters} params - The document initialization\n * parameters. The \"url\" key is always present.\n * @returns {Promise} A promise, which is resolved with an instance of\n * {IPDFStream}.\n * @ignore\n */\n\n/**\n * @type {IPDFStreamFactory}\n * @private\n */\nlet createPDFNetworkStream;\n\n/**\n * Sets the function that instantiates an {IPDFStream} as an alternative PDF\n * data transport.\n *\n * @param {IPDFStreamFactory} pdfNetworkStreamFactory - The factory function\n * that takes document initialization parameters (including a \"url\") and\n * returns a promise which is resolved with an instance of {IPDFStream}.\n * @ignore\n */\nfunction setPDFNetworkStreamFactory(pdfNetworkStreamFactory) {\n createPDFNetworkStream = pdfNetworkStreamFactory;\n}\n\n/**\n * @typedef { Int8Array | Uint8Array | Uint8ClampedArray |\n * Int16Array | Uint16Array |\n * Int32Array | Uint32Array | Float32Array |\n * Float64Array\n * } TypedArray\n */\n\n/**\n * @typedef { TypedArray | ArrayBuffer | Array | string } BinaryData\n */\n\n/**\n * @typedef {Object} RefProxy\n * @property {number} num\n * @property {number} gen\n */\n\n/**\n * Document initialization / loading parameters object.\n *\n * @typedef {Object} DocumentInitParameters\n * @property {string | URL} [url] - The URL of the PDF.\n * @property {BinaryData} [data] - Binary PDF data.\n * Use typed arrays (Uint8Array) to improve the memory usage. If PDF data is\n * BASE64-encoded, use `atob()` to convert it to a binary string first.\n * @property {Object} [httpHeaders] - Basic authentication headers.\n * @property {boolean} [withCredentials] - Indicates whether or not\n * cross-site Access-Control requests should be made using credentials such\n * as cookies or authorization headers. The default is `false`.\n * @property {string} [password] - For decrypting password-protected PDFs.\n * @property {TypedArray} [initialData] - A typed array with the first portion\n * or all of the pdf data. Used by the extension since some data is already\n * loaded before the switch to range requests.\n * @property {number} [length] - The PDF file length. It's used for progress\n * reports and range requests operations.\n * @property {PDFDataRangeTransport} [range] - Allows for using a custom range\n * transport implementation.\n * @property {number} [rangeChunkSize] - Specify maximum number of bytes fetched\n * per range request. The default value is {@link DEFAULT_RANGE_CHUNK_SIZE}.\n * @property {PDFWorker} [worker] - The worker that will be used for loading and\n * parsing the PDF data.\n * @property {number} [verbosity] - Controls the logging level; the constants\n * from {@link VerbosityLevel} should be used.\n * @property {string} [docBaseUrl] - The base URL of the document, used when\n * attempting to recover valid absolute URLs for annotations, and outline\n * items, that (incorrectly) only specify relative URLs.\n * @property {string} [cMapUrl] - The URL where the predefined Adobe CMaps are\n * located. Include the trailing slash.\n * @property {boolean} [cMapPacked] - Specifies if the Adobe CMaps are binary\n * packed or not.\n * @property {Object} [CMapReaderFactory] - The factory that will be used when\n * reading built-in CMap files. Providing a custom factory is useful for\n * environments without Fetch API or `XMLHttpRequest` support, such as\n * Node.js. The default value is {DOMCMapReaderFactory}.\n * @property {boolean} [useSystemFonts] - When `true`, fonts that aren't\n * embedded in the PDF document will fallback to a system font.\n * The default value is `true` in web environments and `false` in Node.js;\n * unless `disableFontFace === true` in which case this defaults to `false`\n * regardless of the environment (to prevent completely broken fonts).\n * @property {string} [standardFontDataUrl] - The URL where the standard font\n * files are located. Include the trailing slash.\n * @property {Object} [StandardFontDataFactory] - The factory that will be used\n * when reading the standard font files. Providing a custom factory is useful\n * for environments without Fetch API or `XMLHttpRequest` support, such as\n * Node.js. The default value is {DOMStandardFontDataFactory}.\n * @property {boolean} [useWorkerFetch] - Enable using the Fetch API in the\n * worker-thread when reading CMap and standard font files. When `true`,\n * the `CMapReaderFactory` and `StandardFontDataFactory` options are ignored.\n * The default value is `true` in web environments and `false` in Node.js.\n * @property {boolean} [stopAtErrors] - Reject certain promises, e.g.\n * `getOperatorList`, `getTextContent`, and `RenderTask`, when the associated\n * PDF data cannot be successfully parsed, instead of attempting to recover\n * whatever possible of the data. The default value is `false`.\n * @property {number} [maxImageSize] - The maximum allowed image size in total\n * pixels, i.e. width * height. Images above this value will not be rendered.\n * Use -1 for no limit, which is also the default value.\n * @property {boolean} [isEvalSupported] - Determines if we can evaluate strings\n * as JavaScript. Primarily used to improve performance of font rendering, and\n * when parsing PDF functions. The default value is `true`.\n * @property {boolean} [disableFontFace] - By default fonts are converted to\n * OpenType fonts and loaded via the Font Loading API or `@font-face` rules.\n * If disabled, fonts will be rendered using a built-in font renderer that\n * constructs the glyphs with primitive path commands.\n * The default value is `false` in web environments and `true` in Node.js.\n * @property {boolean} [fontExtraProperties] - Include additional properties,\n * which are unused during rendering of PDF documents, when exporting the\n * parsed font data from the worker-thread. This may be useful for debugging\n * purposes (and backwards compatibility), but note that it will lead to\n * increased memory usage. The default value is `false`.\n * @property {boolean} [enableXfa] - Render Xfa forms if any.\n * The default value is `false`.\n * @property {HTMLDocument} [ownerDocument] - Specify an explicit document\n * context to create elements with and to load resources, such as fonts,\n * into. Defaults to the current document.\n * @property {boolean} [disableRange] - Disable range request loading of PDF\n * files. When enabled, and if the server supports partial content requests,\n * then the PDF will be fetched in chunks. The default value is `false`.\n * @property {boolean} [disableStream] - Disable streaming of PDF file data.\n * By default PDF.js attempts to load PDF files in chunks. The default value\n * is `false`.\n * @property {boolean} [disableAutoFetch] - Disable pre-fetching of PDF file\n * data. When range requests are enabled PDF.js will automatically keep\n * fetching more data even if it isn't needed to display the current page.\n * The default value is `false`.\n *\n * NOTE: It is also necessary to disable streaming, see above, in order for\n * disabling of pre-fetching to work correctly.\n * @property {boolean} [pdfBug] - Enables special hooks for debugging PDF.js\n * (see `web/debugger.js`). The default value is `false`.\n */\n\n/**\n * @typedef { string | URL | TypedArray | ArrayBuffer |\n * PDFDataRangeTransport | DocumentInitParameters\n * } GetDocumentParameters\n */\n\n/**\n * This is the main entry point for loading a PDF and interacting with it.\n *\n * NOTE: If a URL is used to fetch the PDF data a standard Fetch API call (or\n * XHR as fallback) is used, which means it must follow same origin rules,\n * e.g. no cross-domain requests without CORS.\n *\n * @param {GetDocumentParameters}\n * src - Can be a URL where a PDF file is located, a typed array (Uint8Array)\n * already populated with data, or a parameter object.\n * @returns {PDFDocumentLoadingTask}\n */\nfunction getDocument(src) {\n const task = new PDFDocumentLoadingTask();\n\n let source;\n if (typeof src === \"string\" || src instanceof URL) {\n source = { url: src };\n } else if (isArrayBuffer(src)) {\n source = { data: src };\n } else if (src instanceof PDFDataRangeTransport) {\n source = { range: src };\n } else {\n if (typeof src !== \"object\") {\n throw new Error(\n \"Invalid parameter in getDocument, \" +\n \"need either string, URL, TypedArray, or parameter object.\"\n );\n }\n if (!src.url && !src.data && !src.range) {\n throw new Error(\n \"Invalid parameter object: need either .data, .range or .url\"\n );\n }\n source = src;\n }\n const params = Object.create(null);\n let rangeTransport = null,\n worker = null;\n\n for (const key in source) {\n const value = source[key];\n\n switch (key) {\n case \"url\":\n if (typeof window !== \"undefined\") {\n try {\n // The full path is required in the 'url' field.\n params[key] = new URL(value, window.location).href;\n continue;\n } catch (ex) {\n warn(`Cannot create valid URL: \"${ex}\".`);\n }\n } else if (typeof value === \"string\" || value instanceof URL) {\n params[key] = value.toString(); // Support Node.js environments.\n continue;\n }\n throw new Error(\n \"Invalid PDF url data: \" +\n \"either string or URL-object is expected in the url property.\"\n );\n case \"range\":\n rangeTransport = value;\n continue;\n case \"worker\":\n worker = value;\n continue;\n case \"data\":\n // Converting string or array-like data to Uint8Array.\n if (\n typeof PDFJSDev !== \"undefined\" &&\n PDFJSDev.test(\"GENERIC\") &&\n isNodeJS &&\n typeof Buffer !== \"undefined\" && // eslint-disable-line no-undef\n value instanceof Buffer // eslint-disable-line no-undef\n ) {\n params[key] = new Uint8Array(value);\n } else if (value instanceof Uint8Array) {\n break; // Use the data as-is when it's already a Uint8Array.\n } else if (typeof value === \"string\") {\n params[key] = stringToBytes(value);\n } else if (\n typeof value === \"object\" &&\n value !== null &&\n !isNaN(value.length)\n ) {\n params[key] = new Uint8Array(value);\n } else if (isArrayBuffer(value)) {\n params[key] = new Uint8Array(value);\n } else {\n throw new Error(\n \"Invalid PDF binary data: either TypedArray, \" +\n \"string, or array-like object is expected in the data property.\"\n );\n }\n continue;\n }\n params[key] = value;\n }\n\n params.CMapReaderFactory =\n params.CMapReaderFactory || DefaultCMapReaderFactory;\n params.StandardFontDataFactory =\n params.StandardFontDataFactory || DefaultStandardFontDataFactory;\n params.ignoreErrors = params.stopAtErrors !== true;\n params.fontExtraProperties = params.fontExtraProperties === true;\n params.pdfBug = params.pdfBug === true;\n params.enableXfa = params.enableXfa === true;\n\n if (!Number.isInteger(params.rangeChunkSize) || params.rangeChunkSize < 1) {\n params.rangeChunkSize = DEFAULT_RANGE_CHUNK_SIZE;\n }\n if (\n typeof params.docBaseUrl !== \"string\" ||\n isDataScheme(params.docBaseUrl)\n ) {\n // Ignore \"data:\"-URLs, since they can't be used to recover valid absolute\n // URLs anyway. We want to avoid sending them to the worker-thread, since\n // they contain the *entire* PDF document and can thus be arbitrarily long.\n params.docBaseUrl = null;\n }\n if (!Number.isInteger(params.maxImageSize) || params.maxImageSize < -1) {\n params.maxImageSize = -1;\n }\n if (typeof params.cMapUrl !== \"string\") {\n params.cMapUrl = null;\n }\n if (typeof params.standardFontDataUrl !== \"string\") {\n params.standardFontDataUrl = null;\n }\n if (typeof params.useWorkerFetch !== \"boolean\") {\n params.useWorkerFetch =\n params.CMapReaderFactory === DOMCMapReaderFactory &&\n params.StandardFontDataFactory === DOMStandardFontDataFactory;\n }\n if (typeof params.isEvalSupported !== \"boolean\") {\n params.isEvalSupported = true;\n }\n if (typeof params.disableFontFace !== \"boolean\") {\n params.disableFontFace = isNodeJS;\n }\n if (typeof params.useSystemFonts !== \"boolean\") {\n params.useSystemFonts = !isNodeJS && !params.disableFontFace;\n }\n if (\n typeof params.ownerDocument !== \"object\" ||\n params.ownerDocument === null\n ) {\n params.ownerDocument = globalThis.document;\n }\n\n if (typeof params.disableRange !== \"boolean\") {\n params.disableRange = false;\n }\n if (typeof params.disableStream !== \"boolean\") {\n params.disableStream = false;\n }\n if (typeof params.disableAutoFetch !== \"boolean\") {\n params.disableAutoFetch = false;\n }\n\n // Set the main-thread verbosity level.\n setVerbosityLevel(params.verbosity);\n\n if (!worker) {\n const workerParams = {\n verbosity: params.verbosity,\n port: GlobalWorkerOptions.workerPort,\n };\n // Worker was not provided -- creating and owning our own. If message port\n // is specified in global worker options, using it.\n worker = workerParams.port\n ? PDFWorker.fromPort(workerParams)\n : new PDFWorker(workerParams);\n task._worker = worker;\n }\n const docId = task.docId;\n worker.promise\n .then(function () {\n if (task.destroyed) {\n throw new Error(\"Loading aborted\");\n }\n\n const workerIdPromise = _fetchDocument(\n worker,\n params,\n rangeTransport,\n docId\n );\n const networkStreamPromise = new Promise(function (resolve) {\n let networkStream;\n if (rangeTransport) {\n networkStream = new PDFDataTransportStream(\n {\n length: params.length,\n initialData: params.initialData,\n progressiveDone: params.progressiveDone,\n contentDispositionFilename: params.contentDispositionFilename,\n disableRange: params.disableRange,\n disableStream: params.disableStream,\n },\n rangeTransport\n );\n } else if (!params.data) {\n networkStream = createPDFNetworkStream({\n url: params.url,\n length: params.length,\n httpHeaders: params.httpHeaders,\n withCredentials: params.withCredentials,\n rangeChunkSize: params.rangeChunkSize,\n disableRange: params.disableRange,\n disableStream: params.disableStream,\n });\n }\n resolve(networkStream);\n });\n\n return Promise.all([workerIdPromise, networkStreamPromise]).then(\n function ([workerId, networkStream]) {\n if (task.destroyed) {\n throw new Error(\"Loading aborted\");\n }\n\n const messageHandler = new MessageHandler(\n docId,\n workerId,\n worker.port\n );\n const transport = new WorkerTransport(\n messageHandler,\n task,\n networkStream,\n params\n );\n task._transport = transport;\n messageHandler.send(\"Ready\", null);\n }\n );\n })\n .catch(task._capability.reject);\n\n return task;\n}\n\n/**\n * Starts fetching of specified PDF document/data.\n *\n * @param {PDFWorker} worker\n * @param {Object} source\n * @param {PDFDataRangeTransport} pdfDataRangeTransport\n * @param {string} docId - Unique document ID, used in `MessageHandler`.\n * @returns {Promise} A promise that is resolved when the worker ID of\n * the `MessageHandler` is known.\n * @private\n */\nasync function _fetchDocument(worker, source, pdfDataRangeTransport, docId) {\n if (worker.destroyed) {\n throw new Error(\"Worker was destroyed\");\n }\n\n if (pdfDataRangeTransport) {\n source.length = pdfDataRangeTransport.length;\n source.initialData = pdfDataRangeTransport.initialData;\n source.progressiveDone = pdfDataRangeTransport.progressiveDone;\n source.contentDispositionFilename =\n pdfDataRangeTransport.contentDispositionFilename;\n }\n const workerId = await worker.messageHandler.sendWithPromise(\n \"GetDocRequest\",\n {\n docId,\n apiVersion:\n typeof PDFJSDev !== \"undefined\" && !PDFJSDev.test(\"TESTING\")\n ? PDFJSDev.eval(\"BUNDLE_VERSION\")\n : null,\n // Only send the required properties, and *not* the entire object.\n source: {\n data: source.data,\n url: source.url,\n password: source.password,\n disableAutoFetch: source.disableAutoFetch,\n rangeChunkSize: source.rangeChunkSize,\n length: source.length,\n },\n maxImageSize: source.maxImageSize,\n disableFontFace: source.disableFontFace,\n docBaseUrl: source.docBaseUrl,\n ignoreErrors: source.ignoreErrors,\n isEvalSupported: source.isEvalSupported,\n fontExtraProperties: source.fontExtraProperties,\n enableXfa: source.enableXfa,\n useSystemFonts: source.useSystemFonts,\n cMapUrl: source.useWorkerFetch ? source.cMapUrl : null,\n standardFontDataUrl: source.useWorkerFetch\n ? source.standardFontDataUrl\n : null,\n }\n );\n\n // Release the TypedArray data, when it exists, since it's no longer needed\n // on the main-thread *after* it's been sent to the worker-thread.\n if (source.data) {\n source.data = null;\n }\n\n if (worker.destroyed) {\n throw new Error(\"Worker was destroyed\");\n }\n return workerId;\n}\n\n/**\n * @typedef {Object} OnProgressParameters\n * @property {number} loaded - Currently loaded number of bytes.\n * @property {number} total - Total number of bytes in the PDF file.\n */\n\n/**\n * The loading task controls the operations required to load a PDF document\n * (such as network requests) and provides a way to listen for completion,\n * after which individual pages can be rendered.\n */\nclass PDFDocumentLoadingTask {\n static #docId = 0;\n\n constructor() {\n this._capability = createPromiseCapability();\n this._transport = null;\n this._worker = null;\n\n /**\n * Unique identifier for the document loading task.\n * @type {string}\n */\n this.docId = `d${PDFDocumentLoadingTask.#docId++}`;\n\n /**\n * Whether the loading task is destroyed or not.\n * @type {boolean}\n */\n this.destroyed = false;\n\n /**\n * Callback to request a password if a wrong or no password was provided.\n * The callback receives two parameters: a function that should be called\n * with the new password, and a reason (see {@link PasswordResponses}).\n * @type {function}\n */\n this.onPassword = null;\n\n /**\n * Callback to be able to monitor the loading progress of the PDF file\n * (necessary to implement e.g. a loading bar).\n * The callback receives an {@link OnProgressParameters} argument.\n * @type {function}\n */\n this.onProgress = null;\n\n /**\n * Callback for when an unsupported feature is used in the PDF document.\n * The callback receives an {@link UNSUPPORTED_FEATURES} argument.\n * @type {function}\n */\n this.onUnsupportedFeature = null;\n }\n\n /**\n * Promise for document loading task completion.\n * @type {Promise}\n */\n get promise() {\n return this._capability.promise;\n }\n\n /**\n * Abort all network requests and destroy the worker.\n * @returns {Promise} A promise that is resolved when destruction is\n * completed.\n */\n async destroy() {\n this.destroyed = true;\n await this._transport?.destroy();\n\n this._transport = null;\n if (this._worker) {\n this._worker.destroy();\n this._worker = null;\n }\n }\n}\n\n/**\n * Abstract class to support range requests file loading.\n */\nclass PDFDataRangeTransport {\n /**\n * @param {number} length\n * @param {Uint8Array} initialData\n * @param {boolean} [progressiveDone]\n * @param {string} [contentDispositionFilename]\n */\n constructor(\n length,\n initialData,\n progressiveDone = false,\n contentDispositionFilename = null\n ) {\n this.length = length;\n this.initialData = initialData;\n this.progressiveDone = progressiveDone;\n this.contentDispositionFilename = contentDispositionFilename;\n\n this._rangeListeners = [];\n this._progressListeners = [];\n this._progressiveReadListeners = [];\n this._progressiveDoneListeners = [];\n this._readyCapability = createPromiseCapability();\n }\n\n addRangeListener(listener) {\n this._rangeListeners.push(listener);\n }\n\n addProgressListener(listener) {\n this._progressListeners.push(listener);\n }\n\n addProgressiveReadListener(listener) {\n this._progressiveReadListeners.push(listener);\n }\n\n addProgressiveDoneListener(listener) {\n this._progressiveDoneListeners.push(listener);\n }\n\n onDataRange(begin, chunk) {\n for (const listener of this._rangeListeners) {\n listener(begin, chunk);\n }\n }\n\n onDataProgress(loaded, total) {\n this._readyCapability.promise.then(() => {\n for (const listener of this._progressListeners) {\n listener(loaded, total);\n }\n });\n }\n\n onDataProgressiveRead(chunk) {\n this._readyCapability.promise.then(() => {\n for (const listener of this._progressiveReadListeners) {\n listener(chunk);\n }\n });\n }\n\n onDataProgressiveDone() {\n this._readyCapability.promise.then(() => {\n for (const listener of this._progressiveDoneListeners) {\n listener();\n }\n });\n }\n\n transportReady() {\n this._readyCapability.resolve();\n }\n\n requestDataRange(begin, end) {\n unreachable(\"Abstract method PDFDataRangeTransport.requestDataRange\");\n }\n\n abort() {}\n}\n\n/**\n * Proxy to a `PDFDocument` in the worker thread.\n */\nclass PDFDocumentProxy {\n constructor(pdfInfo, transport) {\n this._pdfInfo = pdfInfo;\n this._transport = transport;\n\n if (typeof PDFJSDev === \"undefined\" || PDFJSDev.test(\"GENERIC\")) {\n Object.defineProperty(this, \"fingerprint\", {\n get() {\n deprecated(\n \"`PDFDocumentProxy.fingerprint`, \" +\n \"please use `PDFDocumentProxy.fingerprints` instead.\"\n );\n return this.fingerprints[0];\n },\n });\n\n Object.defineProperty(this, \"getStats\", {\n value: async () => {\n deprecated(\n \"`PDFDocumentProxy.getStats`, \" +\n \"please use the `PDFDocumentProxy.stats`-getter instead.\"\n );\n return this.stats || { streamTypes: {}, fontTypes: {} };\n },\n });\n }\n }\n\n /**\n * @type {AnnotationStorage} Storage for annotation data in forms.\n */\n get annotationStorage() {\n return this._transport.annotationStorage;\n }\n\n /**\n * @type {number} Total number of pages in the PDF file.\n */\n get numPages() {\n return this._pdfInfo.numPages;\n }\n\n /**\n * @type {Array} A (not guaranteed to be) unique ID to\n * identify the PDF document.\n * NOTE: The first element will always be defined for all PDF documents,\n * whereas the second element is only defined for *modified* PDF documents.\n */\n get fingerprints() {\n return this._pdfInfo.fingerprints;\n }\n\n /**\n * @typedef {Object} PDFDocumentStats\n * @property {Object} streamTypes - Used stream types in the\n * document (an item is set to true if specific stream ID was used in the\n * document).\n * @property {Object} fontTypes - Used font types in the\n * document (an item is set to true if specific font ID was used in the\n * document).\n */\n\n /**\n * @type {PDFDocumentStats | null} The current statistics about document\n * structures, or `null` when no statistics exists.\n */\n get stats() {\n return this._transport.stats;\n }\n\n /**\n * @type {boolean} True if only XFA form.\n */\n get isPureXfa() {\n return !!this._transport._htmlForXfa;\n }\n\n /**\n * NOTE: This is (mostly) intended to support printing of XFA forms.\n *\n * @type {Object | null} An object representing a HTML tree structure\n * to render the XFA, or `null` when no XFA form exists.\n */\n get allXfaHtml() {\n return this._transport._htmlForXfa;\n }\n\n /**\n * @param {number} pageNumber - The page number to get. The first page is 1.\n * @returns {Promise} A promise that is resolved with\n * a {@link PDFPageProxy} object.\n */\n getPage(pageNumber) {\n return this._transport.getPage(pageNumber);\n }\n\n /**\n * @param {RefProxy} ref - The page reference.\n * @returns {Promise} A promise that is resolved with the page index,\n * starting from zero, that is associated with the reference.\n */\n getPageIndex(ref) {\n return this._transport.getPageIndex(ref);\n }\n\n /**\n * @returns {Promise>>} A promise that is resolved\n * with a mapping from named destinations to references.\n *\n * This can be slow for large documents. Use `getDestination` instead.\n */\n getDestinations() {\n return this._transport.getDestinations();\n }\n\n /**\n * @param {string} id - The named destination to get.\n * @returns {Promise | null>} A promise that is resolved with all\n * information of the given named destination, or `null` when the named\n * destination is not present in the PDF file.\n */\n getDestination(id) {\n return this._transport.getDestination(id);\n }\n\n /**\n * @returns {Promise | null>} A promise that is resolved with\n * an {Array} containing the page labels that correspond to the page\n * indexes, or `null` when no page labels are present in the PDF file.\n */\n getPageLabels() {\n return this._transport.getPageLabels();\n }\n\n /**\n * @returns {Promise} A promise that is resolved with a {string}\n * containing the page layout name.\n */\n getPageLayout() {\n return this._transport.getPageLayout();\n }\n\n /**\n * @returns {Promise} A promise that is resolved with a {string}\n * containing the page mode name.\n */\n getPageMode() {\n return this._transport.getPageMode();\n }\n\n /**\n * @returns {Promise} A promise that is resolved with an\n * {Object} containing the viewer preferences, or `null` when no viewer\n * preferences are present in the PDF file.\n */\n getViewerPreferences() {\n return this._transport.getViewerPreferences();\n }\n\n /**\n * @returns {Promise} A promise that is resolved with an {Array}\n * containing the destination, or `null` when no open action is present\n * in the PDF.\n */\n getOpenAction() {\n return this._transport.getOpenAction();\n }\n\n /**\n * @returns {Promise} A promise that is resolved with a lookup table\n * for mapping named attachments to their content.\n */\n getAttachments() {\n return this._transport.getAttachments();\n }\n\n /**\n * @returns {Promise | null>} A promise that is resolved with\n * an {Array} of all the JavaScript strings in the name tree, or `null`\n * if no JavaScript exists.\n */\n getJavaScript() {\n return this._transport.getJavaScript();\n }\n\n /**\n * @returns {Promise} A promise that is resolved with\n * an {Object} with the JavaScript actions:\n * - from the name tree (like getJavaScript);\n * - from A or AA entries in the catalog dictionary.\n * , or `null` if no JavaScript exists.\n */\n getJSActions() {\n return this._transport.getDocJSActions();\n }\n\n /**\n * @typedef {Object} OutlineNode\n * @property {string} title\n * @property {boolean} bold\n * @property {boolean} italic\n * @property {Uint8ClampedArray} color - The color in RGB format to use for\n * display purposes.\n * @property {string | Array | null} dest\n * @property {string | null} url\n * @property {string | undefined} unsafeUrl\n * @property {boolean | undefined} newWindow\n * @property {number | undefined} count\n * @property {Array} items\n */\n\n /**\n * @returns {Promise>} A promise that is resolved with an\n * {Array} that is a tree outline (if it has one) of the PDF file.\n */\n getOutline() {\n return this._transport.getOutline();\n }\n\n /**\n * @returns {Promise} A promise that is resolved with\n * an {@link OptionalContentConfig} that contains all the optional content\n * groups (assuming that the document has any).\n */\n getOptionalContentConfig() {\n return this._transport.getOptionalContentConfig();\n }\n\n /**\n * @returns {Promise | null>} A promise that is resolved with\n * an {Array} that contains the permission flags for the PDF document, or\n * `null` when no permissions are present in the PDF file.\n */\n getPermissions() {\n return this._transport.getPermissions();\n }\n\n /**\n * @returns {Promise<{ info: Object, metadata: Metadata }>} A promise that is\n * resolved with an {Object} that has `info` and `metadata` properties.\n * `info` is an {Object} filled with anything available in the information\n * dictionary and similarly `metadata` is a {Metadata} object with\n * information from the metadata section of the PDF.\n */\n getMetadata() {\n return this._transport.getMetadata();\n }\n\n /**\n * @typedef {Object} MarkInfo\n * Properties correspond to Table 321 of the PDF 32000-1:2008 spec.\n * @property {boolean} Marked\n * @property {boolean} UserProperties\n * @property {boolean} Suspects\n */\n\n /**\n * @returns {Promise} A promise that is resolved with\n * a {MarkInfo} object that contains the MarkInfo flags for the PDF\n * document, or `null` when no MarkInfo values are present in the PDF file.\n */\n getMarkInfo() {\n return this._transport.getMarkInfo();\n }\n\n /**\n * @returns {Promise} A promise that is resolved with a\n * {Uint8Array} that has the raw data from the PDF.\n */\n getData() {\n return this._transport.getData();\n }\n\n /**\n * @returns {Promise<{ length: number }>} A promise that is resolved when the\n * document's data is loaded. It is resolved with an {Object} that contains\n * the `length` property that indicates size of the PDF data in bytes.\n */\n getDownloadInfo() {\n return this._transport.downloadInfoCapability.promise;\n }\n\n /**\n * Cleans up resources allocated by the document on both the main and worker\n * threads.\n *\n * NOTE: Do not, under any circumstances, call this method when rendering is\n * currently ongoing since that may lead to rendering errors.\n *\n * @param {boolean} [keepLoadedFonts] - Let fonts remain attached to the DOM.\n * NOTE: This will increase persistent memory usage, hence don't use this\n * option unless absolutely necessary. The default value is `false`.\n * @returns {Promise} A promise that is resolved when clean-up has finished.\n */\n cleanup(keepLoadedFonts = false) {\n return this._transport.startCleanup(keepLoadedFonts || this.isPureXfa);\n }\n\n /**\n * Destroys the current document instance and terminates the worker.\n */\n destroy() {\n return this.loadingTask.destroy();\n }\n\n /**\n * @type {DocumentInitParameters} A subset of the current\n * {DocumentInitParameters}, which are needed in the viewer.\n */\n get loadingParams() {\n return this._transport.loadingParams;\n }\n\n /**\n * @type {PDFDocumentLoadingTask} The loadingTask for the current document.\n */\n get loadingTask() {\n return this._transport.loadingTask;\n }\n\n /**\n * @returns {Promise} A promise that is resolved with a\n * {Uint8Array} containing the full data of the saved document.\n */\n saveDocument() {\n if (\n (typeof PDFJSDev === \"undefined\" || PDFJSDev.test(\"GENERIC\")) &&\n this._transport.annotationStorage.size <= 0\n ) {\n deprecated(\n \"saveDocument called while `annotationStorage` is empty, \" +\n \"please use the getData-method instead.\"\n );\n }\n return this._transport.saveDocument();\n }\n\n /**\n * @returns {Promise> | null>} A promise that is\n * resolved with an {Object} containing /AcroForm field data for the JS\n * sandbox, or `null` when no field data is present in the PDF file.\n */\n getFieldObjects() {\n return this._transport.getFieldObjects();\n }\n\n /**\n * @returns {Promise} A promise that is resolved with `true`\n * if some /AcroForm fields have JavaScript actions.\n */\n hasJSActions() {\n return this._transport.hasJSActions();\n }\n\n /**\n * @returns {Promise | null>} A promise that is resolved with an\n * {Array} containing IDs of annotations that have a calculation\n * action, or `null` when no such annotations are present in the PDF file.\n */\n getCalculationOrderIds() {\n return this._transport.getCalculationOrderIds();\n }\n}\n\n/**\n * Page getViewport parameters.\n *\n * @typedef {Object} GetViewportParameters\n * @property {number} scale - The desired scale of the viewport.\n * @property {number} [rotation] - The desired rotation, in degrees, of\n * the viewport. If omitted it defaults to the page rotation.\n * @property {number} [offsetX] - The horizontal, i.e. x-axis, offset.\n * The default value is `0`.\n * @property {number} [offsetY] - The vertical, i.e. y-axis, offset.\n * The default value is `0`.\n * @property {boolean} [dontFlip] - If true, the y-axis will not be\n * flipped. The default value is `false`.\n */\n\n/**\n * Page getTextContent parameters.\n *\n * @typedef {Object} getTextContentParameters\n * @property {boolean} disableCombineTextItems - Do not attempt to combine\n * same line {@link TextItem}'s. The default value is `false`.\n * @property {boolean} [includeMarkedContent] - When true include marked\n * content items in the items array of TextContent. The default is `false`.\n */\n\n/**\n * Page text content.\n *\n * @typedef {Object} TextContent\n * @property {Array} items - Array of\n * {@link TextItem} and {@link TextMarkedContent} objects. TextMarkedContent\n * items are included when includeMarkedContent is true.\n * @property {Object} styles - {@link TextStyle} objects,\n * indexed by font name.\n */\n\n/**\n * Page text content part.\n *\n * @typedef {Object} TextItem\n * @property {string} str - Text content.\n * @property {string} dir - Text direction: 'ttb', 'ltr' or 'rtl'.\n * @property {Array} transform - Transformation matrix.\n * @property {number} width - Width in device space.\n * @property {number} height - Height in device space.\n * @property {string} fontName - Font name used by PDF.js for converted font.\n * @property {boolean} hasEOL - Indicating if the text content is followed by a\n * line-break.\n */\n\n/**\n * Page text marked content part.\n *\n * @typedef {Object} TextMarkedContent\n * @property {string} type - Either 'beginMarkedContent',\n * 'beginMarkedContentProps', or 'endMarkedContent'.\n * @property {string} id - The marked content identifier. Only used for type\n * 'beginMarkedContentProps'.\n */\n\n/**\n * Text style.\n *\n * @typedef {Object} TextStyle\n * @property {number} ascent - Font ascent.\n * @property {number} descent - Font descent.\n * @property {boolean} vertical - Whether or not the text is in vertical mode.\n * @property {string} fontFamily - The possible font family.\n */\n\n/**\n * Page annotation parameters.\n *\n * @typedef {Object} GetAnnotationsParameters\n * @property {string} [intent] - Determines the annotations that are fetched,\n * can be 'display' (viewable annotations), 'print' (printable annotations),\n * or 'any' (all annotations). The default value is 'display'.\n */\n\n/**\n * Page render parameters.\n *\n * @typedef {Object} RenderParameters\n * @property {Object} canvasContext - A 2D context of a DOM Canvas object.\n * @property {PageViewport} viewport - Rendering viewport obtained by calling\n * the `PDFPageProxy.getViewport` method.\n * @property {string} [intent] - Rendering intent, can be 'display', 'print',\n * or 'any'. The default value is 'display'.\n * @property {number} [annotationMode] Controls which annotations are rendered\n * onto the canvas, for annotations with appearance-data; the values from\n * {@link AnnotationMode} should be used. The following values are supported:\n * - `AnnotationMode.DISABLE`, which disables all annotations.\n * - `AnnotationMode.ENABLE`, which includes all possible annotations (thus\n * it also depends on the `intent`-option, see above).\n * - `AnnotationMode.ENABLE_FORMS`, which excludes annotations that contain\n * interactive form elements (those will be rendered in the display layer).\n * - `AnnotationMode.ENABLE_STORAGE`, which includes all possible annotations\n * (as above) but where interactive form elements are updated with data\n * from the {@link AnnotationStorage}-instance; useful e.g. for printing.\n * The default value is `AnnotationMode.ENABLE`.\n * @property {Array} [transform] - Additional transform, applied just\n * before viewport transform.\n * @property {Object} [imageLayer] - An object that has `beginLayout`,\n * `endLayout` and `appendImage` functions.\n * @property {Object} [canvasFactory] - The factory instance that will be used\n * when creating canvases. The default value is {new DOMCanvasFactory()}.\n * @property {Object | string} [background] - Background to use for the canvas.\n * Any valid `canvas.fillStyle` can be used: a `DOMString` parsed as CSS\n * value, a `CanvasGradient` object (a linear or radial gradient) or\n * a `CanvasPattern` object (a repetitive image). The default value is\n * 'rgb(255,255,255)'.\n *\n * NOTE: This option may be partially, or completely, ignored when the\n * `pageColors`-option is used.\n * @property {Object} [pageColors] - Overwrites background and foreground colors\n * with user defined ones in order to improve readability in high contrast\n * mode.\n * @property {Promise} [optionalContentConfigPromise] -\n * A promise that should resolve with an {@link OptionalContentConfig}\n * created from `PDFDocumentProxy.getOptionalContentConfig`. If `null`,\n * the configuration will be fetched automatically with the default visibility\n * states set.\n * @property {Map} [annotationCanvasMap] - Map some\n * annotation ids with canvases used to render them.\n * @property {PrintAnnotationStorage} [printAnnotationStorage]\n */\n\n/**\n * Page getOperatorList parameters.\n *\n * @typedef {Object} GetOperatorListParameters\n * @property {string} [intent] - Rendering intent, can be 'display', 'print',\n * or 'any'. The default value is 'display'.\n * @property {number} [annotationMode] Controls which annotations are included\n * in the operatorList, for annotations with appearance-data; the values from\n * {@link AnnotationMode} should be used. The following values are supported:\n * - `AnnotationMode.DISABLE`, which disables all annotations.\n * - `AnnotationMode.ENABLE`, which includes all possible annotations (thus\n * it also depends on the `intent`-option, see above).\n * - `AnnotationMode.ENABLE_FORMS`, which excludes annotations that contain\n * interactive form elements (those will be rendered in the display layer).\n * - `AnnotationMode.ENABLE_STORAGE`, which includes all possible annotations\n * (as above) but where interactive form elements are updated with data\n * from the {@link AnnotationStorage}-instance; useful e.g. for printing.\n * The default value is `AnnotationMode.ENABLE`.\n * @property {PrintAnnotationStorage} [printAnnotationStorage]\n */\n\n/**\n * Structure tree node. The root node will have a role \"Root\".\n *\n * @typedef {Object} StructTreeNode\n * @property {Array} children - Array of\n * {@link StructTreeNode} and {@link StructTreeContent} objects.\n * @property {string} role - element's role, already mapped if a role map exists\n * in the PDF.\n */\n\n/**\n * Structure tree content.\n *\n * @typedef {Object} StructTreeContent\n * @property {string} type - either \"content\" for page and stream structure\n * elements or \"object\" for object references.\n * @property {string} id - unique id that will map to the text layer.\n */\n\n/**\n * PDF page operator list.\n *\n * @typedef {Object} PDFOperatorList\n * @property {Array} fnArray - Array containing the operator functions.\n * @property {Array} argsArray - Array containing the arguments of the\n * functions.\n */\n\n/**\n * Proxy to a `PDFPage` in the worker thread.\n */\nclass PDFPageProxy {\n constructor(pageIndex, pageInfo, transport, ownerDocument, pdfBug = false) {\n this._pageIndex = pageIndex;\n this._pageInfo = pageInfo;\n this._ownerDocument = ownerDocument;\n this._transport = transport;\n this._stats = pdfBug ? new StatTimer() : null;\n this._pdfBug = pdfBug;\n /** @type {PDFObjects} */\n this.commonObjs = transport.commonObjs;\n this.objs = new PDFObjects();\n\n this._bitmaps = new Set();\n\n this.cleanupAfterRender = false;\n this.pendingCleanup = false;\n this._intentStates = new Map();\n this._annotationPromises = new Map();\n this.destroyed = false;\n }\n\n /**\n * @type {number} Page number of the page. First page is 1.\n */\n get pageNumber() {\n return this._pageIndex + 1;\n }\n\n /**\n * @type {number} The number of degrees the page is rotated clockwise.\n */\n get rotate() {\n return this._pageInfo.rotate;\n }\n\n /**\n * @type {RefProxy | null} The reference that points to this page.\n */\n get ref() {\n return this._pageInfo.ref;\n }\n\n /**\n * @type {number} The default size of units in 1/72nds of an inch.\n */\n get userUnit() {\n return this._pageInfo.userUnit;\n }\n\n /**\n * @type {Array} An array of the visible portion of the PDF page in\n * user space units [x1, y1, x2, y2].\n */\n get view() {\n return this._pageInfo.view;\n }\n\n /**\n * @param {GetViewportParameters} params - Viewport parameters.\n * @returns {PageViewport} Contains 'width' and 'height' properties\n * along with transforms required for rendering.\n */\n getViewport({\n scale,\n rotation = this.rotate,\n offsetX = 0,\n offsetY = 0,\n dontFlip = false,\n } = {}) {\n return new PageViewport({\n viewBox: this.view,\n scale,\n rotation,\n offsetX,\n offsetY,\n dontFlip,\n });\n }\n\n /**\n * @param {GetAnnotationsParameters} params - Annotation parameters.\n * @returns {Promise>} A promise that is resolved with an\n * {Array} of the annotation objects.\n */\n getAnnotations({ intent = \"display\" } = {}) {\n const intentArgs = this._transport.getRenderingIntent(intent);\n\n let promise = this._annotationPromises.get(intentArgs.cacheKey);\n if (!promise) {\n promise = this._transport.getAnnotations(\n this._pageIndex,\n intentArgs.renderingIntent\n );\n this._annotationPromises.set(intentArgs.cacheKey, promise);\n\n if (typeof PDFJSDev === \"undefined\" || PDFJSDev.test(\"GENERIC\")) {\n promise = promise.then(annotations => {\n for (const annotation of annotations) {\n if (annotation.titleObj !== undefined) {\n Object.defineProperty(annotation, \"title\", {\n get() {\n deprecated(\n \"`title`-property on annotation, please use `titleObj` instead.\"\n );\n return annotation.titleObj.str;\n },\n });\n }\n if (annotation.contentsObj !== undefined) {\n Object.defineProperty(annotation, \"contents\", {\n get() {\n deprecated(\n \"`contents`-property on annotation, please use `contentsObj` instead.\"\n );\n return annotation.contentsObj.str;\n },\n });\n }\n }\n return annotations;\n });\n }\n }\n return promise;\n }\n\n /**\n * @returns {Promise} A promise that is resolved with an\n * {Object} with JS actions.\n */\n getJSActions() {\n return (this._jsActionsPromise ||= this._transport.getPageJSActions(\n this._pageIndex\n ));\n }\n\n /**\n * @returns {Promise} A promise that is resolved with\n * an {Object} with a fake DOM object (a tree structure where elements\n * are {Object} with a name, attributes (class, style, ...), value and\n * children, very similar to a HTML DOM tree), or `null` if no XFA exists.\n */\n async getXfa() {\n return this._transport._htmlForXfa?.children[this._pageIndex] || null;\n }\n\n /**\n * Begins the process of rendering a page to the desired context.\n *\n * @param {RenderParameters} params - Page render parameters.\n * @returns {RenderTask} An object that contains a promise that is\n * resolved when the page finishes rendering.\n */\n render({\n canvasContext,\n viewport,\n intent = \"display\",\n annotationMode = AnnotationMode.ENABLE,\n transform = null,\n imageLayer = null,\n canvasFactory = null,\n background = null,\n optionalContentConfigPromise = null,\n annotationCanvasMap = null,\n pageColors = null,\n printAnnotationStorage = null,\n }) {\n if (typeof PDFJSDev !== \"undefined\" && PDFJSDev.test(\"GENERIC\")) {\n if (arguments[0]?.renderInteractiveForms !== undefined) {\n deprecated(\n \"render no longer accepts the `renderInteractiveForms`-option, \" +\n \"please use the `annotationMode`-option instead.\"\n );\n if (\n arguments[0].renderInteractiveForms === true &&\n annotationMode === AnnotationMode.ENABLE\n ) {\n annotationMode = AnnotationMode.ENABLE_FORMS;\n }\n }\n if (arguments[0]?.includeAnnotationStorage !== undefined) {\n deprecated(\n \"render no longer accepts the `includeAnnotationStorage`-option, \" +\n \"please use the `annotationMode`-option instead.\"\n );\n if (\n arguments[0].includeAnnotationStorage === true &&\n annotationMode === AnnotationMode.ENABLE\n ) {\n annotationMode = AnnotationMode.ENABLE_STORAGE;\n }\n }\n }\n\n if (this._stats) {\n this._stats.time(\"Overall\");\n }\n\n const intentArgs = this._transport.getRenderingIntent(\n intent,\n annotationMode,\n printAnnotationStorage\n );\n // If there was a pending destroy, cancel it so no cleanup happens during\n // this call to render.\n this.pendingCleanup = false;\n\n if (!optionalContentConfigPromise) {\n optionalContentConfigPromise = this._transport.getOptionalContentConfig();\n }\n\n let intentState = this._intentStates.get(intentArgs.cacheKey);\n if (!intentState) {\n intentState = Object.create(null);\n this._intentStates.set(intentArgs.cacheKey, intentState);\n }\n\n // Ensure that a pending `streamReader` cancel timeout is always aborted.\n if (intentState.streamReaderCancelTimeout) {\n clearTimeout(intentState.streamReaderCancelTimeout);\n intentState.streamReaderCancelTimeout = null;\n }\n\n const canvasFactoryInstance =\n canvasFactory ||\n new DefaultCanvasFactory({ ownerDocument: this._ownerDocument });\n const intentPrint = !!(\n intentArgs.renderingIntent & RenderingIntentFlag.PRINT\n );\n\n // If there's no displayReadyCapability yet, then the operatorList\n // was never requested before. Make the request and create the promise.\n if (!intentState.displayReadyCapability) {\n intentState.displayReadyCapability = createPromiseCapability();\n intentState.operatorList = {\n fnArray: [],\n argsArray: [],\n lastChunk: false,\n separateAnnots: null,\n };\n\n if (this._stats) {\n this._stats.time(\"Page Request\");\n }\n this._pumpOperatorList(intentArgs);\n }\n\n const complete = error => {\n intentState.renderTasks.delete(internalRenderTask);\n\n // Attempt to reduce memory usage during *printing*, by always running\n // cleanup once rendering has finished (regardless of cleanupAfterRender).\n if (this.cleanupAfterRender || intentPrint) {\n this.pendingCleanup = true;\n }\n this._tryCleanup();\n\n if (error) {\n internalRenderTask.capability.reject(error);\n\n this._abortOperatorList({\n intentState,\n reason: error instanceof Error ? error : new Error(error),\n });\n } else {\n internalRenderTask.capability.resolve();\n }\n if (this._stats) {\n this._stats.timeEnd(\"Rendering\");\n this._stats.timeEnd(\"Overall\");\n }\n };\n\n const internalRenderTask = new InternalRenderTask({\n callback: complete,\n // Only include the required properties, and *not* the entire object.\n params: {\n canvasContext,\n viewport,\n transform,\n imageLayer,\n background,\n },\n objs: this.objs,\n commonObjs: this.commonObjs,\n annotationCanvasMap,\n operatorList: intentState.operatorList,\n pageIndex: this._pageIndex,\n canvasFactory: canvasFactoryInstance,\n useRequestAnimationFrame: !intentPrint,\n pdfBug: this._pdfBug,\n pageColors,\n });\n\n (intentState.renderTasks ||= new Set()).add(internalRenderTask);\n const renderTask = internalRenderTask.task;\n\n Promise.all([\n intentState.displayReadyCapability.promise,\n optionalContentConfigPromise,\n ])\n .then(([transparency, optionalContentConfig]) => {\n if (this.pendingCleanup) {\n complete();\n return;\n }\n if (this._stats) {\n this._stats.time(\"Rendering\");\n }\n internalRenderTask.initializeGraphics({\n transparency,\n optionalContentConfig,\n });\n internalRenderTask.operatorListChanged();\n })\n .catch(complete);\n\n return renderTask;\n }\n\n /**\n * @param {GetOperatorListParameters} params - Page getOperatorList\n * parameters.\n * @returns {Promise} A promise resolved with an\n * {@link PDFOperatorList} object that represents the page's operator list.\n */\n getOperatorList({\n intent = \"display\",\n annotationMode = AnnotationMode.ENABLE,\n printAnnotationStorage = null,\n } = {}) {\n function operatorListChanged() {\n if (intentState.operatorList.lastChunk) {\n intentState.opListReadCapability.resolve(intentState.operatorList);\n\n intentState.renderTasks.delete(opListTask);\n }\n }\n\n const intentArgs = this._transport.getRenderingIntent(\n intent,\n annotationMode,\n printAnnotationStorage,\n /* isOpList = */ true\n );\n let intentState = this._intentStates.get(intentArgs.cacheKey);\n if (!intentState) {\n intentState = Object.create(null);\n this._intentStates.set(intentArgs.cacheKey, intentState);\n }\n let opListTask;\n\n if (!intentState.opListReadCapability) {\n opListTask = Object.create(null);\n opListTask.operatorListChanged = operatorListChanged;\n intentState.opListReadCapability = createPromiseCapability();\n (intentState.renderTasks ||= new Set()).add(opListTask);\n intentState.operatorList = {\n fnArray: [],\n argsArray: [],\n lastChunk: false,\n separateAnnots: null,\n };\n\n if (this._stats) {\n this._stats.time(\"Page Request\");\n }\n this._pumpOperatorList(intentArgs);\n }\n return intentState.opListReadCapability.promise;\n }\n\n /**\n * NOTE: All occurrences of whitespace will be replaced by\n * standard spaces (0x20).\n *\n * @param {getTextContentParameters} params - getTextContent parameters.\n * @returns {ReadableStream} Stream for reading text content chunks.\n */\n streamTextContent({\n disableCombineTextItems = false,\n includeMarkedContent = false,\n } = {}) {\n const TEXT_CONTENT_CHUNK_SIZE = 100;\n\n return this._transport.messageHandler.sendWithStream(\n \"GetTextContent\",\n {\n pageIndex: this._pageIndex,\n combineTextItems: disableCombineTextItems !== true,\n includeMarkedContent: includeMarkedContent === true,\n },\n {\n highWaterMark: TEXT_CONTENT_CHUNK_SIZE,\n size(textContent) {\n return textContent.items.length;\n },\n }\n );\n }\n\n /**\n * NOTE: All occurrences of whitespace will be replaced by\n * standard spaces (0x20).\n *\n * @param {getTextContentParameters} params - getTextContent parameters.\n * @returns {Promise} A promise that is resolved with a\n * {@link TextContent} object that represents the page's text content.\n */\n getTextContent(params = {}) {\n if (this._transport._htmlForXfa) {\n // TODO: We need to revisit this once the XFA foreground patch lands and\n // only do this for non-foreground XFA.\n return this.getXfa().then(xfa => {\n return XfaText.textContent(xfa);\n });\n }\n const readableStream = this.streamTextContent(params);\n\n return new Promise(function (resolve, reject) {\n function pump() {\n reader.read().then(function ({ value, done }) {\n if (done) {\n resolve(textContent);\n return;\n }\n Object.assign(textContent.styles, value.styles);\n textContent.items.push(...value.items);\n pump();\n }, reject);\n }\n\n const reader = readableStream.getReader();\n const textContent = {\n items: [],\n styles: Object.create(null),\n };\n pump();\n });\n }\n\n /**\n * @returns {Promise} A promise that is resolved with a\n * {@link StructTreeNode} object that represents the page's structure tree,\n * or `null` when no structure tree is present for the current page.\n */\n getStructTree() {\n return (this._structTreePromise ||= this._transport.getStructTree(\n this._pageIndex\n ));\n }\n\n /**\n * Destroys the page object.\n * @private\n */\n _destroy() {\n this.destroyed = true;\n\n const waitOn = [];\n for (const intentState of this._intentStates.values()) {\n this._abortOperatorList({\n intentState,\n reason: new Error(\"Page was destroyed.\"),\n force: true,\n });\n\n if (intentState.opListReadCapability) {\n // Avoid errors below, since the renderTasks are just stubs.\n continue;\n }\n for (const internalRenderTask of intentState.renderTasks) {\n waitOn.push(internalRenderTask.completed);\n internalRenderTask.cancel();\n }\n }\n this.objs.clear();\n for (const bitmap of this._bitmaps) {\n bitmap.close();\n }\n this._bitmaps.clear();\n this._annotationPromises.clear();\n this._jsActionsPromise = null;\n this._structTreePromise = null;\n this.pendingCleanup = false;\n return Promise.all(waitOn);\n }\n\n /**\n * Cleans up resources allocated by the page.\n *\n * @param {boolean} [resetStats] - Reset page stats, if enabled.\n * The default value is `false`.\n * @returns {boolean} Indicates if clean-up was successfully run.\n */\n cleanup(resetStats = false) {\n this.pendingCleanup = true;\n return this._tryCleanup(resetStats);\n }\n\n /**\n * Attempts to clean up if rendering is in a state where that's possible.\n * @private\n */\n _tryCleanup(resetStats = false) {\n if (!this.pendingCleanup) {\n return false;\n }\n for (const { renderTasks, operatorList } of this._intentStates.values()) {\n if (renderTasks.size > 0 || !operatorList.lastChunk) {\n return false;\n }\n }\n\n this._intentStates.clear();\n this.objs.clear();\n this._annotationPromises.clear();\n this._jsActionsPromise = null;\n this._structTreePromise = null;\n if (resetStats && this._stats) {\n this._stats = new StatTimer();\n }\n for (const bitmap of this._bitmaps) {\n bitmap.close();\n }\n this._bitmaps.clear();\n this.pendingCleanup = false;\n return true;\n }\n\n /**\n * @private\n */\n _startRenderPage(transparency, cacheKey) {\n const intentState = this._intentStates.get(cacheKey);\n if (!intentState) {\n return; // Rendering was cancelled.\n }\n if (this._stats) {\n this._stats.timeEnd(\"Page Request\");\n }\n // TODO Refactor RenderPageRequest to separate rendering\n // and operator list logic\n if (intentState.displayReadyCapability) {\n intentState.displayReadyCapability.resolve(transparency);\n }\n }\n\n /**\n * @private\n */\n _renderPageChunk(operatorListChunk, intentState) {\n // Add the new chunk to the current operator list.\n for (let i = 0, ii = operatorListChunk.length; i < ii; i++) {\n intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]);\n intentState.operatorList.argsArray.push(operatorListChunk.argsArray[i]);\n }\n intentState.operatorList.lastChunk = operatorListChunk.lastChunk;\n intentState.operatorList.separateAnnots = operatorListChunk.separateAnnots;\n\n // Notify all the rendering tasks there are more operators to be consumed.\n for (const internalRenderTask of intentState.renderTasks) {\n internalRenderTask.operatorListChanged();\n }\n\n if (operatorListChunk.lastChunk) {\n this._tryCleanup();\n }\n }\n\n /**\n * @private\n */\n _pumpOperatorList({ renderingIntent, cacheKey, annotationStorageMap }) {\n if (\n typeof PDFJSDev === \"undefined\" ||\n PDFJSDev.test(\"!PRODUCTION || TESTING\")\n ) {\n assert(\n Number.isInteger(renderingIntent) && renderingIntent > 0,\n '_pumpOperatorList: Expected valid \"renderingIntent\" argument.'\n );\n }\n\n const readableStream = this._transport.messageHandler.sendWithStream(\n \"GetOperatorList\",\n {\n pageIndex: this._pageIndex,\n intent: renderingIntent,\n cacheKey,\n annotationStorage: annotationStorageMap,\n }\n );\n const reader = readableStream.getReader();\n\n const intentState = this._intentStates.get(cacheKey);\n intentState.streamReader = reader;\n\n const pump = () => {\n reader.read().then(\n ({ value, done }) => {\n if (done) {\n intentState.streamReader = null;\n return;\n }\n if (this._transport.destroyed) {\n return; // Ignore any pending requests if the worker was terminated.\n }\n this._renderPageChunk(value, intentState);\n pump();\n },\n reason => {\n intentState.streamReader = null;\n\n if (this._transport.destroyed) {\n return; // Ignore any pending requests if the worker was terminated.\n }\n if (intentState.operatorList) {\n // Mark operator list as complete.\n intentState.operatorList.lastChunk = true;\n\n for (const internalRenderTask of intentState.renderTasks) {\n internalRenderTask.operatorListChanged();\n }\n this._tryCleanup();\n }\n\n if (intentState.displayReadyCapability) {\n intentState.displayReadyCapability.reject(reason);\n } else if (intentState.opListReadCapability) {\n intentState.opListReadCapability.reject(reason);\n } else {\n throw reason;\n }\n }\n );\n };\n pump();\n }\n\n /**\n * @private\n */\n _abortOperatorList({ intentState, reason, force = false }) {\n if (\n typeof PDFJSDev === \"undefined\" ||\n PDFJSDev.test(\"!PRODUCTION || TESTING\")\n ) {\n assert(\n reason instanceof Error,\n '_abortOperatorList: Expected valid \"reason\" argument.'\n );\n }\n\n if (!intentState.streamReader) {\n return;\n }\n if (!force) {\n // Ensure that an Error occurring in *only* one `InternalRenderTask`, e.g.\n // multiple render() calls on the same canvas, won't break all rendering.\n if (intentState.renderTasks.size > 0) {\n return;\n }\n // Don't immediately abort parsing on the worker-thread when rendering is\n // cancelled, since that will unnecessarily delay re-rendering when (for\n // partially parsed pages) e.g. zooming/rotation occurs in the viewer.\n if (reason instanceof RenderingCancelledException) {\n intentState.streamReaderCancelTimeout = setTimeout(() => {\n this._abortOperatorList({ intentState, reason, force: true });\n intentState.streamReaderCancelTimeout = null;\n }, RENDERING_CANCELLED_TIMEOUT);\n return;\n }\n }\n intentState.streamReader\n .cancel(new AbortException(reason.message))\n .catch(() => {\n // Avoid \"Uncaught promise\" messages in the console.\n });\n intentState.streamReader = null;\n\n if (this._transport.destroyed) {\n return; // Ignore any pending requests if the worker was terminated.\n }\n // Remove the current `intentState`, since a cancelled `getOperatorList`\n // call on the worker-thread cannot be re-started...\n for (const [curCacheKey, curIntentState] of this._intentStates) {\n if (curIntentState === intentState) {\n this._intentStates.delete(curCacheKey);\n break;\n }\n }\n // ... and force clean-up to ensure that any old state is always removed.\n this.cleanup();\n }\n\n /**\n * @type {Object} Returns page stats, if enabled; returns `null` otherwise.\n */\n get stats() {\n return this._stats;\n }\n}\n\nclass LoopbackPort {\n constructor() {\n this._listeners = [];\n this._deferred = Promise.resolve();\n }\n\n postMessage(obj, transfers) {\n const event = {\n data: structuredClone(obj, transfers),\n };\n\n this._deferred.then(() => {\n for (const listener of this._listeners) {\n listener.call(this, event);\n }\n });\n }\n\n addEventListener(name, listener) {\n this._listeners.push(listener);\n }\n\n removeEventListener(name, listener) {\n const i = this._listeners.indexOf(listener);\n this._listeners.splice(i, 1);\n }\n\n terminate() {\n this._listeners.length = 0;\n }\n}\n\n/**\n * @typedef {Object} PDFWorkerParameters\n * @property {string} [name] - The name of the worker.\n * @property {Object} [port] - The `workerPort` object.\n * @property {number} [verbosity] - Controls the logging level;\n * the constants from {@link VerbosityLevel} should be used.\n */\n\nconst PDFWorkerUtil = {\n isWorkerDisabled: false,\n fallbackWorkerSrc: null,\n fakeWorkerId: 0,\n};\nif (typeof PDFJSDev === \"undefined\" || PDFJSDev.test(\"GENERIC\")) {\n // eslint-disable-next-line no-undef\n if (isNodeJS && typeof __non_webpack_require__ === \"function\") {\n // Workers aren't supported in Node.js, force-disabling them there.\n PDFWorkerUtil.isWorkerDisabled = true;\n\n PDFWorkerUtil.fallbackWorkerSrc = PDFJSDev.test(\"LIB\")\n ? \"../pdf.worker.js\"\n : \"./pdf.worker.js\";\n } else if (typeof document === \"object\") {\n const pdfjsFilePath = document?.currentScript?.src;\n if (pdfjsFilePath) {\n PDFWorkerUtil.fallbackWorkerSrc = pdfjsFilePath.replace(\n /(\\.(?:min\\.)?js)(\\?.*)?$/i,\n \".worker$1$2\"\n );\n }\n }\n\n // Check if URLs have the same origin. For non-HTTP based URLs, returns false.\n PDFWorkerUtil.isSameOrigin = function (baseUrl, otherUrl) {\n let base;\n try {\n base = new URL(baseUrl);\n if (!base.origin || base.origin === \"null\") {\n return false; // non-HTTP url\n }\n } catch (e) {\n return false;\n }\n\n const other = new URL(otherUrl, base);\n return base.origin === other.origin;\n };\n\n PDFWorkerUtil.createCDNWrapper = function (url) {\n // We will rely on blob URL's property to specify origin.\n // We want this function to fail in case if createObjectURL or Blob do not\n // exist or fail for some reason -- our Worker creation will fail anyway.\n const wrapper = `importScripts(\"${url}\");`;\n return URL.createObjectURL(new Blob([wrapper]));\n };\n}\n\n/**\n * PDF.js web worker abstraction that controls the instantiation of PDF\n * documents. Message handlers are used to pass information from the main\n * thread to the worker thread and vice versa. If the creation of a web\n * worker is not possible, a \"fake\" worker will be used instead.\n *\n * @param {PDFWorkerParameters} params - The worker initialization parameters.\n */\nclass PDFWorker {\n static #workerPorts = new WeakMap();\n\n constructor({\n name = null,\n port = null,\n verbosity = getVerbosityLevel(),\n } = {}) {\n if (port && PDFWorker.#workerPorts.has(port)) {\n throw new Error(\"Cannot use more than one PDFWorker per port.\");\n }\n\n this.name = name;\n this.destroyed = false;\n this.verbosity = verbosity;\n\n this._readyCapability = createPromiseCapability();\n this._port = null;\n this._webWorker = null;\n this._messageHandler = null;\n\n if (port) {\n PDFWorker.#workerPorts.set(port, this);\n this._initializeFromPort(port);\n return;\n }\n this._initialize();\n }\n\n /**\n * Promise for worker initialization completion.\n * @type {Promise}\n */\n get promise() {\n return this._readyCapability.promise;\n }\n\n /**\n * The current `workerPort`, when it exists.\n * @type {Worker}\n */\n get port() {\n return this._port;\n }\n\n /**\n * The current MessageHandler-instance.\n * @type {MessageHandler}\n */\n get messageHandler() {\n return this._messageHandler;\n }\n\n _initializeFromPort(port) {\n this._port = port;\n this._messageHandler = new MessageHandler(\"main\", \"worker\", port);\n this._messageHandler.on(\"ready\", function () {\n // Ignoring \"ready\" event -- MessageHandler should already be initialized\n // and ready to accept messages.\n });\n this._readyCapability.resolve();\n }\n\n _initialize() {\n // If worker support isn't disabled explicit and the browser has worker\n // support, create a new web worker and test if it/the browser fulfills\n // all requirements to run parts of pdf.js in a web worker.\n // Right now, the requirement is, that an Uint8Array is still an\n // Uint8Array as it arrives on the worker. (Chrome added this with v.15.)\n if (\n !PDFWorkerUtil.isWorkerDisabled &&\n !PDFWorker._mainThreadWorkerMessageHandler\n ) {\n let { workerSrc } = PDFWorker;\n\n try {\n // Wraps workerSrc path into blob URL, if the former does not belong\n // to the same origin.\n if (\n typeof PDFJSDev !== \"undefined\" &&\n PDFJSDev.test(\"GENERIC\") &&\n !PDFWorkerUtil.isSameOrigin(window.location.href, workerSrc)\n ) {\n workerSrc = PDFWorkerUtil.createCDNWrapper(\n new URL(workerSrc, window.location).href\n );\n }\n\n // Some versions of FF can't create a worker on localhost, see:\n // https://bugzilla.mozilla.org/show_bug.cgi?id=683280\n const worker = new Worker(workerSrc);\n const messageHandler = new MessageHandler(\"main\", \"worker\", worker);\n const terminateEarly = () => {\n worker.removeEventListener(\"error\", onWorkerError);\n messageHandler.destroy();\n worker.terminate();\n if (this.destroyed) {\n this._readyCapability.reject(new Error(\"Worker was destroyed\"));\n } else {\n // Fall back to fake worker if the termination is caused by an\n // error (e.g. NetworkError / SecurityError).\n this._setupFakeWorker();\n }\n };\n\n const onWorkerError = () => {\n if (!this._webWorker) {\n // Worker failed to initialize due to an error. Clean up and fall\n // back to the fake worker.\n terminateEarly();\n }\n };\n worker.addEventListener(\"error\", onWorkerError);\n\n messageHandler.on(\"test\", data => {\n worker.removeEventListener(\"error\", onWorkerError);\n if (this.destroyed) {\n terminateEarly();\n return; // worker was destroyed\n }\n if (data) {\n this._messageHandler = messageHandler;\n this._port = worker;\n this._webWorker = worker;\n\n this._readyCapability.resolve();\n // Send global setting, e.g. verbosity level.\n messageHandler.send(\"configure\", {\n verbosity: this.verbosity,\n });\n } else {\n this._setupFakeWorker();\n messageHandler.destroy();\n worker.terminate();\n }\n });\n\n messageHandler.on(\"ready\", data => {\n worker.removeEventListener(\"error\", onWorkerError);\n if (this.destroyed) {\n terminateEarly();\n return; // worker was destroyed\n }\n try {\n sendTest();\n } catch (e) {\n // We need fallback to a faked worker.\n this._setupFakeWorker();\n }\n });\n\n const sendTest = () => {\n const testObj = new Uint8Array();\n // Ensure that we can use `postMessage` transfers.\n messageHandler.send(\"test\", testObj, [testObj.buffer]);\n };\n\n // It might take time for the worker to initialize. We will try to send\n // the \"test\" message immediately, and once the \"ready\" message arrives.\n // The worker shall process only the first received \"test\" message.\n sendTest();\n return;\n } catch (e) {\n info(\"The worker has been disabled.\");\n }\n }\n // Either workers are disabled, not supported or have thrown an exception.\n // Thus, we fallback to a faked worker.\n this._setupFakeWorker();\n }\n\n _setupFakeWorker() {\n if (!PDFWorkerUtil.isWorkerDisabled) {\n warn(\"Setting up fake worker.\");\n PDFWorkerUtil.isWorkerDisabled = true;\n }\n\n PDFWorker._setupFakeWorkerGlobal\n .then(WorkerMessageHandler => {\n if (this.destroyed) {\n this._readyCapability.reject(new Error(\"Worker was destroyed\"));\n return;\n }\n const port = new LoopbackPort();\n this._port = port;\n\n // All fake workers use the same port, making id unique.\n const id = `fake${PDFWorkerUtil.fakeWorkerId++}`;\n\n // If the main thread is our worker, setup the handling for the\n // messages -- the main thread sends to it self.\n const workerHandler = new MessageHandler(id + \"_worker\", id, port);\n WorkerMessageHandler.setup(workerHandler, port);\n\n const messageHandler = new MessageHandler(id, id + \"_worker\", port);\n this._messageHandler = messageHandler;\n this._readyCapability.resolve();\n // Send global setting, e.g. verbosity level.\n messageHandler.send(\"configure\", {\n verbosity: this.verbosity,\n });\n })\n .catch(reason => {\n this._readyCapability.reject(\n new Error(`Setting up fake worker failed: \"${reason.message}\".`)\n );\n });\n }\n\n /**\n * Destroys the worker instance.\n */\n destroy() {\n this.destroyed = true;\n if (this._webWorker) {\n // We need to terminate only web worker created resource.\n this._webWorker.terminate();\n this._webWorker = null;\n }\n PDFWorker.#workerPorts.delete(this._port);\n this._port = null;\n if (this._messageHandler) {\n this._messageHandler.destroy();\n this._messageHandler = null;\n }\n }\n\n /**\n * @param {PDFWorkerParameters} params - The worker initialization parameters.\n */\n static fromPort(params) {\n if (!params?.port) {\n throw new Error(\"PDFWorker.fromPort - invalid method signature.\");\n }\n if (this.#workerPorts.has(params.port)) {\n return this.#workerPorts.get(params.port);\n }\n return new PDFWorker(params);\n }\n\n /**\n * The current `workerSrc`, when it exists.\n * @type {string}\n */\n static get workerSrc() {\n if (GlobalWorkerOptions.workerSrc) {\n return GlobalWorkerOptions.workerSrc;\n }\n if (\n (typeof PDFJSDev === \"undefined\" || PDFJSDev.test(\"GENERIC\")) &&\n PDFWorkerUtil.fallbackWorkerSrc !== null\n ) {\n if (!isNodeJS) {\n deprecated('No \"GlobalWorkerOptions.workerSrc\" specified.');\n }\n return PDFWorkerUtil.fallbackWorkerSrc;\n }\n throw new Error('No \"GlobalWorkerOptions.workerSrc\" specified.');\n }\n\n static get _mainThreadWorkerMessageHandler() {\n try {\n return globalThis.pdfjsWorker?.WorkerMessageHandler || null;\n } catch (ex) {\n return null;\n }\n }\n\n // Loads worker code into the main-thread.\n static get _setupFakeWorkerGlobal() {\n const loader = async () => {\n const mainWorkerMessageHandler = this._mainThreadWorkerMessageHandler;\n\n if (mainWorkerMessageHandler) {\n // The worker was already loaded using e.g. a ` + + + + + + +
+ +
+
+
+
+ + + + +
+
+ +
+ +
+
+
+
+
+ + + +
+
+
+ +
+ + + + + + + + +
+
+
+
+ +
+ +
+ +
+ +
+ + +
+
+ + + + + + + + + Current View + + +
+ + + + + + + +
+
+
+ +
+ +
+ + + +
+
+
+
+
+
+
+
+
+
+ +
+
+
+ + +
+ +
+ +
+ +
+
+ +
+
+ + +
+
+ +
+ File name: +

-

+
+
+ File size: +

-

+
+
+
+ Title: +

-

+
+
+ Author: +

-

+
+
+ Subject: +

-

+
+
+ Keywords: +

-

+
+
+ Creation Date: +

-

+
+
+ Modification Date: +

-

+
+
+ Creator: +

-

+
+
+
+ PDF Producer: +

-

+
+
+ PDF Version: +

-

+
+
+ Page Count: +

-

+
+
+ Page Size: +

-

+
+
+
+ Fast Web View: +

-

+
+
+ +
+
+ +
+ Preparing document for printing… +
+
+ + 0% +
+
+ +
+
+
+ +
+
+ + + + diff --git a/frontend/public/pdfjs/web/viewer.js b/frontend/public/pdfjs/web/viewer.js new file mode 100644 index 0000000..2d37734 --- /dev/null +++ b/frontend/public/pdfjs/web/viewer.js @@ -0,0 +1,18626 @@ +/** + * @licstart The following is the entire license notice for the + * JavaScript code in this page + * + * Copyright 2022 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @licend The above is the entire license notice for the + * JavaScript code in this page + */ + +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ([ +/* 0 */, +/* 1 */ +/***/ ((__unused_webpack_module, exports) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.animationStarted = exports.VERTICAL_PADDING = exports.UNKNOWN_SCALE = exports.TextLayerMode = exports.SpreadMode = exports.SidebarView = exports.ScrollMode = exports.SCROLLBAR_PADDING = exports.RenderingStates = exports.RendererType = exports.ProgressBar = exports.PresentationModeState = exports.OutputScale = exports.MIN_SCALE = exports.MAX_SCALE = exports.MAX_AUTO_SCALE = exports.DEFAULT_SCALE_VALUE = exports.DEFAULT_SCALE_DELTA = exports.DEFAULT_SCALE = exports.AutoPrintRegExp = void 0; +exports.apiPageLayoutToViewerModes = apiPageLayoutToViewerModes; +exports.apiPageModeToSidebarView = apiPageModeToSidebarView; +exports.approximateFraction = approximateFraction; +exports.backtrackBeforeAllVisibleElements = backtrackBeforeAllVisibleElements; +exports.binarySearchFirstItem = binarySearchFirstItem; +exports.docStyle = void 0; +exports.getActiveOrFocusedElement = getActiveOrFocusedElement; +exports.getPageSizeInches = getPageSizeInches; +exports.getVisibleElements = getVisibleElements; +exports.isPortraitOrientation = isPortraitOrientation; +exports.isValidRotation = isValidRotation; +exports.isValidScrollMode = isValidScrollMode; +exports.isValidSpreadMode = isValidSpreadMode; +exports.noContextMenuHandler = noContextMenuHandler; +exports.normalizeWheelEventDelta = normalizeWheelEventDelta; +exports.normalizeWheelEventDirection = normalizeWheelEventDirection; +exports.parseQueryString = parseQueryString; +exports.removeNullCharacters = removeNullCharacters; +exports.roundToDivide = roundToDivide; +exports.scrollIntoView = scrollIntoView; +exports.watchScroll = watchScroll; + +function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } + +function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } + +function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } + +const DEFAULT_SCALE_VALUE = "auto"; +exports.DEFAULT_SCALE_VALUE = DEFAULT_SCALE_VALUE; +const DEFAULT_SCALE = 1.0; +exports.DEFAULT_SCALE = DEFAULT_SCALE; +const DEFAULT_SCALE_DELTA = 1.1; +exports.DEFAULT_SCALE_DELTA = DEFAULT_SCALE_DELTA; +const MIN_SCALE = 0.1; +exports.MIN_SCALE = MIN_SCALE; +const MAX_SCALE = 10.0; +exports.MAX_SCALE = MAX_SCALE; +const UNKNOWN_SCALE = 0; +exports.UNKNOWN_SCALE = UNKNOWN_SCALE; +const MAX_AUTO_SCALE = 1.25; +exports.MAX_AUTO_SCALE = MAX_AUTO_SCALE; +const SCROLLBAR_PADDING = 40; +exports.SCROLLBAR_PADDING = SCROLLBAR_PADDING; +const VERTICAL_PADDING = 5; +exports.VERTICAL_PADDING = VERTICAL_PADDING; +const RenderingStates = { + INITIAL: 0, + RUNNING: 1, + PAUSED: 2, + FINISHED: 3 +}; +exports.RenderingStates = RenderingStates; +const PresentationModeState = { + UNKNOWN: 0, + NORMAL: 1, + CHANGING: 2, + FULLSCREEN: 3 +}; +exports.PresentationModeState = PresentationModeState; +const SidebarView = { + UNKNOWN: -1, + NONE: 0, + THUMBS: 1, + OUTLINE: 2, + ATTACHMENTS: 3, + LAYERS: 4 +}; +exports.SidebarView = SidebarView; +const RendererType = { + CANVAS: "canvas", + SVG: "svg" +}; +exports.RendererType = RendererType; +const TextLayerMode = { + DISABLE: 0, + ENABLE: 1, + ENABLE_ENHANCE: 2 +}; +exports.TextLayerMode = TextLayerMode; +const ScrollMode = { + UNKNOWN: -1, + VERTICAL: 0, + HORIZONTAL: 1, + WRAPPED: 2, + PAGE: 3 +}; +exports.ScrollMode = ScrollMode; +const SpreadMode = { + UNKNOWN: -1, + NONE: 0, + ODD: 1, + EVEN: 2 +}; +exports.SpreadMode = SpreadMode; +const AutoPrintRegExp = /\bprint\s*\(/; +exports.AutoPrintRegExp = AutoPrintRegExp; + +class OutputScale { + constructor() { + const pixelRatio = window.devicePixelRatio || 1; + this.sx = pixelRatio; + this.sy = pixelRatio; + } + + get scaled() { + return this.sx !== 1 || this.sy !== 1; + } + +} + +exports.OutputScale = OutputScale; + +function scrollIntoView(element, spot) { + let scrollMatches = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + let parent = element.offsetParent; + + if (!parent) { + console.error("offsetParent is not set -- cannot scroll"); + return; + } + + let offsetY = element.offsetTop + element.clientTop; + let offsetX = element.offsetLeft + element.clientLeft; + + while (parent.clientHeight === parent.scrollHeight && parent.clientWidth === parent.scrollWidth || scrollMatches && (parent.classList.contains("markedContent") || getComputedStyle(parent).overflow === "hidden")) { + offsetY += parent.offsetTop; + offsetX += parent.offsetLeft; + parent = parent.offsetParent; + + if (!parent) { + return; + } + } + + if (spot) { + if (spot.top !== undefined) { + offsetY += spot.top; + } + + if (spot.left !== undefined) { + offsetX += spot.left; + parent.scrollLeft = offsetX; + } + } + + parent.scrollTop = offsetY; +} + +function watchScroll(viewAreaElement, callback) { + const debounceScroll = function (evt) { + if (rAF) { + return; + } + + rAF = window.requestAnimationFrame(function viewAreaElementScrolled() { + rAF = null; + const currentX = viewAreaElement.scrollLeft; + const lastX = state.lastX; + + if (currentX !== lastX) { + state.right = currentX > lastX; + } + + state.lastX = currentX; + const currentY = viewAreaElement.scrollTop; + const lastY = state.lastY; + + if (currentY !== lastY) { + state.down = currentY > lastY; + } + + state.lastY = currentY; + callback(state); + }); + }; + + const state = { + right: true, + down: true, + lastX: viewAreaElement.scrollLeft, + lastY: viewAreaElement.scrollTop, + _eventHandler: debounceScroll + }; + let rAF = null; + viewAreaElement.addEventListener("scroll", debounceScroll, true); + return state; +} + +function parseQueryString(query) { + const params = new Map(); + + for (const [key, value] of new URLSearchParams(query)) { + params.set(key.toLowerCase(), value); + } + + return params; +} + +const NullCharactersRegExp = /\x00/g; +const InvisibleCharactersRegExp = /[\x01-\x1F]/g; + +function removeNullCharacters(str) { + let replaceInvisible = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + if (typeof str !== "string") { + console.error(`The argument must be a string.`); + return str; + } + + if (replaceInvisible) { + str = str.replace(InvisibleCharactersRegExp, " "); + } + + return str.replace(NullCharactersRegExp, ""); +} + +function binarySearchFirstItem(items, condition) { + let start = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; + let minIndex = start; + let maxIndex = items.length - 1; + + if (maxIndex < 0 || !condition(items[maxIndex])) { + return items.length; + } + + if (condition(items[minIndex])) { + return minIndex; + } + + while (minIndex < maxIndex) { + const currentIndex = minIndex + maxIndex >> 1; + const currentItem = items[currentIndex]; + + if (condition(currentItem)) { + maxIndex = currentIndex; + } else { + minIndex = currentIndex + 1; + } + } + + return minIndex; +} + +function approximateFraction(x) { + if (Math.floor(x) === x) { + return [x, 1]; + } + + const xinv = 1 / x; + const limit = 8; + + if (xinv > limit) { + return [1, limit]; + } else if (Math.floor(xinv) === xinv) { + return [1, xinv]; + } + + const x_ = x > 1 ? xinv : x; + let a = 0, + b = 1, + c = 1, + d = 1; + + while (true) { + const p = a + c, + q = b + d; + + if (q > limit) { + break; + } + + if (x_ <= p / q) { + c = p; + d = q; + } else { + a = p; + b = q; + } + } + + let result; + + if (x_ - a / b < c / d - x_) { + result = x_ === x ? [a, b] : [b, a]; + } else { + result = x_ === x ? [c, d] : [d, c]; + } + + return result; +} + +function roundToDivide(x, div) { + const r = x % div; + return r === 0 ? x : Math.round(x - r + div); +} + +function getPageSizeInches(_ref) { + let { + view, + userUnit, + rotate + } = _ref; + const [x1, y1, x2, y2] = view; + const changeOrientation = rotate % 180 !== 0; + const width = (x2 - x1) / 72 * userUnit; + const height = (y2 - y1) / 72 * userUnit; + return { + width: changeOrientation ? height : width, + height: changeOrientation ? width : height + }; +} + +function backtrackBeforeAllVisibleElements(index, views, top) { + if (index < 2) { + return index; + } + + let elt = views[index].div; + let pageTop = elt.offsetTop + elt.clientTop; + + if (pageTop >= top) { + elt = views[index - 1].div; + pageTop = elt.offsetTop + elt.clientTop; + } + + for (let i = index - 2; i >= 0; --i) { + elt = views[i].div; + + if (elt.offsetTop + elt.clientTop + elt.clientHeight <= pageTop) { + break; + } + + index = i; + } + + return index; +} + +function getVisibleElements(_ref2) { + let { + scrollEl, + views, + sortByVisibility = false, + horizontal = false, + rtl = false + } = _ref2; + const top = scrollEl.scrollTop, + bottom = top + scrollEl.clientHeight; + const left = scrollEl.scrollLeft, + right = left + scrollEl.clientWidth; + + function isElementBottomAfterViewTop(view) { + const element = view.div; + const elementBottom = element.offsetTop + element.clientTop + element.clientHeight; + return elementBottom > top; + } + + function isElementNextAfterViewHorizontally(view) { + const element = view.div; + const elementLeft = element.offsetLeft + element.clientLeft; + const elementRight = elementLeft + element.clientWidth; + return rtl ? elementLeft < right : elementRight > left; + } + + const visible = [], + ids = new Set(), + numViews = views.length; + let firstVisibleElementInd = binarySearchFirstItem(views, horizontal ? isElementNextAfterViewHorizontally : isElementBottomAfterViewTop); + + if (firstVisibleElementInd > 0 && firstVisibleElementInd < numViews && !horizontal) { + firstVisibleElementInd = backtrackBeforeAllVisibleElements(firstVisibleElementInd, views, top); + } + + let lastEdge = horizontal ? right : -1; + + for (let i = firstVisibleElementInd; i < numViews; i++) { + const view = views[i], + element = view.div; + const currentWidth = element.offsetLeft + element.clientLeft; + const currentHeight = element.offsetTop + element.clientTop; + const viewWidth = element.clientWidth, + viewHeight = element.clientHeight; + const viewRight = currentWidth + viewWidth; + const viewBottom = currentHeight + viewHeight; + + if (lastEdge === -1) { + if (viewBottom >= bottom) { + lastEdge = viewBottom; + } + } else if ((horizontal ? currentWidth : currentHeight) > lastEdge) { + break; + } + + if (viewBottom <= top || currentHeight >= bottom || viewRight <= left || currentWidth >= right) { + continue; + } + + const hiddenHeight = Math.max(0, top - currentHeight) + Math.max(0, viewBottom - bottom); + const hiddenWidth = Math.max(0, left - currentWidth) + Math.max(0, viewRight - right); + const fractionHeight = (viewHeight - hiddenHeight) / viewHeight, + fractionWidth = (viewWidth - hiddenWidth) / viewWidth; + const percent = fractionHeight * fractionWidth * 100 | 0; + visible.push({ + id: view.id, + x: currentWidth, + y: currentHeight, + view, + percent, + widthPercent: fractionWidth * 100 | 0 + }); + ids.add(view.id); + } + + const first = visible[0], + last = visible.at(-1); + + if (sortByVisibility) { + visible.sort(function (a, b) { + const pc = a.percent - b.percent; + + if (Math.abs(pc) > 0.001) { + return -pc; + } + + return a.id - b.id; + }); + } + + return { + first, + last, + views: visible, + ids + }; +} + +function noContextMenuHandler(evt) { + evt.preventDefault(); +} + +function normalizeWheelEventDirection(evt) { + let delta = Math.hypot(evt.deltaX, evt.deltaY); + const angle = Math.atan2(evt.deltaY, evt.deltaX); + + if (-0.25 * Math.PI < angle && angle < 0.75 * Math.PI) { + delta = -delta; + } + + return delta; +} + +function normalizeWheelEventDelta(evt) { + let delta = normalizeWheelEventDirection(evt); + const MOUSE_DOM_DELTA_PIXEL_MODE = 0; + const MOUSE_DOM_DELTA_LINE_MODE = 1; + const MOUSE_PIXELS_PER_LINE = 30; + const MOUSE_LINES_PER_PAGE = 30; + + if (evt.deltaMode === MOUSE_DOM_DELTA_PIXEL_MODE) { + delta /= MOUSE_PIXELS_PER_LINE * MOUSE_LINES_PER_PAGE; + } else if (evt.deltaMode === MOUSE_DOM_DELTA_LINE_MODE) { + delta /= MOUSE_LINES_PER_PAGE; + } + + return delta; +} + +function isValidRotation(angle) { + return Number.isInteger(angle) && angle % 90 === 0; +} + +function isValidScrollMode(mode) { + return Number.isInteger(mode) && Object.values(ScrollMode).includes(mode) && mode !== ScrollMode.UNKNOWN; +} + +function isValidSpreadMode(mode) { + return Number.isInteger(mode) && Object.values(SpreadMode).includes(mode) && mode !== SpreadMode.UNKNOWN; +} + +function isPortraitOrientation(size) { + return size.width <= size.height; +} + +const animationStarted = new Promise(function (resolve) { + window.requestAnimationFrame(resolve); +}); +exports.animationStarted = animationStarted; +const docStyle = document.documentElement.style; +exports.docStyle = docStyle; + +function clamp(v, min, max) { + return Math.min(Math.max(v, min), max); +} + +var _classList = /*#__PURE__*/new WeakMap(); + +var _percent = /*#__PURE__*/new WeakMap(); + +var _visible = /*#__PURE__*/new WeakMap(); + +class ProgressBar { + constructor(id) { + _classPrivateFieldInitSpec(this, _classList, { + writable: true, + value: null + }); + + _classPrivateFieldInitSpec(this, _percent, { + writable: true, + value: 0 + }); + + _classPrivateFieldInitSpec(this, _visible, { + writable: true, + value: true + }); + + if (arguments.length > 1) { + throw new Error("ProgressBar no longer accepts any additional options, " + "please use CSS rules to modify its appearance instead."); + } + + const bar = document.getElementById(id); + + _classPrivateFieldSet(this, _classList, bar.classList); + } + + get percent() { + return _classPrivateFieldGet(this, _percent); + } + + set percent(val) { + _classPrivateFieldSet(this, _percent, clamp(val, 0, 100)); + + if (isNaN(val)) { + _classPrivateFieldGet(this, _classList).add("indeterminate"); + + return; + } + + _classPrivateFieldGet(this, _classList).remove("indeterminate"); + + docStyle.setProperty("--progressBar-percent", `${_classPrivateFieldGet(this, _percent)}%`); + } + + setWidth(viewer) { + if (!viewer) { + return; + } + + const container = viewer.parentNode; + const scrollbarWidth = container.offsetWidth - viewer.offsetWidth; + + if (scrollbarWidth > 0) { + docStyle.setProperty("--progressBar-end-offset", `${scrollbarWidth}px`); + } + } + + hide() { + if (!_classPrivateFieldGet(this, _visible)) { + return; + } + + _classPrivateFieldSet(this, _visible, false); + + _classPrivateFieldGet(this, _classList).add("hidden"); + } + + show() { + if (_classPrivateFieldGet(this, _visible)) { + return; + } + + _classPrivateFieldSet(this, _visible, true); + + _classPrivateFieldGet(this, _classList).remove("hidden"); + } + +} + +exports.ProgressBar = ProgressBar; + +function getActiveOrFocusedElement() { + let curRoot = document; + let curActiveOrFocused = curRoot.activeElement || curRoot.querySelector(":focus"); + + while ((_curActiveOrFocused = curActiveOrFocused) !== null && _curActiveOrFocused !== void 0 && _curActiveOrFocused.shadowRoot) { + var _curActiveOrFocused; + + curRoot = curActiveOrFocused.shadowRoot; + curActiveOrFocused = curRoot.activeElement || curRoot.querySelector(":focus"); + } + + return curActiveOrFocused; +} + +function apiPageLayoutToViewerModes(layout) { + let scrollMode = ScrollMode.VERTICAL, + spreadMode = SpreadMode.NONE; + + switch (layout) { + case "SinglePage": + scrollMode = ScrollMode.PAGE; + break; + + case "OneColumn": + break; + + case "TwoPageLeft": + scrollMode = ScrollMode.PAGE; + + case "TwoColumnLeft": + spreadMode = SpreadMode.ODD; + break; + + case "TwoPageRight": + scrollMode = ScrollMode.PAGE; + + case "TwoColumnRight": + spreadMode = SpreadMode.EVEN; + break; + } + + return { + scrollMode, + spreadMode + }; +} + +function apiPageModeToSidebarView(mode) { + switch (mode) { + case "UseNone": + return SidebarView.NONE; + + case "UseThumbs": + return SidebarView.THUMBS; + + case "UseOutlines": + return SidebarView.OUTLINE; + + case "UseAttachments": + return SidebarView.ATTACHMENTS; + + case "UseOC": + return SidebarView.LAYERS; + } + + return SidebarView.NONE; +} + +/***/ }), +/* 2 */ +/***/ ((__unused_webpack_module, exports) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.compatibilityParams = exports.OptionKind = exports.AppOptions = void 0; +const compatibilityParams = Object.create(null); +exports.compatibilityParams = compatibilityParams; +{ + const userAgent = navigator.userAgent || ""; + const platform = navigator.platform || ""; + const maxTouchPoints = navigator.maxTouchPoints || 1; + const isAndroid = /Android/.test(userAgent); + const isIOS = /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent) || platform === "MacIntel" && maxTouchPoints > 1; + + (function checkCanvasSizeLimitation() { + if (isIOS || isAndroid) { + compatibilityParams.maxCanvasPixels = 5242880; + } + })(); +} +const OptionKind = { + VIEWER: 0x02, + API: 0x04, + WORKER: 0x08, + PREFERENCE: 0x80 +}; +exports.OptionKind = OptionKind; +const defaultOptions = { + annotationEditorMode: { + value: -1, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + annotationMode: { + value: 2, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + cursorToolOnLoad: { + value: 0, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + defaultZoomValue: { + value: "", + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + disableHistory: { + value: false, + kind: OptionKind.VIEWER + }, + disablePageLabels: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + enablePermissions: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + enablePrintAutoRotate: { + value: true, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + enableScripting: { + value: true, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + externalLinkRel: { + value: "noopener noreferrer nofollow", + kind: OptionKind.VIEWER + }, + externalLinkTarget: { + value: 0, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + historyUpdateUrl: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + ignoreDestinationZoom: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + imageResourcesPath: { + value: "./images/", + kind: OptionKind.VIEWER + }, + maxCanvasPixels: { + value: 16777216, + kind: OptionKind.VIEWER + }, + forcePageColors: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + pageColorsBackground: { + value: "Canvas", + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + pageColorsForeground: { + value: "CanvasText", + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + pdfBugEnabled: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + printResolution: { + value: 150, + kind: OptionKind.VIEWER + }, + sidebarViewOnLoad: { + value: -1, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + scrollModeOnLoad: { + value: -1, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + spreadModeOnLoad: { + value: -1, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + textLayerMode: { + value: 1, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + useOnlyCssZoom: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + viewerCssTheme: { + value: 0, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + viewOnLoad: { + value: 0, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + cMapPacked: { + value: true, + kind: OptionKind.API + }, + cMapUrl: { + value: "../web/cmaps/", + kind: OptionKind.API + }, + disableAutoFetch: { + value: false, + kind: OptionKind.API + OptionKind.PREFERENCE + }, + disableFontFace: { + value: false, + kind: OptionKind.API + OptionKind.PREFERENCE + }, + disableRange: { + value: false, + kind: OptionKind.API + OptionKind.PREFERENCE + }, + disableStream: { + value: false, + kind: OptionKind.API + OptionKind.PREFERENCE + }, + docBaseUrl: { + value: "", + kind: OptionKind.API + }, + enableXfa: { + value: true, + kind: OptionKind.API + OptionKind.PREFERENCE + }, + fontExtraProperties: { + value: false, + kind: OptionKind.API + }, + isEvalSupported: { + value: true, + kind: OptionKind.API + }, + maxImageSize: { + value: -1, + kind: OptionKind.API + }, + pdfBug: { + value: false, + kind: OptionKind.API + }, + standardFontDataUrl: { + value: "../web/standard_fonts/", + kind: OptionKind.API + }, + verbosity: { + value: 1, + kind: OptionKind.API + }, + workerPort: { + value: null, + kind: OptionKind.WORKER + }, + workerSrc: { + value: "../build/pdf.worker.js", + kind: OptionKind.WORKER + } +}; +{ + defaultOptions.defaultUrl = { + value: "compressed.tracemonkey-pldi-09.pdf", + kind: OptionKind.VIEWER + }; + defaultOptions.disablePreferences = { + value: false, + kind: OptionKind.VIEWER + }; + defaultOptions.locale = { + value: navigator.language || "en-US", + kind: OptionKind.VIEWER + }; + defaultOptions.renderer = { + value: "canvas", + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }; + defaultOptions.sandboxBundleSrc = { + value: "../build/pdf.sandbox.js", + kind: OptionKind.VIEWER + }; +} +const userOptions = Object.create(null); + +class AppOptions { + constructor() { + throw new Error("Cannot initialize AppOptions."); + } + + static get(name) { + const userOption = userOptions[name]; + + if (userOption !== undefined) { + return userOption; + } + + const defaultOption = defaultOptions[name]; + + if (defaultOption !== undefined) { + var _compatibilityParams$; + + return (_compatibilityParams$ = compatibilityParams[name]) !== null && _compatibilityParams$ !== void 0 ? _compatibilityParams$ : defaultOption.value; + } + + return undefined; + } + + static getAll() { + let kind = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + const options = Object.create(null); + + for (const name in defaultOptions) { + var _compatibilityParams$2; + + const defaultOption = defaultOptions[name]; + + if (kind) { + if ((kind & defaultOption.kind) === 0) { + continue; + } + + if (kind === OptionKind.PREFERENCE) { + const value = defaultOption.value, + valueType = typeof value; + + if (valueType === "boolean" || valueType === "string" || valueType === "number" && Number.isInteger(value)) { + options[name] = value; + continue; + } + + throw new Error(`Invalid type for preference: ${name}`); + } + } + + const userOption = userOptions[name]; + options[name] = userOption !== undefined ? userOption : (_compatibilityParams$2 = compatibilityParams[name]) !== null && _compatibilityParams$2 !== void 0 ? _compatibilityParams$2 : defaultOption.value; + } + + return options; + } + + static set(name, value) { + userOptions[name] = value; + } + + static setAll(options) { + for (const name in options) { + userOptions[name] = options[name]; + } + } + + static remove(name) { + delete userOptions[name]; + } + + static _hasUserOptions() { + return Object.keys(userOptions).length > 0; + } + +} + +exports.AppOptions = AppOptions; + +/***/ }), +/* 3 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.SimpleLinkService = exports.PDFLinkService = exports.LinkTarget = void 0; + +var _ui_utils = __webpack_require__(1); + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classStaticPrivateMethodGet(receiver, classConstructor, method) { _classCheckPrivateStaticAccess(receiver, classConstructor); return method; } + +function _classCheckPrivateStaticAccess(receiver, classConstructor) { if (receiver !== classConstructor) { throw new TypeError("Private static access of wrong provenance"); } } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +const DEFAULT_LINK_REL = "noopener noreferrer nofollow"; +const LinkTarget = { + NONE: 0, + SELF: 1, + BLANK: 2, + PARENT: 3, + TOP: 4 +}; +exports.LinkTarget = LinkTarget; + +function addLinkAttributes(link) { + let { + url, + target, + rel, + enabled = true + } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + if (!url || typeof url !== "string") { + throw new Error('A valid "url" parameter must provided.'); + } + + const urlNullRemoved = (0, _ui_utils.removeNullCharacters)(url); + + if (enabled) { + link.href = link.title = urlNullRemoved; + } else { + link.href = ""; + link.title = `Disabled: ${urlNullRemoved}`; + + link.onclick = () => { + return false; + }; + } + + let targetStr = ""; + + switch (target) { + case LinkTarget.NONE: + break; + + case LinkTarget.SELF: + targetStr = "_self"; + break; + + case LinkTarget.BLANK: + targetStr = "_blank"; + break; + + case LinkTarget.PARENT: + targetStr = "_parent"; + break; + + case LinkTarget.TOP: + targetStr = "_top"; + break; + } + + link.target = targetStr; + link.rel = typeof rel === "string" ? rel : DEFAULT_LINK_REL; +} + +var _pagesRefCache = /*#__PURE__*/new WeakMap(); + +var _goToDestinationHelper = /*#__PURE__*/new WeakSet(); + +class PDFLinkService { + constructor() { + let { + eventBus, + externalLinkTarget = null, + externalLinkRel = null, + ignoreDestinationZoom = false + } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + _classPrivateMethodInitSpec(this, _goToDestinationHelper); + + _classPrivateFieldInitSpec(this, _pagesRefCache, { + writable: true, + value: new Map() + }); + + this.eventBus = eventBus; + this.externalLinkTarget = externalLinkTarget; + this.externalLinkRel = externalLinkRel; + this.externalLinkEnabled = true; + this._ignoreDestinationZoom = ignoreDestinationZoom; + this.baseUrl = null; + this.pdfDocument = null; + this.pdfViewer = null; + this.pdfHistory = null; + } + + setDocument(pdfDocument) { + let baseUrl = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + this.baseUrl = baseUrl; + this.pdfDocument = pdfDocument; + + _classPrivateFieldGet(this, _pagesRefCache).clear(); + } + + setViewer(pdfViewer) { + this.pdfViewer = pdfViewer; + } + + setHistory(pdfHistory) { + this.pdfHistory = pdfHistory; + } + + get pagesCount() { + return this.pdfDocument ? this.pdfDocument.numPages : 0; + } + + get page() { + return this.pdfViewer.currentPageNumber; + } + + set page(value) { + this.pdfViewer.currentPageNumber = value; + } + + get rotation() { + return this.pdfViewer.pagesRotation; + } + + set rotation(value) { + this.pdfViewer.pagesRotation = value; + } + + async goToDestination(dest) { + if (!this.pdfDocument) { + return; + } + + let namedDest, explicitDest; + + if (typeof dest === "string") { + namedDest = dest; + explicitDest = await this.pdfDocument.getDestination(dest); + } else { + namedDest = null; + explicitDest = await dest; + } + + if (!Array.isArray(explicitDest)) { + console.error(`PDFLinkService.goToDestination: "${explicitDest}" is not ` + `a valid destination array, for dest="${dest}".`); + return; + } + + _classPrivateMethodGet(this, _goToDestinationHelper, _goToDestinationHelper2).call(this, dest, namedDest, explicitDest); + } + + goToPage(val) { + if (!this.pdfDocument) { + return; + } + + const pageNumber = typeof val === "string" && this.pdfViewer.pageLabelToPageNumber(val) || val | 0; + + if (!(Number.isInteger(pageNumber) && pageNumber > 0 && pageNumber <= this.pagesCount)) { + console.error(`PDFLinkService.goToPage: "${val}" is not a valid page.`); + return; + } + + if (this.pdfHistory) { + this.pdfHistory.pushCurrentPosition(); + this.pdfHistory.pushPage(pageNumber); + } + + this.pdfViewer.scrollPageIntoView({ + pageNumber + }); + } + + addLinkAttributes(link, url) { + let newWindow = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + addLinkAttributes(link, { + url, + target: newWindow ? LinkTarget.BLANK : this.externalLinkTarget, + rel: this.externalLinkRel, + enabled: this.externalLinkEnabled + }); + } + + getDestinationHash(dest) { + if (typeof dest === "string") { + if (dest.length > 0) { + return this.getAnchorUrl("#" + escape(dest)); + } + } else if (Array.isArray(dest)) { + const str = JSON.stringify(dest); + + if (str.length > 0) { + return this.getAnchorUrl("#" + escape(str)); + } + } + + return this.getAnchorUrl(""); + } + + getAnchorUrl(anchor) { + return (this.baseUrl || "") + anchor; + } + + setHash(hash) { + if (!this.pdfDocument) { + return; + } + + let pageNumber, dest; + + if (hash.includes("=")) { + const params = (0, _ui_utils.parseQueryString)(hash); + + if (params.has("search")) { + this.eventBus.dispatch("findfromurlhash", { + source: this, + query: params.get("search").replace(/"/g, ""), + phraseSearch: params.get("phrase") === "true" + }); + } + + if (params.has("page")) { + pageNumber = params.get("page") | 0 || 1; + } + + if (params.has("zoom")) { + const zoomArgs = params.get("zoom").split(","); + const zoomArg = zoomArgs[0]; + const zoomArgNumber = parseFloat(zoomArg); + + if (!zoomArg.includes("Fit")) { + dest = [null, { + name: "XYZ" + }, zoomArgs.length > 1 ? zoomArgs[1] | 0 : null, zoomArgs.length > 2 ? zoomArgs[2] | 0 : null, zoomArgNumber ? zoomArgNumber / 100 : zoomArg]; + } else { + if (zoomArg === "Fit" || zoomArg === "FitB") { + dest = [null, { + name: zoomArg + }]; + } else if (zoomArg === "FitH" || zoomArg === "FitBH" || zoomArg === "FitV" || zoomArg === "FitBV") { + dest = [null, { + name: zoomArg + }, zoomArgs.length > 1 ? zoomArgs[1] | 0 : null]; + } else if (zoomArg === "FitR") { + if (zoomArgs.length !== 5) { + console.error('PDFLinkService.setHash: Not enough parameters for "FitR".'); + } else { + dest = [null, { + name: zoomArg + }, zoomArgs[1] | 0, zoomArgs[2] | 0, zoomArgs[3] | 0, zoomArgs[4] | 0]; + } + } else { + console.error(`PDFLinkService.setHash: "${zoomArg}" is not a valid zoom value.`); + } + } + } + + if (dest) { + this.pdfViewer.scrollPageIntoView({ + pageNumber: pageNumber || this.page, + destArray: dest, + allowNegativeOffset: true + }); + } else if (pageNumber) { + this.page = pageNumber; + } + + if (params.has("pagemode")) { + this.eventBus.dispatch("pagemode", { + source: this, + mode: params.get("pagemode") + }); + } + + if (params.has("nameddest")) { + this.goToDestination(params.get("nameddest")); + } + } else { + dest = unescape(hash); + + try { + dest = JSON.parse(dest); + + if (!Array.isArray(dest)) { + dest = dest.toString(); + } + } catch (ex) {} + + if (typeof dest === "string" || _classStaticPrivateMethodGet(PDFLinkService, PDFLinkService, _isValidExplicitDestination).call(PDFLinkService, dest)) { + this.goToDestination(dest); + return; + } + + console.error(`PDFLinkService.setHash: "${unescape(hash)}" is not a valid destination.`); + } + } + + executeNamedAction(action) { + var _this$pdfHistory, _this$pdfHistory2; + + switch (action) { + case "GoBack": + (_this$pdfHistory = this.pdfHistory) === null || _this$pdfHistory === void 0 ? void 0 : _this$pdfHistory.back(); + break; + + case "GoForward": + (_this$pdfHistory2 = this.pdfHistory) === null || _this$pdfHistory2 === void 0 ? void 0 : _this$pdfHistory2.forward(); + break; + + case "NextPage": + this.pdfViewer.nextPage(); + break; + + case "PrevPage": + this.pdfViewer.previousPage(); + break; + + case "LastPage": + this.page = this.pagesCount; + break; + + case "FirstPage": + this.page = 1; + break; + + default: + break; + } + + this.eventBus.dispatch("namedaction", { + source: this, + action + }); + } + + cachePageRef(pageNum, pageRef) { + if (!pageRef) { + return; + } + + const refStr = pageRef.gen === 0 ? `${pageRef.num}R` : `${pageRef.num}R${pageRef.gen}`; + + _classPrivateFieldGet(this, _pagesRefCache).set(refStr, pageNum); + } + + _cachedPageNumber(pageRef) { + if (!pageRef) { + return null; + } + + const refStr = pageRef.gen === 0 ? `${pageRef.num}R` : `${pageRef.num}R${pageRef.gen}`; + return _classPrivateFieldGet(this, _pagesRefCache).get(refStr) || null; + } + + isPageVisible(pageNumber) { + return this.pdfViewer.isPageVisible(pageNumber); + } + + isPageCached(pageNumber) { + return this.pdfViewer.isPageCached(pageNumber); + } + +} + +exports.PDFLinkService = PDFLinkService; + +function _goToDestinationHelper2(rawDest) { + let namedDest = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + let explicitDest = arguments.length > 2 ? arguments[2] : undefined; + const destRef = explicitDest[0]; + let pageNumber; + + if (typeof destRef === "object" && destRef !== null) { + pageNumber = this._cachedPageNumber(destRef); + + if (!pageNumber) { + this.pdfDocument.getPageIndex(destRef).then(pageIndex => { + this.cachePageRef(pageIndex + 1, destRef); + + _classPrivateMethodGet(this, _goToDestinationHelper, _goToDestinationHelper2).call(this, rawDest, namedDest, explicitDest); + }).catch(() => { + console.error(`PDFLinkService.#goToDestinationHelper: "${destRef}" is not ` + `a valid page reference, for dest="${rawDest}".`); + }); + return; + } + } else if (Number.isInteger(destRef)) { + pageNumber = destRef + 1; + } else { + console.error(`PDFLinkService.#goToDestinationHelper: "${destRef}" is not ` + `a valid destination reference, for dest="${rawDest}".`); + return; + } + + if (!pageNumber || pageNumber < 1 || pageNumber > this.pagesCount) { + console.error(`PDFLinkService.#goToDestinationHelper: "${pageNumber}" is not ` + `a valid page number, for dest="${rawDest}".`); + return; + } + + if (this.pdfHistory) { + this.pdfHistory.pushCurrentPosition(); + this.pdfHistory.push({ + namedDest, + explicitDest, + pageNumber + }); + } + + this.pdfViewer.scrollPageIntoView({ + pageNumber, + destArray: explicitDest, + ignoreDestinationZoom: this._ignoreDestinationZoom + }); +} + +function _isValidExplicitDestination(dest) { + if (!Array.isArray(dest)) { + return false; + } + + const destLength = dest.length; + + if (destLength < 2) { + return false; + } + + const page = dest[0]; + + if (!(typeof page === "object" && Number.isInteger(page.num) && Number.isInteger(page.gen)) && !(Number.isInteger(page) && page >= 0)) { + return false; + } + + const zoom = dest[1]; + + if (!(typeof zoom === "object" && typeof zoom.name === "string")) { + return false; + } + + let allowNull = true; + + switch (zoom.name) { + case "XYZ": + if (destLength !== 5) { + return false; + } + + break; + + case "Fit": + case "FitB": + return destLength === 2; + + case "FitH": + case "FitBH": + case "FitV": + case "FitBV": + if (destLength !== 3) { + return false; + } + + break; + + case "FitR": + if (destLength !== 6) { + return false; + } + + allowNull = false; + break; + + default: + return false; + } + + for (let i = 2; i < destLength; i++) { + const param = dest[i]; + + if (!(typeof param === "number" || allowNull && param === null)) { + return false; + } + } + + return true; +} + +class SimpleLinkService { + constructor() { + this.externalLinkEnabled = true; + } + + get pagesCount() { + return 0; + } + + get page() { + return 0; + } + + set page(value) {} + + get rotation() { + return 0; + } + + set rotation(value) {} + + async goToDestination(dest) {} + + goToPage(val) {} + + addLinkAttributes(link, url) { + let newWindow = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + addLinkAttributes(link, { + url, + enabled: this.externalLinkEnabled + }); + } + + getDestinationHash(dest) { + return "#"; + } + + getAnchorUrl(hash) { + return "#"; + } + + setHash(hash) {} + + executeNamedAction(action) {} + + cachePageRef(pageNum, pageRef) {} + + isPageVisible(pageNumber) { + return true; + } + + isPageCached(pageNumber) { + return true; + } + +} + +exports.SimpleLinkService = SimpleLinkService; + +/***/ }), +/* 4 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFViewerApplication = exports.PDFPrintServiceFactory = exports.DefaultExternalServices = void 0; + +var _ui_utils = __webpack_require__(1); + +var _pdfjsLib = __webpack_require__(5); + +var _app_options = __webpack_require__(2); + +var _event_utils = __webpack_require__(6); + +var _pdf_cursor_tools = __webpack_require__(7); + +var _pdf_link_service = __webpack_require__(3); + +var _annotation_editor_params = __webpack_require__(9); + +var _overlay_manager = __webpack_require__(10); + +var _password_prompt = __webpack_require__(12); + +var _pdf_attachment_viewer = __webpack_require__(13); + +var _pdf_document_properties = __webpack_require__(15); + +var _pdf_find_bar = __webpack_require__(16); + +var _pdf_find_controller = __webpack_require__(17); + +var _pdf_history = __webpack_require__(19); + +var _pdf_layer_viewer = __webpack_require__(20); + +var _pdf_outline_viewer = __webpack_require__(21); + +var _pdf_presentation_mode = __webpack_require__(22); + +var _pdf_rendering_queue = __webpack_require__(23); + +var _pdf_scripting_manager = __webpack_require__(24); + +var _pdf_sidebar = __webpack_require__(25); + +var _pdf_sidebar_resizer = __webpack_require__(26); + +var _pdf_thumbnail_viewer = __webpack_require__(27); + +var _pdf_viewer = __webpack_require__(29); + +var _secondary_toolbar = __webpack_require__(40); + +var _toolbar = __webpack_require__(41); + +var _view_history = __webpack_require__(42); + +const DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT = 5000; +const FORCE_PAGES_LOADED_TIMEOUT = 10000; +const WHEEL_ZOOM_DISABLED_TIMEOUT = 1000; +const ViewOnLoad = { + UNKNOWN: -1, + PREVIOUS: 0, + INITIAL: 1 +}; +const ViewerCssTheme = { + AUTOMATIC: 0, + LIGHT: 1, + DARK: 2 +}; +const KNOWN_VERSIONS = ["1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "2.0", "2.1", "2.2", "2.3"]; +const KNOWN_GENERATORS = ["acrobat distiller", "acrobat pdfwriter", "adobe livecycle", "adobe pdf library", "adobe photoshop", "ghostscript", "tcpdf", "cairo", "dvipdfm", "dvips", "pdftex", "pdfkit", "itext", "prince", "quarkxpress", "mac os x", "microsoft", "openoffice", "oracle", "luradocument", "pdf-xchange", "antenna house", "aspose.cells", "fpdf"]; + +class DefaultExternalServices { + constructor() { + throw new Error("Cannot initialize DefaultExternalServices."); + } + + static updateFindControlState(data) {} + + static updateFindMatchesCount(data) {} + + static initPassiveLoading(callbacks) {} + + static reportTelemetry(data) {} + + static createDownloadManager(options) { + throw new Error("Not implemented: createDownloadManager"); + } + + static createPreferences() { + throw new Error("Not implemented: createPreferences"); + } + + static createL10n(options) { + throw new Error("Not implemented: createL10n"); + } + + static createScripting(options) { + throw new Error("Not implemented: createScripting"); + } + + static get supportsIntegratedFind() { + return (0, _pdfjsLib.shadow)(this, "supportsIntegratedFind", false); + } + + static get supportsDocumentFonts() { + return (0, _pdfjsLib.shadow)(this, "supportsDocumentFonts", true); + } + + static get supportedMouseWheelZoomModifierKeys() { + return (0, _pdfjsLib.shadow)(this, "supportedMouseWheelZoomModifierKeys", { + ctrlKey: true, + metaKey: true + }); + } + + static get isInAutomation() { + return (0, _pdfjsLib.shadow)(this, "isInAutomation", false); + } + + static updateEditorStates(data) { + throw new Error("Not implemented: updateEditorStates"); + } + +} + +exports.DefaultExternalServices = DefaultExternalServices; +const PDFViewerApplication = { + initialBookmark: document.location.hash.substring(1), + _initializedCapability: (0, _pdfjsLib.createPromiseCapability)(), + appConfig: null, + pdfDocument: null, + pdfLoadingTask: null, + printService: null, + pdfViewer: null, + pdfThumbnailViewer: null, + pdfRenderingQueue: null, + pdfPresentationMode: null, + pdfDocumentProperties: null, + pdfLinkService: null, + pdfHistory: null, + pdfSidebar: null, + pdfSidebarResizer: null, + pdfOutlineViewer: null, + pdfAttachmentViewer: null, + pdfLayerViewer: null, + pdfCursorTools: null, + pdfScriptingManager: null, + store: null, + downloadManager: null, + overlayManager: null, + preferences: null, + toolbar: null, + secondaryToolbar: null, + eventBus: null, + l10n: null, + annotationEditorParams: null, + isInitialViewSet: false, + downloadComplete: false, + isViewerEmbedded: window.parent !== window, + url: "", + baseUrl: "", + _downloadUrl: "", + externalServices: DefaultExternalServices, + _boundEvents: Object.create(null), + documentInfo: null, + metadata: null, + _contentDispositionFilename: null, + _contentLength: null, + _saveInProgress: false, + _docStats: null, + _wheelUnusedTicks: 0, + _idleCallbacks: new Set(), + _PDFBug: null, + _hasAnnotationEditors: false, + _title: document.title, + _printAnnotationStoragePromise: null, + + async initialize(appConfig) { + this.preferences = this.externalServices.createPreferences(); + this.appConfig = appConfig; + await this._readPreferences(); + await this._parseHashParameters(); + + this._forceCssTheme(); + + await this._initializeL10n(); + + if (this.isViewerEmbedded && _app_options.AppOptions.get("externalLinkTarget") === _pdf_link_service.LinkTarget.NONE) { + _app_options.AppOptions.set("externalLinkTarget", _pdf_link_service.LinkTarget.TOP); + } + + await this._initializeViewerComponents(); + this.bindEvents(); + this.bindWindowEvents(); + const appContainer = appConfig.appContainer || document.documentElement; + this.l10n.translate(appContainer).then(() => { + this.eventBus.dispatch("localized", { + source: this + }); + }); + + this._initializedCapability.resolve(); + }, + + async _readPreferences() { + if (_app_options.AppOptions.get("disablePreferences")) { + return; + } + + if (_app_options.AppOptions._hasUserOptions()) { + console.warn("_readPreferences: The Preferences may override manually set AppOptions; " + 'please use the "disablePreferences"-option in order to prevent that.'); + } + + try { + _app_options.AppOptions.setAll(await this.preferences.getAll()); + } catch (reason) { + console.error(`_readPreferences: "${reason === null || reason === void 0 ? void 0 : reason.message}".`); + } + }, + + async _parseHashParameters() { + if (!_app_options.AppOptions.get("pdfBugEnabled")) { + return; + } + + const hash = document.location.hash.substring(1); + + if (!hash) { + return; + } + + const { + mainContainer, + viewerContainer + } = this.appConfig, + params = (0, _ui_utils.parseQueryString)(hash); + + if (params.get("disableworker") === "true") { + try { + await loadFakeWorker(); + } catch (ex) { + console.error(`_parseHashParameters: "${ex.message}".`); + } + } + + if (params.has("disablerange")) { + _app_options.AppOptions.set("disableRange", params.get("disablerange") === "true"); + } + + if (params.has("disablestream")) { + _app_options.AppOptions.set("disableStream", params.get("disablestream") === "true"); + } + + if (params.has("disableautofetch")) { + _app_options.AppOptions.set("disableAutoFetch", params.get("disableautofetch") === "true"); + } + + if (params.has("disablefontface")) { + _app_options.AppOptions.set("disableFontFace", params.get("disablefontface") === "true"); + } + + if (params.has("disablehistory")) { + _app_options.AppOptions.set("disableHistory", params.get("disablehistory") === "true"); + } + + if (params.has("verbosity")) { + _app_options.AppOptions.set("verbosity", params.get("verbosity") | 0); + } + + if (params.has("textlayer")) { + switch (params.get("textlayer")) { + case "off": + _app_options.AppOptions.set("textLayerMode", _ui_utils.TextLayerMode.DISABLE); + + break; + + case "visible": + case "shadow": + case "hover": + viewerContainer.classList.add(`textLayer-${params.get("textlayer")}`); + + try { + await loadPDFBug(this); + + this._PDFBug.loadCSS(); + } catch (ex) { + console.error(`_parseHashParameters: "${ex.message}".`); + } + + break; + } + } + + if (params.has("pdfbug")) { + _app_options.AppOptions.set("pdfBug", true); + + _app_options.AppOptions.set("fontExtraProperties", true); + + const enabled = params.get("pdfbug").split(","); + + try { + await loadPDFBug(this); + + this._PDFBug.init({ + OPS: _pdfjsLib.OPS + }, mainContainer, enabled); + } catch (ex) { + console.error(`_parseHashParameters: "${ex.message}".`); + } + } + + if (params.has("locale")) { + _app_options.AppOptions.set("locale", params.get("locale")); + } + }, + + async _initializeL10n() { + this.l10n = this.externalServices.createL10n({ + locale: _app_options.AppOptions.get("locale") + }); + const dir = await this.l10n.getDirection(); + document.getElementsByTagName("html")[0].dir = dir; + }, + + _forceCssTheme() { + const cssTheme = _app_options.AppOptions.get("viewerCssTheme"); + + if (cssTheme === ViewerCssTheme.AUTOMATIC || !Object.values(ViewerCssTheme).includes(cssTheme)) { + return; + } + + try { + const styleSheet = document.styleSheets[0]; + const cssRules = (styleSheet === null || styleSheet === void 0 ? void 0 : styleSheet.cssRules) || []; + + for (let i = 0, ii = cssRules.length; i < ii; i++) { + var _rule$media; + + const rule = cssRules[i]; + + if (rule instanceof CSSMediaRule && ((_rule$media = rule.media) === null || _rule$media === void 0 ? void 0 : _rule$media[0]) === "(prefers-color-scheme: dark)") { + if (cssTheme === ViewerCssTheme.LIGHT) { + styleSheet.deleteRule(i); + return; + } + + const darkRules = /^@media \(prefers-color-scheme: dark\) {\n\s*([\w\s-.,:;/\\{}()]+)\n}$/.exec(rule.cssText); + + if (darkRules !== null && darkRules !== void 0 && darkRules[1]) { + styleSheet.deleteRule(i); + styleSheet.insertRule(darkRules[1], i); + } + + return; + } + } + } catch (reason) { + console.error(`_forceCssTheme: "${reason === null || reason === void 0 ? void 0 : reason.message}".`); + } + }, + + async _initializeViewerComponents() { + const { + appConfig, + externalServices + } = this; + const eventBus = externalServices.isInAutomation ? new _event_utils.AutomationEventBus() : new _event_utils.EventBus(); + this.eventBus = eventBus; + this.overlayManager = new _overlay_manager.OverlayManager(); + const pdfRenderingQueue = new _pdf_rendering_queue.PDFRenderingQueue(); + pdfRenderingQueue.onIdle = this._cleanup.bind(this); + this.pdfRenderingQueue = pdfRenderingQueue; + const pdfLinkService = new _pdf_link_service.PDFLinkService({ + eventBus, + externalLinkTarget: _app_options.AppOptions.get("externalLinkTarget"), + externalLinkRel: _app_options.AppOptions.get("externalLinkRel"), + ignoreDestinationZoom: _app_options.AppOptions.get("ignoreDestinationZoom") + }); + this.pdfLinkService = pdfLinkService; + const downloadManager = externalServices.createDownloadManager(); + this.downloadManager = downloadManager; + const findController = new _pdf_find_controller.PDFFindController({ + linkService: pdfLinkService, + eventBus + }); + this.findController = findController; + const pdfScriptingManager = new _pdf_scripting_manager.PDFScriptingManager({ + eventBus, + sandboxBundleSrc: _app_options.AppOptions.get("sandboxBundleSrc"), + scriptingFactory: externalServices, + docPropertiesLookup: this._scriptingDocProperties.bind(this) + }); + this.pdfScriptingManager = pdfScriptingManager; + const container = appConfig.mainContainer, + viewer = appConfig.viewerContainer; + + const annotationEditorMode = _app_options.AppOptions.get("annotationEditorMode"); + + const pageColors = _app_options.AppOptions.get("forcePageColors") || window.matchMedia("(forced-colors: active)").matches ? { + background: _app_options.AppOptions.get("pageColorsBackground"), + foreground: _app_options.AppOptions.get("pageColorsForeground") + } : null; + this.pdfViewer = new _pdf_viewer.PDFViewer({ + container, + viewer, + eventBus, + renderingQueue: pdfRenderingQueue, + linkService: pdfLinkService, + downloadManager, + findController, + scriptingManager: _app_options.AppOptions.get("enableScripting") && pdfScriptingManager, + renderer: _app_options.AppOptions.get("renderer"), + l10n: this.l10n, + textLayerMode: _app_options.AppOptions.get("textLayerMode"), + annotationMode: _app_options.AppOptions.get("annotationMode"), + annotationEditorMode, + imageResourcesPath: _app_options.AppOptions.get("imageResourcesPath"), + enablePrintAutoRotate: _app_options.AppOptions.get("enablePrintAutoRotate"), + useOnlyCssZoom: _app_options.AppOptions.get("useOnlyCssZoom"), + maxCanvasPixels: _app_options.AppOptions.get("maxCanvasPixels"), + enablePermissions: _app_options.AppOptions.get("enablePermissions"), + pageColors + }); + pdfRenderingQueue.setViewer(this.pdfViewer); + pdfLinkService.setViewer(this.pdfViewer); + pdfScriptingManager.setViewer(this.pdfViewer); + this.pdfThumbnailViewer = new _pdf_thumbnail_viewer.PDFThumbnailViewer({ + container: appConfig.sidebar.thumbnailView, + eventBus, + renderingQueue: pdfRenderingQueue, + linkService: pdfLinkService, + l10n: this.l10n, + pageColors + }); + pdfRenderingQueue.setThumbnailViewer(this.pdfThumbnailViewer); + + if (!this.isViewerEmbedded && !_app_options.AppOptions.get("disableHistory")) { + this.pdfHistory = new _pdf_history.PDFHistory({ + linkService: pdfLinkService, + eventBus + }); + pdfLinkService.setHistory(this.pdfHistory); + } + + if (!this.supportsIntegratedFind) { + this.findBar = new _pdf_find_bar.PDFFindBar(appConfig.findBar, eventBus, this.l10n); + } + + if (annotationEditorMode !== _pdfjsLib.AnnotationEditorType.DISABLE) { + this.annotationEditorParams = new _annotation_editor_params.AnnotationEditorParams(appConfig.annotationEditorParams, eventBus); + + for (const element of [document.getElementById("editorModeButtons"), document.getElementById("editorModeSeparator")]) { + element.classList.remove("hidden"); + } + } + + this.pdfDocumentProperties = new _pdf_document_properties.PDFDocumentProperties(appConfig.documentProperties, this.overlayManager, eventBus, this.l10n, () => { + return this._docFilename; + }); + this.pdfCursorTools = new _pdf_cursor_tools.PDFCursorTools({ + container, + eventBus, + cursorToolOnLoad: _app_options.AppOptions.get("cursorToolOnLoad") + }); + this.toolbar = new _toolbar.Toolbar(appConfig.toolbar, eventBus, this.l10n); + this.secondaryToolbar = new _secondary_toolbar.SecondaryToolbar(appConfig.secondaryToolbar, eventBus); + + if (this.supportsFullscreen) { + this.pdfPresentationMode = new _pdf_presentation_mode.PDFPresentationMode({ + container, + pdfViewer: this.pdfViewer, + eventBus + }); + } + + this.passwordPrompt = new _password_prompt.PasswordPrompt(appConfig.passwordOverlay, this.overlayManager, this.l10n, this.isViewerEmbedded); + this.pdfOutlineViewer = new _pdf_outline_viewer.PDFOutlineViewer({ + container: appConfig.sidebar.outlineView, + eventBus, + linkService: pdfLinkService + }); + this.pdfAttachmentViewer = new _pdf_attachment_viewer.PDFAttachmentViewer({ + container: appConfig.sidebar.attachmentsView, + eventBus, + downloadManager + }); + this.pdfLayerViewer = new _pdf_layer_viewer.PDFLayerViewer({ + container: appConfig.sidebar.layersView, + eventBus, + l10n: this.l10n + }); + this.pdfSidebar = new _pdf_sidebar.PDFSidebar({ + elements: appConfig.sidebar, + pdfViewer: this.pdfViewer, + pdfThumbnailViewer: this.pdfThumbnailViewer, + eventBus, + l10n: this.l10n + }); + this.pdfSidebar.onToggled = this.forceRendering.bind(this); + this.pdfSidebarResizer = new _pdf_sidebar_resizer.PDFSidebarResizer(appConfig.sidebarResizer, eventBus, this.l10n); + }, + + run(config) { + this.initialize(config).then(webViewerInitialized); + }, + + get initialized() { + return this._initializedCapability.settled; + }, + + get initializedPromise() { + return this._initializedCapability.promise; + }, + + zoomIn(steps) { + if (this.pdfViewer.isInPresentationMode) { + return; + } + + this.pdfViewer.increaseScale(steps); + }, + + zoomOut(steps) { + if (this.pdfViewer.isInPresentationMode) { + return; + } + + this.pdfViewer.decreaseScale(steps); + }, + + zoomReset() { + if (this.pdfViewer.isInPresentationMode) { + return; + } + + this.pdfViewer.currentScaleValue = _ui_utils.DEFAULT_SCALE_VALUE; + }, + + get pagesCount() { + return this.pdfDocument ? this.pdfDocument.numPages : 0; + }, + + get page() { + return this.pdfViewer.currentPageNumber; + }, + + set page(val) { + this.pdfViewer.currentPageNumber = val; + }, + + get supportsPrinting() { + return PDFPrintServiceFactory.instance.supportsPrinting; + }, + + get supportsFullscreen() { + return (0, _pdfjsLib.shadow)(this, "supportsFullscreen", document.fullscreenEnabled); + }, + + get supportsIntegratedFind() { + return this.externalServices.supportsIntegratedFind; + }, + + get supportsDocumentFonts() { + return this.externalServices.supportsDocumentFonts; + }, + + get loadingBar() { + const bar = new _ui_utils.ProgressBar("loadingBar"); + return (0, _pdfjsLib.shadow)(this, "loadingBar", bar); + }, + + get supportedMouseWheelZoomModifierKeys() { + return this.externalServices.supportedMouseWheelZoomModifierKeys; + }, + + initPassiveLoading() { + throw new Error("Not implemented: initPassiveLoading"); + }, + + setTitleUsingUrl() { + let url = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ""; + let downloadUrl = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + this.url = url; + this.baseUrl = url.split("#")[0]; + + if (downloadUrl) { + this._downloadUrl = downloadUrl === url ? this.baseUrl : downloadUrl.split("#")[0]; + } + + let title = (0, _pdfjsLib.getPdfFilenameFromUrl)(url, ""); + + if (!title) { + try { + title = decodeURIComponent((0, _pdfjsLib.getFilenameFromUrl)(url)) || url; + } catch (ex) { + title = url; + } + } + + this.setTitle(title); + }, + + setTitle() { + let title = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._title; + this._title = title; + + if (this.isViewerEmbedded) { + return; + } + + document.title = `${this._hasAnnotationEditors ? "* " : ""}${title}`; + }, + + get _docFilename() { + return this._contentDispositionFilename || (0, _pdfjsLib.getPdfFilenameFromUrl)(this.url); + }, + + _hideViewBookmark() { + const { + toolbar, + secondaryToolbar + } = this.appConfig; + toolbar.viewBookmark.hidden = true; + secondaryToolbar.viewBookmarkButton.hidden = true; + }, + + _cancelIdleCallbacks() { + if (!this._idleCallbacks.size) { + return; + } + + for (const callback of this._idleCallbacks) { + window.cancelIdleCallback(callback); + } + + this._idleCallbacks.clear(); + }, + + async close() { + var _this$pdfDocument, _this$pdfHistory, _this$findBar, _this$_PDFBug; + + this._unblockDocumentLoadEvent(); + + this._hideViewBookmark(); + + const { + container + } = this.appConfig.errorWrapper; + container.hidden = true; + + if (!this.pdfLoadingTask) { + return; + } + + if (((_this$pdfDocument = this.pdfDocument) === null || _this$pdfDocument === void 0 ? void 0 : _this$pdfDocument.annotationStorage.size) > 0 && this._annotationStorageModified) { + try { + await this.save(); + } catch (reason) {} + } + + const promises = []; + promises.push(this.pdfLoadingTask.destroy()); + this.pdfLoadingTask = null; + + if (this.pdfDocument) { + this.pdfDocument = null; + this.pdfThumbnailViewer.setDocument(null); + this.pdfViewer.setDocument(null); + this.pdfLinkService.setDocument(null); + this.pdfDocumentProperties.setDocument(null); + } + + this.pdfLinkService.externalLinkEnabled = true; + this.store = null; + this.isInitialViewSet = false; + this.downloadComplete = false; + this.url = ""; + this.baseUrl = ""; + this._downloadUrl = ""; + this.documentInfo = null; + this.metadata = null; + this._contentDispositionFilename = null; + this._contentLength = null; + this._saveInProgress = false; + this._docStats = null; + this._hasAnnotationEditors = false; + + this._cancelIdleCallbacks(); + + promises.push(this.pdfScriptingManager.destroyPromise); + this.setTitle(); + this.pdfSidebar.reset(); + this.pdfOutlineViewer.reset(); + this.pdfAttachmentViewer.reset(); + this.pdfLayerViewer.reset(); + (_this$pdfHistory = this.pdfHistory) === null || _this$pdfHistory === void 0 ? void 0 : _this$pdfHistory.reset(); + (_this$findBar = this.findBar) === null || _this$findBar === void 0 ? void 0 : _this$findBar.reset(); + this.toolbar.reset(); + this.secondaryToolbar.reset(); + (_this$_PDFBug = this._PDFBug) === null || _this$_PDFBug === void 0 ? void 0 : _this$_PDFBug.cleanup(); + await Promise.all(promises); + }, + + async open(file, args) { + if (this.pdfLoadingTask) { + await this.close(); + } + + const workerParameters = _app_options.AppOptions.getAll(_app_options.OptionKind.WORKER); + + for (const key in workerParameters) { + _pdfjsLib.GlobalWorkerOptions[key] = workerParameters[key]; + } + + const parameters = Object.create(null); + + if (typeof file === "string") { + this.setTitleUsingUrl(file, file); + parameters.url = file; + } else if (file && "byteLength" in file) { + parameters.data = file; + } else if (file.url && file.originalUrl) { + this.setTitleUsingUrl(file.originalUrl, file.url); + parameters.url = file.url; + } + + const apiParameters = _app_options.AppOptions.getAll(_app_options.OptionKind.API); + + for (const key in apiParameters) { + let value = apiParameters[key]; + + if (key === "docBaseUrl" && !value) {} + + parameters[key] = value; + } + + if (args) { + for (const key in args) { + parameters[key] = args[key]; + } + } + + const loadingTask = (0, _pdfjsLib.getDocument)(parameters); + this.pdfLoadingTask = loadingTask; + + loadingTask.onPassword = (updateCallback, reason) => { + this.pdfLinkService.externalLinkEnabled = false; + this.passwordPrompt.setUpdateCallback(updateCallback, reason); + this.passwordPrompt.open(); + }; + + loadingTask.onProgress = _ref => { + let { + loaded, + total + } = _ref; + this.progress(loaded / total); + }; + + loadingTask.onUnsupportedFeature = this.fallback.bind(this); + return loadingTask.promise.then(pdfDocument => { + this.load(pdfDocument); + }, reason => { + if (loadingTask !== this.pdfLoadingTask) { + return undefined; + } + + let key = "loading_error"; + + if (reason instanceof _pdfjsLib.InvalidPDFException) { + key = "invalid_file_error"; + } else if (reason instanceof _pdfjsLib.MissingPDFException) { + key = "missing_file_error"; + } else if (reason instanceof _pdfjsLib.UnexpectedResponseException) { + key = "unexpected_response_error"; + } + + return this.l10n.get(key).then(msg => { + this._documentError(msg, { + message: reason === null || reason === void 0 ? void 0 : reason.message + }); + + throw reason; + }); + }); + }, + + _ensureDownloadComplete() { + if (this.pdfDocument && this.downloadComplete) { + return; + } + + throw new Error("PDF document not downloaded."); + }, + + async download() { + const url = this._downloadUrl, + filename = this._docFilename; + + try { + this._ensureDownloadComplete(); + + const data = await this.pdfDocument.getData(); + const blob = new Blob([data], { + type: "application/pdf" + }); + await this.downloadManager.download(blob, url, filename); + } catch (reason) { + await this.downloadManager.downloadUrl(url, filename); + } + }, + + async save() { + if (this._saveInProgress) { + return; + } + + this._saveInProgress = true; + await this.pdfScriptingManager.dispatchWillSave(); + const url = this._downloadUrl, + filename = this._docFilename; + + try { + this._ensureDownloadComplete(); + + const data = await this.pdfDocument.saveDocument(); + const blob = new Blob([data], { + type: "application/pdf" + }); + await this.downloadManager.download(blob, url, filename); + } catch (reason) { + console.error(`Error when saving the document: ${reason.message}`); + await this.download(); + } finally { + await this.pdfScriptingManager.dispatchDidSave(); + this._saveInProgress = false; + } + + if (this._hasAnnotationEditors) { + this.externalServices.reportTelemetry({ + type: "editing", + data: { + type: "save" + } + }); + } + }, + + downloadOrSave() { + var _this$pdfDocument2; + + if (((_this$pdfDocument2 = this.pdfDocument) === null || _this$pdfDocument2 === void 0 ? void 0 : _this$pdfDocument2.annotationStorage.size) > 0) { + this.save(); + } else { + this.download(); + } + }, + + fallback(featureId) { + this.externalServices.reportTelemetry({ + type: "unsupportedFeature", + featureId + }); + }, + + _documentError(message) { + var _moreInfo$message; + + let moreInfo = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + + this._unblockDocumentLoadEvent(); + + this._otherError(message, moreInfo); + + this.eventBus.dispatch("documenterror", { + source: this, + message, + reason: (_moreInfo$message = moreInfo === null || moreInfo === void 0 ? void 0 : moreInfo.message) !== null && _moreInfo$message !== void 0 ? _moreInfo$message : null + }); + }, + + _otherError(message) { + let moreInfo = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + const moreInfoText = [this.l10n.get("error_version_info", { + version: _pdfjsLib.version || "?", + build: _pdfjsLib.build || "?" + })]; + + if (moreInfo) { + moreInfoText.push(this.l10n.get("error_message", { + message: moreInfo.message + })); + + if (moreInfo.stack) { + moreInfoText.push(this.l10n.get("error_stack", { + stack: moreInfo.stack + })); + } else { + if (moreInfo.filename) { + moreInfoText.push(this.l10n.get("error_file", { + file: moreInfo.filename + })); + } + + if (moreInfo.lineNumber) { + moreInfoText.push(this.l10n.get("error_line", { + line: moreInfo.lineNumber + })); + } + } + } + + const errorWrapperConfig = this.appConfig.errorWrapper; + const errorWrapper = errorWrapperConfig.container; + errorWrapper.hidden = false; + const errorMessage = errorWrapperConfig.errorMessage; + errorMessage.textContent = message; + const closeButton = errorWrapperConfig.closeButton; + + closeButton.onclick = function () { + errorWrapper.hidden = true; + }; + + const errorMoreInfo = errorWrapperConfig.errorMoreInfo; + const moreInfoButton = errorWrapperConfig.moreInfoButton; + const lessInfoButton = errorWrapperConfig.lessInfoButton; + + moreInfoButton.onclick = function () { + errorMoreInfo.hidden = false; + moreInfoButton.hidden = true; + lessInfoButton.hidden = false; + errorMoreInfo.style.height = errorMoreInfo.scrollHeight + "px"; + }; + + lessInfoButton.onclick = function () { + errorMoreInfo.hidden = true; + moreInfoButton.hidden = false; + lessInfoButton.hidden = true; + }; + + moreInfoButton.oncontextmenu = _ui_utils.noContextMenuHandler; + lessInfoButton.oncontextmenu = _ui_utils.noContextMenuHandler; + closeButton.oncontextmenu = _ui_utils.noContextMenuHandler; + moreInfoButton.hidden = false; + lessInfoButton.hidden = true; + Promise.all(moreInfoText).then(parts => { + errorMoreInfo.value = parts.join("\n"); + }); + }, + + progress(level) { + var _this$pdfDocument$loa, _this$pdfDocument3; + + if (this.downloadComplete) { + return; + } + + const percent = Math.round(level * 100); + + if (percent <= this.loadingBar.percent) { + return; + } + + this.loadingBar.percent = percent; + const disableAutoFetch = (_this$pdfDocument$loa = (_this$pdfDocument3 = this.pdfDocument) === null || _this$pdfDocument3 === void 0 ? void 0 : _this$pdfDocument3.loadingParams.disableAutoFetch) !== null && _this$pdfDocument$loa !== void 0 ? _this$pdfDocument$loa : _app_options.AppOptions.get("disableAutoFetch"); + + if (!disableAutoFetch || isNaN(percent)) { + return; + } + + if (this.disableAutoFetchLoadingBarTimeout) { + clearTimeout(this.disableAutoFetchLoadingBarTimeout); + this.disableAutoFetchLoadingBarTimeout = null; + } + + this.loadingBar.show(); + this.disableAutoFetchLoadingBarTimeout = setTimeout(() => { + this.loadingBar.hide(); + this.disableAutoFetchLoadingBarTimeout = null; + }, DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT); + }, + + load(pdfDocument) { + this.pdfDocument = pdfDocument; + pdfDocument.getDownloadInfo().then(_ref2 => { + let { + length + } = _ref2; + this._contentLength = length; + this.downloadComplete = true; + this.loadingBar.hide(); + firstPagePromise.then(() => { + this.eventBus.dispatch("documentloaded", { + source: this + }); + }); + }); + const pageLayoutPromise = pdfDocument.getPageLayout().catch(function () {}); + const pageModePromise = pdfDocument.getPageMode().catch(function () {}); + const openActionPromise = pdfDocument.getOpenAction().catch(function () {}); + this.toolbar.setPagesCount(pdfDocument.numPages, false); + this.secondaryToolbar.setPagesCount(pdfDocument.numPages); + let baseDocumentUrl; + baseDocumentUrl = null; + this.pdfLinkService.setDocument(pdfDocument, baseDocumentUrl); + this.pdfDocumentProperties.setDocument(pdfDocument); + const pdfViewer = this.pdfViewer; + pdfViewer.setDocument(pdfDocument); + const { + firstPagePromise, + onePageRendered, + pagesPromise + } = pdfViewer; + const pdfThumbnailViewer = this.pdfThumbnailViewer; + pdfThumbnailViewer.setDocument(pdfDocument); + const storedPromise = (this.store = new _view_history.ViewHistory(pdfDocument.fingerprints[0])).getMultiple({ + page: null, + zoom: _ui_utils.DEFAULT_SCALE_VALUE, + scrollLeft: "0", + scrollTop: "0", + rotation: null, + sidebarView: _ui_utils.SidebarView.UNKNOWN, + scrollMode: _ui_utils.ScrollMode.UNKNOWN, + spreadMode: _ui_utils.SpreadMode.UNKNOWN + }).catch(() => { + return Object.create(null); + }); + firstPagePromise.then(pdfPage => { + this.loadingBar.setWidth(this.appConfig.viewerContainer); + + this._initializeAnnotationStorageCallbacks(pdfDocument); + + Promise.all([_ui_utils.animationStarted, storedPromise, pageLayoutPromise, pageModePromise, openActionPromise]).then(async _ref3 => { + let [timeStamp, stored, pageLayout, pageMode, openAction] = _ref3; + + const viewOnLoad = _app_options.AppOptions.get("viewOnLoad"); + + this._initializePdfHistory({ + fingerprint: pdfDocument.fingerprints[0], + viewOnLoad, + initialDest: openAction === null || openAction === void 0 ? void 0 : openAction.dest + }); + + const initialBookmark = this.initialBookmark; + + const zoom = _app_options.AppOptions.get("defaultZoomValue"); + + let hash = zoom ? `zoom=${zoom}` : null; + let rotation = null; + + let sidebarView = _app_options.AppOptions.get("sidebarViewOnLoad"); + + let scrollMode = _app_options.AppOptions.get("scrollModeOnLoad"); + + let spreadMode = _app_options.AppOptions.get("spreadModeOnLoad"); + + if (stored.page && viewOnLoad !== ViewOnLoad.INITIAL) { + hash = `page=${stored.page}&zoom=${zoom || stored.zoom},` + `${stored.scrollLeft},${stored.scrollTop}`; + rotation = parseInt(stored.rotation, 10); + + if (sidebarView === _ui_utils.SidebarView.UNKNOWN) { + sidebarView = stored.sidebarView | 0; + } + + if (scrollMode === _ui_utils.ScrollMode.UNKNOWN) { + scrollMode = stored.scrollMode | 0; + } + + if (spreadMode === _ui_utils.SpreadMode.UNKNOWN) { + spreadMode = stored.spreadMode | 0; + } + } + + if (pageMode && sidebarView === _ui_utils.SidebarView.UNKNOWN) { + sidebarView = (0, _ui_utils.apiPageModeToSidebarView)(pageMode); + } + + if (pageLayout && scrollMode === _ui_utils.ScrollMode.UNKNOWN && spreadMode === _ui_utils.SpreadMode.UNKNOWN) { + const modes = (0, _ui_utils.apiPageLayoutToViewerModes)(pageLayout); + spreadMode = modes.spreadMode; + } + + this.setInitialView(hash, { + rotation, + sidebarView, + scrollMode, + spreadMode + }); + this.eventBus.dispatch("documentinit", { + source: this + }); + + if (!this.isViewerEmbedded) { + pdfViewer.focus(); + } + + await Promise.race([pagesPromise, new Promise(resolve => { + setTimeout(resolve, FORCE_PAGES_LOADED_TIMEOUT); + })]); + + if (!initialBookmark && !hash) { + return; + } + + if (pdfViewer.hasEqualPageSizes) { + return; + } + + this.initialBookmark = initialBookmark; + pdfViewer.currentScaleValue = pdfViewer.currentScaleValue; + this.setInitialView(hash); + }).catch(() => { + this.setInitialView(); + }).then(function () { + pdfViewer.update(); + }); + }); + pagesPromise.then(() => { + this._unblockDocumentLoadEvent(); + + this._initializeAutoPrint(pdfDocument, openActionPromise); + }, reason => { + this.l10n.get("loading_error").then(msg => { + this._documentError(msg, { + message: reason === null || reason === void 0 ? void 0 : reason.message + }); + }); + }); + onePageRendered.then(data => { + this.externalServices.reportTelemetry({ + type: "pageInfo", + timestamp: data.timestamp + }); + pdfDocument.getOutline().then(outline => { + if (pdfDocument !== this.pdfDocument) { + return; + } + + this.pdfOutlineViewer.render({ + outline, + pdfDocument + }); + }); + pdfDocument.getAttachments().then(attachments => { + if (pdfDocument !== this.pdfDocument) { + return; + } + + this.pdfAttachmentViewer.render({ + attachments + }); + }); + pdfViewer.optionalContentConfigPromise.then(optionalContentConfig => { + if (pdfDocument !== this.pdfDocument) { + return; + } + + this.pdfLayerViewer.render({ + optionalContentConfig, + pdfDocument + }); + }); + + if ("requestIdleCallback" in window) { + const callback = window.requestIdleCallback(() => { + this._collectTelemetry(pdfDocument); + + this._idleCallbacks.delete(callback); + }, { + timeout: 1000 + }); + + this._idleCallbacks.add(callback); + } + }); + + this._initializePageLabels(pdfDocument); + + this._initializeMetadata(pdfDocument); + }, + + async _scriptingDocProperties(pdfDocument) { + var _this$metadata, _this$metadata2; + + if (!this.documentInfo) { + await new Promise(resolve => { + this.eventBus._on("metadataloaded", resolve, { + once: true + }); + }); + + if (pdfDocument !== this.pdfDocument) { + return null; + } + } + + if (!this._contentLength) { + await new Promise(resolve => { + this.eventBus._on("documentloaded", resolve, { + once: true + }); + }); + + if (pdfDocument !== this.pdfDocument) { + return null; + } + } + + return { ...this.documentInfo, + baseURL: this.baseUrl, + filesize: this._contentLength, + filename: this._docFilename, + metadata: (_this$metadata = this.metadata) === null || _this$metadata === void 0 ? void 0 : _this$metadata.getRaw(), + authors: (_this$metadata2 = this.metadata) === null || _this$metadata2 === void 0 ? void 0 : _this$metadata2.get("dc:creator"), + numPages: this.pagesCount, + URL: this.url + }; + }, + + async _collectTelemetry(pdfDocument) { + const markInfo = await this.pdfDocument.getMarkInfo(); + + if (pdfDocument !== this.pdfDocument) { + return; + } + + const tagged = (markInfo === null || markInfo === void 0 ? void 0 : markInfo.Marked) || false; + this.externalServices.reportTelemetry({ + type: "tagged", + tagged + }); + }, + + async _initializeAutoPrint(pdfDocument, openActionPromise) { + const [openAction, javaScript] = await Promise.all([openActionPromise, !this.pdfViewer.enableScripting ? pdfDocument.getJavaScript() : null]); + + if (pdfDocument !== this.pdfDocument) { + return; + } + + let triggerAutoPrint = false; + + if ((openAction === null || openAction === void 0 ? void 0 : openAction.action) === "Print") { + triggerAutoPrint = true; + } + + if (javaScript) { + javaScript.some(js => { + if (!js) { + return false; + } + + console.warn("Warning: JavaScript support is not enabled"); + this.fallback(_pdfjsLib.UNSUPPORTED_FEATURES.javaScript); + return true; + }); + + if (!triggerAutoPrint) { + for (const js of javaScript) { + if (js && _ui_utils.AutoPrintRegExp.test(js)) { + triggerAutoPrint = true; + break; + } + } + } + } + + if (triggerAutoPrint) { + this.triggerPrinting(); + } + }, + + async _initializeMetadata(pdfDocument) { + var _this$_contentDisposi, _this$_contentLength; + + const { + info, + metadata, + contentDispositionFilename, + contentLength + } = await pdfDocument.getMetadata(); + + if (pdfDocument !== this.pdfDocument) { + return; + } + + this.documentInfo = info; + this.metadata = metadata; + (_this$_contentDisposi = this._contentDispositionFilename) !== null && _this$_contentDisposi !== void 0 ? _this$_contentDisposi : this._contentDispositionFilename = contentDispositionFilename; + (_this$_contentLength = this._contentLength) !== null && _this$_contentLength !== void 0 ? _this$_contentLength : this._contentLength = contentLength; + console.log(`PDF ${pdfDocument.fingerprints[0]} [${info.PDFFormatVersion} ` + `${(info.Producer || "-").trim()} / ${(info.Creator || "-").trim()}] ` + `(PDF.js: ${_pdfjsLib.version || "-"})`); + let pdfTitle = info.Title; + const metadataTitle = metadata === null || metadata === void 0 ? void 0 : metadata.get("dc:title"); + + if (metadataTitle) { + if (metadataTitle !== "Untitled" && !/[\uFFF0-\uFFFF]/g.test(metadataTitle)) { + pdfTitle = metadataTitle; + } + } + + if (pdfTitle) { + this.setTitle(`${pdfTitle} - ${this._contentDispositionFilename || this._title}`); + } else if (this._contentDispositionFilename) { + this.setTitle(this._contentDispositionFilename); + } + + if (info.IsXFAPresent && !info.IsAcroFormPresent && !pdfDocument.isPureXfa) { + if (pdfDocument.loadingParams.enableXfa) { + console.warn("Warning: XFA Foreground documents are not supported"); + } else { + console.warn("Warning: XFA support is not enabled"); + } + + this.fallback(_pdfjsLib.UNSUPPORTED_FEATURES.forms); + } else if ((info.IsAcroFormPresent || info.IsXFAPresent) && !this.pdfViewer.renderForms) { + console.warn("Warning: Interactive form support is not enabled"); + this.fallback(_pdfjsLib.UNSUPPORTED_FEATURES.forms); + } + + if (info.IsSignaturesPresent) { + console.warn("Warning: Digital signatures validation is not supported"); + this.fallback(_pdfjsLib.UNSUPPORTED_FEATURES.signatures); + } + + let versionId = "other"; + + if (KNOWN_VERSIONS.includes(info.PDFFormatVersion)) { + versionId = `v${info.PDFFormatVersion.replace(".", "_")}`; + } + + let generatorId = "other"; + + if (info.Producer) { + const producer = info.Producer.toLowerCase(); + KNOWN_GENERATORS.some(function (generator) { + if (!producer.includes(generator)) { + return false; + } + + generatorId = generator.replace(/[ .-]/g, "_"); + return true; + }); + } + + let formType = null; + + if (info.IsXFAPresent) { + formType = "xfa"; + } else if (info.IsAcroFormPresent) { + formType = "acroform"; + } + + this.externalServices.reportTelemetry({ + type: "documentInfo", + version: versionId, + generator: generatorId, + formType + }); + this.eventBus.dispatch("metadataloaded", { + source: this + }); + }, + + async _initializePageLabels(pdfDocument) { + const labels = await pdfDocument.getPageLabels(); + + if (pdfDocument !== this.pdfDocument) { + return; + } + + if (!labels || _app_options.AppOptions.get("disablePageLabels")) { + return; + } + + const numLabels = labels.length; + let standardLabels = 0, + emptyLabels = 0; + + for (let i = 0; i < numLabels; i++) { + const label = labels[i]; + + if (label === (i + 1).toString()) { + standardLabels++; + } else if (label === "") { + emptyLabels++; + } else { + break; + } + } + + if (standardLabels >= numLabels || emptyLabels >= numLabels) { + return; + } + + const { + pdfViewer, + pdfThumbnailViewer, + toolbar + } = this; + pdfViewer.setPageLabels(labels); + pdfThumbnailViewer.setPageLabels(labels); + toolbar.setPagesCount(numLabels, true); + toolbar.setPageNumber(pdfViewer.currentPageNumber, pdfViewer.currentPageLabel); + }, + + _initializePdfHistory(_ref4) { + let { + fingerprint, + viewOnLoad, + initialDest = null + } = _ref4; + + if (!this.pdfHistory) { + return; + } + + this.pdfHistory.initialize({ + fingerprint, + resetHistory: viewOnLoad === ViewOnLoad.INITIAL, + updateUrl: _app_options.AppOptions.get("historyUpdateUrl") + }); + + if (this.pdfHistory.initialBookmark) { + this.initialBookmark = this.pdfHistory.initialBookmark; + this.initialRotation = this.pdfHistory.initialRotation; + } + + if (initialDest && !this.initialBookmark && viewOnLoad === ViewOnLoad.UNKNOWN) { + this.initialBookmark = JSON.stringify(initialDest); + this.pdfHistory.push({ + explicitDest: initialDest, + pageNumber: null + }); + } + }, + + _initializeAnnotationStorageCallbacks(pdfDocument) { + if (pdfDocument !== this.pdfDocument) { + return; + } + + const { + annotationStorage + } = pdfDocument; + + annotationStorage.onSetModified = () => { + window.addEventListener("beforeunload", beforeUnload); + this._annotationStorageModified = true; + }; + + annotationStorage.onResetModified = () => { + window.removeEventListener("beforeunload", beforeUnload); + delete this._annotationStorageModified; + }; + + annotationStorage.onAnnotationEditor = typeStr => { + this._hasAnnotationEditors = !!typeStr; + this.setTitle(); + + if (typeStr) { + this.externalServices.reportTelemetry({ + type: "editing", + data: { + type: typeStr + } + }); + } + }; + }, + + setInitialView(storedHash) { + let { + rotation, + sidebarView, + scrollMode, + spreadMode + } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + const setRotation = angle => { + if ((0, _ui_utils.isValidRotation)(angle)) { + this.pdfViewer.pagesRotation = angle; + } + }; + + const setViewerModes = (scroll, spread) => { + if ((0, _ui_utils.isValidScrollMode)(scroll)) { + this.pdfViewer.scrollMode = scroll; + } + + if ((0, _ui_utils.isValidSpreadMode)(spread)) { + this.pdfViewer.spreadMode = spread; + } + }; + + this.isInitialViewSet = true; + this.pdfSidebar.setInitialView(sidebarView); + setViewerModes(scrollMode, spreadMode); + + if (this.initialBookmark) { + setRotation(this.initialRotation); + delete this.initialRotation; + this.pdfLinkService.setHash(this.initialBookmark); + this.initialBookmark = null; + } else if (storedHash) { + setRotation(rotation); + this.pdfLinkService.setHash(storedHash); + } + + this.toolbar.setPageNumber(this.pdfViewer.currentPageNumber, this.pdfViewer.currentPageLabel); + this.secondaryToolbar.setPageNumber(this.pdfViewer.currentPageNumber); + + if (!this.pdfViewer.currentScaleValue) { + this.pdfViewer.currentScaleValue = _ui_utils.DEFAULT_SCALE_VALUE; + } + }, + + _cleanup() { + if (!this.pdfDocument) { + return; + } + + this.pdfViewer.cleanup(); + this.pdfThumbnailViewer.cleanup(); + this.pdfDocument.cleanup(this.pdfViewer.renderer === _ui_utils.RendererType.SVG); + }, + + forceRendering() { + this.pdfRenderingQueue.printing = !!this.printService; + this.pdfRenderingQueue.isThumbnailViewEnabled = this.pdfSidebar.visibleView === _ui_utils.SidebarView.THUMBS; + this.pdfRenderingQueue.renderHighestPriority(); + }, + + beforePrint() { + this._printAnnotationStoragePromise = this.pdfScriptingManager.dispatchWillPrint().catch(() => {}).then(() => { + var _this$pdfDocument4; + + return (_this$pdfDocument4 = this.pdfDocument) === null || _this$pdfDocument4 === void 0 ? void 0 : _this$pdfDocument4.annotationStorage.print; + }); + + if (this.printService) { + return; + } + + if (!this.supportsPrinting) { + this.l10n.get("printing_not_supported").then(msg => { + this._otherError(msg); + }); + return; + } + + if (!this.pdfViewer.pageViewsReady) { + this.l10n.get("printing_not_ready").then(msg => { + window.alert(msg); + }); + return; + } + + const pagesOverview = this.pdfViewer.getPagesOverview(); + const printContainer = this.appConfig.printContainer; + + const printResolution = _app_options.AppOptions.get("printResolution"); + + const optionalContentConfigPromise = this.pdfViewer.optionalContentConfigPromise; + const printService = PDFPrintServiceFactory.instance.createPrintService(this.pdfDocument, pagesOverview, printContainer, printResolution, optionalContentConfigPromise, this._printAnnotationStoragePromise, this.l10n); + this.printService = printService; + this.forceRendering(); + printService.layout(); + this.externalServices.reportTelemetry({ + type: "print" + }); + + if (this._hasAnnotationEditors) { + this.externalServices.reportTelemetry({ + type: "editing", + data: { + type: "print" + } + }); + } + }, + + afterPrint() { + if (this._printAnnotationStoragePromise) { + this._printAnnotationStoragePromise.then(() => { + this.pdfScriptingManager.dispatchDidPrint(); + }); + + this._printAnnotationStoragePromise = null; + } + + if (this.printService) { + var _this$pdfDocument5; + + this.printService.destroy(); + this.printService = null; + (_this$pdfDocument5 = this.pdfDocument) === null || _this$pdfDocument5 === void 0 ? void 0 : _this$pdfDocument5.annotationStorage.resetModified(); + } + + this.forceRendering(); + }, + + rotatePages(delta) { + this.pdfViewer.pagesRotation += delta; + }, + + requestPresentationMode() { + var _this$pdfPresentation; + + (_this$pdfPresentation = this.pdfPresentationMode) === null || _this$pdfPresentation === void 0 ? void 0 : _this$pdfPresentation.request(); + }, + + triggerPrinting() { + if (!this.supportsPrinting) { + return; + } + + window.print(); + }, + + bindEvents() { + const { + eventBus, + _boundEvents + } = this; + _boundEvents.beforePrint = this.beforePrint.bind(this); + _boundEvents.afterPrint = this.afterPrint.bind(this); + + eventBus._on("resize", webViewerResize); + + eventBus._on("hashchange", webViewerHashchange); + + eventBus._on("beforeprint", _boundEvents.beforePrint); + + eventBus._on("afterprint", _boundEvents.afterPrint); + + eventBus._on("pagerendered", webViewerPageRendered); + + eventBus._on("updateviewarea", webViewerUpdateViewarea); + + eventBus._on("pagechanging", webViewerPageChanging); + + eventBus._on("scalechanging", webViewerScaleChanging); + + eventBus._on("rotationchanging", webViewerRotationChanging); + + eventBus._on("sidebarviewchanged", webViewerSidebarViewChanged); + + eventBus._on("pagemode", webViewerPageMode); + + eventBus._on("namedaction", webViewerNamedAction); + + eventBus._on("presentationmodechanged", webViewerPresentationModeChanged); + + eventBus._on("presentationmode", webViewerPresentationMode); + + eventBus._on("switchannotationeditormode", webViewerSwitchAnnotationEditorMode); + + eventBus._on("switchannotationeditorparams", webViewerSwitchAnnotationEditorParams); + + eventBus._on("print", webViewerPrint); + + eventBus._on("download", webViewerDownload); + + eventBus._on("firstpage", webViewerFirstPage); + + eventBus._on("lastpage", webViewerLastPage); + + eventBus._on("nextpage", webViewerNextPage); + + eventBus._on("previouspage", webViewerPreviousPage); + + eventBus._on("zoomin", webViewerZoomIn); + + eventBus._on("zoomout", webViewerZoomOut); + + eventBus._on("zoomreset", webViewerZoomReset); + + eventBus._on("pagenumberchanged", webViewerPageNumberChanged); + + eventBus._on("scalechanged", webViewerScaleChanged); + + eventBus._on("rotatecw", webViewerRotateCw); + + eventBus._on("rotateccw", webViewerRotateCcw); + + eventBus._on("optionalcontentconfig", webViewerOptionalContentConfig); + + eventBus._on("switchscrollmode", webViewerSwitchScrollMode); + + eventBus._on("scrollmodechanged", webViewerScrollModeChanged); + + eventBus._on("switchspreadmode", webViewerSwitchSpreadMode); + + eventBus._on("spreadmodechanged", webViewerSpreadModeChanged); + + eventBus._on("documentproperties", webViewerDocumentProperties); + + eventBus._on("findfromurlhash", webViewerFindFromUrlHash); + + eventBus._on("updatefindmatchescount", webViewerUpdateFindMatchesCount); + + eventBus._on("updatefindcontrolstate", webViewerUpdateFindControlState); + + if (_app_options.AppOptions.get("pdfBug")) { + _boundEvents.reportPageStatsPDFBug = reportPageStatsPDFBug; + + eventBus._on("pagerendered", _boundEvents.reportPageStatsPDFBug); + + eventBus._on("pagechanging", _boundEvents.reportPageStatsPDFBug); + } + + eventBus._on("fileinputchange", webViewerFileInputChange); + + eventBus._on("openfile", webViewerOpenFile); + }, + + bindWindowEvents() { + const { + eventBus, + _boundEvents + } = this; + + function addWindowResolutionChange() { + let evt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + + if (evt) { + webViewerResolutionChange(evt); + } + + const mediaQueryList = window.matchMedia(`(resolution: ${window.devicePixelRatio || 1}dppx)`); + mediaQueryList.addEventListener("change", addWindowResolutionChange, { + once: true + }); + _boundEvents.removeWindowResolutionChange || (_boundEvents.removeWindowResolutionChange = function () { + mediaQueryList.removeEventListener("change", addWindowResolutionChange); + _boundEvents.removeWindowResolutionChange = null; + }); + } + + addWindowResolutionChange(); + + _boundEvents.windowResize = () => { + eventBus.dispatch("resize", { + source: window + }); + }; + + _boundEvents.windowHashChange = () => { + eventBus.dispatch("hashchange", { + source: window, + hash: document.location.hash.substring(1) + }); + }; + + _boundEvents.windowBeforePrint = () => { + eventBus.dispatch("beforeprint", { + source: window + }); + }; + + _boundEvents.windowAfterPrint = () => { + eventBus.dispatch("afterprint", { + source: window + }); + }; + + _boundEvents.windowUpdateFromSandbox = event => { + eventBus.dispatch("updatefromsandbox", { + source: window, + detail: event.detail + }); + }; + + window.addEventListener("visibilitychange", webViewerVisibilityChange); + window.addEventListener("wheel", webViewerWheel, { + passive: false + }); + window.addEventListener("touchstart", webViewerTouchStart, { + passive: false + }); + window.addEventListener("click", webViewerClick); + window.addEventListener("keydown", webViewerKeyDown); + window.addEventListener("resize", _boundEvents.windowResize); + window.addEventListener("hashchange", _boundEvents.windowHashChange); + window.addEventListener("beforeprint", _boundEvents.windowBeforePrint); + window.addEventListener("afterprint", _boundEvents.windowAfterPrint); + window.addEventListener("updatefromsandbox", _boundEvents.windowUpdateFromSandbox); + }, + + unbindEvents() { + const { + eventBus, + _boundEvents + } = this; + + eventBus._off("resize", webViewerResize); + + eventBus._off("hashchange", webViewerHashchange); + + eventBus._off("beforeprint", _boundEvents.beforePrint); + + eventBus._off("afterprint", _boundEvents.afterPrint); + + eventBus._off("pagerendered", webViewerPageRendered); + + eventBus._off("updateviewarea", webViewerUpdateViewarea); + + eventBus._off("pagechanging", webViewerPageChanging); + + eventBus._off("scalechanging", webViewerScaleChanging); + + eventBus._off("rotationchanging", webViewerRotationChanging); + + eventBus._off("sidebarviewchanged", webViewerSidebarViewChanged); + + eventBus._off("pagemode", webViewerPageMode); + + eventBus._off("namedaction", webViewerNamedAction); + + eventBus._off("presentationmodechanged", webViewerPresentationModeChanged); + + eventBus._off("presentationmode", webViewerPresentationMode); + + eventBus._off("print", webViewerPrint); + + eventBus._off("download", webViewerDownload); + + eventBus._off("firstpage", webViewerFirstPage); + + eventBus._off("lastpage", webViewerLastPage); + + eventBus._off("nextpage", webViewerNextPage); + + eventBus._off("previouspage", webViewerPreviousPage); + + eventBus._off("zoomin", webViewerZoomIn); + + eventBus._off("zoomout", webViewerZoomOut); + + eventBus._off("zoomreset", webViewerZoomReset); + + eventBus._off("pagenumberchanged", webViewerPageNumberChanged); + + eventBus._off("scalechanged", webViewerScaleChanged); + + eventBus._off("rotatecw", webViewerRotateCw); + + eventBus._off("rotateccw", webViewerRotateCcw); + + eventBus._off("optionalcontentconfig", webViewerOptionalContentConfig); + + eventBus._off("switchscrollmode", webViewerSwitchScrollMode); + + eventBus._off("scrollmodechanged", webViewerScrollModeChanged); + + eventBus._off("switchspreadmode", webViewerSwitchSpreadMode); + + eventBus._off("spreadmodechanged", webViewerSpreadModeChanged); + + eventBus._off("documentproperties", webViewerDocumentProperties); + + eventBus._off("findfromurlhash", webViewerFindFromUrlHash); + + eventBus._off("updatefindmatchescount", webViewerUpdateFindMatchesCount); + + eventBus._off("updatefindcontrolstate", webViewerUpdateFindControlState); + + if (_boundEvents.reportPageStatsPDFBug) { + eventBus._off("pagerendered", _boundEvents.reportPageStatsPDFBug); + + eventBus._off("pagechanging", _boundEvents.reportPageStatsPDFBug); + + _boundEvents.reportPageStatsPDFBug = null; + } + + eventBus._off("fileinputchange", webViewerFileInputChange); + + eventBus._off("openfile", webViewerOpenFile); + + _boundEvents.beforePrint = null; + _boundEvents.afterPrint = null; + }, + + unbindWindowEvents() { + var _boundEvents$removeWi; + + const { + _boundEvents + } = this; + window.removeEventListener("visibilitychange", webViewerVisibilityChange); + window.removeEventListener("wheel", webViewerWheel, { + passive: false + }); + window.removeEventListener("touchstart", webViewerTouchStart, { + passive: false + }); + window.removeEventListener("click", webViewerClick); + window.removeEventListener("keydown", webViewerKeyDown); + window.removeEventListener("resize", _boundEvents.windowResize); + window.removeEventListener("hashchange", _boundEvents.windowHashChange); + window.removeEventListener("beforeprint", _boundEvents.windowBeforePrint); + window.removeEventListener("afterprint", _boundEvents.windowAfterPrint); + window.removeEventListener("updatefromsandbox", _boundEvents.windowUpdateFromSandbox); + (_boundEvents$removeWi = _boundEvents.removeWindowResolutionChange) === null || _boundEvents$removeWi === void 0 ? void 0 : _boundEvents$removeWi.call(_boundEvents); + _boundEvents.windowResize = null; + _boundEvents.windowHashChange = null; + _boundEvents.windowBeforePrint = null; + _boundEvents.windowAfterPrint = null; + _boundEvents.windowUpdateFromSandbox = null; + }, + + accumulateWheelTicks(ticks) { + if (this._wheelUnusedTicks > 0 && ticks < 0 || this._wheelUnusedTicks < 0 && ticks > 0) { + this._wheelUnusedTicks = 0; + } + + this._wheelUnusedTicks += ticks; + const wholeTicks = Math.sign(this._wheelUnusedTicks) * Math.floor(Math.abs(this._wheelUnusedTicks)); + this._wheelUnusedTicks -= wholeTicks; + return wholeTicks; + }, + + _unblockDocumentLoadEvent() { + var _document$blockUnbloc, _document; + + (_document$blockUnbloc = (_document = document).blockUnblockOnload) === null || _document$blockUnbloc === void 0 ? void 0 : _document$blockUnbloc.call(_document, false); + + this._unblockDocumentLoadEvent = () => {}; + }, + + _reportDocumentStatsTelemetry() { + const { + stats + } = this.pdfDocument; + + if (stats !== this._docStats) { + this._docStats = stats; + this.externalServices.reportTelemetry({ + type: "documentStats", + stats + }); + } + }, + + get scriptingReady() { + return this.pdfScriptingManager.ready; + } + +}; +exports.PDFViewerApplication = PDFViewerApplication; +let validateFileURL; +{ + const HOSTED_VIEWER_ORIGINS = ["null", "http://mozilla.github.io", "https://mozilla.github.io"]; + + validateFileURL = function (file) { + if (!file) { + return; + } + + try { + const viewerOrigin = new URL(window.location.href).origin || "null"; + + if (HOSTED_VIEWER_ORIGINS.includes(viewerOrigin)) { + return; + } + + const fileOrigin = new URL(file, window.location.href).origin; + + if (fileOrigin !== viewerOrigin) { + throw new Error("file origin does not match viewer's"); + } + } catch (ex) { + PDFViewerApplication.l10n.get("loading_error").then(msg => { + PDFViewerApplication._documentError(msg, { + message: ex === null || ex === void 0 ? void 0 : ex.message + }); + }); + throw ex; + } + }; +} + +async function loadFakeWorker() { + _pdfjsLib.GlobalWorkerOptions.workerSrc || (_pdfjsLib.GlobalWorkerOptions.workerSrc = _app_options.AppOptions.get("workerSrc")); + await (0, _pdfjsLib.loadScript)(_pdfjsLib.PDFWorker.workerSrc); +} + +async function loadPDFBug(self) { + const { + debuggerScriptPath + } = self.appConfig; + const { + PDFBug + } = await import(debuggerScriptPath); + self._PDFBug = PDFBug; +} + +function reportPageStatsPDFBug(_ref5) { + var _globalThis$Stats, _pageView$pdfPage; + + let { + pageNumber + } = _ref5; + + if (!((_globalThis$Stats = globalThis.Stats) !== null && _globalThis$Stats !== void 0 && _globalThis$Stats.enabled)) { + return; + } + + const pageView = PDFViewerApplication.pdfViewer.getPageView(pageNumber - 1); + globalThis.Stats.add(pageNumber, pageView === null || pageView === void 0 ? void 0 : (_pageView$pdfPage = pageView.pdfPage) === null || _pageView$pdfPage === void 0 ? void 0 : _pageView$pdfPage.stats); +} + +function webViewerInitialized() { + var _params$get; + + const { + appConfig, + eventBus + } = PDFViewerApplication; + let file; + const queryString = document.location.search.substring(1); + const params = (0, _ui_utils.parseQueryString)(queryString); + file = (_params$get = params.get("file")) !== null && _params$get !== void 0 ? _params$get : _app_options.AppOptions.get("defaultUrl"); + validateFileURL(file); + const fileInput = appConfig.openFileInput; + fileInput.value = null; + fileInput.addEventListener("change", function (evt) { + const { + files + } = evt.target; + + if (!files || files.length === 0) { + return; + } + + eventBus.dispatch("fileinputchange", { + source: this, + fileInput: evt.target + }); + }); + appConfig.mainContainer.addEventListener("dragover", function (evt) { + evt.preventDefault(); + evt.dataTransfer.dropEffect = evt.dataTransfer.effectAllowed === "copy" ? "copy" : "move"; + }); + appConfig.mainContainer.addEventListener("drop", function (evt) { + evt.preventDefault(); + const { + files + } = evt.dataTransfer; + + if (!files || files.length === 0) { + return; + } + + eventBus.dispatch("fileinputchange", { + source: this, + fileInput: evt.dataTransfer + }); + }); + + if (!PDFViewerApplication.supportsDocumentFonts) { + _app_options.AppOptions.set("disableFontFace", true); + + PDFViewerApplication.l10n.get("web_fonts_disabled").then(msg => { + console.warn(msg); + }); + } + + if (!PDFViewerApplication.supportsPrinting) { + appConfig.toolbar.print.classList.add("hidden"); + appConfig.secondaryToolbar.printButton.classList.add("hidden"); + } + + if (!PDFViewerApplication.supportsFullscreen) { + appConfig.toolbar.presentationModeButton.classList.add("hidden"); + appConfig.secondaryToolbar.presentationModeButton.classList.add("hidden"); + } + + if (PDFViewerApplication.supportsIntegratedFind) { + appConfig.toolbar.viewFind.classList.add("hidden"); + } + + appConfig.mainContainer.addEventListener("transitionend", function (evt) { + if (evt.target === this) { + eventBus.dispatch("resize", { + source: this + }); + } + }, true); + + try { + if (file) { + PDFViewerApplication.open(file); + } else { + PDFViewerApplication._hideViewBookmark(); + } + } catch (reason) { + PDFViewerApplication.l10n.get("loading_error").then(msg => { + PDFViewerApplication._documentError(msg, reason); + }); + } +} + +function webViewerPageRendered(_ref6) { + let { + pageNumber, + error + } = _ref6; + + if (pageNumber === PDFViewerApplication.page) { + PDFViewerApplication.toolbar.updateLoadingIndicatorState(false); + } + + if (PDFViewerApplication.pdfSidebar.visibleView === _ui_utils.SidebarView.THUMBS) { + const pageView = PDFViewerApplication.pdfViewer.getPageView(pageNumber - 1); + const thumbnailView = PDFViewerApplication.pdfThumbnailViewer.getThumbnail(pageNumber - 1); + + if (pageView && thumbnailView) { + thumbnailView.setImage(pageView); + } + } + + if (error) { + PDFViewerApplication.l10n.get("rendering_error").then(msg => { + PDFViewerApplication._otherError(msg, error); + }); + } + + PDFViewerApplication._reportDocumentStatsTelemetry(); +} + +function webViewerPageMode(_ref7) { + let { + mode + } = _ref7; + let view; + + switch (mode) { + case "thumbs": + view = _ui_utils.SidebarView.THUMBS; + break; + + case "bookmarks": + case "outline": + view = _ui_utils.SidebarView.OUTLINE; + break; + + case "attachments": + view = _ui_utils.SidebarView.ATTACHMENTS; + break; + + case "layers": + view = _ui_utils.SidebarView.LAYERS; + break; + + case "none": + view = _ui_utils.SidebarView.NONE; + break; + + default: + console.error('Invalid "pagemode" hash parameter: ' + mode); + return; + } + + PDFViewerApplication.pdfSidebar.switchView(view, true); +} + +function webViewerNamedAction(evt) { + switch (evt.action) { + case "GoToPage": + PDFViewerApplication.appConfig.toolbar.pageNumber.select(); + break; + + case "Find": + if (!PDFViewerApplication.supportsIntegratedFind) { + PDFViewerApplication.findBar.toggle(); + } + + break; + + case "Print": + PDFViewerApplication.triggerPrinting(); + break; + + case "SaveAs": + PDFViewerApplication.downloadOrSave(); + break; + } +} + +function webViewerPresentationModeChanged(evt) { + PDFViewerApplication.pdfViewer.presentationModeState = evt.state; +} + +function webViewerSidebarViewChanged(_ref8) { + let { + view + } = _ref8; + PDFViewerApplication.pdfRenderingQueue.isThumbnailViewEnabled = view === _ui_utils.SidebarView.THUMBS; + + if (PDFViewerApplication.isInitialViewSet) { + var _PDFViewerApplication; + + (_PDFViewerApplication = PDFViewerApplication.store) === null || _PDFViewerApplication === void 0 ? void 0 : _PDFViewerApplication.set("sidebarView", view).catch(() => {}); + } +} + +function webViewerUpdateViewarea(_ref9) { + let { + location + } = _ref9; + + if (PDFViewerApplication.isInitialViewSet) { + var _PDFViewerApplication2; + + (_PDFViewerApplication2 = PDFViewerApplication.store) === null || _PDFViewerApplication2 === void 0 ? void 0 : _PDFViewerApplication2.setMultiple({ + page: location.pageNumber, + zoom: location.scale, + scrollLeft: location.left, + scrollTop: location.top, + rotation: location.rotation + }).catch(() => {}); + } + + const href = PDFViewerApplication.pdfLinkService.getAnchorUrl(location.pdfOpenParams); + PDFViewerApplication.appConfig.toolbar.viewBookmark.href = href; + PDFViewerApplication.appConfig.secondaryToolbar.viewBookmarkButton.href = href; + const currentPage = PDFViewerApplication.pdfViewer.getPageView(PDFViewerApplication.page - 1); + const loading = (currentPage === null || currentPage === void 0 ? void 0 : currentPage.renderingState) !== _ui_utils.RenderingStates.FINISHED; + PDFViewerApplication.toolbar.updateLoadingIndicatorState(loading); +} + +function webViewerScrollModeChanged(evt) { + if (PDFViewerApplication.isInitialViewSet) { + var _PDFViewerApplication3; + + (_PDFViewerApplication3 = PDFViewerApplication.store) === null || _PDFViewerApplication3 === void 0 ? void 0 : _PDFViewerApplication3.set("scrollMode", evt.mode).catch(() => {}); + } +} + +function webViewerSpreadModeChanged(evt) { + if (PDFViewerApplication.isInitialViewSet) { + var _PDFViewerApplication4; + + (_PDFViewerApplication4 = PDFViewerApplication.store) === null || _PDFViewerApplication4 === void 0 ? void 0 : _PDFViewerApplication4.set("spreadMode", evt.mode).catch(() => {}); + } +} + +function webViewerResize() { + const { + pdfDocument, + pdfViewer, + pdfRenderingQueue + } = PDFViewerApplication; + + if (pdfRenderingQueue.printing && window.matchMedia("print").matches) { + return; + } + + pdfViewer.updateContainerHeightCss(); + + if (!pdfDocument) { + return; + } + + const currentScaleValue = pdfViewer.currentScaleValue; + + if (currentScaleValue === "auto" || currentScaleValue === "page-fit" || currentScaleValue === "page-width") { + pdfViewer.currentScaleValue = currentScaleValue; + } + + pdfViewer.update(); +} + +function webViewerHashchange(evt) { + var _PDFViewerApplication5; + + const hash = evt.hash; + + if (!hash) { + return; + } + + if (!PDFViewerApplication.isInitialViewSet) { + PDFViewerApplication.initialBookmark = hash; + } else if (!((_PDFViewerApplication5 = PDFViewerApplication.pdfHistory) !== null && _PDFViewerApplication5 !== void 0 && _PDFViewerApplication5.popStateInProgress)) { + PDFViewerApplication.pdfLinkService.setHash(hash); + } +} + +{ + var webViewerFileInputChange = function (evt) { + var _PDFViewerApplication6; + + if ((_PDFViewerApplication6 = PDFViewerApplication.pdfViewer) !== null && _PDFViewerApplication6 !== void 0 && _PDFViewerApplication6.isInPresentationMode) { + return; + } + + const file = evt.fileInput.files[0]; + let url = URL.createObjectURL(file); + + if (file.name) { + url = { + url, + originalUrl: file.name + }; + } + + PDFViewerApplication.open(url); + }; + + var webViewerOpenFile = function (evt) { + const fileInput = PDFViewerApplication.appConfig.openFileInput; + fileInput.click(); + }; +} + +function webViewerPresentationMode() { + PDFViewerApplication.requestPresentationMode(); +} + +function webViewerSwitchAnnotationEditorMode(evt) { + PDFViewerApplication.pdfViewer.annotationEditorMode = evt.mode; +} + +function webViewerSwitchAnnotationEditorParams(evt) { + PDFViewerApplication.pdfViewer.annotationEditorParams = evt; +} + +function webViewerPrint() { + PDFViewerApplication.triggerPrinting(); +} + +function webViewerDownload() { + PDFViewerApplication.downloadOrSave(); +} + +function webViewerFirstPage() { + if (PDFViewerApplication.pdfDocument) { + PDFViewerApplication.page = 1; + } +} + +function webViewerLastPage() { + if (PDFViewerApplication.pdfDocument) { + PDFViewerApplication.page = PDFViewerApplication.pagesCount; + } +} + +function webViewerNextPage() { + PDFViewerApplication.pdfViewer.nextPage(); +} + +function webViewerPreviousPage() { + PDFViewerApplication.pdfViewer.previousPage(); +} + +function webViewerZoomIn() { + PDFViewerApplication.zoomIn(); +} + +function webViewerZoomOut() { + PDFViewerApplication.zoomOut(); +} + +function webViewerZoomReset() { + PDFViewerApplication.zoomReset(); +} + +function webViewerPageNumberChanged(evt) { + const pdfViewer = PDFViewerApplication.pdfViewer; + + if (evt.value !== "") { + PDFViewerApplication.pdfLinkService.goToPage(evt.value); + } + + if (evt.value !== pdfViewer.currentPageNumber.toString() && evt.value !== pdfViewer.currentPageLabel) { + PDFViewerApplication.toolbar.setPageNumber(pdfViewer.currentPageNumber, pdfViewer.currentPageLabel); + } +} + +function webViewerScaleChanged(evt) { + PDFViewerApplication.pdfViewer.currentScaleValue = evt.value; +} + +function webViewerRotateCw() { + PDFViewerApplication.rotatePages(90); +} + +function webViewerRotateCcw() { + PDFViewerApplication.rotatePages(-90); +} + +function webViewerOptionalContentConfig(evt) { + PDFViewerApplication.pdfViewer.optionalContentConfigPromise = evt.promise; +} + +function webViewerSwitchScrollMode(evt) { + PDFViewerApplication.pdfViewer.scrollMode = evt.mode; +} + +function webViewerSwitchSpreadMode(evt) { + PDFViewerApplication.pdfViewer.spreadMode = evt.mode; +} + +function webViewerDocumentProperties() { + PDFViewerApplication.pdfDocumentProperties.open(); +} + +function webViewerFindFromUrlHash(evt) { + PDFViewerApplication.eventBus.dispatch("find", { + source: evt.source, + type: "", + query: evt.query, + phraseSearch: evt.phraseSearch, + caseSensitive: false, + entireWord: false, + highlightAll: true, + findPrevious: false, + matchDiacritics: true + }); +} + +function webViewerUpdateFindMatchesCount(_ref10) { + let { + matchesCount + } = _ref10; + + if (PDFViewerApplication.supportsIntegratedFind) { + PDFViewerApplication.externalServices.updateFindMatchesCount(matchesCount); + } else { + PDFViewerApplication.findBar.updateResultsCount(matchesCount); + } +} + +function webViewerUpdateFindControlState(_ref11) { + let { + state, + previous, + matchesCount, + rawQuery + } = _ref11; + + if (PDFViewerApplication.supportsIntegratedFind) { + PDFViewerApplication.externalServices.updateFindControlState({ + result: state, + findPrevious: previous, + matchesCount, + rawQuery + }); + } else { + PDFViewerApplication.findBar.updateUIState(state, previous, matchesCount); + } +} + +function webViewerScaleChanging(evt) { + PDFViewerApplication.toolbar.setPageScale(evt.presetValue, evt.scale); + PDFViewerApplication.pdfViewer.update(); +} + +function webViewerRotationChanging(evt) { + PDFViewerApplication.pdfThumbnailViewer.pagesRotation = evt.pagesRotation; + PDFViewerApplication.forceRendering(); + PDFViewerApplication.pdfViewer.currentPageNumber = evt.pageNumber; +} + +function webViewerPageChanging(_ref12) { + let { + pageNumber, + pageLabel + } = _ref12; + PDFViewerApplication.toolbar.setPageNumber(pageNumber, pageLabel); + PDFViewerApplication.secondaryToolbar.setPageNumber(pageNumber); + + if (PDFViewerApplication.pdfSidebar.visibleView === _ui_utils.SidebarView.THUMBS) { + PDFViewerApplication.pdfThumbnailViewer.scrollThumbnailIntoView(pageNumber); + } +} + +function webViewerResolutionChange(evt) { + PDFViewerApplication.pdfViewer.refresh(); +} + +function webViewerVisibilityChange(evt) { + if (document.visibilityState === "visible") { + setZoomDisabledTimeout(); + } +} + +let zoomDisabledTimeout = null; + +function setZoomDisabledTimeout() { + if (zoomDisabledTimeout) { + clearTimeout(zoomDisabledTimeout); + } + + zoomDisabledTimeout = setTimeout(function () { + zoomDisabledTimeout = null; + }, WHEEL_ZOOM_DISABLED_TIMEOUT); +} + +function webViewerWheel(evt) { + const { + pdfViewer, + supportedMouseWheelZoomModifierKeys + } = PDFViewerApplication; + + if (pdfViewer.isInPresentationMode) { + return; + } + + if (evt.ctrlKey && supportedMouseWheelZoomModifierKeys.ctrlKey || evt.metaKey && supportedMouseWheelZoomModifierKeys.metaKey) { + evt.preventDefault(); + + if (zoomDisabledTimeout || document.visibilityState === "hidden") { + return; + } + + const deltaMode = evt.deltaMode; + const delta = (0, _ui_utils.normalizeWheelEventDirection)(evt); + const previousScale = pdfViewer.currentScale; + let ticks = 0; + + if (deltaMode === WheelEvent.DOM_DELTA_LINE || deltaMode === WheelEvent.DOM_DELTA_PAGE) { + if (Math.abs(delta) >= 1) { + ticks = Math.sign(delta); + } else { + ticks = PDFViewerApplication.accumulateWheelTicks(delta); + } + } else { + const PIXELS_PER_LINE_SCALE = 30; + ticks = PDFViewerApplication.accumulateWheelTicks(delta / PIXELS_PER_LINE_SCALE); + } + + if (ticks < 0) { + PDFViewerApplication.zoomOut(-ticks); + } else if (ticks > 0) { + PDFViewerApplication.zoomIn(ticks); + } + + const currentScale = pdfViewer.currentScale; + + if (previousScale !== currentScale) { + const scaleCorrectionFactor = currentScale / previousScale - 1; + const rect = pdfViewer.container.getBoundingClientRect(); + const dx = evt.clientX - rect.left; + const dy = evt.clientY - rect.top; + pdfViewer.container.scrollLeft += dx * scaleCorrectionFactor; + pdfViewer.container.scrollTop += dy * scaleCorrectionFactor; + } + } else { + setZoomDisabledTimeout(); + } +} + +function webViewerTouchStart(evt) { + if (evt.touches.length > 1) { + evt.preventDefault(); + } +} + +function webViewerClick(evt) { + if (!PDFViewerApplication.secondaryToolbar.isOpen) { + return; + } + + const appConfig = PDFViewerApplication.appConfig; + + if (PDFViewerApplication.pdfViewer.containsElement(evt.target) || appConfig.toolbar.container.contains(evt.target) && evt.target !== appConfig.secondaryToolbar.toggleButton) { + PDFViewerApplication.secondaryToolbar.close(); + } +} + +function webViewerKeyDown(evt) { + if (PDFViewerApplication.overlayManager.active) { + return; + } + + const { + eventBus, + pdfViewer + } = PDFViewerApplication; + const isViewerInPresentationMode = pdfViewer.isInPresentationMode; + let handled = false, + ensureViewerFocused = false; + const cmd = (evt.ctrlKey ? 1 : 0) | (evt.altKey ? 2 : 0) | (evt.shiftKey ? 4 : 0) | (evt.metaKey ? 8 : 0); + + if (cmd === 1 || cmd === 8 || cmd === 5 || cmd === 12) { + switch (evt.keyCode) { + case 70: + if (!PDFViewerApplication.supportsIntegratedFind && !evt.shiftKey) { + PDFViewerApplication.findBar.open(); + handled = true; + } + + break; + + case 71: + if (!PDFViewerApplication.supportsIntegratedFind) { + const { + state + } = PDFViewerApplication.findController; + + if (state) { + const eventState = Object.assign(Object.create(null), state, { + source: window, + type: "again", + findPrevious: cmd === 5 || cmd === 12 + }); + eventBus.dispatch("find", eventState); + } + + handled = true; + } + + break; + + case 61: + case 107: + case 187: + case 171: + if (!isViewerInPresentationMode) { + PDFViewerApplication.zoomIn(); + } + + handled = true; + break; + + case 173: + case 109: + case 189: + if (!isViewerInPresentationMode) { + PDFViewerApplication.zoomOut(); + } + + handled = true; + break; + + case 48: + case 96: + if (!isViewerInPresentationMode) { + setTimeout(function () { + PDFViewerApplication.zoomReset(); + }); + handled = false; + } + + break; + + case 38: + if (isViewerInPresentationMode || PDFViewerApplication.page > 1) { + PDFViewerApplication.page = 1; + handled = true; + ensureViewerFocused = true; + } + + break; + + case 40: + if (isViewerInPresentationMode || PDFViewerApplication.page < PDFViewerApplication.pagesCount) { + PDFViewerApplication.page = PDFViewerApplication.pagesCount; + handled = true; + ensureViewerFocused = true; + } + + break; + } + } + + if (cmd === 1 || cmd === 8) { + switch (evt.keyCode) { + case 83: + eventBus.dispatch("download", { + source: window + }); + handled = true; + break; + + case 79: + { + eventBus.dispatch("openfile", { + source: window + }); + handled = true; + } + break; + } + } + + if (cmd === 3 || cmd === 10) { + switch (evt.keyCode) { + case 80: + PDFViewerApplication.requestPresentationMode(); + handled = true; + break; + + case 71: + PDFViewerApplication.appConfig.toolbar.pageNumber.select(); + handled = true; + break; + } + } + + if (handled) { + if (ensureViewerFocused && !isViewerInPresentationMode) { + pdfViewer.focus(); + } + + evt.preventDefault(); + return; + } + + const curElement = (0, _ui_utils.getActiveOrFocusedElement)(); + const curElementTagName = curElement === null || curElement === void 0 ? void 0 : curElement.tagName.toUpperCase(); + + if (curElementTagName === "INPUT" || curElementTagName === "TEXTAREA" || curElementTagName === "SELECT" || curElement !== null && curElement !== void 0 && curElement.isContentEditable) { + if (evt.keyCode !== 27) { + return; + } + } + + if (cmd === 0) { + let turnPage = 0, + turnOnlyIfPageFit = false; + + switch (evt.keyCode) { + case 38: + case 33: + if (pdfViewer.isVerticalScrollbarEnabled) { + turnOnlyIfPageFit = true; + } + + turnPage = -1; + break; + + case 8: + if (!isViewerInPresentationMode) { + turnOnlyIfPageFit = true; + } + + turnPage = -1; + break; + + case 37: + if (pdfViewer.isHorizontalScrollbarEnabled) { + turnOnlyIfPageFit = true; + } + + case 75: + case 80: + turnPage = -1; + break; + + case 27: + if (PDFViewerApplication.secondaryToolbar.isOpen) { + PDFViewerApplication.secondaryToolbar.close(); + handled = true; + } + + if (!PDFViewerApplication.supportsIntegratedFind && PDFViewerApplication.findBar.opened) { + PDFViewerApplication.findBar.close(); + handled = true; + } + + break; + + case 40: + case 34: + if (pdfViewer.isVerticalScrollbarEnabled) { + turnOnlyIfPageFit = true; + } + + turnPage = 1; + break; + + case 13: + case 32: + if (!isViewerInPresentationMode) { + turnOnlyIfPageFit = true; + } + + turnPage = 1; + break; + + case 39: + if (pdfViewer.isHorizontalScrollbarEnabled) { + turnOnlyIfPageFit = true; + } + + case 74: + case 78: + turnPage = 1; + break; + + case 36: + if (isViewerInPresentationMode || PDFViewerApplication.page > 1) { + PDFViewerApplication.page = 1; + handled = true; + ensureViewerFocused = true; + } + + break; + + case 35: + if (isViewerInPresentationMode || PDFViewerApplication.page < PDFViewerApplication.pagesCount) { + PDFViewerApplication.page = PDFViewerApplication.pagesCount; + handled = true; + ensureViewerFocused = true; + } + + break; + + case 83: + PDFViewerApplication.pdfCursorTools.switchTool(_pdf_cursor_tools.CursorTool.SELECT); + break; + + case 72: + PDFViewerApplication.pdfCursorTools.switchTool(_pdf_cursor_tools.CursorTool.HAND); + break; + + case 82: + PDFViewerApplication.rotatePages(90); + break; + + case 115: + PDFViewerApplication.pdfSidebar.toggle(); + break; + } + + if (turnPage !== 0 && (!turnOnlyIfPageFit || pdfViewer.currentScaleValue === "page-fit")) { + if (turnPage > 0) { + pdfViewer.nextPage(); + } else { + pdfViewer.previousPage(); + } + + handled = true; + } + } + + if (cmd === 4) { + switch (evt.keyCode) { + case 13: + case 32: + if (!isViewerInPresentationMode && pdfViewer.currentScaleValue !== "page-fit") { + break; + } + + pdfViewer.previousPage(); + handled = true; + break; + + case 82: + PDFViewerApplication.rotatePages(-90); + break; + } + } + + if (!handled && !isViewerInPresentationMode) { + if (evt.keyCode >= 33 && evt.keyCode <= 40 || evt.keyCode === 32 && curElementTagName !== "BUTTON") { + ensureViewerFocused = true; + } + } + + if (ensureViewerFocused && !pdfViewer.containsElement(curElement)) { + pdfViewer.focus(); + } + + if (handled) { + evt.preventDefault(); + } +} + +function beforeUnload(evt) { + evt.preventDefault(); + evt.returnValue = ""; + return false; +} + +function webViewerAnnotationEditorStatesChanged(data) { + PDFViewerApplication.externalServices.updateEditorStates(data); +} + +const PDFPrintServiceFactory = { + instance: { + supportsPrinting: false, + + createPrintService() { + throw new Error("Not implemented: createPrintService"); + } + + } +}; +exports.PDFPrintServiceFactory = PDFPrintServiceFactory; + +/***/ }), +/* 5 */ +/***/ ((module) => { + + + +let pdfjsLib; + +if (typeof window !== "undefined" && window["pdfjs-dist/build/pdf"]) { + pdfjsLib = window["pdfjs-dist/build/pdf"]; +} else { + pdfjsLib = require("../build/pdf.js"); +} + +module.exports = pdfjsLib; + +/***/ }), +/* 6 */ +/***/ ((__unused_webpack_module, exports) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.WaitOnType = exports.EventBus = exports.AutomationEventBus = void 0; +exports.waitOnEventOrTimeout = waitOnEventOrTimeout; +const WaitOnType = { + EVENT: "event", + TIMEOUT: "timeout" +}; +exports.WaitOnType = WaitOnType; + +function waitOnEventOrTimeout(_ref) { + let { + target, + name, + delay = 0 + } = _ref; + return new Promise(function (resolve, reject) { + if (typeof target !== "object" || !(name && typeof name === "string") || !(Number.isInteger(delay) && delay >= 0)) { + throw new Error("waitOnEventOrTimeout - invalid parameters."); + } + + function handler(type) { + if (target instanceof EventBus) { + target._off(name, eventHandler); + } else { + target.removeEventListener(name, eventHandler); + } + + if (timeout) { + clearTimeout(timeout); + } + + resolve(type); + } + + const eventHandler = handler.bind(null, WaitOnType.EVENT); + + if (target instanceof EventBus) { + target._on(name, eventHandler); + } else { + target.addEventListener(name, eventHandler); + } + + const timeoutHandler = handler.bind(null, WaitOnType.TIMEOUT); + const timeout = setTimeout(timeoutHandler, delay); + }); +} + +class EventBus { + constructor() { + this._listeners = Object.create(null); + } + + on(eventName, listener) { + let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + + this._on(eventName, listener, { + external: true, + once: options === null || options === void 0 ? void 0 : options.once + }); + } + + off(eventName, listener) { + let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + + this._off(eventName, listener, { + external: true, + once: options === null || options === void 0 ? void 0 : options.once + }); + } + + dispatch(eventName, data) { + const eventListeners = this._listeners[eventName]; + + if (!eventListeners || eventListeners.length === 0) { + return; + } + + let externalListeners; + + for (const { + listener, + external, + once + } of eventListeners.slice(0)) { + if (once) { + this._off(eventName, listener); + } + + if (external) { + (externalListeners || (externalListeners = [])).push(listener); + continue; + } + + listener(data); + } + + if (externalListeners) { + for (const listener of externalListeners) { + listener(data); + } + + externalListeners = null; + } + } + + _on(eventName, listener) { + var _this$_listeners; + + let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + const eventListeners = (_this$_listeners = this._listeners)[eventName] || (_this$_listeners[eventName] = []); + eventListeners.push({ + listener, + external: (options === null || options === void 0 ? void 0 : options.external) === true, + once: (options === null || options === void 0 ? void 0 : options.once) === true + }); + } + + _off(eventName, listener) { + let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + const eventListeners = this._listeners[eventName]; + + if (!eventListeners) { + return; + } + + for (let i = 0, ii = eventListeners.length; i < ii; i++) { + if (eventListeners[i].listener === listener) { + eventListeners.splice(i, 1); + return; + } + } + } + +} + +exports.EventBus = EventBus; + +class AutomationEventBus extends EventBus { + dispatch(eventName, data) { + throw new Error("Not implemented: AutomationEventBus.dispatch"); + } + +} + +exports.AutomationEventBus = AutomationEventBus; + +/***/ }), +/* 7 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFCursorTools = exports.CursorTool = void 0; + +var _grab_to_pan = __webpack_require__(8); + +var _ui_utils = __webpack_require__(1); + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +const CursorTool = { + SELECT: 0, + HAND: 1, + ZOOM: 2 +}; +exports.CursorTool = CursorTool; + +var _dispatchEvent = /*#__PURE__*/new WeakSet(); + +var _addEventListeners = /*#__PURE__*/new WeakSet(); + +class PDFCursorTools { + constructor(_ref) { + let { + container, + eventBus, + cursorToolOnLoad = CursorTool.SELECT + } = _ref; + + _classPrivateMethodInitSpec(this, _addEventListeners); + + _classPrivateMethodInitSpec(this, _dispatchEvent); + + this.container = container; + this.eventBus = eventBus; + this.active = CursorTool.SELECT; + this.activeBeforePresentationMode = null; + this.handTool = new _grab_to_pan.GrabToPan({ + element: this.container + }); + + _classPrivateMethodGet(this, _addEventListeners, _addEventListeners2).call(this); + + Promise.resolve().then(() => { + this.switchTool(cursorToolOnLoad); + }); + } + + get activeTool() { + return this.active; + } + + switchTool(tool) { + if (this.activeBeforePresentationMode !== null) { + return; + } + + if (tool === this.active) { + return; + } + + const disableActiveTool = () => { + switch (this.active) { + case CursorTool.SELECT: + break; + + case CursorTool.HAND: + this.handTool.deactivate(); + break; + + case CursorTool.ZOOM: + } + }; + + switch (tool) { + case CursorTool.SELECT: + disableActiveTool(); + break; + + case CursorTool.HAND: + disableActiveTool(); + this.handTool.activate(); + break; + + case CursorTool.ZOOM: + default: + console.error(`switchTool: "${tool}" is an unsupported value.`); + return; + } + + this.active = tool; + + _classPrivateMethodGet(this, _dispatchEvent, _dispatchEvent2).call(this); + } + +} + +exports.PDFCursorTools = PDFCursorTools; + +function _dispatchEvent2() { + this.eventBus.dispatch("cursortoolchanged", { + source: this, + tool: this.active + }); +} + +function _addEventListeners2() { + this.eventBus._on("switchcursortool", evt => { + this.switchTool(evt.tool); + }); + + this.eventBus._on("presentationmodechanged", evt => { + switch (evt.state) { + case _ui_utils.PresentationModeState.FULLSCREEN: + { + const previouslyActive = this.active; + this.switchTool(CursorTool.SELECT); + this.activeBeforePresentationMode = previouslyActive; + break; + } + + case _ui_utils.PresentationModeState.NORMAL: + { + const previouslyActive = this.activeBeforePresentationMode; + this.activeBeforePresentationMode = null; + this.switchTool(previouslyActive); + break; + } + } + }); +} + +/***/ }), +/* 8 */ +/***/ ((__unused_webpack_module, exports) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.GrabToPan = void 0; + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +const CSS_CLASS_GRAB = "grab-to-pan-grab"; + +var _onMouseDown = /*#__PURE__*/new WeakSet(); + +var _onMouseMove = /*#__PURE__*/new WeakSet(); + +var _endPan = /*#__PURE__*/new WeakSet(); + +class GrabToPan { + constructor(options) { + _classPrivateMethodInitSpec(this, _endPan); + + _classPrivateMethodInitSpec(this, _onMouseMove); + + _classPrivateMethodInitSpec(this, _onMouseDown); + + this.element = options.element; + this.document = options.element.ownerDocument; + + if (typeof options.ignoreTarget === "function") { + this.ignoreTarget = options.ignoreTarget; + } + + this.onActiveChanged = options.onActiveChanged; + this.activate = this.activate.bind(this); + this.deactivate = this.deactivate.bind(this); + this.toggle = this.toggle.bind(this); + this._onMouseDown = _classPrivateMethodGet(this, _onMouseDown, _onMouseDown2).bind(this); + this._onMouseMove = _classPrivateMethodGet(this, _onMouseMove, _onMouseMove2).bind(this); + this._endPan = _classPrivateMethodGet(this, _endPan, _endPan2).bind(this); + const overlay = this.overlay = document.createElement("div"); + overlay.className = "grab-to-pan-grabbing"; + } + + activate() { + if (!this.active) { + var _this$onActiveChanged; + + this.active = true; + this.element.addEventListener("mousedown", this._onMouseDown, true); + this.element.classList.add(CSS_CLASS_GRAB); + (_this$onActiveChanged = this.onActiveChanged) === null || _this$onActiveChanged === void 0 ? void 0 : _this$onActiveChanged.call(this, true); + } + } + + deactivate() { + if (this.active) { + var _this$onActiveChanged2; + + this.active = false; + this.element.removeEventListener("mousedown", this._onMouseDown, true); + + this._endPan(); + + this.element.classList.remove(CSS_CLASS_GRAB); + (_this$onActiveChanged2 = this.onActiveChanged) === null || _this$onActiveChanged2 === void 0 ? void 0 : _this$onActiveChanged2.call(this, false); + } + } + + toggle() { + if (this.active) { + this.deactivate(); + } else { + this.activate(); + } + } + + ignoreTarget(node) { + return node.matches("a[href], a[href] *, input, textarea, button, button *, select, option"); + } + +} + +exports.GrabToPan = GrabToPan; + +function _onMouseDown2(event) { + if (event.button !== 0 || this.ignoreTarget(event.target)) { + return; + } + + if (event.originalTarget) { + try { + event.originalTarget.tagName; + } catch (e) { + return; + } + } + + this.scrollLeftStart = this.element.scrollLeft; + this.scrollTopStart = this.element.scrollTop; + this.clientXStart = event.clientX; + this.clientYStart = event.clientY; + this.document.addEventListener("mousemove", this._onMouseMove, true); + this.document.addEventListener("mouseup", this._endPan, true); + this.element.addEventListener("scroll", this._endPan, true); + event.preventDefault(); + event.stopPropagation(); + const focusedElement = document.activeElement; + + if (focusedElement && !focusedElement.contains(event.target)) { + focusedElement.blur(); + } +} + +function _onMouseMove2(event) { + this.element.removeEventListener("scroll", this._endPan, true); + + if (!(event.buttons & 1)) { + this._endPan(); + + return; + } + + const xDiff = event.clientX - this.clientXStart; + const yDiff = event.clientY - this.clientYStart; + const scrollTop = this.scrollTopStart - yDiff; + const scrollLeft = this.scrollLeftStart - xDiff; + + if (this.element.scrollTo) { + this.element.scrollTo({ + top: scrollTop, + left: scrollLeft, + behavior: "instant" + }); + } else { + this.element.scrollTop = scrollTop; + this.element.scrollLeft = scrollLeft; + } + + if (!this.overlay.parentNode) { + document.body.append(this.overlay); + } +} + +function _endPan2() { + this.element.removeEventListener("scroll", this._endPan, true); + this.document.removeEventListener("mousemove", this._onMouseMove, true); + this.document.removeEventListener("mouseup", this._endPan, true); + this.overlay.remove(); +} + +/***/ }), +/* 9 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.AnnotationEditorParams = void 0; + +var _pdfjsLib = __webpack_require__(5); + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +var _bindListeners = /*#__PURE__*/new WeakSet(); + +class AnnotationEditorParams { + constructor(options, eventBus) { + _classPrivateMethodInitSpec(this, _bindListeners); + + this.eventBus = eventBus; + + _classPrivateMethodGet(this, _bindListeners, _bindListeners2).call(this, options); + } + +} + +exports.AnnotationEditorParams = AnnotationEditorParams; + +function _bindListeners2(_ref) { + let { + editorFreeTextFontSize, + editorFreeTextColor, + editorInkColor, + editorInkThickness, + editorInkOpacity + } = _ref; + editorFreeTextFontSize.addEventListener("input", evt => { + this.eventBus.dispatch("switchannotationeditorparams", { + source: this, + type: _pdfjsLib.AnnotationEditorParamsType.FREETEXT_SIZE, + value: editorFreeTextFontSize.valueAsNumber + }); + }); + editorFreeTextColor.addEventListener("input", evt => { + this.eventBus.dispatch("switchannotationeditorparams", { + source: this, + type: _pdfjsLib.AnnotationEditorParamsType.FREETEXT_COLOR, + value: editorFreeTextColor.value + }); + }); + editorInkColor.addEventListener("input", evt => { + this.eventBus.dispatch("switchannotationeditorparams", { + source: this, + type: _pdfjsLib.AnnotationEditorParamsType.INK_COLOR, + value: editorInkColor.value + }); + }); + editorInkThickness.addEventListener("input", evt => { + this.eventBus.dispatch("switchannotationeditorparams", { + source: this, + type: _pdfjsLib.AnnotationEditorParamsType.INK_THICKNESS, + value: editorInkThickness.valueAsNumber + }); + }); + editorInkOpacity.addEventListener("input", evt => { + this.eventBus.dispatch("switchannotationeditorparams", { + source: this, + type: _pdfjsLib.AnnotationEditorParamsType.INK_OPACITY, + value: editorInkOpacity.valueAsNumber + }); + }); + + this.eventBus._on("annotationeditorparamschanged", evt => { + for (const [type, value] of evt.details) { + switch (type) { + case _pdfjsLib.AnnotationEditorParamsType.FREETEXT_SIZE: + editorFreeTextFontSize.value = value; + break; + + case _pdfjsLib.AnnotationEditorParamsType.FREETEXT_COLOR: + editorFreeTextColor.value = value; + break; + + case _pdfjsLib.AnnotationEditorParamsType.INK_COLOR: + editorInkColor.value = value; + break; + + case _pdfjsLib.AnnotationEditorParamsType.INK_THICKNESS: + editorInkThickness.value = value; + break; + + case _pdfjsLib.AnnotationEditorParamsType.INK_OPACITY: + editorInkOpacity.value = value; + break; + } + } + }); +} + +/***/ }), +/* 10 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.OverlayManager = void 0; + +function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } + +function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } + +function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +var _overlays = /*#__PURE__*/new WeakMap(); + +var _active = /*#__PURE__*/new WeakMap(); + +class OverlayManager { + constructor() { + _classPrivateFieldInitSpec(this, _overlays, { + writable: true, + value: new WeakMap() + }); + + _classPrivateFieldInitSpec(this, _active, { + writable: true, + value: null + }); + } + + get active() { + return _classPrivateFieldGet(this, _active); + } + + async register(dialog) { + let canForceClose = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + if (typeof dialog !== "object") { + throw new Error("Not enough parameters."); + } else if (_classPrivateFieldGet(this, _overlays).has(dialog)) { + throw new Error("The overlay is already registered."); + } + + _classPrivateFieldGet(this, _overlays).set(dialog, { + canForceClose + }); + + if (!dialog.showModal) { + const dialogPolyfill = __webpack_require__(11); + + dialogPolyfill.registerDialog(dialog); + + if (!this._dialogPolyfillCSS) { + this._dialogPolyfillCSS = true; + const style = document.createElement("style"); + style.textContent = 'dialog {\n position: absolute;\n left: 0; right: 0;\n width: -moz-fit-content;\n width: -webkit-fit-content;\n width: fit-content;\n height: -moz-fit-content;\n height: -webkit-fit-content;\n height: fit-content;\n margin: auto;\n border: solid;\n padding: 1em;\n background: white;\n color: black;\n display: block;\n}\n\ndialog:not([open]) {\n display: none;\n}\n\ndialog + .backdrop {\n position: fixed;\n top: 0; right: 0; bottom: 0; left: 0;\n background: rgba(0,0,0,0.1);\n}\n\n._dialog_overlay {\n position: fixed;\n top: 0; right: 0; bottom: 0; left: 0;\n}\n\ndialog.fixed {\n position: fixed;\n top: 50%;\n transform: translate(0, -50%);\n}'; + document.head.prepend(style); + } + } + + dialog.addEventListener("cancel", evt => { + _classPrivateFieldSet(this, _active, null); + }); + } + + async unregister(dialog) { + if (!_classPrivateFieldGet(this, _overlays).has(dialog)) { + throw new Error("The overlay does not exist."); + } else if (_classPrivateFieldGet(this, _active) === dialog) { + throw new Error("The overlay cannot be removed while it is active."); + } + + _classPrivateFieldGet(this, _overlays).delete(dialog); + } + + async open(dialog) { + if (!_classPrivateFieldGet(this, _overlays).has(dialog)) { + throw new Error("The overlay does not exist."); + } else if (_classPrivateFieldGet(this, _active)) { + if (_classPrivateFieldGet(this, _active) === dialog) { + throw new Error("The overlay is already active."); + } else if (_classPrivateFieldGet(this, _overlays).get(dialog).canForceClose) { + await this.close(); + } else { + throw new Error("Another overlay is currently active."); + } + } + + _classPrivateFieldSet(this, _active, dialog); + + dialog.showModal(); + } + + async close() { + let dialog = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _classPrivateFieldGet(this, _active); + + if (!_classPrivateFieldGet(this, _overlays).has(dialog)) { + throw new Error("The overlay does not exist."); + } else if (!_classPrivateFieldGet(this, _active)) { + throw new Error("The overlay is currently not active."); + } else if (_classPrivateFieldGet(this, _active) !== dialog) { + throw new Error("Another overlay is currently active."); + } + + dialog.close(); + + _classPrivateFieldSet(this, _active, null); + } + +} + +exports.OverlayManager = OverlayManager; + +/***/ }), +/* 11 */ +/***/ ((module) => { + + + +(function (global, factory) { + true ? module.exports = factory() : 0; +})(void 0, function () { + 'use strict'; + + var supportCustomEvent = window.CustomEvent; + + if (!supportCustomEvent || typeof supportCustomEvent === 'object') { + supportCustomEvent = function CustomEvent(event, x) { + x = x || {}; + var ev = document.createEvent('CustomEvent'); + ev.initCustomEvent(event, !!x.bubbles, !!x.cancelable, x.detail || null); + return ev; + }; + + supportCustomEvent.prototype = window.Event.prototype; + } + + function safeDispatchEvent(target, event) { + var check = 'on' + event.type.toLowerCase(); + + if (typeof target[check] === 'function') { + target[check](event); + } + + return target.dispatchEvent(event); + } + + function createsStackingContext(el) { + while (el && el !== document.body) { + var s = window.getComputedStyle(el); + + var invalid = function (k, ok) { + return !(s[k] === undefined || s[k] === ok); + }; + + if (s.opacity < 1 || invalid('zIndex', 'auto') || invalid('transform', 'none') || invalid('mixBlendMode', 'normal') || invalid('filter', 'none') || invalid('perspective', 'none') || s['isolation'] === 'isolate' || s.position === 'fixed' || s.webkitOverflowScrolling === 'touch') { + return true; + } + + el = el.parentElement; + } + + return false; + } + + function findNearestDialog(el) { + while (el) { + if (el.localName === 'dialog') { + return el; + } + + if (el.parentElement) { + el = el.parentElement; + } else if (el.parentNode) { + el = el.parentNode.host; + } else { + el = null; + } + } + + return null; + } + + function safeBlur(el) { + while (el && el.shadowRoot && el.shadowRoot.activeElement) { + el = el.shadowRoot.activeElement; + } + + if (el && el.blur && el !== document.body) { + el.blur(); + } + } + + function inNodeList(nodeList, node) { + for (var i = 0; i < nodeList.length; ++i) { + if (nodeList[i] === node) { + return true; + } + } + + return false; + } + + function isFormMethodDialog(el) { + if (!el || !el.hasAttribute('method')) { + return false; + } + + return el.getAttribute('method').toLowerCase() === 'dialog'; + } + + function findFocusableElementWithin(hostElement) { + var opts = ['button', 'input', 'keygen', 'select', 'textarea']; + var query = opts.map(function (el) { + return el + ':not([disabled])'; + }); + query.push('[tabindex]:not([disabled]):not([tabindex=""])'); + var target = hostElement.querySelector(query.join(', ')); + + if (!target && 'attachShadow' in Element.prototype) { + var elems = hostElement.querySelectorAll('*'); + + for (var i = 0; i < elems.length; i++) { + if (elems[i].tagName && elems[i].shadowRoot) { + target = findFocusableElementWithin(elems[i].shadowRoot); + + if (target) { + break; + } + } + } + } + + return target; + } + + function isConnected(element) { + return element.isConnected || document.body.contains(element); + } + + function findFormSubmitter(event) { + if (event.submitter) { + return event.submitter; + } + + var form = event.target; + + if (!(form instanceof HTMLFormElement)) { + return null; + } + + var submitter = dialogPolyfill.formSubmitter; + + if (!submitter) { + var target = event.target; + var root = 'getRootNode' in target && target.getRootNode() || document; + submitter = root.activeElement; + } + + if (!submitter || submitter.form !== form) { + return null; + } + + return submitter; + } + + function maybeHandleSubmit(event) { + if (event.defaultPrevented) { + return; + } + + var form = event.target; + var value = dialogPolyfill.imagemapUseValue; + var submitter = findFormSubmitter(event); + + if (value === null && submitter) { + value = submitter.value; + } + + var dialog = findNearestDialog(form); + + if (!dialog) { + return; + } + + var formmethod = submitter && submitter.getAttribute('formmethod') || form.getAttribute('method'); + + if (formmethod !== 'dialog') { + return; + } + + event.preventDefault(); + + if (value != null) { + dialog.close(value); + } else { + dialog.close(); + } + } + + function dialogPolyfillInfo(dialog) { + this.dialog_ = dialog; + this.replacedStyleTop_ = false; + this.openAsModal_ = false; + + if (!dialog.hasAttribute('role')) { + dialog.setAttribute('role', 'dialog'); + } + + dialog.show = this.show.bind(this); + dialog.showModal = this.showModal.bind(this); + dialog.close = this.close.bind(this); + dialog.addEventListener('submit', maybeHandleSubmit, false); + + if (!('returnValue' in dialog)) { + dialog.returnValue = ''; + } + + if ('MutationObserver' in window) { + var mo = new MutationObserver(this.maybeHideModal.bind(this)); + mo.observe(dialog, { + attributes: true, + attributeFilter: ['open'] + }); + } else { + var removed = false; + + var cb = function () { + removed ? this.downgradeModal() : this.maybeHideModal(); + removed = false; + }.bind(this); + + var timeout; + + var delayModel = function (ev) { + if (ev.target !== dialog) { + return; + } + + var cand = 'DOMNodeRemoved'; + removed |= ev.type.substr(0, cand.length) === cand; + window.clearTimeout(timeout); + timeout = window.setTimeout(cb, 0); + }; + + ['DOMAttrModified', 'DOMNodeRemoved', 'DOMNodeRemovedFromDocument'].forEach(function (name) { + dialog.addEventListener(name, delayModel); + }); + } + + Object.defineProperty(dialog, 'open', { + set: this.setOpen.bind(this), + get: dialog.hasAttribute.bind(dialog, 'open') + }); + this.backdrop_ = document.createElement('div'); + this.backdrop_.className = 'backdrop'; + this.backdrop_.addEventListener('mouseup', this.backdropMouseEvent_.bind(this)); + this.backdrop_.addEventListener('mousedown', this.backdropMouseEvent_.bind(this)); + this.backdrop_.addEventListener('click', this.backdropMouseEvent_.bind(this)); + } + + dialogPolyfillInfo.prototype = { + get dialog() { + return this.dialog_; + }, + + maybeHideModal: function () { + if (this.dialog_.hasAttribute('open') && isConnected(this.dialog_)) { + return; + } + + this.downgradeModal(); + }, + downgradeModal: function () { + if (!this.openAsModal_) { + return; + } + + this.openAsModal_ = false; + this.dialog_.style.zIndex = ''; + + if (this.replacedStyleTop_) { + this.dialog_.style.top = ''; + this.replacedStyleTop_ = false; + } + + this.backdrop_.parentNode && this.backdrop_.parentNode.removeChild(this.backdrop_); + dialogPolyfill.dm.removeDialog(this); + }, + setOpen: function (value) { + if (value) { + this.dialog_.hasAttribute('open') || this.dialog_.setAttribute('open', ''); + } else { + this.dialog_.removeAttribute('open'); + this.maybeHideModal(); + } + }, + backdropMouseEvent_: function (e) { + if (!this.dialog_.hasAttribute('tabindex')) { + var fake = document.createElement('div'); + this.dialog_.insertBefore(fake, this.dialog_.firstChild); + fake.tabIndex = -1; + fake.focus(); + this.dialog_.removeChild(fake); + } else { + this.dialog_.focus(); + } + + var redirectedEvent = document.createEvent('MouseEvents'); + redirectedEvent.initMouseEvent(e.type, e.bubbles, e.cancelable, window, e.detail, e.screenX, e.screenY, e.clientX, e.clientY, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget); + this.dialog_.dispatchEvent(redirectedEvent); + e.stopPropagation(); + }, + focus_: function () { + var target = this.dialog_.querySelector('[autofocus]:not([disabled])'); + + if (!target && this.dialog_.tabIndex >= 0) { + target = this.dialog_; + } + + if (!target) { + target = findFocusableElementWithin(this.dialog_); + } + + safeBlur(document.activeElement); + target && target.focus(); + }, + updateZIndex: function (dialogZ, backdropZ) { + if (dialogZ < backdropZ) { + throw new Error('dialogZ should never be < backdropZ'); + } + + this.dialog_.style.zIndex = dialogZ; + this.backdrop_.style.zIndex = backdropZ; + }, + show: function () { + if (!this.dialog_.open) { + this.setOpen(true); + this.focus_(); + } + }, + showModal: function () { + if (this.dialog_.hasAttribute('open')) { + throw new Error('Failed to execute \'showModal\' on dialog: The element is already open, and therefore cannot be opened modally.'); + } + + if (!isConnected(this.dialog_)) { + throw new Error('Failed to execute \'showModal\' on dialog: The element is not in a Document.'); + } + + if (!dialogPolyfill.dm.pushDialog(this)) { + throw new Error('Failed to execute \'showModal\' on dialog: There are too many open modal dialogs.'); + } + + if (createsStackingContext(this.dialog_.parentElement)) { + console.warn('A dialog is being shown inside a stacking context. ' + 'This may cause it to be unusable. For more information, see this link: ' + 'https://github.com/GoogleChrome/dialog-polyfill/#stacking-context'); + } + + this.setOpen(true); + this.openAsModal_ = true; + + if (dialogPolyfill.needsCentering(this.dialog_)) { + dialogPolyfill.reposition(this.dialog_); + this.replacedStyleTop_ = true; + } else { + this.replacedStyleTop_ = false; + } + + this.dialog_.parentNode.insertBefore(this.backdrop_, this.dialog_.nextSibling); + this.focus_(); + }, + close: function (opt_returnValue) { + if (!this.dialog_.hasAttribute('open')) { + throw new Error('Failed to execute \'close\' on dialog: The element does not have an \'open\' attribute, and therefore cannot be closed.'); + } + + this.setOpen(false); + + if (opt_returnValue !== undefined) { + this.dialog_.returnValue = opt_returnValue; + } + + var closeEvent = new supportCustomEvent('close', { + bubbles: false, + cancelable: false + }); + safeDispatchEvent(this.dialog_, closeEvent); + } + }; + var dialogPolyfill = {}; + + dialogPolyfill.reposition = function (element) { + var scrollTop = document.body.scrollTop || document.documentElement.scrollTop; + var topValue = scrollTop + (window.innerHeight - element.offsetHeight) / 2; + element.style.top = Math.max(scrollTop, topValue) + 'px'; + }; + + dialogPolyfill.isInlinePositionSetByStylesheet = function (element) { + for (var i = 0; i < document.styleSheets.length; ++i) { + var styleSheet = document.styleSheets[i]; + var cssRules = null; + + try { + cssRules = styleSheet.cssRules; + } catch (e) {} + + if (!cssRules) { + continue; + } + + for (var j = 0; j < cssRules.length; ++j) { + var rule = cssRules[j]; + var selectedNodes = null; + + try { + selectedNodes = document.querySelectorAll(rule.selectorText); + } catch (e) {} + + if (!selectedNodes || !inNodeList(selectedNodes, element)) { + continue; + } + + var cssTop = rule.style.getPropertyValue('top'); + var cssBottom = rule.style.getPropertyValue('bottom'); + + if (cssTop && cssTop !== 'auto' || cssBottom && cssBottom !== 'auto') { + return true; + } + } + } + + return false; + }; + + dialogPolyfill.needsCentering = function (dialog) { + var computedStyle = window.getComputedStyle(dialog); + + if (computedStyle.position !== 'absolute') { + return false; + } + + if (dialog.style.top !== 'auto' && dialog.style.top !== '' || dialog.style.bottom !== 'auto' && dialog.style.bottom !== '') { + return false; + } + + return !dialogPolyfill.isInlinePositionSetByStylesheet(dialog); + }; + + dialogPolyfill.forceRegisterDialog = function (element) { + if (window.HTMLDialogElement || element.showModal) { + console.warn('This browser already supports , the polyfill ' + 'may not work correctly', element); + } + + if (element.localName !== 'dialog') { + throw new Error('Failed to register dialog: The element is not a dialog.'); + } + + new dialogPolyfillInfo(element); + }; + + dialogPolyfill.registerDialog = function (element) { + if (!element.showModal) { + dialogPolyfill.forceRegisterDialog(element); + } + }; + + dialogPolyfill.DialogManager = function () { + this.pendingDialogStack = []; + var checkDOM = this.checkDOM_.bind(this); + this.overlay = document.createElement('div'); + this.overlay.className = '_dialog_overlay'; + this.overlay.addEventListener('click', function (e) { + this.forwardTab_ = undefined; + e.stopPropagation(); + checkDOM([]); + }.bind(this)); + this.handleKey_ = this.handleKey_.bind(this); + this.handleFocus_ = this.handleFocus_.bind(this); + this.zIndexLow_ = 100000; + this.zIndexHigh_ = 100000 + 150; + this.forwardTab_ = undefined; + + if ('MutationObserver' in window) { + this.mo_ = new MutationObserver(function (records) { + var removed = []; + records.forEach(function (rec) { + for (var i = 0, c; c = rec.removedNodes[i]; ++i) { + if (!(c instanceof Element)) { + continue; + } else if (c.localName === 'dialog') { + removed.push(c); + } + + removed = removed.concat(c.querySelectorAll('dialog')); + } + }); + removed.length && checkDOM(removed); + }); + } + }; + + dialogPolyfill.DialogManager.prototype.blockDocument = function () { + document.documentElement.addEventListener('focus', this.handleFocus_, true); + document.addEventListener('keydown', this.handleKey_); + this.mo_ && this.mo_.observe(document, { + childList: true, + subtree: true + }); + }; + + dialogPolyfill.DialogManager.prototype.unblockDocument = function () { + document.documentElement.removeEventListener('focus', this.handleFocus_, true); + document.removeEventListener('keydown', this.handleKey_); + this.mo_ && this.mo_.disconnect(); + }; + + dialogPolyfill.DialogManager.prototype.updateStacking = function () { + var zIndex = this.zIndexHigh_; + + for (var i = 0, dpi; dpi = this.pendingDialogStack[i]; ++i) { + dpi.updateZIndex(--zIndex, --zIndex); + + if (i === 0) { + this.overlay.style.zIndex = --zIndex; + } + } + + var last = this.pendingDialogStack[0]; + + if (last) { + var p = last.dialog.parentNode || document.body; + p.appendChild(this.overlay); + } else if (this.overlay.parentNode) { + this.overlay.parentNode.removeChild(this.overlay); + } + }; + + dialogPolyfill.DialogManager.prototype.containedByTopDialog_ = function (candidate) { + while (candidate = findNearestDialog(candidate)) { + for (var i = 0, dpi; dpi = this.pendingDialogStack[i]; ++i) { + if (dpi.dialog === candidate) { + return i === 0; + } + } + + candidate = candidate.parentElement; + } + + return false; + }; + + dialogPolyfill.DialogManager.prototype.handleFocus_ = function (event) { + var target = event.composedPath ? event.composedPath()[0] : event.target; + + if (this.containedByTopDialog_(target)) { + return; + } + + if (document.activeElement === document.documentElement) { + return; + } + + event.preventDefault(); + event.stopPropagation(); + safeBlur(target); + + if (this.forwardTab_ === undefined) { + return; + } + + var dpi = this.pendingDialogStack[0]; + var dialog = dpi.dialog; + var position = dialog.compareDocumentPosition(target); + + if (position & Node.DOCUMENT_POSITION_PRECEDING) { + if (this.forwardTab_) { + dpi.focus_(); + } else if (target !== document.documentElement) { + document.documentElement.focus(); + } + } + + return false; + }; + + dialogPolyfill.DialogManager.prototype.handleKey_ = function (event) { + this.forwardTab_ = undefined; + + if (event.keyCode === 27) { + event.preventDefault(); + event.stopPropagation(); + var cancelEvent = new supportCustomEvent('cancel', { + bubbles: false, + cancelable: true + }); + var dpi = this.pendingDialogStack[0]; + + if (dpi && safeDispatchEvent(dpi.dialog, cancelEvent)) { + dpi.dialog.close(); + } + } else if (event.keyCode === 9) { + this.forwardTab_ = !event.shiftKey; + } + }; + + dialogPolyfill.DialogManager.prototype.checkDOM_ = function (removed) { + var clone = this.pendingDialogStack.slice(); + clone.forEach(function (dpi) { + if (removed.indexOf(dpi.dialog) !== -1) { + dpi.downgradeModal(); + } else { + dpi.maybeHideModal(); + } + }); + }; + + dialogPolyfill.DialogManager.prototype.pushDialog = function (dpi) { + var allowed = (this.zIndexHigh_ - this.zIndexLow_) / 2 - 1; + + if (this.pendingDialogStack.length >= allowed) { + return false; + } + + if (this.pendingDialogStack.unshift(dpi) === 1) { + this.blockDocument(); + } + + this.updateStacking(); + return true; + }; + + dialogPolyfill.DialogManager.prototype.removeDialog = function (dpi) { + var index = this.pendingDialogStack.indexOf(dpi); + + if (index === -1) { + return; + } + + this.pendingDialogStack.splice(index, 1); + + if (this.pendingDialogStack.length === 0) { + this.unblockDocument(); + } + + this.updateStacking(); + }; + + dialogPolyfill.dm = new dialogPolyfill.DialogManager(); + dialogPolyfill.formSubmitter = null; + dialogPolyfill.imagemapUseValue = null; + + if (window.HTMLDialogElement === undefined) { + var testForm = document.createElement('form'); + testForm.setAttribute('method', 'dialog'); + + if (testForm.method !== 'dialog') { + var methodDescriptor = Object.getOwnPropertyDescriptor(HTMLFormElement.prototype, 'method'); + + if (methodDescriptor) { + var realGet = methodDescriptor.get; + + methodDescriptor.get = function () { + if (isFormMethodDialog(this)) { + return 'dialog'; + } + + return realGet.call(this); + }; + + var realSet = methodDescriptor.set; + + methodDescriptor.set = function (v) { + if (typeof v === 'string' && v.toLowerCase() === 'dialog') { + return this.setAttribute('method', v); + } + + return realSet.call(this, v); + }; + + Object.defineProperty(HTMLFormElement.prototype, 'method', methodDescriptor); + } + } + + document.addEventListener('click', function (ev) { + dialogPolyfill.formSubmitter = null; + dialogPolyfill.imagemapUseValue = null; + + if (ev.defaultPrevented) { + return; + } + + var target = ev.target; + + if ('composedPath' in ev) { + var path = ev.composedPath(); + target = path.shift() || target; + } + + if (!target || !isFormMethodDialog(target.form)) { + return; + } + + var valid = target.type === 'submit' && ['button', 'input'].indexOf(target.localName) > -1; + + if (!valid) { + if (!(target.localName === 'input' && target.type === 'image')) { + return; + } + + dialogPolyfill.imagemapUseValue = ev.offsetX + ',' + ev.offsetY; + } + + var dialog = findNearestDialog(target); + + if (!dialog) { + return; + } + + dialogPolyfill.formSubmitter = target; + }, false); + document.addEventListener('submit', function (ev) { + var form = ev.target; + var dialog = findNearestDialog(form); + + if (dialog) { + return; + } + + var submitter = findFormSubmitter(ev); + var formmethod = submitter && submitter.getAttribute('formmethod') || form.getAttribute('method'); + + if (formmethod === 'dialog') { + ev.preventDefault(); + } + }); + var nativeFormSubmit = HTMLFormElement.prototype.submit; + + var replacementFormSubmit = function () { + if (!isFormMethodDialog(this)) { + return nativeFormSubmit.call(this); + } + + var dialog = findNearestDialog(this); + dialog && dialog.close(); + }; + + HTMLFormElement.prototype.submit = replacementFormSubmit; + } + + return dialogPolyfill; +}); + +/***/ }), +/* 12 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PasswordPrompt = void 0; + +var _pdfjsLib = __webpack_require__(5); + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } + +function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } + +function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +var _activeCapability = /*#__PURE__*/new WeakMap(); + +var _updateCallback = /*#__PURE__*/new WeakMap(); + +var _reason = /*#__PURE__*/new WeakMap(); + +var _verify = /*#__PURE__*/new WeakSet(); + +var _cancel = /*#__PURE__*/new WeakSet(); + +var _invokeCallback = /*#__PURE__*/new WeakSet(); + +class PasswordPrompt { + constructor(options, overlayManager, l10n) { + let isViewerEmbedded = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; + + _classPrivateMethodInitSpec(this, _invokeCallback); + + _classPrivateMethodInitSpec(this, _cancel); + + _classPrivateMethodInitSpec(this, _verify); + + _classPrivateFieldInitSpec(this, _activeCapability, { + writable: true, + value: null + }); + + _classPrivateFieldInitSpec(this, _updateCallback, { + writable: true, + value: null + }); + + _classPrivateFieldInitSpec(this, _reason, { + writable: true, + value: null + }); + + this.dialog = options.dialog; + this.label = options.label; + this.input = options.input; + this.submitButton = options.submitButton; + this.cancelButton = options.cancelButton; + this.overlayManager = overlayManager; + this.l10n = l10n; + this._isViewerEmbedded = isViewerEmbedded; + this.submitButton.addEventListener("click", _classPrivateMethodGet(this, _verify, _verify2).bind(this)); + this.cancelButton.addEventListener("click", this.close.bind(this)); + this.input.addEventListener("keydown", e => { + if (e.keyCode === 13) { + _classPrivateMethodGet(this, _verify, _verify2).call(this); + } + }); + this.overlayManager.register(this.dialog, true); + this.dialog.addEventListener("close", _classPrivateMethodGet(this, _cancel, _cancel2).bind(this)); + } + + async open() { + if (_classPrivateFieldGet(this, _activeCapability)) { + await _classPrivateFieldGet(this, _activeCapability).promise; + } + + _classPrivateFieldSet(this, _activeCapability, (0, _pdfjsLib.createPromiseCapability)()); + + try { + await this.overlayManager.open(this.dialog); + } catch (ex) { + _classPrivateFieldSet(this, _activeCapability, null); + + throw ex; + } + + const passwordIncorrect = _classPrivateFieldGet(this, _reason) === _pdfjsLib.PasswordResponses.INCORRECT_PASSWORD; + + if (!this._isViewerEmbedded || passwordIncorrect) { + this.input.focus(); + } + + this.label.textContent = await this.l10n.get(`password_${passwordIncorrect ? "invalid" : "label"}`); + } + + async close() { + if (this.overlayManager.active === this.dialog) { + this.overlayManager.close(this.dialog); + } + } + + async setUpdateCallback(updateCallback, reason) { + if (_classPrivateFieldGet(this, _activeCapability)) { + await _classPrivateFieldGet(this, _activeCapability).promise; + } + + _classPrivateFieldSet(this, _updateCallback, updateCallback); + + _classPrivateFieldSet(this, _reason, reason); + } + +} + +exports.PasswordPrompt = PasswordPrompt; + +function _verify2() { + const password = this.input.value; + + if ((password === null || password === void 0 ? void 0 : password.length) > 0) { + _classPrivateMethodGet(this, _invokeCallback, _invokeCallback2).call(this, password); + } +} + +function _cancel2() { + _classPrivateMethodGet(this, _invokeCallback, _invokeCallback2).call(this, new Error("PasswordPrompt cancelled.")); + + _classPrivateFieldGet(this, _activeCapability).resolve(); +} + +function _invokeCallback2(password) { + if (!_classPrivateFieldGet(this, _updateCallback)) { + return; + } + + this.close(); + this.input.value = ""; + + _classPrivateFieldGet(this, _updateCallback).call(this, password); + + _classPrivateFieldSet(this, _updateCallback, null); +} + +/***/ }), +/* 13 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFAttachmentViewer = void 0; + +var _pdfjsLib = __webpack_require__(5); + +var _base_tree_viewer = __webpack_require__(14); + +var _event_utils = __webpack_require__(6); + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +var _appendAttachment = /*#__PURE__*/new WeakSet(); + +class PDFAttachmentViewer extends _base_tree_viewer.BaseTreeViewer { + constructor(options) { + super(options); + + _classPrivateMethodInitSpec(this, _appendAttachment); + + this.downloadManager = options.downloadManager; + + this.eventBus._on("fileattachmentannotation", _classPrivateMethodGet(this, _appendAttachment, _appendAttachment2).bind(this)); + } + + reset() { + let keepRenderedCapability = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + super.reset(); + this._attachments = null; + + if (!keepRenderedCapability) { + this._renderedCapability = (0, _pdfjsLib.createPromiseCapability)(); + } + + this._pendingDispatchEvent = false; + } + + async _dispatchEvent(attachmentsCount) { + this._renderedCapability.resolve(); + + if (attachmentsCount === 0 && !this._pendingDispatchEvent) { + this._pendingDispatchEvent = true; + await (0, _event_utils.waitOnEventOrTimeout)({ + target: this.eventBus, + name: "annotationlayerrendered", + delay: 1000 + }); + + if (!this._pendingDispatchEvent) { + return; + } + } + + this._pendingDispatchEvent = false; + this.eventBus.dispatch("attachmentsloaded", { + source: this, + attachmentsCount + }); + } + + _bindLink(element, _ref) { + let { + content, + filename + } = _ref; + + element.onclick = () => { + this.downloadManager.openOrDownloadData(element, content, filename); + return false; + }; + } + + render(_ref2) { + let { + attachments, + keepRenderedCapability = false + } = _ref2; + + if (this._attachments) { + this.reset(keepRenderedCapability); + } + + this._attachments = attachments || null; + + if (!attachments) { + this._dispatchEvent(0); + + return; + } + + const names = Object.keys(attachments).sort(function (a, b) { + return a.toLowerCase().localeCompare(b.toLowerCase()); + }); + const fragment = document.createDocumentFragment(); + let attachmentsCount = 0; + + for (const name of names) { + const item = attachments[name]; + const content = item.content, + filename = (0, _pdfjsLib.getFilenameFromUrl)(item.filename); + const div = document.createElement("div"); + div.className = "treeItem"; + const element = document.createElement("a"); + + this._bindLink(element, { + content, + filename + }); + + element.textContent = this._normalizeTextContent(filename); + div.append(element); + fragment.append(div); + attachmentsCount++; + } + + this._finishRendering(fragment, attachmentsCount); + } + +} + +exports.PDFAttachmentViewer = PDFAttachmentViewer; + +function _appendAttachment2(_ref3) { + let { + filename, + content + } = _ref3; + const renderedPromise = this._renderedCapability.promise; + renderedPromise.then(() => { + if (renderedPromise !== this._renderedCapability.promise) { + return; + } + + const attachments = this._attachments || Object.create(null); + + for (const name in attachments) { + if (filename === name) { + return; + } + } + + attachments[filename] = { + filename, + content + }; + this.render({ + attachments, + keepRenderedCapability: true + }); + }); +} + +/***/ }), +/* 14 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.BaseTreeViewer = void 0; + +var _ui_utils = __webpack_require__(1); + +const TREEITEM_OFFSET_TOP = -100; +const TREEITEM_SELECTED_CLASS = "selected"; + +class BaseTreeViewer { + constructor(options) { + if (this.constructor === BaseTreeViewer) { + throw new Error("Cannot initialize BaseTreeViewer."); + } + + this.container = options.container; + this.eventBus = options.eventBus; + this.reset(); + } + + reset() { + this._pdfDocument = null; + this._lastToggleIsShow = true; + this._currentTreeItem = null; + this.container.textContent = ""; + this.container.classList.remove("treeWithDeepNesting"); + } + + _dispatchEvent(count) { + throw new Error("Not implemented: _dispatchEvent"); + } + + _bindLink(element, params) { + throw new Error("Not implemented: _bindLink"); + } + + _normalizeTextContent(str) { + return (0, _ui_utils.removeNullCharacters)(str, true) || "\u2013"; + } + + _addToggleButton(div) { + let hidden = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + const toggler = document.createElement("div"); + toggler.className = "treeItemToggler"; + + if (hidden) { + toggler.classList.add("treeItemsHidden"); + } + + toggler.onclick = evt => { + evt.stopPropagation(); + toggler.classList.toggle("treeItemsHidden"); + + if (evt.shiftKey) { + const shouldShowAll = !toggler.classList.contains("treeItemsHidden"); + + this._toggleTreeItem(div, shouldShowAll); + } + }; + + div.prepend(toggler); + } + + _toggleTreeItem(root) { + let show = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + this._lastToggleIsShow = show; + + for (const toggler of root.querySelectorAll(".treeItemToggler")) { + toggler.classList.toggle("treeItemsHidden", !show); + } + } + + _toggleAllTreeItems() { + this._toggleTreeItem(this.container, !this._lastToggleIsShow); + } + + _finishRendering(fragment, count) { + let hasAnyNesting = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + + if (hasAnyNesting) { + this.container.classList.add("treeWithDeepNesting"); + this._lastToggleIsShow = !fragment.querySelector(".treeItemsHidden"); + } + + this.container.append(fragment); + + this._dispatchEvent(count); + } + + render(params) { + throw new Error("Not implemented: render"); + } + + _updateCurrentTreeItem() { + let treeItem = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + + if (this._currentTreeItem) { + this._currentTreeItem.classList.remove(TREEITEM_SELECTED_CLASS); + + this._currentTreeItem = null; + } + + if (treeItem) { + treeItem.classList.add(TREEITEM_SELECTED_CLASS); + this._currentTreeItem = treeItem; + } + } + + _scrollToCurrentTreeItem(treeItem) { + if (!treeItem) { + return; + } + + let currentNode = treeItem.parentNode; + + while (currentNode && currentNode !== this.container) { + if (currentNode.classList.contains("treeItem")) { + const toggler = currentNode.firstElementChild; + toggler === null || toggler === void 0 ? void 0 : toggler.classList.remove("treeItemsHidden"); + } + + currentNode = currentNode.parentNode; + } + + this._updateCurrentTreeItem(treeItem); + + this.container.scrollTo(treeItem.offsetLeft, treeItem.offsetTop + TREEITEM_OFFSET_TOP); + } + +} + +exports.BaseTreeViewer = BaseTreeViewer; + +/***/ }), +/* 15 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFDocumentProperties = void 0; + +var _pdfjsLib = __webpack_require__(5); + +var _ui_utils = __webpack_require__(1); + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } + +function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } + +function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +const DEFAULT_FIELD_CONTENT = "-"; +const NON_METRIC_LOCALES = ["en-us", "en-lr", "my"]; +const US_PAGE_NAMES = { + "8.5x11": "Letter", + "8.5x14": "Legal" +}; +const METRIC_PAGE_NAMES = { + "297x420": "A3", + "210x297": "A4" +}; + +function getPageName(size, isPortrait, pageNames) { + const width = isPortrait ? size.width : size.height; + const height = isPortrait ? size.height : size.width; + return pageNames[`${width}x${height}`]; +} + +var _fieldData = /*#__PURE__*/new WeakMap(); + +var _reset = /*#__PURE__*/new WeakSet(); + +var _updateUI = /*#__PURE__*/new WeakSet(); + +var _parseFileSize = /*#__PURE__*/new WeakSet(); + +var _parsePageSize = /*#__PURE__*/new WeakSet(); + +var _parseDate = /*#__PURE__*/new WeakSet(); + +var _parseLinearization = /*#__PURE__*/new WeakSet(); + +class PDFDocumentProperties { + constructor(_ref, overlayManager, eventBus, l10n, fileNameLookup) { + let { + dialog, + fields, + closeButton + } = _ref; + + _classPrivateMethodInitSpec(this, _parseLinearization); + + _classPrivateMethodInitSpec(this, _parseDate); + + _classPrivateMethodInitSpec(this, _parsePageSize); + + _classPrivateMethodInitSpec(this, _parseFileSize); + + _classPrivateMethodInitSpec(this, _updateUI); + + _classPrivateMethodInitSpec(this, _reset); + + _classPrivateFieldInitSpec(this, _fieldData, { + writable: true, + value: null + }); + + this.dialog = dialog; + this.fields = fields; + this.overlayManager = overlayManager; + this.l10n = l10n; + this._fileNameLookup = fileNameLookup; + + _classPrivateMethodGet(this, _reset, _reset2).call(this); + + closeButton.addEventListener("click", this.close.bind(this)); + this.overlayManager.register(this.dialog); + + eventBus._on("pagechanging", evt => { + this._currentPageNumber = evt.pageNumber; + }); + + eventBus._on("rotationchanging", evt => { + this._pagesRotation = evt.pagesRotation; + }); + + this._isNonMetricLocale = true; + l10n.getLanguage().then(locale => { + this._isNonMetricLocale = NON_METRIC_LOCALES.includes(locale); + }); + } + + async open() { + await Promise.all([this.overlayManager.open(this.dialog), this._dataAvailableCapability.promise]); + const currentPageNumber = this._currentPageNumber; + const pagesRotation = this._pagesRotation; + + if (_classPrivateFieldGet(this, _fieldData) && currentPageNumber === _classPrivateFieldGet(this, _fieldData)._currentPageNumber && pagesRotation === _classPrivateFieldGet(this, _fieldData)._pagesRotation) { + _classPrivateMethodGet(this, _updateUI, _updateUI2).call(this); + + return; + } + + const { + info, + contentLength + } = await this.pdfDocument.getMetadata(); + const [fileName, fileSize, creationDate, modificationDate, pageSize, isLinearized] = await Promise.all([this._fileNameLookup(), _classPrivateMethodGet(this, _parseFileSize, _parseFileSize2).call(this, contentLength), _classPrivateMethodGet(this, _parseDate, _parseDate2).call(this, info.CreationDate), _classPrivateMethodGet(this, _parseDate, _parseDate2).call(this, info.ModDate), this.pdfDocument.getPage(currentPageNumber).then(pdfPage => { + return _classPrivateMethodGet(this, _parsePageSize, _parsePageSize2).call(this, (0, _ui_utils.getPageSizeInches)(pdfPage), pagesRotation); + }), _classPrivateMethodGet(this, _parseLinearization, _parseLinearization2).call(this, info.IsLinearized)]); + + _classPrivateFieldSet(this, _fieldData, Object.freeze({ + fileName, + fileSize, + title: info.Title, + author: info.Author, + subject: info.Subject, + keywords: info.Keywords, + creationDate, + modificationDate, + creator: info.Creator, + producer: info.Producer, + version: info.PDFFormatVersion, + pageCount: this.pdfDocument.numPages, + pageSize, + linearized: isLinearized, + _currentPageNumber: currentPageNumber, + _pagesRotation: pagesRotation + })); + + _classPrivateMethodGet(this, _updateUI, _updateUI2).call(this); + + const { + length + } = await this.pdfDocument.getDownloadInfo(); + + if (contentLength === length) { + return; + } + + const data = Object.assign(Object.create(null), _classPrivateFieldGet(this, _fieldData)); + data.fileSize = await _classPrivateMethodGet(this, _parseFileSize, _parseFileSize2).call(this, length); + + _classPrivateFieldSet(this, _fieldData, Object.freeze(data)); + + _classPrivateMethodGet(this, _updateUI, _updateUI2).call(this); + } + + async close() { + this.overlayManager.close(this.dialog); + } + + setDocument(pdfDocument) { + if (this.pdfDocument) { + _classPrivateMethodGet(this, _reset, _reset2).call(this); + + _classPrivateMethodGet(this, _updateUI, _updateUI2).call(this, true); + } + + if (!pdfDocument) { + return; + } + + this.pdfDocument = pdfDocument; + + this._dataAvailableCapability.resolve(); + } + +} + +exports.PDFDocumentProperties = PDFDocumentProperties; + +function _reset2() { + this.pdfDocument = null; + + _classPrivateFieldSet(this, _fieldData, null); + + this._dataAvailableCapability = (0, _pdfjsLib.createPromiseCapability)(); + this._currentPageNumber = 1; + this._pagesRotation = 0; +} + +function _updateUI2() { + let reset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + if (reset || !_classPrivateFieldGet(this, _fieldData)) { + for (const id in this.fields) { + this.fields[id].textContent = DEFAULT_FIELD_CONTENT; + } + + return; + } + + if (this.overlayManager.active !== this.dialog) { + return; + } + + for (const id in this.fields) { + const content = _classPrivateFieldGet(this, _fieldData)[id]; + + this.fields[id].textContent = content || content === 0 ? content : DEFAULT_FIELD_CONTENT; + } +} + +async function _parseFileSize2() { + let fileSize = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + const kb = fileSize / 1024, + mb = kb / 1024; + + if (!kb) { + return undefined; + } + + return this.l10n.get(`document_properties_${mb >= 1 ? "mb" : "kb"}`, { + size_mb: mb >= 1 && (+mb.toPrecision(3)).toLocaleString(), + size_kb: mb < 1 && (+kb.toPrecision(3)).toLocaleString(), + size_b: fileSize.toLocaleString() + }); +} + +async function _parsePageSize2(pageSizeInches, pagesRotation) { + if (!pageSizeInches) { + return undefined; + } + + if (pagesRotation % 180 !== 0) { + pageSizeInches = { + width: pageSizeInches.height, + height: pageSizeInches.width + }; + } + + const isPortrait = (0, _ui_utils.isPortraitOrientation)(pageSizeInches); + let sizeInches = { + width: Math.round(pageSizeInches.width * 100) / 100, + height: Math.round(pageSizeInches.height * 100) / 100 + }; + let sizeMillimeters = { + width: Math.round(pageSizeInches.width * 25.4 * 10) / 10, + height: Math.round(pageSizeInches.height * 25.4 * 10) / 10 + }; + let rawName = getPageName(sizeInches, isPortrait, US_PAGE_NAMES) || getPageName(sizeMillimeters, isPortrait, METRIC_PAGE_NAMES); + + if (!rawName && !(Number.isInteger(sizeMillimeters.width) && Number.isInteger(sizeMillimeters.height))) { + const exactMillimeters = { + width: pageSizeInches.width * 25.4, + height: pageSizeInches.height * 25.4 + }; + const intMillimeters = { + width: Math.round(sizeMillimeters.width), + height: Math.round(sizeMillimeters.height) + }; + + if (Math.abs(exactMillimeters.width - intMillimeters.width) < 0.1 && Math.abs(exactMillimeters.height - intMillimeters.height) < 0.1) { + rawName = getPageName(intMillimeters, isPortrait, METRIC_PAGE_NAMES); + + if (rawName) { + sizeInches = { + width: Math.round(intMillimeters.width / 25.4 * 100) / 100, + height: Math.round(intMillimeters.height / 25.4 * 100) / 100 + }; + sizeMillimeters = intMillimeters; + } + } + } + + const [{ + width, + height + }, unit, name, orientation] = await Promise.all([this._isNonMetricLocale ? sizeInches : sizeMillimeters, this.l10n.get(`document_properties_page_size_unit_${this._isNonMetricLocale ? "inches" : "millimeters"}`), rawName && this.l10n.get(`document_properties_page_size_name_${rawName.toLowerCase()}`), this.l10n.get(`document_properties_page_size_orientation_${isPortrait ? "portrait" : "landscape"}`)]); + return this.l10n.get(`document_properties_page_size_dimension_${name ? "name_" : ""}string`, { + width: width.toLocaleString(), + height: height.toLocaleString(), + unit, + name, + orientation + }); +} + +async function _parseDate2(inputDate) { + const dateObject = _pdfjsLib.PDFDateString.toDateObject(inputDate); + + if (!dateObject) { + return undefined; + } + + return this.l10n.get("document_properties_date_string", { + date: dateObject.toLocaleDateString(), + time: dateObject.toLocaleTimeString() + }); +} + +function _parseLinearization2(isLinearized) { + return this.l10n.get(`document_properties_linearized_${isLinearized ? "yes" : "no"}`); +} + +/***/ }), +/* 16 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFFindBar = void 0; + +var _pdf_find_controller = __webpack_require__(17); + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +const MATCHES_COUNT_LIMIT = 1000; + +var _adjustWidth = /*#__PURE__*/new WeakSet(); + +class PDFFindBar { + constructor(options, eventBus, l10n) { + _classPrivateMethodInitSpec(this, _adjustWidth); + + this.opened = false; + this.bar = options.bar; + this.toggleButton = options.toggleButton; + this.findField = options.findField; + this.highlightAll = options.highlightAllCheckbox; + this.caseSensitive = options.caseSensitiveCheckbox; + this.matchDiacritics = options.matchDiacriticsCheckbox; + this.entireWord = options.entireWordCheckbox; + this.findMsg = options.findMsg; + this.findResultsCount = options.findResultsCount; + this.findPreviousButton = options.findPreviousButton; + this.findNextButton = options.findNextButton; + this.eventBus = eventBus; + this.l10n = l10n; + this.toggleButton.addEventListener("click", () => { + this.toggle(); + }); + this.findField.addEventListener("input", () => { + this.dispatchEvent(""); + }); + this.bar.addEventListener("keydown", e => { + switch (e.keyCode) { + case 13: + if (e.target === this.findField) { + this.dispatchEvent("again", e.shiftKey); + } + + break; + + case 27: + this.close(); + break; + } + }); + this.findPreviousButton.addEventListener("click", () => { + this.dispatchEvent("again", true); + }); + this.findNextButton.addEventListener("click", () => { + this.dispatchEvent("again", false); + }); + this.highlightAll.addEventListener("click", () => { + this.dispatchEvent("highlightallchange"); + }); + this.caseSensitive.addEventListener("click", () => { + this.dispatchEvent("casesensitivitychange"); + }); + this.entireWord.addEventListener("click", () => { + this.dispatchEvent("entirewordchange"); + }); + this.matchDiacritics.addEventListener("click", () => { + this.dispatchEvent("diacriticmatchingchange"); + }); + + this.eventBus._on("resize", _classPrivateMethodGet(this, _adjustWidth, _adjustWidth2).bind(this)); + } + + reset() { + this.updateUIState(); + } + + dispatchEvent(type) { + let findPrev = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + this.eventBus.dispatch("find", { + source: this, + type, + query: this.findField.value, + phraseSearch: true, + caseSensitive: this.caseSensitive.checked, + entireWord: this.entireWord.checked, + highlightAll: this.highlightAll.checked, + findPrevious: findPrev, + matchDiacritics: this.matchDiacritics.checked + }); + } + + updateUIState(state, previous, matchesCount) { + let findMsg = Promise.resolve(""); + let status = ""; + + switch (state) { + case _pdf_find_controller.FindState.FOUND: + break; + + case _pdf_find_controller.FindState.PENDING: + status = "pending"; + break; + + case _pdf_find_controller.FindState.NOT_FOUND: + findMsg = this.l10n.get("find_not_found"); + status = "notFound"; + break; + + case _pdf_find_controller.FindState.WRAPPED: + findMsg = this.l10n.get(`find_reached_${previous ? "top" : "bottom"}`); + break; + } + + this.findField.setAttribute("data-status", status); + this.findField.setAttribute("aria-invalid", state === _pdf_find_controller.FindState.NOT_FOUND); + findMsg.then(msg => { + this.findMsg.textContent = msg; + + _classPrivateMethodGet(this, _adjustWidth, _adjustWidth2).call(this); + }); + this.updateResultsCount(matchesCount); + } + + updateResultsCount() { + let { + current = 0, + total = 0 + } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + const limit = MATCHES_COUNT_LIMIT; + let matchCountMsg = Promise.resolve(""); + + if (total > 0) { + if (total > limit) { + let key = "find_match_count_limit"; + matchCountMsg = this.l10n.get(key, { + limit + }); + } else { + let key = "find_match_count"; + matchCountMsg = this.l10n.get(key, { + current, + total + }); + } + } + + matchCountMsg.then(msg => { + this.findResultsCount.textContent = msg; + + _classPrivateMethodGet(this, _adjustWidth, _adjustWidth2).call(this); + }); + } + + open() { + if (!this.opened) { + this.opened = true; + this.toggleButton.classList.add("toggled"); + this.toggleButton.setAttribute("aria-expanded", "true"); + this.bar.classList.remove("hidden"); + } + + this.findField.select(); + this.findField.focus(); + + _classPrivateMethodGet(this, _adjustWidth, _adjustWidth2).call(this); + } + + close() { + if (!this.opened) { + return; + } + + this.opened = false; + this.toggleButton.classList.remove("toggled"); + this.toggleButton.setAttribute("aria-expanded", "false"); + this.bar.classList.add("hidden"); + this.eventBus.dispatch("findbarclose", { + source: this + }); + } + + toggle() { + if (this.opened) { + this.close(); + } else { + this.open(); + } + } + +} + +exports.PDFFindBar = PDFFindBar; + +function _adjustWidth2() { + if (!this.opened) { + return; + } + + this.bar.classList.remove("wrapContainers"); + const findbarHeight = this.bar.clientHeight; + const inputContainerHeight = this.bar.firstElementChild.clientHeight; + + if (findbarHeight > inputContainerHeight) { + this.bar.classList.add("wrapContainers"); + } +} + +/***/ }), +/* 17 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFFindController = exports.FindState = void 0; + +var _ui_utils = __webpack_require__(1); + +var _pdfjsLib = __webpack_require__(5); + +var _pdf_find_utils = __webpack_require__(18); + +function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +const FindState = { + FOUND: 0, + NOT_FOUND: 1, + WRAPPED: 2, + PENDING: 3 +}; +exports.FindState = FindState; +const FIND_TIMEOUT = 250; +const MATCH_SCROLL_OFFSET_TOP = -50; +const MATCH_SCROLL_OFFSET_LEFT = -400; +const CHARACTERS_TO_NORMALIZE = { + "\u2010": "-", + "\u2018": "'", + "\u2019": "'", + "\u201A": "'", + "\u201B": "'", + "\u201C": '"', + "\u201D": '"', + "\u201E": '"', + "\u201F": '"', + "\u00BC": "1/4", + "\u00BD": "1/2", + "\u00BE": "3/4" +}; +const DIACRITICS_EXCEPTION = new Set([0x3099, 0x309a, 0x094d, 0x09cd, 0x0a4d, 0x0acd, 0x0b4d, 0x0bcd, 0x0c4d, 0x0ccd, 0x0d3b, 0x0d3c, 0x0d4d, 0x0dca, 0x0e3a, 0x0eba, 0x0f84, 0x1039, 0x103a, 0x1714, 0x1734, 0x17d2, 0x1a60, 0x1b44, 0x1baa, 0x1bab, 0x1bf2, 0x1bf3, 0x2d7f, 0xa806, 0xa82c, 0xa8c4, 0xa953, 0xa9c0, 0xaaf6, 0xabed, 0x0c56, 0x0f71, 0x0f72, 0x0f7a, 0x0f7b, 0x0f7c, 0x0f7d, 0x0f80, 0x0f74]); +const DIACRITICS_EXCEPTION_STR = [...DIACRITICS_EXCEPTION.values()].map(x => String.fromCharCode(x)).join(""); +const DIACRITICS_REG_EXP = /\p{M}+/gu; +const SPECIAL_CHARS_REG_EXP = /([.*+?^${}()|[\]\\])|(\p{P})|(\s+)|(\p{M})|(\p{L})/gu; +const NOT_DIACRITIC_FROM_END_REG_EXP = /([^\p{M}])\p{M}*$/u; +const NOT_DIACRITIC_FROM_START_REG_EXP = /^\p{M}*([^\p{M}])/u; +const SYLLABLES_REG_EXP = /[\uAC00-\uD7AF\uFA6C\uFACF-\uFAD1\uFAD5-\uFAD7]+/g; +const SYLLABLES_LENGTHS = new Map(); +const FIRST_CHAR_SYLLABLES_REG_EXP = "[\\u1100-\\u1112\\ud7a4-\\ud7af\\ud84a\\ud84c\\ud850\\ud854\\ud857\\ud85f]"; +let noSyllablesRegExp = null; +let withSyllablesRegExp = null; + +function normalize(text) { + const syllablePositions = []; + let m; + + while ((m = SYLLABLES_REG_EXP.exec(text)) !== null) { + let { + index + } = m; + + for (const char of m[0]) { + let len = SYLLABLES_LENGTHS.get(char); + + if (!len) { + len = char.normalize("NFD").length; + SYLLABLES_LENGTHS.set(char, len); + } + + syllablePositions.push([len, index++]); + } + } + + let normalizationRegex; + + if (syllablePositions.length === 0 && noSyllablesRegExp) { + normalizationRegex = noSyllablesRegExp; + } else if (syllablePositions.length > 0 && withSyllablesRegExp) { + normalizationRegex = withSyllablesRegExp; + } else { + const replace = Object.keys(CHARACTERS_TO_NORMALIZE).join(""); + const regexp = `([${replace}])|(\\p{M}+(?:-\\n)?)|(\\S-\\n)|(\\n)`; + + if (syllablePositions.length === 0) { + normalizationRegex = noSyllablesRegExp = new RegExp(regexp + "|(\\u0000)", "gum"); + } else { + normalizationRegex = withSyllablesRegExp = new RegExp(regexp + `|(${FIRST_CHAR_SYLLABLES_REG_EXP})`, "gum"); + } + } + + const rawDiacriticsPositions = []; + + while ((m = DIACRITICS_REG_EXP.exec(text)) !== null) { + rawDiacriticsPositions.push([m[0].length, m.index]); + } + + let normalized = text.normalize("NFD"); + const positions = [[0, 0]]; + let rawDiacriticsIndex = 0; + let syllableIndex = 0; + let shift = 0; + let shiftOrigin = 0; + let eol = 0; + let hasDiacritics = false; + normalized = normalized.replace(normalizationRegex, (match, p1, p2, p3, p4, p5, i) => { + var _syllablePositions$sy; + + i -= shiftOrigin; + + if (p1) { + const replacement = CHARACTERS_TO_NORMALIZE[match]; + const jj = replacement.length; + + for (let j = 1; j < jj; j++) { + positions.push([i - shift + j, shift - j]); + } + + shift -= jj - 1; + return replacement; + } + + if (p2) { + var _rawDiacriticsPositio; + + const hasTrailingDashEOL = p2.endsWith("\n"); + const len = hasTrailingDashEOL ? p2.length - 2 : p2.length; + hasDiacritics = true; + let jj = len; + + if (i + eol === ((_rawDiacriticsPositio = rawDiacriticsPositions[rawDiacriticsIndex]) === null || _rawDiacriticsPositio === void 0 ? void 0 : _rawDiacriticsPositio[1])) { + jj -= rawDiacriticsPositions[rawDiacriticsIndex][0]; + ++rawDiacriticsIndex; + } + + for (let j = 1; j <= jj; j++) { + positions.push([i - 1 - shift + j, shift - j]); + } + + shift -= jj; + shiftOrigin += jj; + + if (hasTrailingDashEOL) { + i += len - 1; + positions.push([i - shift + 1, 1 + shift]); + shift += 1; + shiftOrigin += 1; + eol += 1; + return p2.slice(0, len); + } + + return p2; + } + + if (p3) { + positions.push([i - shift + 1, 1 + shift]); + shift += 1; + shiftOrigin += 1; + eol += 1; + return p3.charAt(0); + } + + if (p4) { + positions.push([i - shift + 1, shift - 1]); + shift -= 1; + shiftOrigin += 1; + eol += 1; + return " "; + } + + if (i + eol === ((_syllablePositions$sy = syllablePositions[syllableIndex]) === null || _syllablePositions$sy === void 0 ? void 0 : _syllablePositions$sy[1])) { + const newCharLen = syllablePositions[syllableIndex][0] - 1; + ++syllableIndex; + + for (let j = 1; j <= newCharLen; j++) { + positions.push([i - (shift - j), shift - j]); + } + + shift -= newCharLen; + shiftOrigin += newCharLen; + } + + return p5; + }); + positions.push([normalized.length, shift]); + return [normalized, positions, hasDiacritics]; +} + +function getOriginalIndex(diffs, pos, len) { + if (!diffs) { + return [pos, len]; + } + + const start = pos; + const end = pos + len; + let i = (0, _ui_utils.binarySearchFirstItem)(diffs, x => x[0] >= start); + + if (diffs[i][0] > start) { + --i; + } + + let j = (0, _ui_utils.binarySearchFirstItem)(diffs, x => x[0] >= end, i); + + if (diffs[j][0] > end) { + --j; + } + + return [start + diffs[i][1], len + diffs[j][1] - diffs[i][1]]; +} + +var _onFind = /*#__PURE__*/new WeakSet(); + +var _reset = /*#__PURE__*/new WeakSet(); + +var _query = /*#__PURE__*/new WeakMap(); + +var _shouldDirtyMatch = /*#__PURE__*/new WeakSet(); + +var _isEntireWord = /*#__PURE__*/new WeakSet(); + +var _calculateRegExpMatch = /*#__PURE__*/new WeakSet(); + +var _convertToRegExpString = /*#__PURE__*/new WeakSet(); + +var _calculateMatch = /*#__PURE__*/new WeakSet(); + +var _extractText = /*#__PURE__*/new WeakSet(); + +var _updatePage = /*#__PURE__*/new WeakSet(); + +var _updateAllPages = /*#__PURE__*/new WeakSet(); + +var _nextMatch = /*#__PURE__*/new WeakSet(); + +var _matchesReady = /*#__PURE__*/new WeakSet(); + +var _nextPageMatch = /*#__PURE__*/new WeakSet(); + +var _advanceOffsetPage = /*#__PURE__*/new WeakSet(); + +var _updateMatch = /*#__PURE__*/new WeakSet(); + +var _onFindBarClose = /*#__PURE__*/new WeakSet(); + +var _requestMatchesCount = /*#__PURE__*/new WeakSet(); + +var _updateUIResultsCount = /*#__PURE__*/new WeakSet(); + +var _updateUIState = /*#__PURE__*/new WeakSet(); + +class PDFFindController { + constructor(_ref) { + let { + linkService: _linkService, + eventBus + } = _ref; + + _classPrivateMethodInitSpec(this, _updateUIState); + + _classPrivateMethodInitSpec(this, _updateUIResultsCount); + + _classPrivateMethodInitSpec(this, _requestMatchesCount); + + _classPrivateMethodInitSpec(this, _onFindBarClose); + + _classPrivateMethodInitSpec(this, _updateMatch); + + _classPrivateMethodInitSpec(this, _advanceOffsetPage); + + _classPrivateMethodInitSpec(this, _nextPageMatch); + + _classPrivateMethodInitSpec(this, _matchesReady); + + _classPrivateMethodInitSpec(this, _nextMatch); + + _classPrivateMethodInitSpec(this, _updateAllPages); + + _classPrivateMethodInitSpec(this, _updatePage); + + _classPrivateMethodInitSpec(this, _extractText); + + _classPrivateMethodInitSpec(this, _calculateMatch); + + _classPrivateMethodInitSpec(this, _convertToRegExpString); + + _classPrivateMethodInitSpec(this, _calculateRegExpMatch); + + _classPrivateMethodInitSpec(this, _isEntireWord); + + _classPrivateMethodInitSpec(this, _shouldDirtyMatch); + + _classPrivateFieldInitSpec(this, _query, { + get: _get_query, + set: void 0 + }); + + _classPrivateMethodInitSpec(this, _reset); + + _classPrivateMethodInitSpec(this, _onFind); + + this._linkService = _linkService; + this._eventBus = eventBus; + + _classPrivateMethodGet(this, _reset, _reset2).call(this); + + eventBus._on("find", _classPrivateMethodGet(this, _onFind, _onFind2).bind(this)); + + eventBus._on("findbarclose", _classPrivateMethodGet(this, _onFindBarClose, _onFindBarClose2).bind(this)); + } + + get highlightMatches() { + return this._highlightMatches; + } + + get pageMatches() { + return this._pageMatches; + } + + get pageMatchesLength() { + return this._pageMatchesLength; + } + + get selected() { + return this._selected; + } + + get state() { + return this._state; + } + + setDocument(pdfDocument) { + if (this._pdfDocument) { + _classPrivateMethodGet(this, _reset, _reset2).call(this); + } + + if (!pdfDocument) { + return; + } + + this._pdfDocument = pdfDocument; + + this._firstPageCapability.resolve(); + } + + scrollMatchIntoView(_ref2) { + let { + element = null, + selectedLeft = 0, + pageIndex = -1, + matchIndex = -1 + } = _ref2; + + if (!this._scrollMatches || !element) { + return; + } else if (matchIndex === -1 || matchIndex !== this._selected.matchIdx) { + return; + } else if (pageIndex === -1 || pageIndex !== this._selected.pageIdx) { + return; + } + + this._scrollMatches = false; + const spot = { + top: MATCH_SCROLL_OFFSET_TOP, + left: selectedLeft + MATCH_SCROLL_OFFSET_LEFT + }; + (0, _ui_utils.scrollIntoView)(element, spot, true); + } + +} + +exports.PDFFindController = PDFFindController; + +function _onFind2(state) { + if (!state) { + return; + } + + const pdfDocument = this._pdfDocument; + const { + type + } = state; + + if (this._state === null || _classPrivateMethodGet(this, _shouldDirtyMatch, _shouldDirtyMatch2).call(this, state)) { + this._dirtyMatch = true; + } + + this._state = state; + + if (type !== "highlightallchange") { + _classPrivateMethodGet(this, _updateUIState, _updateUIState2).call(this, FindState.PENDING); + } + + this._firstPageCapability.promise.then(() => { + if (!this._pdfDocument || pdfDocument && this._pdfDocument !== pdfDocument) { + return; + } + + _classPrivateMethodGet(this, _extractText, _extractText2).call(this); + + const findbarClosed = !this._highlightMatches; + const pendingTimeout = !!this._findTimeout; + + if (this._findTimeout) { + clearTimeout(this._findTimeout); + this._findTimeout = null; + } + + if (!type) { + this._findTimeout = setTimeout(() => { + _classPrivateMethodGet(this, _nextMatch, _nextMatch2).call(this); + + this._findTimeout = null; + }, FIND_TIMEOUT); + } else if (this._dirtyMatch) { + _classPrivateMethodGet(this, _nextMatch, _nextMatch2).call(this); + } else if (type === "again") { + _classPrivateMethodGet(this, _nextMatch, _nextMatch2).call(this); + + if (findbarClosed && this._state.highlightAll) { + _classPrivateMethodGet(this, _updateAllPages, _updateAllPages2).call(this); + } + } else if (type === "highlightallchange") { + if (pendingTimeout) { + _classPrivateMethodGet(this, _nextMatch, _nextMatch2).call(this); + } else { + this._highlightMatches = true; + } + + _classPrivateMethodGet(this, _updateAllPages, _updateAllPages2).call(this); + } else { + _classPrivateMethodGet(this, _nextMatch, _nextMatch2).call(this); + } + }); +} + +function _reset2() { + this._highlightMatches = false; + this._scrollMatches = false; + this._pdfDocument = null; + this._pageMatches = []; + this._pageMatchesLength = []; + this._state = null; + this._selected = { + pageIdx: -1, + matchIdx: -1 + }; + this._offset = { + pageIdx: null, + matchIdx: null, + wrapped: false + }; + this._extractTextPromises = []; + this._pageContents = []; + this._pageDiffs = []; + this._hasDiacritics = []; + this._matchesCountTotal = 0; + this._pagesToSearch = null; + this._pendingFindMatches = new Set(); + this._resumePageIdx = null; + this._dirtyMatch = false; + clearTimeout(this._findTimeout); + this._findTimeout = null; + this._firstPageCapability = (0, _pdfjsLib.createPromiseCapability)(); +} + +function _get_query() { + if (this._state.query !== this._rawQuery) { + this._rawQuery = this._state.query; + [this._normalizedQuery] = normalize(this._state.query); + } + + return this._normalizedQuery; +} + +function _shouldDirtyMatch2(state) { + if (state.query !== this._state.query) { + return true; + } + + switch (state.type) { + case "again": + const pageNumber = this._selected.pageIdx + 1; + const linkService = this._linkService; + + if (pageNumber >= 1 && pageNumber <= linkService.pagesCount && pageNumber !== linkService.page && !linkService.isPageVisible(pageNumber)) { + return true; + } + + return false; + + case "highlightallchange": + return false; + } + + return true; +} + +function _isEntireWord2(content, startIdx, length) { + let match = content.slice(0, startIdx).match(NOT_DIACRITIC_FROM_END_REG_EXP); + + if (match) { + const first = content.charCodeAt(startIdx); + const limit = match[1].charCodeAt(0); + + if ((0, _pdf_find_utils.getCharacterType)(first) === (0, _pdf_find_utils.getCharacterType)(limit)) { + return false; + } + } + + match = content.slice(startIdx + length).match(NOT_DIACRITIC_FROM_START_REG_EXP); + + if (match) { + const last = content.charCodeAt(startIdx + length - 1); + const limit = match[1].charCodeAt(0); + + if ((0, _pdf_find_utils.getCharacterType)(last) === (0, _pdf_find_utils.getCharacterType)(limit)) { + return false; + } + } + + return true; +} + +function _calculateRegExpMatch2(query, entireWord, pageIndex, pageContent) { + const matches = [], + matchesLength = []; + const diffs = this._pageDiffs[pageIndex]; + let match; + + while ((match = query.exec(pageContent)) !== null) { + if (entireWord && !_classPrivateMethodGet(this, _isEntireWord, _isEntireWord2).call(this, pageContent, match.index, match[0].length)) { + continue; + } + + const [matchPos, matchLen] = getOriginalIndex(diffs, match.index, match[0].length); + + if (matchLen) { + matches.push(matchPos); + matchesLength.push(matchLen); + } + } + + this._pageMatches[pageIndex] = matches; + this._pageMatchesLength[pageIndex] = matchesLength; +} + +function _convertToRegExpString2(query, hasDiacritics) { + const { + matchDiacritics + } = this._state; + let isUnicode = false; + query = query.replace(SPECIAL_CHARS_REG_EXP, (match, p1, p2, p3, p4, p5) => { + if (p1) { + return `[ ]*\\${p1}[ ]*`; + } + + if (p2) { + return `[ ]*${p2}[ ]*`; + } + + if (p3) { + return "[ ]+"; + } + + if (matchDiacritics) { + return p4 || p5; + } + + if (p4) { + return DIACRITICS_EXCEPTION.has(p4.charCodeAt(0)) ? p4 : ""; + } + + if (hasDiacritics) { + isUnicode = true; + return `${p5}\\p{M}*`; + } + + return p5; + }); + const trailingSpaces = "[ ]*"; + + if (query.endsWith(trailingSpaces)) { + query = query.slice(0, query.length - trailingSpaces.length); + } + + if (matchDiacritics) { + if (hasDiacritics) { + isUnicode = true; + query = `${query}(?=[${DIACRITICS_EXCEPTION_STR}]|[^\\p{M}]|$)`; + } + } + + return [isUnicode, query]; +} + +function _calculateMatch2(pageIndex) { + let query = _classPrivateFieldGet(this, _query); + + if (query.length === 0) { + return; + } + + const { + caseSensitive, + entireWord, + phraseSearch + } = this._state; + const pageContent = this._pageContents[pageIndex]; + const hasDiacritics = this._hasDiacritics[pageIndex]; + let isUnicode = false; + + if (phraseSearch) { + [isUnicode, query] = _classPrivateMethodGet(this, _convertToRegExpString, _convertToRegExpString2).call(this, query, hasDiacritics); + } else { + const match = query.match(/\S+/g); + + if (match) { + query = match.sort().reverse().map(q => { + const [isUnicodePart, queryPart] = _classPrivateMethodGet(this, _convertToRegExpString, _convertToRegExpString2).call(this, q, hasDiacritics); + + isUnicode || (isUnicode = isUnicodePart); + return `(${queryPart})`; + }).join("|"); + } + } + + const flags = `g${isUnicode ? "u" : ""}${caseSensitive ? "" : "i"}`; + query = new RegExp(query, flags); + + _classPrivateMethodGet(this, _calculateRegExpMatch, _calculateRegExpMatch2).call(this, query, entireWord, pageIndex, pageContent); + + if (this._state.highlightAll) { + _classPrivateMethodGet(this, _updatePage, _updatePage2).call(this, pageIndex); + } + + if (this._resumePageIdx === pageIndex) { + this._resumePageIdx = null; + + _classPrivateMethodGet(this, _nextPageMatch, _nextPageMatch2).call(this); + } + + const pageMatchesCount = this._pageMatches[pageIndex].length; + + if (pageMatchesCount > 0) { + this._matchesCountTotal += pageMatchesCount; + + _classPrivateMethodGet(this, _updateUIResultsCount, _updateUIResultsCount2).call(this); + } +} + +function _extractText2() { + if (this._extractTextPromises.length > 0) { + return; + } + + let promise = Promise.resolve(); + + for (let i = 0, ii = this._linkService.pagesCount; i < ii; i++) { + const extractTextCapability = (0, _pdfjsLib.createPromiseCapability)(); + this._extractTextPromises[i] = extractTextCapability.promise; + promise = promise.then(() => { + return this._pdfDocument.getPage(i + 1).then(pdfPage => { + return pdfPage.getTextContent(); + }).then(textContent => { + const strBuf = []; + + for (const textItem of textContent.items) { + strBuf.push(textItem.str); + + if (textItem.hasEOL) { + strBuf.push("\n"); + } + } + + [this._pageContents[i], this._pageDiffs[i], this._hasDiacritics[i]] = normalize(strBuf.join("")); + extractTextCapability.resolve(); + }, reason => { + console.error(`Unable to get text content for page ${i + 1}`, reason); + this._pageContents[i] = ""; + this._pageDiffs[i] = null; + this._hasDiacritics[i] = false; + extractTextCapability.resolve(); + }); + }); + } +} + +function _updatePage2(index) { + if (this._scrollMatches && this._selected.pageIdx === index) { + this._linkService.page = index + 1; + } + + this._eventBus.dispatch("updatetextlayermatches", { + source: this, + pageIndex: index + }); +} + +function _updateAllPages2() { + this._eventBus.dispatch("updatetextlayermatches", { + source: this, + pageIndex: -1 + }); +} + +function _nextMatch2() { + const previous = this._state.findPrevious; + const currentPageIndex = this._linkService.page - 1; + const numPages = this._linkService.pagesCount; + this._highlightMatches = true; + + if (this._dirtyMatch) { + this._dirtyMatch = false; + this._selected.pageIdx = this._selected.matchIdx = -1; + this._offset.pageIdx = currentPageIndex; + this._offset.matchIdx = null; + this._offset.wrapped = false; + this._resumePageIdx = null; + this._pageMatches.length = 0; + this._pageMatchesLength.length = 0; + this._matchesCountTotal = 0; + + _classPrivateMethodGet(this, _updateAllPages, _updateAllPages2).call(this); + + for (let i = 0; i < numPages; i++) { + if (this._pendingFindMatches.has(i)) { + continue; + } + + this._pendingFindMatches.add(i); + + this._extractTextPromises[i].then(() => { + this._pendingFindMatches.delete(i); + + _classPrivateMethodGet(this, _calculateMatch, _calculateMatch2).call(this, i); + }); + } + } + + if (_classPrivateFieldGet(this, _query) === "") { + _classPrivateMethodGet(this, _updateUIState, _updateUIState2).call(this, FindState.FOUND); + + return; + } + + if (this._resumePageIdx) { + return; + } + + const offset = this._offset; + this._pagesToSearch = numPages; + + if (offset.matchIdx !== null) { + const numPageMatches = this._pageMatches[offset.pageIdx].length; + + if (!previous && offset.matchIdx + 1 < numPageMatches || previous && offset.matchIdx > 0) { + offset.matchIdx = previous ? offset.matchIdx - 1 : offset.matchIdx + 1; + + _classPrivateMethodGet(this, _updateMatch, _updateMatch2).call(this, true); + + return; + } + + _classPrivateMethodGet(this, _advanceOffsetPage, _advanceOffsetPage2).call(this, previous); + } + + _classPrivateMethodGet(this, _nextPageMatch, _nextPageMatch2).call(this); +} + +function _matchesReady2(matches) { + const offset = this._offset; + const numMatches = matches.length; + const previous = this._state.findPrevious; + + if (numMatches) { + offset.matchIdx = previous ? numMatches - 1 : 0; + + _classPrivateMethodGet(this, _updateMatch, _updateMatch2).call(this, true); + + return true; + } + + _classPrivateMethodGet(this, _advanceOffsetPage, _advanceOffsetPage2).call(this, previous); + + if (offset.wrapped) { + offset.matchIdx = null; + + if (this._pagesToSearch < 0) { + _classPrivateMethodGet(this, _updateMatch, _updateMatch2).call(this, false); + + return true; + } + } + + return false; +} + +function _nextPageMatch2() { + if (this._resumePageIdx !== null) { + console.error("There can only be one pending page."); + } + + let matches = null; + + do { + const pageIdx = this._offset.pageIdx; + matches = this._pageMatches[pageIdx]; + + if (!matches) { + this._resumePageIdx = pageIdx; + break; + } + } while (!_classPrivateMethodGet(this, _matchesReady, _matchesReady2).call(this, matches)); +} + +function _advanceOffsetPage2(previous) { + const offset = this._offset; + const numPages = this._linkService.pagesCount; + offset.pageIdx = previous ? offset.pageIdx - 1 : offset.pageIdx + 1; + offset.matchIdx = null; + this._pagesToSearch--; + + if (offset.pageIdx >= numPages || offset.pageIdx < 0) { + offset.pageIdx = previous ? numPages - 1 : 0; + offset.wrapped = true; + } +} + +function _updateMatch2() { + let found = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + let state = FindState.NOT_FOUND; + const wrapped = this._offset.wrapped; + this._offset.wrapped = false; + + if (found) { + const previousPage = this._selected.pageIdx; + this._selected.pageIdx = this._offset.pageIdx; + this._selected.matchIdx = this._offset.matchIdx; + state = wrapped ? FindState.WRAPPED : FindState.FOUND; + + if (previousPage !== -1 && previousPage !== this._selected.pageIdx) { + _classPrivateMethodGet(this, _updatePage, _updatePage2).call(this, previousPage); + } + } + + _classPrivateMethodGet(this, _updateUIState, _updateUIState2).call(this, state, this._state.findPrevious); + + if (this._selected.pageIdx !== -1) { + this._scrollMatches = true; + + _classPrivateMethodGet(this, _updatePage, _updatePage2).call(this, this._selected.pageIdx); + } +} + +function _onFindBarClose2(evt) { + const pdfDocument = this._pdfDocument; + + this._firstPageCapability.promise.then(() => { + if (!this._pdfDocument || pdfDocument && this._pdfDocument !== pdfDocument) { + return; + } + + if (this._findTimeout) { + clearTimeout(this._findTimeout); + this._findTimeout = null; + } + + if (this._resumePageIdx) { + this._resumePageIdx = null; + this._dirtyMatch = true; + } + + _classPrivateMethodGet(this, _updateUIState, _updateUIState2).call(this, FindState.FOUND); + + this._highlightMatches = false; + + _classPrivateMethodGet(this, _updateAllPages, _updateAllPages2).call(this); + }); +} + +function _requestMatchesCount2() { + const { + pageIdx, + matchIdx + } = this._selected; + let current = 0, + total = this._matchesCountTotal; + + if (matchIdx !== -1) { + for (let i = 0; i < pageIdx; i++) { + var _this$_pageMatches$i; + + current += ((_this$_pageMatches$i = this._pageMatches[i]) === null || _this$_pageMatches$i === void 0 ? void 0 : _this$_pageMatches$i.length) || 0; + } + + current += matchIdx + 1; + } + + if (current < 1 || current > total) { + current = total = 0; + } + + return { + current, + total + }; +} + +function _updateUIResultsCount2() { + this._eventBus.dispatch("updatefindmatchescount", { + source: this, + matchesCount: _classPrivateMethodGet(this, _requestMatchesCount, _requestMatchesCount2).call(this) + }); +} + +function _updateUIState2(state) { + var _this$_state$query, _this$_state; + + let previous = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + this._eventBus.dispatch("updatefindcontrolstate", { + source: this, + state, + previous, + matchesCount: _classPrivateMethodGet(this, _requestMatchesCount, _requestMatchesCount2).call(this), + rawQuery: (_this$_state$query = (_this$_state = this._state) === null || _this$_state === void 0 ? void 0 : _this$_state.query) !== null && _this$_state$query !== void 0 ? _this$_state$query : null + }); +} + +/***/ }), +/* 18 */ +/***/ ((__unused_webpack_module, exports) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.CharacterType = void 0; +exports.getCharacterType = getCharacterType; +const CharacterType = { + SPACE: 0, + ALPHA_LETTER: 1, + PUNCT: 2, + HAN_LETTER: 3, + KATAKANA_LETTER: 4, + HIRAGANA_LETTER: 5, + HALFWIDTH_KATAKANA_LETTER: 6, + THAI_LETTER: 7 +}; +exports.CharacterType = CharacterType; + +function isAlphabeticalScript(charCode) { + return charCode < 0x2e80; +} + +function isAscii(charCode) { + return (charCode & 0xff80) === 0; +} + +function isAsciiAlpha(charCode) { + return charCode >= 0x61 && charCode <= 0x7a || charCode >= 0x41 && charCode <= 0x5a; +} + +function isAsciiDigit(charCode) { + return charCode >= 0x30 && charCode <= 0x39; +} + +function isAsciiSpace(charCode) { + return charCode === 0x20 || charCode === 0x09 || charCode === 0x0d || charCode === 0x0a; +} + +function isHan(charCode) { + return charCode >= 0x3400 && charCode <= 0x9fff || charCode >= 0xf900 && charCode <= 0xfaff; +} + +function isKatakana(charCode) { + return charCode >= 0x30a0 && charCode <= 0x30ff; +} + +function isHiragana(charCode) { + return charCode >= 0x3040 && charCode <= 0x309f; +} + +function isHalfwidthKatakana(charCode) { + return charCode >= 0xff60 && charCode <= 0xff9f; +} + +function isThai(charCode) { + return (charCode & 0xff80) === 0x0e00; +} + +function getCharacterType(charCode) { + if (isAlphabeticalScript(charCode)) { + if (isAscii(charCode)) { + if (isAsciiSpace(charCode)) { + return CharacterType.SPACE; + } else if (isAsciiAlpha(charCode) || isAsciiDigit(charCode) || charCode === 0x5f) { + return CharacterType.ALPHA_LETTER; + } + + return CharacterType.PUNCT; + } else if (isThai(charCode)) { + return CharacterType.THAI_LETTER; + } else if (charCode === 0xa0) { + return CharacterType.SPACE; + } + + return CharacterType.ALPHA_LETTER; + } + + if (isHan(charCode)) { + return CharacterType.HAN_LETTER; + } else if (isKatakana(charCode)) { + return CharacterType.KATAKANA_LETTER; + } else if (isHiragana(charCode)) { + return CharacterType.HIRAGANA_LETTER; + } else if (isHalfwidthKatakana(charCode)) { + return CharacterType.HALFWIDTH_KATAKANA_LETTER; + } + + return CharacterType.ALPHA_LETTER; +} + +/***/ }), +/* 19 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFHistory = void 0; +exports.isDestArraysEqual = isDestArraysEqual; +exports.isDestHashesEqual = isDestHashesEqual; + +var _ui_utils = __webpack_require__(1); + +var _event_utils = __webpack_require__(6); + +const HASH_CHANGE_TIMEOUT = 1000; +const POSITION_UPDATED_THRESHOLD = 50; +const UPDATE_VIEWAREA_TIMEOUT = 1000; + +function getCurrentHash() { + return document.location.hash; +} + +class PDFHistory { + constructor(_ref) { + let { + linkService, + eventBus + } = _ref; + this.linkService = linkService; + this.eventBus = eventBus; + this._initialized = false; + this._fingerprint = ""; + this.reset(); + this._boundEvents = null; + + this.eventBus._on("pagesinit", () => { + this._isPagesLoaded = false; + + this.eventBus._on("pagesloaded", evt => { + this._isPagesLoaded = !!evt.pagesCount; + }, { + once: true + }); + }); + } + + initialize(_ref2) { + let { + fingerprint, + resetHistory = false, + updateUrl = false + } = _ref2; + + if (!fingerprint || typeof fingerprint !== "string") { + console.error('PDFHistory.initialize: The "fingerprint" must be a non-empty string.'); + return; + } + + if (this._initialized) { + this.reset(); + } + + const reInitialized = this._fingerprint !== "" && this._fingerprint !== fingerprint; + this._fingerprint = fingerprint; + this._updateUrl = updateUrl === true; + this._initialized = true; + + this._bindEvents(); + + const state = window.history.state; + this._popStateInProgress = false; + this._blockHashChange = 0; + this._currentHash = getCurrentHash(); + this._numPositionUpdates = 0; + this._uid = this._maxUid = 0; + this._destination = null; + this._position = null; + + if (!this._isValidState(state, true) || resetHistory) { + const { + hash, + page, + rotation + } = this._parseCurrentHash(true); + + if (!hash || reInitialized || resetHistory) { + this._pushOrReplaceState(null, true); + + return; + } + + this._pushOrReplaceState({ + hash, + page, + rotation + }, true); + + return; + } + + const destination = state.destination; + + this._updateInternalState(destination, state.uid, true); + + if (destination.rotation !== undefined) { + this._initialRotation = destination.rotation; + } + + if (destination.dest) { + this._initialBookmark = JSON.stringify(destination.dest); + this._destination.page = null; + } else if (destination.hash) { + this._initialBookmark = destination.hash; + } else if (destination.page) { + this._initialBookmark = `page=${destination.page}`; + } + } + + reset() { + if (this._initialized) { + this._pageHide(); + + this._initialized = false; + + this._unbindEvents(); + } + + if (this._updateViewareaTimeout) { + clearTimeout(this._updateViewareaTimeout); + this._updateViewareaTimeout = null; + } + + this._initialBookmark = null; + this._initialRotation = null; + } + + push(_ref3) { + let { + namedDest = null, + explicitDest, + pageNumber + } = _ref3; + + if (!this._initialized) { + return; + } + + if (namedDest && typeof namedDest !== "string") { + console.error("PDFHistory.push: " + `"${namedDest}" is not a valid namedDest parameter.`); + return; + } else if (!Array.isArray(explicitDest)) { + console.error("PDFHistory.push: " + `"${explicitDest}" is not a valid explicitDest parameter.`); + return; + } else if (!this._isValidPage(pageNumber)) { + if (pageNumber !== null || this._destination) { + console.error("PDFHistory.push: " + `"${pageNumber}" is not a valid pageNumber parameter.`); + return; + } + } + + const hash = namedDest || JSON.stringify(explicitDest); + + if (!hash) { + return; + } + + let forceReplace = false; + + if (this._destination && (isDestHashesEqual(this._destination.hash, hash) || isDestArraysEqual(this._destination.dest, explicitDest))) { + if (this._destination.page) { + return; + } + + forceReplace = true; + } + + if (this._popStateInProgress && !forceReplace) { + return; + } + + this._pushOrReplaceState({ + dest: explicitDest, + hash, + page: pageNumber, + rotation: this.linkService.rotation + }, forceReplace); + + if (!this._popStateInProgress) { + this._popStateInProgress = true; + Promise.resolve().then(() => { + this._popStateInProgress = false; + }); + } + } + + pushPage(pageNumber) { + var _this$_destination; + + if (!this._initialized) { + return; + } + + if (!this._isValidPage(pageNumber)) { + console.error(`PDFHistory.pushPage: "${pageNumber}" is not a valid page number.`); + return; + } + + if (((_this$_destination = this._destination) === null || _this$_destination === void 0 ? void 0 : _this$_destination.page) === pageNumber) { + return; + } + + if (this._popStateInProgress) { + return; + } + + this._pushOrReplaceState({ + dest: null, + hash: `page=${pageNumber}`, + page: pageNumber, + rotation: this.linkService.rotation + }); + + if (!this._popStateInProgress) { + this._popStateInProgress = true; + Promise.resolve().then(() => { + this._popStateInProgress = false; + }); + } + } + + pushCurrentPosition() { + if (!this._initialized || this._popStateInProgress) { + return; + } + + this._tryPushCurrentPosition(); + } + + back() { + if (!this._initialized || this._popStateInProgress) { + return; + } + + const state = window.history.state; + + if (this._isValidState(state) && state.uid > 0) { + window.history.back(); + } + } + + forward() { + if (!this._initialized || this._popStateInProgress) { + return; + } + + const state = window.history.state; + + if (this._isValidState(state) && state.uid < this._maxUid) { + window.history.forward(); + } + } + + get popStateInProgress() { + return this._initialized && (this._popStateInProgress || this._blockHashChange > 0); + } + + get initialBookmark() { + return this._initialized ? this._initialBookmark : null; + } + + get initialRotation() { + return this._initialized ? this._initialRotation : null; + } + + _pushOrReplaceState(destination) { + let forceReplace = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + const shouldReplace = forceReplace || !this._destination; + const newState = { + fingerprint: this._fingerprint, + uid: shouldReplace ? this._uid : this._uid + 1, + destination + }; + + this._updateInternalState(destination, newState.uid); + + let newUrl; + + if (this._updateUrl && destination !== null && destination !== void 0 && destination.hash) { + const baseUrl = document.location.href.split("#")[0]; + + if (!baseUrl.startsWith("file://")) { + newUrl = `${baseUrl}#${destination.hash}`; + } + } + + if (shouldReplace) { + window.history.replaceState(newState, "", newUrl); + } else { + window.history.pushState(newState, "", newUrl); + } + } + + _tryPushCurrentPosition() { + let temporary = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + if (!this._position) { + return; + } + + let position = this._position; + + if (temporary) { + position = Object.assign(Object.create(null), this._position); + position.temporary = true; + } + + if (!this._destination) { + this._pushOrReplaceState(position); + + return; + } + + if (this._destination.temporary) { + this._pushOrReplaceState(position, true); + + return; + } + + if (this._destination.hash === position.hash) { + return; + } + + if (!this._destination.page && (POSITION_UPDATED_THRESHOLD <= 0 || this._numPositionUpdates <= POSITION_UPDATED_THRESHOLD)) { + return; + } + + let forceReplace = false; + + if (this._destination.page >= position.first && this._destination.page <= position.page) { + if (this._destination.dest !== undefined || !this._destination.first) { + return; + } + + forceReplace = true; + } + + this._pushOrReplaceState(position, forceReplace); + } + + _isValidPage(val) { + return Number.isInteger(val) && val > 0 && val <= this.linkService.pagesCount; + } + + _isValidState(state) { + let checkReload = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + if (!state) { + return false; + } + + if (state.fingerprint !== this._fingerprint) { + if (checkReload) { + if (typeof state.fingerprint !== "string" || state.fingerprint.length !== this._fingerprint.length) { + return false; + } + + const [perfEntry] = performance.getEntriesByType("navigation"); + + if ((perfEntry === null || perfEntry === void 0 ? void 0 : perfEntry.type) !== "reload") { + return false; + } + } else { + return false; + } + } + + if (!Number.isInteger(state.uid) || state.uid < 0) { + return false; + } + + if (state.destination === null || typeof state.destination !== "object") { + return false; + } + + return true; + } + + _updateInternalState(destination, uid) { + let removeTemporary = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + + if (this._updateViewareaTimeout) { + clearTimeout(this._updateViewareaTimeout); + this._updateViewareaTimeout = null; + } + + if (removeTemporary && destination !== null && destination !== void 0 && destination.temporary) { + delete destination.temporary; + } + + this._destination = destination; + this._uid = uid; + this._maxUid = Math.max(this._maxUid, uid); + this._numPositionUpdates = 0; + } + + _parseCurrentHash() { + let checkNameddest = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + const hash = unescape(getCurrentHash()).substring(1); + const params = (0, _ui_utils.parseQueryString)(hash); + const nameddest = params.get("nameddest") || ""; + let page = params.get("page") | 0; + + if (!this._isValidPage(page) || checkNameddest && nameddest.length > 0) { + page = null; + } + + return { + hash, + page, + rotation: this.linkService.rotation + }; + } + + _updateViewarea(_ref4) { + let { + location + } = _ref4; + + if (this._updateViewareaTimeout) { + clearTimeout(this._updateViewareaTimeout); + this._updateViewareaTimeout = null; + } + + this._position = { + hash: location.pdfOpenParams.substring(1), + page: this.linkService.page, + first: location.pageNumber, + rotation: location.rotation + }; + + if (this._popStateInProgress) { + return; + } + + if (POSITION_UPDATED_THRESHOLD > 0 && this._isPagesLoaded && this._destination && !this._destination.page) { + this._numPositionUpdates++; + } + + if (UPDATE_VIEWAREA_TIMEOUT > 0) { + this._updateViewareaTimeout = setTimeout(() => { + if (!this._popStateInProgress) { + this._tryPushCurrentPosition(true); + } + + this._updateViewareaTimeout = null; + }, UPDATE_VIEWAREA_TIMEOUT); + } + } + + _popState(_ref5) { + let { + state + } = _ref5; + const newHash = getCurrentHash(), + hashChanged = this._currentHash !== newHash; + this._currentHash = newHash; + + if (!state) { + this._uid++; + + const { + hash, + page, + rotation + } = this._parseCurrentHash(); + + this._pushOrReplaceState({ + hash, + page, + rotation + }, true); + + return; + } + + if (!this._isValidState(state)) { + return; + } + + this._popStateInProgress = true; + + if (hashChanged) { + this._blockHashChange++; + (0, _event_utils.waitOnEventOrTimeout)({ + target: window, + name: "hashchange", + delay: HASH_CHANGE_TIMEOUT + }).then(() => { + this._blockHashChange--; + }); + } + + const destination = state.destination; + + this._updateInternalState(destination, state.uid, true); + + if ((0, _ui_utils.isValidRotation)(destination.rotation)) { + this.linkService.rotation = destination.rotation; + } + + if (destination.dest) { + this.linkService.goToDestination(destination.dest); + } else if (destination.hash) { + this.linkService.setHash(destination.hash); + } else if (destination.page) { + this.linkService.page = destination.page; + } + + Promise.resolve().then(() => { + this._popStateInProgress = false; + }); + } + + _pageHide() { + if (!this._destination || this._destination.temporary) { + this._tryPushCurrentPosition(); + } + } + + _bindEvents() { + if (this._boundEvents) { + return; + } + + this._boundEvents = { + updateViewarea: this._updateViewarea.bind(this), + popState: this._popState.bind(this), + pageHide: this._pageHide.bind(this) + }; + + this.eventBus._on("updateviewarea", this._boundEvents.updateViewarea); + + window.addEventListener("popstate", this._boundEvents.popState); + window.addEventListener("pagehide", this._boundEvents.pageHide); + } + + _unbindEvents() { + if (!this._boundEvents) { + return; + } + + this.eventBus._off("updateviewarea", this._boundEvents.updateViewarea); + + window.removeEventListener("popstate", this._boundEvents.popState); + window.removeEventListener("pagehide", this._boundEvents.pageHide); + this._boundEvents = null; + } + +} + +exports.PDFHistory = PDFHistory; + +function isDestHashesEqual(destHash, pushHash) { + if (typeof destHash !== "string" || typeof pushHash !== "string") { + return false; + } + + if (destHash === pushHash) { + return true; + } + + const nameddest = (0, _ui_utils.parseQueryString)(destHash).get("nameddest"); + + if (nameddest === pushHash) { + return true; + } + + return false; +} + +function isDestArraysEqual(firstDest, secondDest) { + function isEntryEqual(first, second) { + if (typeof first !== typeof second) { + return false; + } + + if (Array.isArray(first) || Array.isArray(second)) { + return false; + } + + if (first !== null && typeof first === "object" && second !== null) { + if (Object.keys(first).length !== Object.keys(second).length) { + return false; + } + + for (const key in first) { + if (!isEntryEqual(first[key], second[key])) { + return false; + } + } + + return true; + } + + return first === second || Number.isNaN(first) && Number.isNaN(second); + } + + if (!(Array.isArray(firstDest) && Array.isArray(secondDest))) { + return false; + } + + if (firstDest.length !== secondDest.length) { + return false; + } + + for (let i = 0, ii = firstDest.length; i < ii; i++) { + if (!isEntryEqual(firstDest[i], secondDest[i])) { + return false; + } + } + + return true; +} + +/***/ }), +/* 20 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFLayerViewer = void 0; + +var _base_tree_viewer = __webpack_require__(14); + +class PDFLayerViewer extends _base_tree_viewer.BaseTreeViewer { + constructor(options) { + super(options); + this.l10n = options.l10n; + + this.eventBus._on("resetlayers", this._resetLayers.bind(this)); + + this.eventBus._on("togglelayerstree", this._toggleAllTreeItems.bind(this)); + } + + reset() { + super.reset(); + this._optionalContentConfig = null; + } + + _dispatchEvent(layersCount) { + this.eventBus.dispatch("layersloaded", { + source: this, + layersCount + }); + } + + _bindLink(element, _ref) { + let { + groupId, + input + } = _ref; + + const setVisibility = () => { + this._optionalContentConfig.setVisibility(groupId, input.checked); + + this.eventBus.dispatch("optionalcontentconfig", { + source: this, + promise: Promise.resolve(this._optionalContentConfig) + }); + }; + + element.onclick = evt => { + if (evt.target === input) { + setVisibility(); + return true; + } else if (evt.target !== element) { + return true; + } + + input.checked = !input.checked; + setVisibility(); + return false; + }; + } + + async _setNestedName(element, _ref2) { + let { + name = null + } = _ref2; + + if (typeof name === "string") { + element.textContent = this._normalizeTextContent(name); + return; + } + + element.textContent = await this.l10n.get("additional_layers"); + element.style.fontStyle = "italic"; + } + + _addToggleButton(div, _ref3) { + let { + name = null + } = _ref3; + + super._addToggleButton(div, name === null); + } + + _toggleAllTreeItems() { + if (!this._optionalContentConfig) { + return; + } + + super._toggleAllTreeItems(); + } + + render(_ref4) { + let { + optionalContentConfig, + pdfDocument + } = _ref4; + + if (this._optionalContentConfig) { + this.reset(); + } + + this._optionalContentConfig = optionalContentConfig || null; + this._pdfDocument = pdfDocument || null; + const groups = optionalContentConfig === null || optionalContentConfig === void 0 ? void 0 : optionalContentConfig.getOrder(); + + if (!groups) { + this._dispatchEvent(0); + + return; + } + + const fragment = document.createDocumentFragment(), + queue = [{ + parent: fragment, + groups + }]; + let layersCount = 0, + hasAnyNesting = false; + + while (queue.length > 0) { + const levelData = queue.shift(); + + for (const groupId of levelData.groups) { + const div = document.createElement("div"); + div.className = "treeItem"; + const element = document.createElement("a"); + div.append(element); + + if (typeof groupId === "object") { + hasAnyNesting = true; + + this._addToggleButton(div, groupId); + + this._setNestedName(element, groupId); + + const itemsDiv = document.createElement("div"); + itemsDiv.className = "treeItems"; + div.append(itemsDiv); + queue.push({ + parent: itemsDiv, + groups: groupId.order + }); + } else { + const group = optionalContentConfig.getGroup(groupId); + const input = document.createElement("input"); + + this._bindLink(element, { + groupId, + input + }); + + input.type = "checkbox"; + input.checked = group.visible; + const label = document.createElement("label"); + label.textContent = this._normalizeTextContent(group.name); + label.append(input); + element.append(label); + layersCount++; + } + + levelData.parent.append(div); + } + } + + this._finishRendering(fragment, layersCount, hasAnyNesting); + } + + async _resetLayers() { + if (!this._optionalContentConfig) { + return; + } + + const optionalContentConfig = await this._pdfDocument.getOptionalContentConfig(); + this.eventBus.dispatch("optionalcontentconfig", { + source: this, + promise: Promise.resolve(optionalContentConfig) + }); + this.render({ + optionalContentConfig, + pdfDocument: this._pdfDocument + }); + } + +} + +exports.PDFLayerViewer = PDFLayerViewer; + +/***/ }), +/* 21 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFOutlineViewer = void 0; + +var _base_tree_viewer = __webpack_require__(14); + +var _pdfjsLib = __webpack_require__(5); + +var _ui_utils = __webpack_require__(1); + +class PDFOutlineViewer extends _base_tree_viewer.BaseTreeViewer { + constructor(options) { + super(options); + this.linkService = options.linkService; + + this.eventBus._on("toggleoutlinetree", this._toggleAllTreeItems.bind(this)); + + this.eventBus._on("currentoutlineitem", this._currentOutlineItem.bind(this)); + + this.eventBus._on("pagechanging", evt => { + this._currentPageNumber = evt.pageNumber; + }); + + this.eventBus._on("pagesloaded", evt => { + this._isPagesLoaded = !!evt.pagesCount; + + if (this._currentOutlineItemCapability && !this._currentOutlineItemCapability.settled) { + this._currentOutlineItemCapability.resolve(this._isPagesLoaded); + } + }); + + this.eventBus._on("sidebarviewchanged", evt => { + this._sidebarView = evt.view; + }); + } + + reset() { + super.reset(); + this._outline = null; + this._pageNumberToDestHashCapability = null; + this._currentPageNumber = 1; + this._isPagesLoaded = null; + + if (this._currentOutlineItemCapability && !this._currentOutlineItemCapability.settled) { + this._currentOutlineItemCapability.resolve(false); + } + + this._currentOutlineItemCapability = null; + } + + _dispatchEvent(outlineCount) { + var _this$_pdfDocument; + + this._currentOutlineItemCapability = (0, _pdfjsLib.createPromiseCapability)(); + + if (outlineCount === 0 || (_this$_pdfDocument = this._pdfDocument) !== null && _this$_pdfDocument !== void 0 && _this$_pdfDocument.loadingParams.disableAutoFetch) { + this._currentOutlineItemCapability.resolve(false); + } else if (this._isPagesLoaded !== null) { + this._currentOutlineItemCapability.resolve(this._isPagesLoaded); + } + + this.eventBus.dispatch("outlineloaded", { + source: this, + outlineCount, + currentOutlineItemPromise: this._currentOutlineItemCapability.promise + }); + } + + _bindLink(element, _ref) { + let { + url, + newWindow, + dest + } = _ref; + const { + linkService + } = this; + + if (url) { + linkService.addLinkAttributes(element, url, newWindow); + return; + } + + element.href = linkService.getDestinationHash(dest); + + element.onclick = evt => { + this._updateCurrentTreeItem(evt.target.parentNode); + + if (dest) { + linkService.goToDestination(dest); + } + + return false; + }; + } + + _setStyles(element, _ref2) { + let { + bold, + italic + } = _ref2; + + if (bold) { + element.style.fontWeight = "bold"; + } + + if (italic) { + element.style.fontStyle = "italic"; + } + } + + _addToggleButton(div, _ref3) { + let { + count, + items + } = _ref3; + let hidden = false; + + if (count < 0) { + let totalCount = items.length; + + if (totalCount > 0) { + const queue = [...items]; + + while (queue.length > 0) { + const { + count: nestedCount, + items: nestedItems + } = queue.shift(); + + if (nestedCount > 0 && nestedItems.length > 0) { + totalCount += nestedItems.length; + queue.push(...nestedItems); + } + } + } + + if (Math.abs(count) === totalCount) { + hidden = true; + } + } + + super._addToggleButton(div, hidden); + } + + _toggleAllTreeItems() { + if (!this._outline) { + return; + } + + super._toggleAllTreeItems(); + } + + render(_ref4) { + let { + outline, + pdfDocument + } = _ref4; + + if (this._outline) { + this.reset(); + } + + this._outline = outline || null; + this._pdfDocument = pdfDocument || null; + + if (!outline) { + this._dispatchEvent(0); + + return; + } + + const fragment = document.createDocumentFragment(); + const queue = [{ + parent: fragment, + items: outline + }]; + let outlineCount = 0, + hasAnyNesting = false; + + while (queue.length > 0) { + const levelData = queue.shift(); + + for (const item of levelData.items) { + const div = document.createElement("div"); + div.className = "treeItem"; + const element = document.createElement("a"); + + this._bindLink(element, item); + + this._setStyles(element, item); + + element.textContent = this._normalizeTextContent(item.title); + div.append(element); + + if (item.items.length > 0) { + hasAnyNesting = true; + + this._addToggleButton(div, item); + + const itemsDiv = document.createElement("div"); + itemsDiv.className = "treeItems"; + div.append(itemsDiv); + queue.push({ + parent: itemsDiv, + items: item.items + }); + } + + levelData.parent.append(div); + outlineCount++; + } + } + + this._finishRendering(fragment, outlineCount, hasAnyNesting); + } + + async _currentOutlineItem() { + if (!this._isPagesLoaded) { + throw new Error("_currentOutlineItem: All pages have not been loaded."); + } + + if (!this._outline || !this._pdfDocument) { + return; + } + + const pageNumberToDestHash = await this._getPageNumberToDestHash(this._pdfDocument); + + if (!pageNumberToDestHash) { + return; + } + + this._updateCurrentTreeItem(null); + + if (this._sidebarView !== _ui_utils.SidebarView.OUTLINE) { + return; + } + + for (let i = this._currentPageNumber; i > 0; i--) { + const destHash = pageNumberToDestHash.get(i); + + if (!destHash) { + continue; + } + + const linkElement = this.container.querySelector(`a[href="${destHash}"]`); + + if (!linkElement) { + continue; + } + + this._scrollToCurrentTreeItem(linkElement.parentNode); + + break; + } + } + + async _getPageNumberToDestHash(pdfDocument) { + if (this._pageNumberToDestHashCapability) { + return this._pageNumberToDestHashCapability.promise; + } + + this._pageNumberToDestHashCapability = (0, _pdfjsLib.createPromiseCapability)(); + const pageNumberToDestHash = new Map(), + pageNumberNesting = new Map(); + const queue = [{ + nesting: 0, + items: this._outline + }]; + + while (queue.length > 0) { + const levelData = queue.shift(), + currentNesting = levelData.nesting; + + for (const { + dest, + items + } of levelData.items) { + let explicitDest, pageNumber; + + if (typeof dest === "string") { + explicitDest = await pdfDocument.getDestination(dest); + + if (pdfDocument !== this._pdfDocument) { + return null; + } + } else { + explicitDest = dest; + } + + if (Array.isArray(explicitDest)) { + const [destRef] = explicitDest; + + if (typeof destRef === "object" && destRef !== null) { + pageNumber = this.linkService._cachedPageNumber(destRef); + + if (!pageNumber) { + try { + pageNumber = (await pdfDocument.getPageIndex(destRef)) + 1; + + if (pdfDocument !== this._pdfDocument) { + return null; + } + + this.linkService.cachePageRef(pageNumber, destRef); + } catch (ex) {} + } + } else if (Number.isInteger(destRef)) { + pageNumber = destRef + 1; + } + + if (Number.isInteger(pageNumber) && (!pageNumberToDestHash.has(pageNumber) || currentNesting > pageNumberNesting.get(pageNumber))) { + const destHash = this.linkService.getDestinationHash(dest); + pageNumberToDestHash.set(pageNumber, destHash); + pageNumberNesting.set(pageNumber, currentNesting); + } + } + + if (items.length > 0) { + queue.push({ + nesting: currentNesting + 1, + items + }); + } + } + } + + this._pageNumberToDestHashCapability.resolve(pageNumberToDestHash.size > 0 ? pageNumberToDestHash : null); + + return this._pageNumberToDestHashCapability.promise; + } + +} + +exports.PDFOutlineViewer = PDFOutlineViewer; + +/***/ }), +/* 22 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFPresentationMode = void 0; + +var _ui_utils = __webpack_require__(1); + +var _pdfjsLib = __webpack_require__(5); + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } + +function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } + +function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +const DELAY_BEFORE_HIDING_CONTROLS = 3000; +const ACTIVE_SELECTOR = "pdfPresentationMode"; +const CONTROLS_SELECTOR = "pdfPresentationModeControls"; +const MOUSE_SCROLL_COOLDOWN_TIME = 50; +const PAGE_SWITCH_THRESHOLD = 0.1; +const SWIPE_MIN_DISTANCE_THRESHOLD = 50; +const SWIPE_ANGLE_THRESHOLD = Math.PI / 6; + +var _state = /*#__PURE__*/new WeakMap(); + +var _args = /*#__PURE__*/new WeakMap(); + +var _mouseWheel = /*#__PURE__*/new WeakSet(); + +var _notifyStateChange = /*#__PURE__*/new WeakSet(); + +var _enter = /*#__PURE__*/new WeakSet(); + +var _exit = /*#__PURE__*/new WeakSet(); + +var _mouseDown = /*#__PURE__*/new WeakSet(); + +var _contextMenu = /*#__PURE__*/new WeakSet(); + +var _showControls = /*#__PURE__*/new WeakSet(); + +var _hideControls = /*#__PURE__*/new WeakSet(); + +var _resetMouseScrollState = /*#__PURE__*/new WeakSet(); + +var _touchSwipe = /*#__PURE__*/new WeakSet(); + +var _addWindowListeners = /*#__PURE__*/new WeakSet(); + +var _removeWindowListeners = /*#__PURE__*/new WeakSet(); + +var _fullscreenChange = /*#__PURE__*/new WeakSet(); + +var _addFullscreenChangeListeners = /*#__PURE__*/new WeakSet(); + +var _removeFullscreenChangeListeners = /*#__PURE__*/new WeakSet(); + +class PDFPresentationMode { + constructor(_ref) { + let { + container, + pdfViewer, + eventBus + } = _ref; + + _classPrivateMethodInitSpec(this, _removeFullscreenChangeListeners); + + _classPrivateMethodInitSpec(this, _addFullscreenChangeListeners); + + _classPrivateMethodInitSpec(this, _fullscreenChange); + + _classPrivateMethodInitSpec(this, _removeWindowListeners); + + _classPrivateMethodInitSpec(this, _addWindowListeners); + + _classPrivateMethodInitSpec(this, _touchSwipe); + + _classPrivateMethodInitSpec(this, _resetMouseScrollState); + + _classPrivateMethodInitSpec(this, _hideControls); + + _classPrivateMethodInitSpec(this, _showControls); + + _classPrivateMethodInitSpec(this, _contextMenu); + + _classPrivateMethodInitSpec(this, _mouseDown); + + _classPrivateMethodInitSpec(this, _exit); + + _classPrivateMethodInitSpec(this, _enter); + + _classPrivateMethodInitSpec(this, _notifyStateChange); + + _classPrivateMethodInitSpec(this, _mouseWheel); + + _classPrivateFieldInitSpec(this, _state, { + writable: true, + value: _ui_utils.PresentationModeState.UNKNOWN + }); + + _classPrivateFieldInitSpec(this, _args, { + writable: true, + value: null + }); + + this.container = container; + this.pdfViewer = pdfViewer; + this.eventBus = eventBus; + this.contextMenuOpen = false; + this.mouseScrollTimeStamp = 0; + this.mouseScrollDelta = 0; + this.touchSwipeState = null; + } + + async request() { + const { + container, + pdfViewer + } = this; + + if (this.active || !pdfViewer.pagesCount || !container.requestFullscreen) { + return false; + } + + _classPrivateMethodGet(this, _addFullscreenChangeListeners, _addFullscreenChangeListeners2).call(this); + + _classPrivateMethodGet(this, _notifyStateChange, _notifyStateChange2).call(this, _ui_utils.PresentationModeState.CHANGING); + + const promise = container.requestFullscreen(); + + _classPrivateFieldSet(this, _args, { + pageNumber: pdfViewer.currentPageNumber, + scaleValue: pdfViewer.currentScaleValue, + scrollMode: pdfViewer.scrollMode, + spreadMode: null, + annotationEditorMode: null + }); + + if (pdfViewer.spreadMode !== _ui_utils.SpreadMode.NONE && !(pdfViewer.pageViewsReady && pdfViewer.hasEqualPageSizes)) { + console.warn("Ignoring Spread modes when entering PresentationMode, " + "since the document may contain varying page sizes."); + _classPrivateFieldGet(this, _args).spreadMode = pdfViewer.spreadMode; + } + + if (pdfViewer.annotationEditorMode !== _pdfjsLib.AnnotationEditorType.DISABLE) { + _classPrivateFieldGet(this, _args).annotationEditorMode = pdfViewer.annotationEditorMode; + } + + try { + await promise; + pdfViewer.focus(); + return true; + } catch (reason) { + _classPrivateMethodGet(this, _removeFullscreenChangeListeners, _removeFullscreenChangeListeners2).call(this); + + _classPrivateMethodGet(this, _notifyStateChange, _notifyStateChange2).call(this, _ui_utils.PresentationModeState.NORMAL); + } + + return false; + } + + get active() { + return _classPrivateFieldGet(this, _state) === _ui_utils.PresentationModeState.CHANGING || _classPrivateFieldGet(this, _state) === _ui_utils.PresentationModeState.FULLSCREEN; + } + +} + +exports.PDFPresentationMode = PDFPresentationMode; + +function _mouseWheel2(evt) { + if (!this.active) { + return; + } + + evt.preventDefault(); + const delta = (0, _ui_utils.normalizeWheelEventDelta)(evt); + const currentTime = Date.now(); + const storedTime = this.mouseScrollTimeStamp; + + if (currentTime > storedTime && currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) { + return; + } + + if (this.mouseScrollDelta > 0 && delta < 0 || this.mouseScrollDelta < 0 && delta > 0) { + _classPrivateMethodGet(this, _resetMouseScrollState, _resetMouseScrollState2).call(this); + } + + this.mouseScrollDelta += delta; + + if (Math.abs(this.mouseScrollDelta) >= PAGE_SWITCH_THRESHOLD) { + const totalDelta = this.mouseScrollDelta; + + _classPrivateMethodGet(this, _resetMouseScrollState, _resetMouseScrollState2).call(this); + + const success = totalDelta > 0 ? this.pdfViewer.previousPage() : this.pdfViewer.nextPage(); + + if (success) { + this.mouseScrollTimeStamp = currentTime; + } + } +} + +function _notifyStateChange2(state) { + _classPrivateFieldSet(this, _state, state); + + this.eventBus.dispatch("presentationmodechanged", { + source: this, + state + }); +} + +function _enter2() { + _classPrivateMethodGet(this, _notifyStateChange, _notifyStateChange2).call(this, _ui_utils.PresentationModeState.FULLSCREEN); + + this.container.classList.add(ACTIVE_SELECTOR); + setTimeout(() => { + this.pdfViewer.scrollMode = _ui_utils.ScrollMode.PAGE; + + if (_classPrivateFieldGet(this, _args).spreadMode !== null) { + this.pdfViewer.spreadMode = _ui_utils.SpreadMode.NONE; + } + + this.pdfViewer.currentPageNumber = _classPrivateFieldGet(this, _args).pageNumber; + this.pdfViewer.currentScaleValue = "page-fit"; + + if (_classPrivateFieldGet(this, _args).annotationEditorMode !== null) { + this.pdfViewer.annotationEditorMode = _pdfjsLib.AnnotationEditorType.NONE; + } + }, 0); + + _classPrivateMethodGet(this, _addWindowListeners, _addWindowListeners2).call(this); + + _classPrivateMethodGet(this, _showControls, _showControls2).call(this); + + this.contextMenuOpen = false; + window.getSelection().removeAllRanges(); +} + +function _exit2() { + const pageNumber = this.pdfViewer.currentPageNumber; + this.container.classList.remove(ACTIVE_SELECTOR); + setTimeout(() => { + _classPrivateMethodGet(this, _removeFullscreenChangeListeners, _removeFullscreenChangeListeners2).call(this); + + _classPrivateMethodGet(this, _notifyStateChange, _notifyStateChange2).call(this, _ui_utils.PresentationModeState.NORMAL); + + this.pdfViewer.scrollMode = _classPrivateFieldGet(this, _args).scrollMode; + + if (_classPrivateFieldGet(this, _args).spreadMode !== null) { + this.pdfViewer.spreadMode = _classPrivateFieldGet(this, _args).spreadMode; + } + + this.pdfViewer.currentScaleValue = _classPrivateFieldGet(this, _args).scaleValue; + this.pdfViewer.currentPageNumber = pageNumber; + + if (_classPrivateFieldGet(this, _args).annotationEditorMode !== null) { + this.pdfViewer.annotationEditorMode = _classPrivateFieldGet(this, _args).annotationEditorMode; + } + + _classPrivateFieldSet(this, _args, null); + }, 0); + + _classPrivateMethodGet(this, _removeWindowListeners, _removeWindowListeners2).call(this); + + _classPrivateMethodGet(this, _hideControls, _hideControls2).call(this); + + _classPrivateMethodGet(this, _resetMouseScrollState, _resetMouseScrollState2).call(this); + + this.contextMenuOpen = false; +} + +function _mouseDown2(evt) { + if (this.contextMenuOpen) { + this.contextMenuOpen = false; + evt.preventDefault(); + return; + } + + if (evt.button === 0) { + const isInternalLink = evt.target.href && evt.target.classList.contains("internalLink"); + + if (!isInternalLink) { + evt.preventDefault(); + + if (evt.shiftKey) { + this.pdfViewer.previousPage(); + } else { + this.pdfViewer.nextPage(); + } + } + } +} + +function _contextMenu2() { + this.contextMenuOpen = true; +} + +function _showControls2() { + if (this.controlsTimeout) { + clearTimeout(this.controlsTimeout); + } else { + this.container.classList.add(CONTROLS_SELECTOR); + } + + this.controlsTimeout = setTimeout(() => { + this.container.classList.remove(CONTROLS_SELECTOR); + delete this.controlsTimeout; + }, DELAY_BEFORE_HIDING_CONTROLS); +} + +function _hideControls2() { + if (!this.controlsTimeout) { + return; + } + + clearTimeout(this.controlsTimeout); + this.container.classList.remove(CONTROLS_SELECTOR); + delete this.controlsTimeout; +} + +function _resetMouseScrollState2() { + this.mouseScrollTimeStamp = 0; + this.mouseScrollDelta = 0; +} + +function _touchSwipe2(evt) { + if (!this.active) { + return; + } + + if (evt.touches.length > 1) { + this.touchSwipeState = null; + return; + } + + switch (evt.type) { + case "touchstart": + this.touchSwipeState = { + startX: evt.touches[0].pageX, + startY: evt.touches[0].pageY, + endX: evt.touches[0].pageX, + endY: evt.touches[0].pageY + }; + break; + + case "touchmove": + if (this.touchSwipeState === null) { + return; + } + + this.touchSwipeState.endX = evt.touches[0].pageX; + this.touchSwipeState.endY = evt.touches[0].pageY; + evt.preventDefault(); + break; + + case "touchend": + if (this.touchSwipeState === null) { + return; + } + + let delta = 0; + const dx = this.touchSwipeState.endX - this.touchSwipeState.startX; + const dy = this.touchSwipeState.endY - this.touchSwipeState.startY; + const absAngle = Math.abs(Math.atan2(dy, dx)); + + if (Math.abs(dx) > SWIPE_MIN_DISTANCE_THRESHOLD && (absAngle <= SWIPE_ANGLE_THRESHOLD || absAngle >= Math.PI - SWIPE_ANGLE_THRESHOLD)) { + delta = dx; + } else if (Math.abs(dy) > SWIPE_MIN_DISTANCE_THRESHOLD && Math.abs(absAngle - Math.PI / 2) <= SWIPE_ANGLE_THRESHOLD) { + delta = dy; + } + + if (delta > 0) { + this.pdfViewer.previousPage(); + } else if (delta < 0) { + this.pdfViewer.nextPage(); + } + + break; + } +} + +function _addWindowListeners2() { + this.showControlsBind = _classPrivateMethodGet(this, _showControls, _showControls2).bind(this); + this.mouseDownBind = _classPrivateMethodGet(this, _mouseDown, _mouseDown2).bind(this); + this.mouseWheelBind = _classPrivateMethodGet(this, _mouseWheel, _mouseWheel2).bind(this); + this.resetMouseScrollStateBind = _classPrivateMethodGet(this, _resetMouseScrollState, _resetMouseScrollState2).bind(this); + this.contextMenuBind = _classPrivateMethodGet(this, _contextMenu, _contextMenu2).bind(this); + this.touchSwipeBind = _classPrivateMethodGet(this, _touchSwipe, _touchSwipe2).bind(this); + window.addEventListener("mousemove", this.showControlsBind); + window.addEventListener("mousedown", this.mouseDownBind); + window.addEventListener("wheel", this.mouseWheelBind, { + passive: false + }); + window.addEventListener("keydown", this.resetMouseScrollStateBind); + window.addEventListener("contextmenu", this.contextMenuBind); + window.addEventListener("touchstart", this.touchSwipeBind); + window.addEventListener("touchmove", this.touchSwipeBind); + window.addEventListener("touchend", this.touchSwipeBind); +} + +function _removeWindowListeners2() { + window.removeEventListener("mousemove", this.showControlsBind); + window.removeEventListener("mousedown", this.mouseDownBind); + window.removeEventListener("wheel", this.mouseWheelBind, { + passive: false + }); + window.removeEventListener("keydown", this.resetMouseScrollStateBind); + window.removeEventListener("contextmenu", this.contextMenuBind); + window.removeEventListener("touchstart", this.touchSwipeBind); + window.removeEventListener("touchmove", this.touchSwipeBind); + window.removeEventListener("touchend", this.touchSwipeBind); + delete this.showControlsBind; + delete this.mouseDownBind; + delete this.mouseWheelBind; + delete this.resetMouseScrollStateBind; + delete this.contextMenuBind; + delete this.touchSwipeBind; +} + +function _fullscreenChange2() { + if (document.fullscreenElement) { + _classPrivateMethodGet(this, _enter, _enter2).call(this); + } else { + _classPrivateMethodGet(this, _exit, _exit2).call(this); + } +} + +function _addFullscreenChangeListeners2() { + this.fullscreenChangeBind = _classPrivateMethodGet(this, _fullscreenChange, _fullscreenChange2).bind(this); + window.addEventListener("fullscreenchange", this.fullscreenChangeBind); +} + +function _removeFullscreenChangeListeners2() { + window.removeEventListener("fullscreenchange", this.fullscreenChangeBind); + delete this.fullscreenChangeBind; +} + +/***/ }), +/* 23 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFRenderingQueue = void 0; + +var _pdfjsLib = __webpack_require__(5); + +var _ui_utils = __webpack_require__(1); + +const CLEANUP_TIMEOUT = 30000; + +class PDFRenderingQueue { + constructor() { + this.pdfViewer = null; + this.pdfThumbnailViewer = null; + this.onIdle = null; + this.highestPriorityPage = null; + this.idleTimeout = null; + this.printing = false; + this.isThumbnailViewEnabled = false; + } + + setViewer(pdfViewer) { + this.pdfViewer = pdfViewer; + } + + setThumbnailViewer(pdfThumbnailViewer) { + this.pdfThumbnailViewer = pdfThumbnailViewer; + } + + isHighestPriority(view) { + return this.highestPriorityPage === view.renderingId; + } + + hasViewer() { + return !!this.pdfViewer; + } + + renderHighestPriority(currentlyVisiblePages) { + var _this$pdfThumbnailVie; + + if (this.idleTimeout) { + clearTimeout(this.idleTimeout); + this.idleTimeout = null; + } + + if (this.pdfViewer.forceRendering(currentlyVisiblePages)) { + return; + } + + if (this.isThumbnailViewEnabled && (_this$pdfThumbnailVie = this.pdfThumbnailViewer) !== null && _this$pdfThumbnailVie !== void 0 && _this$pdfThumbnailVie.forceRendering()) { + return; + } + + if (this.printing) { + return; + } + + if (this.onIdle) { + this.idleTimeout = setTimeout(this.onIdle.bind(this), CLEANUP_TIMEOUT); + } + } + + getHighestPriority(visible, views, scrolledDown) { + let preRenderExtra = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; + const visibleViews = visible.views, + numVisible = visibleViews.length; + + if (numVisible === 0) { + return null; + } + + for (let i = 0; i < numVisible; i++) { + const view = visibleViews[i].view; + + if (!this.isViewFinished(view)) { + return view; + } + } + + const firstId = visible.first.id, + lastId = visible.last.id; + + if (lastId - firstId + 1 > numVisible) { + const visibleIds = visible.ids; + + for (let i = 1, ii = lastId - firstId; i < ii; i++) { + const holeId = scrolledDown ? firstId + i : lastId - i; + + if (visibleIds.has(holeId)) { + continue; + } + + const holeView = views[holeId - 1]; + + if (!this.isViewFinished(holeView)) { + return holeView; + } + } + } + + let preRenderIndex = scrolledDown ? lastId : firstId - 2; + let preRenderView = views[preRenderIndex]; + + if (preRenderView && !this.isViewFinished(preRenderView)) { + return preRenderView; + } + + if (preRenderExtra) { + preRenderIndex += scrolledDown ? 1 : -1; + preRenderView = views[preRenderIndex]; + + if (preRenderView && !this.isViewFinished(preRenderView)) { + return preRenderView; + } + } + + return null; + } + + isViewFinished(view) { + return view.renderingState === _ui_utils.RenderingStates.FINISHED; + } + + renderView(view) { + switch (view.renderingState) { + case _ui_utils.RenderingStates.FINISHED: + return false; + + case _ui_utils.RenderingStates.PAUSED: + this.highestPriorityPage = view.renderingId; + view.resume(); + break; + + case _ui_utils.RenderingStates.RUNNING: + this.highestPriorityPage = view.renderingId; + break; + + case _ui_utils.RenderingStates.INITIAL: + this.highestPriorityPage = view.renderingId; + view.draw().finally(() => { + this.renderHighestPriority(); + }).catch(reason => { + if (reason instanceof _pdfjsLib.RenderingCancelledException) { + return; + } + + console.error(`renderView: "${reason}"`); + }); + break; + } + + return true; + } + +} + +exports.PDFRenderingQueue = PDFRenderingQueue; + +/***/ }), +/* 24 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFScriptingManager = void 0; + +var _ui_utils = __webpack_require__(1); + +var _pdfjsLib = __webpack_require__(5); + +class PDFScriptingManager { + constructor(_ref) { + let { + eventBus, + sandboxBundleSrc = null, + scriptingFactory = null, + docPropertiesLookup = null + } = _ref; + this._pdfDocument = null; + this._pdfViewer = null; + this._closeCapability = null; + this._destroyCapability = null; + this._scripting = null; + this._mouseState = Object.create(null); + this._ready = false; + this._eventBus = eventBus; + this._sandboxBundleSrc = sandboxBundleSrc; + this._scriptingFactory = scriptingFactory; + this._docPropertiesLookup = docPropertiesLookup; + } + + setViewer(pdfViewer) { + this._pdfViewer = pdfViewer; + } + + async setDocument(pdfDocument) { + var _this$_scripting3; + + if (this._pdfDocument) { + await this._destroyScripting(); + } + + this._pdfDocument = pdfDocument; + + if (!pdfDocument) { + return; + } + + const [objects, calculationOrder, docActions] = await Promise.all([pdfDocument.getFieldObjects(), pdfDocument.getCalculationOrderIds(), pdfDocument.getJSActions()]); + + if (!objects && !docActions) { + await this._destroyScripting(); + return; + } + + if (pdfDocument !== this._pdfDocument) { + return; + } + + try { + this._scripting = this._createScripting(); + } catch (error) { + console.error(`PDFScriptingManager.setDocument: "${error === null || error === void 0 ? void 0 : error.message}".`); + await this._destroyScripting(); + return; + } + + this._internalEvents.set("updatefromsandbox", event => { + if ((event === null || event === void 0 ? void 0 : event.source) !== window) { + return; + } + + this._updateFromSandbox(event.detail); + }); + + this._internalEvents.set("dispatcheventinsandbox", event => { + var _this$_scripting; + + (_this$_scripting = this._scripting) === null || _this$_scripting === void 0 ? void 0 : _this$_scripting.dispatchEventInSandbox(event.detail); + }); + + this._internalEvents.set("pagechanging", _ref2 => { + let { + pageNumber, + previous + } = _ref2; + + if (pageNumber === previous) { + return; + } + + this._dispatchPageClose(previous); + + this._dispatchPageOpen(pageNumber); + }); + + this._internalEvents.set("pagerendered", _ref3 => { + let { + pageNumber + } = _ref3; + + if (!this._pageOpenPending.has(pageNumber)) { + return; + } + + if (pageNumber !== this._pdfViewer.currentPageNumber) { + return; + } + + this._dispatchPageOpen(pageNumber); + }); + + this._internalEvents.set("pagesdestroy", async event => { + var _this$_scripting2, _this$_closeCapabilit; + + await this._dispatchPageClose(this._pdfViewer.currentPageNumber); + await ((_this$_scripting2 = this._scripting) === null || _this$_scripting2 === void 0 ? void 0 : _this$_scripting2.dispatchEventInSandbox({ + id: "doc", + name: "WillClose" + })); + (_this$_closeCapabilit = this._closeCapability) === null || _this$_closeCapabilit === void 0 ? void 0 : _this$_closeCapabilit.resolve(); + }); + + this._domEvents.set("mousedown", event => { + this._mouseState.isDown = true; + }); + + this._domEvents.set("mouseup", event => { + this._mouseState.isDown = false; + }); + + for (const [name, listener] of this._internalEvents) { + this._eventBus._on(name, listener); + } + + for (const [name, listener] of this._domEvents) { + window.addEventListener(name, listener, true); + } + + try { + const docProperties = await this._getDocProperties(); + + if (pdfDocument !== this._pdfDocument) { + return; + } + + await this._scripting.createSandbox({ + objects, + calculationOrder, + appInfo: { + platform: navigator.platform, + language: navigator.language + }, + docInfo: { ...docProperties, + actions: docActions + } + }); + + this._eventBus.dispatch("sandboxcreated", { + source: this + }); + } catch (error) { + console.error(`PDFScriptingManager.setDocument: "${error === null || error === void 0 ? void 0 : error.message}".`); + await this._destroyScripting(); + return; + } + + await ((_this$_scripting3 = this._scripting) === null || _this$_scripting3 === void 0 ? void 0 : _this$_scripting3.dispatchEventInSandbox({ + id: "doc", + name: "Open" + })); + await this._dispatchPageOpen(this._pdfViewer.currentPageNumber, true); + Promise.resolve().then(() => { + if (pdfDocument === this._pdfDocument) { + this._ready = true; + } + }); + } + + async dispatchWillSave(detail) { + var _this$_scripting4; + + return (_this$_scripting4 = this._scripting) === null || _this$_scripting4 === void 0 ? void 0 : _this$_scripting4.dispatchEventInSandbox({ + id: "doc", + name: "WillSave" + }); + } + + async dispatchDidSave(detail) { + var _this$_scripting5; + + return (_this$_scripting5 = this._scripting) === null || _this$_scripting5 === void 0 ? void 0 : _this$_scripting5.dispatchEventInSandbox({ + id: "doc", + name: "DidSave" + }); + } + + async dispatchWillPrint(detail) { + var _this$_scripting6; + + return (_this$_scripting6 = this._scripting) === null || _this$_scripting6 === void 0 ? void 0 : _this$_scripting6.dispatchEventInSandbox({ + id: "doc", + name: "WillPrint" + }); + } + + async dispatchDidPrint(detail) { + var _this$_scripting7; + + return (_this$_scripting7 = this._scripting) === null || _this$_scripting7 === void 0 ? void 0 : _this$_scripting7.dispatchEventInSandbox({ + id: "doc", + name: "DidPrint" + }); + } + + get mouseState() { + return this._mouseState; + } + + get destroyPromise() { + var _this$_destroyCapabil; + + return ((_this$_destroyCapabil = this._destroyCapability) === null || _this$_destroyCapabil === void 0 ? void 0 : _this$_destroyCapabil.promise) || null; + } + + get ready() { + return this._ready; + } + + get _internalEvents() { + return (0, _pdfjsLib.shadow)(this, "_internalEvents", new Map()); + } + + get _domEvents() { + return (0, _pdfjsLib.shadow)(this, "_domEvents", new Map()); + } + + get _pageOpenPending() { + return (0, _pdfjsLib.shadow)(this, "_pageOpenPending", new Set()); + } + + get _visitedPages() { + return (0, _pdfjsLib.shadow)(this, "_visitedPages", new Map()); + } + + async _updateFromSandbox(detail) { + const isInPresentationMode = this._pdfViewer.isInPresentationMode || this._pdfViewer.isChangingPresentationMode; + const { + id, + siblings, + command, + value + } = detail; + + if (!id) { + switch (command) { + case "clear": + console.clear(); + break; + + case "error": + console.error(value); + break; + + case "layout": + if (isInPresentationMode) { + return; + } + + const modes = (0, _ui_utils.apiPageLayoutToViewerModes)(value); + this._pdfViewer.spreadMode = modes.spreadMode; + break; + + case "page-num": + this._pdfViewer.currentPageNumber = value + 1; + break; + + case "print": + await this._pdfViewer.pagesPromise; + + this._eventBus.dispatch("print", { + source: this + }); + + break; + + case "println": + console.log(value); + break; + + case "zoom": + if (isInPresentationMode) { + return; + } + + this._pdfViewer.currentScaleValue = value; + break; + + case "SaveAs": + this._eventBus.dispatch("download", { + source: this + }); + + break; + + case "FirstPage": + this._pdfViewer.currentPageNumber = 1; + break; + + case "LastPage": + this._pdfViewer.currentPageNumber = this._pdfViewer.pagesCount; + break; + + case "NextPage": + this._pdfViewer.nextPage(); + + break; + + case "PrevPage": + this._pdfViewer.previousPage(); + + break; + + case "ZoomViewIn": + if (isInPresentationMode) { + return; + } + + this._pdfViewer.increaseScale(); + + break; + + case "ZoomViewOut": + if (isInPresentationMode) { + return; + } + + this._pdfViewer.decreaseScale(); + + break; + } + + return; + } + + if (isInPresentationMode) { + if (detail.focus) { + return; + } + } + + delete detail.id; + delete detail.siblings; + const ids = siblings ? [id, ...siblings] : [id]; + + for (const elementId of ids) { + const element = document.querySelector(`[data-element-id="${elementId}"]`); + + if (element) { + element.dispatchEvent(new CustomEvent("updatefromsandbox", { + detail + })); + } else { + var _this$_pdfDocument; + + (_this$_pdfDocument = this._pdfDocument) === null || _this$_pdfDocument === void 0 ? void 0 : _this$_pdfDocument.annotationStorage.setValue(elementId, detail); + } + } + } + + async _dispatchPageOpen(pageNumber) { + let initialize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + const pdfDocument = this._pdfDocument, + visitedPages = this._visitedPages; + + if (initialize) { + this._closeCapability = (0, _pdfjsLib.createPromiseCapability)(); + } + + if (!this._closeCapability) { + return; + } + + const pageView = this._pdfViewer.getPageView(pageNumber - 1); + + if ((pageView === null || pageView === void 0 ? void 0 : pageView.renderingState) !== _ui_utils.RenderingStates.FINISHED) { + this._pageOpenPending.add(pageNumber); + + return; + } + + this._pageOpenPending.delete(pageNumber); + + const actionsPromise = (async () => { + var _pageView$pdfPage, _this$_scripting8; + + const actions = await (!visitedPages.has(pageNumber) ? (_pageView$pdfPage = pageView.pdfPage) === null || _pageView$pdfPage === void 0 ? void 0 : _pageView$pdfPage.getJSActions() : null); + + if (pdfDocument !== this._pdfDocument) { + return; + } + + await ((_this$_scripting8 = this._scripting) === null || _this$_scripting8 === void 0 ? void 0 : _this$_scripting8.dispatchEventInSandbox({ + id: "page", + name: "PageOpen", + pageNumber, + actions + })); + })(); + + visitedPages.set(pageNumber, actionsPromise); + } + + async _dispatchPageClose(pageNumber) { + var _this$_scripting9; + + const pdfDocument = this._pdfDocument, + visitedPages = this._visitedPages; + + if (!this._closeCapability) { + return; + } + + if (this._pageOpenPending.has(pageNumber)) { + return; + } + + const actionsPromise = visitedPages.get(pageNumber); + + if (!actionsPromise) { + return; + } + + visitedPages.set(pageNumber, null); + await actionsPromise; + + if (pdfDocument !== this._pdfDocument) { + return; + } + + await ((_this$_scripting9 = this._scripting) === null || _this$_scripting9 === void 0 ? void 0 : _this$_scripting9.dispatchEventInSandbox({ + id: "page", + name: "PageClose", + pageNumber + })); + } + + async _getDocProperties() { + if (this._docPropertiesLookup) { + return this._docPropertiesLookup(this._pdfDocument); + } + + throw new Error("_getDocProperties: Unable to lookup properties."); + } + + _createScripting() { + this._destroyCapability = (0, _pdfjsLib.createPromiseCapability)(); + + if (this._scripting) { + throw new Error("_createScripting: Scripting already exists."); + } + + if (this._scriptingFactory) { + return this._scriptingFactory.createScripting({ + sandboxBundleSrc: this._sandboxBundleSrc + }); + } + + throw new Error("_createScripting: Cannot create scripting."); + } + + async _destroyScripting() { + var _this$_destroyCapabil3; + + if (!this._scripting) { + var _this$_destroyCapabil2; + + this._pdfDocument = null; + (_this$_destroyCapabil2 = this._destroyCapability) === null || _this$_destroyCapabil2 === void 0 ? void 0 : _this$_destroyCapabil2.resolve(); + return; + } + + if (this._closeCapability) { + await Promise.race([this._closeCapability.promise, new Promise(resolve => { + setTimeout(resolve, 1000); + })]).catch(reason => {}); + this._closeCapability = null; + } + + this._pdfDocument = null; + + try { + await this._scripting.destroySandbox(); + } catch (ex) {} + + for (const [name, listener] of this._internalEvents) { + this._eventBus._off(name, listener); + } + + this._internalEvents.clear(); + + for (const [name, listener] of this._domEvents) { + window.removeEventListener(name, listener, true); + } + + this._domEvents.clear(); + + this._pageOpenPending.clear(); + + this._visitedPages.clear(); + + this._scripting = null; + delete this._mouseState.isDown; + this._ready = false; + (_this$_destroyCapabil3 = this._destroyCapability) === null || _this$_destroyCapabil3 === void 0 ? void 0 : _this$_destroyCapabil3.resolve(); + } + +} + +exports.PDFScriptingManager = PDFScriptingManager; + +/***/ }), +/* 25 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFSidebar = void 0; + +var _ui_utils = __webpack_require__(1); + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +const UI_NOTIFICATION_CLASS = "pdfSidebarNotification"; + +var _dispatchEvent = /*#__PURE__*/new WeakSet(); + +var _forceRendering = /*#__PURE__*/new WeakSet(); + +var _updateThumbnailViewer = /*#__PURE__*/new WeakSet(); + +var _showUINotification = /*#__PURE__*/new WeakSet(); + +var _hideUINotification = /*#__PURE__*/new WeakSet(); + +var _addEventListeners = /*#__PURE__*/new WeakSet(); + +class PDFSidebar { + constructor(_ref) { + let { + elements, + pdfViewer: _pdfViewer, + pdfThumbnailViewer: _pdfThumbnailViewer, + eventBus, + l10n + } = _ref; + + _classPrivateMethodInitSpec(this, _addEventListeners); + + _classPrivateMethodInitSpec(this, _hideUINotification); + + _classPrivateMethodInitSpec(this, _showUINotification); + + _classPrivateMethodInitSpec(this, _updateThumbnailViewer); + + _classPrivateMethodInitSpec(this, _forceRendering); + + _classPrivateMethodInitSpec(this, _dispatchEvent); + + this.isOpen = false; + this.active = _ui_utils.SidebarView.THUMBS; + this.isInitialViewSet = false; + this.isInitialEventDispatched = false; + this.onToggled = null; + this.pdfViewer = _pdfViewer; + this.pdfThumbnailViewer = _pdfThumbnailViewer; + this.outerContainer = elements.outerContainer; + this.sidebarContainer = elements.sidebarContainer; + this.toggleButton = elements.toggleButton; + this.thumbnailButton = elements.thumbnailButton; + this.outlineButton = elements.outlineButton; + this.attachmentsButton = elements.attachmentsButton; + this.layersButton = elements.layersButton; + this.thumbnailView = elements.thumbnailView; + this.outlineView = elements.outlineView; + this.attachmentsView = elements.attachmentsView; + this.layersView = elements.layersView; + this._outlineOptionsContainer = elements.outlineOptionsContainer; + this._currentOutlineItemButton = elements.currentOutlineItemButton; + this.eventBus = eventBus; + this.l10n = l10n; + + _classPrivateMethodGet(this, _addEventListeners, _addEventListeners2).call(this); + } + + reset() { + this.isInitialViewSet = false; + this.isInitialEventDispatched = false; + + _classPrivateMethodGet(this, _hideUINotification, _hideUINotification2).call(this, true); + + this.switchView(_ui_utils.SidebarView.THUMBS); + this.outlineButton.disabled = false; + this.attachmentsButton.disabled = false; + this.layersButton.disabled = false; + this._currentOutlineItemButton.disabled = true; + } + + get visibleView() { + return this.isOpen ? this.active : _ui_utils.SidebarView.NONE; + } + + setInitialView() { + let view = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _ui_utils.SidebarView.NONE; + + if (this.isInitialViewSet) { + return; + } + + this.isInitialViewSet = true; + + if (view === _ui_utils.SidebarView.NONE || view === _ui_utils.SidebarView.UNKNOWN) { + _classPrivateMethodGet(this, _dispatchEvent, _dispatchEvent2).call(this); + + return; + } + + this.switchView(view, true); + + if (!this.isInitialEventDispatched) { + _classPrivateMethodGet(this, _dispatchEvent, _dispatchEvent2).call(this); + } + } + + switchView(view) { + let forceOpen = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + const isViewChanged = view !== this.active; + let shouldForceRendering = false; + + switch (view) { + case _ui_utils.SidebarView.NONE: + if (this.isOpen) { + this.close(); + } + + return; + + case _ui_utils.SidebarView.THUMBS: + if (this.isOpen && isViewChanged) { + shouldForceRendering = true; + } + + break; + + case _ui_utils.SidebarView.OUTLINE: + if (this.outlineButton.disabled) { + return; + } + + break; + + case _ui_utils.SidebarView.ATTACHMENTS: + if (this.attachmentsButton.disabled) { + return; + } + + break; + + case _ui_utils.SidebarView.LAYERS: + if (this.layersButton.disabled) { + return; + } + + break; + + default: + console.error(`PDFSidebar.switchView: "${view}" is not a valid view.`); + return; + } + + this.active = view; + const isThumbs = view === _ui_utils.SidebarView.THUMBS, + isOutline = view === _ui_utils.SidebarView.OUTLINE, + isAttachments = view === _ui_utils.SidebarView.ATTACHMENTS, + isLayers = view === _ui_utils.SidebarView.LAYERS; + this.thumbnailButton.classList.toggle("toggled", isThumbs); + this.outlineButton.classList.toggle("toggled", isOutline); + this.attachmentsButton.classList.toggle("toggled", isAttachments); + this.layersButton.classList.toggle("toggled", isLayers); + this.thumbnailButton.setAttribute("aria-checked", isThumbs); + this.outlineButton.setAttribute("aria-checked", isOutline); + this.attachmentsButton.setAttribute("aria-checked", isAttachments); + this.layersButton.setAttribute("aria-checked", isLayers); + this.thumbnailView.classList.toggle("hidden", !isThumbs); + this.outlineView.classList.toggle("hidden", !isOutline); + this.attachmentsView.classList.toggle("hidden", !isAttachments); + this.layersView.classList.toggle("hidden", !isLayers); + + this._outlineOptionsContainer.classList.toggle("hidden", !isOutline); + + if (forceOpen && !this.isOpen) { + this.open(); + return; + } + + if (shouldForceRendering) { + _classPrivateMethodGet(this, _updateThumbnailViewer, _updateThumbnailViewer2).call(this); + + _classPrivateMethodGet(this, _forceRendering, _forceRendering2).call(this); + } + + if (isViewChanged) { + _classPrivateMethodGet(this, _dispatchEvent, _dispatchEvent2).call(this); + } + } + + open() { + if (this.isOpen) { + return; + } + + this.isOpen = true; + this.toggleButton.classList.add("toggled"); + this.toggleButton.setAttribute("aria-expanded", "true"); + this.outerContainer.classList.add("sidebarMoving", "sidebarOpen"); + + if (this.active === _ui_utils.SidebarView.THUMBS) { + _classPrivateMethodGet(this, _updateThumbnailViewer, _updateThumbnailViewer2).call(this); + } + + _classPrivateMethodGet(this, _forceRendering, _forceRendering2).call(this); + + _classPrivateMethodGet(this, _dispatchEvent, _dispatchEvent2).call(this); + + _classPrivateMethodGet(this, _hideUINotification, _hideUINotification2).call(this); + } + + close() { + if (!this.isOpen) { + return; + } + + this.isOpen = false; + this.toggleButton.classList.remove("toggled"); + this.toggleButton.setAttribute("aria-expanded", "false"); + this.outerContainer.classList.add("sidebarMoving"); + this.outerContainer.classList.remove("sidebarOpen"); + + _classPrivateMethodGet(this, _forceRendering, _forceRendering2).call(this); + + _classPrivateMethodGet(this, _dispatchEvent, _dispatchEvent2).call(this); + } + + toggle() { + if (this.isOpen) { + this.close(); + } else { + this.open(); + } + } + +} + +exports.PDFSidebar = PDFSidebar; + +function _dispatchEvent2() { + if (this.isInitialViewSet && !this.isInitialEventDispatched) { + this.isInitialEventDispatched = true; + } + + this.eventBus.dispatch("sidebarviewchanged", { + source: this, + view: this.visibleView + }); +} + +function _forceRendering2() { + if (this.onToggled) { + this.onToggled(); + } else { + this.pdfViewer.forceRendering(); + this.pdfThumbnailViewer.forceRendering(); + } +} + +function _updateThumbnailViewer2() { + const { + pdfViewer, + pdfThumbnailViewer + } = this; + const pagesCount = pdfViewer.pagesCount; + + for (let pageIndex = 0; pageIndex < pagesCount; pageIndex++) { + const pageView = pdfViewer.getPageView(pageIndex); + + if ((pageView === null || pageView === void 0 ? void 0 : pageView.renderingState) === _ui_utils.RenderingStates.FINISHED) { + const thumbnailView = pdfThumbnailViewer.getThumbnail(pageIndex); + thumbnailView.setImage(pageView); + } + } + + pdfThumbnailViewer.scrollThumbnailIntoView(pdfViewer.currentPageNumber); +} + +function _showUINotification2() { + this.l10n.get("toggle_sidebar_notification2.title").then(msg => { + this.toggleButton.title = msg; + }); + + if (!this.isOpen) { + this.toggleButton.classList.add(UI_NOTIFICATION_CLASS); + } +} + +function _hideUINotification2() { + let reset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + if (this.isOpen || reset) { + this.toggleButton.classList.remove(UI_NOTIFICATION_CLASS); + } + + if (reset) { + this.l10n.get("toggle_sidebar.title").then(msg => { + this.toggleButton.title = msg; + }); + } +} + +function _addEventListeners2() { + this.sidebarContainer.addEventListener("transitionend", evt => { + if (evt.target === this.sidebarContainer) { + this.outerContainer.classList.remove("sidebarMoving"); + } + }); + this.toggleButton.addEventListener("click", () => { + this.toggle(); + }); + this.thumbnailButton.addEventListener("click", () => { + this.switchView(_ui_utils.SidebarView.THUMBS); + }); + this.outlineButton.addEventListener("click", () => { + this.switchView(_ui_utils.SidebarView.OUTLINE); + }); + this.outlineButton.addEventListener("dblclick", () => { + this.eventBus.dispatch("toggleoutlinetree", { + source: this + }); + }); + this.attachmentsButton.addEventListener("click", () => { + this.switchView(_ui_utils.SidebarView.ATTACHMENTS); + }); + this.layersButton.addEventListener("click", () => { + this.switchView(_ui_utils.SidebarView.LAYERS); + }); + this.layersButton.addEventListener("dblclick", () => { + this.eventBus.dispatch("resetlayers", { + source: this + }); + }); + + this._currentOutlineItemButton.addEventListener("click", () => { + this.eventBus.dispatch("currentoutlineitem", { + source: this + }); + }); + + const onTreeLoaded = (count, button, view) => { + button.disabled = !count; + + if (count) { + _classPrivateMethodGet(this, _showUINotification, _showUINotification2).call(this); + } else if (this.active === view) { + this.switchView(_ui_utils.SidebarView.THUMBS); + } + }; + + this.eventBus._on("outlineloaded", evt => { + onTreeLoaded(evt.outlineCount, this.outlineButton, _ui_utils.SidebarView.OUTLINE); + evt.currentOutlineItemPromise.then(enabled => { + if (!this.isInitialViewSet) { + return; + } + + this._currentOutlineItemButton.disabled = !enabled; + }); + }); + + this.eventBus._on("attachmentsloaded", evt => { + onTreeLoaded(evt.attachmentsCount, this.attachmentsButton, _ui_utils.SidebarView.ATTACHMENTS); + }); + + this.eventBus._on("layersloaded", evt => { + onTreeLoaded(evt.layersCount, this.layersButton, _ui_utils.SidebarView.LAYERS); + }); + + this.eventBus._on("presentationmodechanged", evt => { + if (evt.state === _ui_utils.PresentationModeState.NORMAL && this.visibleView === _ui_utils.SidebarView.THUMBS) { + _classPrivateMethodGet(this, _updateThumbnailViewer, _updateThumbnailViewer2).call(this); + } + }); +} + +/***/ }), +/* 26 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFSidebarResizer = void 0; + +var _ui_utils = __webpack_require__(1); + +const SIDEBAR_WIDTH_VAR = "--sidebar-width"; +const SIDEBAR_MIN_WIDTH = 200; +const SIDEBAR_RESIZING_CLASS = "sidebarResizing"; + +class PDFSidebarResizer { + constructor(options, eventBus, l10n) { + this.isRTL = false; + this.sidebarOpen = false; + this._width = null; + this._outerContainerWidth = null; + this._boundEvents = Object.create(null); + this.outerContainer = options.outerContainer; + this.resizer = options.resizer; + this.eventBus = eventBus; + l10n.getDirection().then(dir => { + this.isRTL = dir === "rtl"; + }); + + this._addEventListeners(); + } + + get outerContainerWidth() { + return this._outerContainerWidth || (this._outerContainerWidth = this.outerContainer.clientWidth); + } + + _updateWidth() { + let width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + const maxWidth = Math.floor(this.outerContainerWidth / 2); + + if (width > maxWidth) { + width = maxWidth; + } + + if (width < SIDEBAR_MIN_WIDTH) { + width = SIDEBAR_MIN_WIDTH; + } + + if (width === this._width) { + return false; + } + + this._width = width; + + _ui_utils.docStyle.setProperty(SIDEBAR_WIDTH_VAR, `${width}px`); + + return true; + } + + _mouseMove(evt) { + let width = evt.clientX; + + if (this.isRTL) { + width = this.outerContainerWidth - width; + } + + this._updateWidth(width); + } + + _mouseUp(evt) { + this.outerContainer.classList.remove(SIDEBAR_RESIZING_CLASS); + this.eventBus.dispatch("resize", { + source: this + }); + const _boundEvents = this._boundEvents; + window.removeEventListener("mousemove", _boundEvents.mouseMove); + window.removeEventListener("mouseup", _boundEvents.mouseUp); + } + + _addEventListeners() { + const _boundEvents = this._boundEvents; + _boundEvents.mouseMove = this._mouseMove.bind(this); + _boundEvents.mouseUp = this._mouseUp.bind(this); + this.resizer.addEventListener("mousedown", evt => { + if (evt.button !== 0) { + return; + } + + this.outerContainer.classList.add(SIDEBAR_RESIZING_CLASS); + window.addEventListener("mousemove", _boundEvents.mouseMove); + window.addEventListener("mouseup", _boundEvents.mouseUp); + }); + + this.eventBus._on("sidebarviewchanged", evt => { + this.sidebarOpen = !!(evt !== null && evt !== void 0 && evt.view); + }); + + this.eventBus._on("resize", evt => { + if ((evt === null || evt === void 0 ? void 0 : evt.source) !== window) { + return; + } + + this._outerContainerWidth = null; + + if (!this._width) { + return; + } + + if (!this.sidebarOpen) { + this._updateWidth(this._width); + + return; + } + + this.outerContainer.classList.add(SIDEBAR_RESIZING_CLASS); + + const updated = this._updateWidth(this._width); + + Promise.resolve().then(() => { + this.outerContainer.classList.remove(SIDEBAR_RESIZING_CLASS); + + if (updated) { + this.eventBus.dispatch("resize", { + source: this + }); + } + }); + }); + } + +} + +exports.PDFSidebarResizer = PDFSidebarResizer; + +/***/ }), +/* 27 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFThumbnailViewer = void 0; + +var _ui_utils = __webpack_require__(1); + +var _pdf_thumbnail_view = __webpack_require__(28); + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +const THUMBNAIL_SCROLL_MARGIN = -19; +const THUMBNAIL_SELECTED_CLASS = "selected"; + +var _ensurePdfPageLoaded = /*#__PURE__*/new WeakSet(); + +var _getScrollAhead = /*#__PURE__*/new WeakSet(); + +class PDFThumbnailViewer { + constructor(_ref) { + let { + container, + eventBus, + linkService, + renderingQueue, + l10n, + pageColors + } = _ref; + + _classPrivateMethodInitSpec(this, _getScrollAhead); + + _classPrivateMethodInitSpec(this, _ensurePdfPageLoaded); + + this.container = container; + this.linkService = linkService; + this.renderingQueue = renderingQueue; + this.l10n = l10n; + this.pageColors = pageColors || null; + + if (this.pageColors && !(CSS.supports("color", this.pageColors.background) && CSS.supports("color", this.pageColors.foreground))) { + if (this.pageColors.background || this.pageColors.foreground) { + console.warn("PDFThumbnailViewer: Ignoring `pageColors`-option, since the browser doesn't support the values used."); + } + + this.pageColors = null; + } + + this.scroll = (0, _ui_utils.watchScroll)(this.container, this._scrollUpdated.bind(this)); + + this._resetView(); + } + + _scrollUpdated() { + this.renderingQueue.renderHighestPriority(); + } + + getThumbnail(index) { + return this._thumbnails[index]; + } + + _getVisibleThumbs() { + return (0, _ui_utils.getVisibleElements)({ + scrollEl: this.container, + views: this._thumbnails + }); + } + + scrollThumbnailIntoView(pageNumber) { + if (!this.pdfDocument) { + return; + } + + const thumbnailView = this._thumbnails[pageNumber - 1]; + + if (!thumbnailView) { + console.error('scrollThumbnailIntoView: Invalid "pageNumber" parameter.'); + return; + } + + if (pageNumber !== this._currentPageNumber) { + const prevThumbnailView = this._thumbnails[this._currentPageNumber - 1]; + prevThumbnailView.div.classList.remove(THUMBNAIL_SELECTED_CLASS); + thumbnailView.div.classList.add(THUMBNAIL_SELECTED_CLASS); + } + + const { + first, + last, + views + } = this._getVisibleThumbs(); + + if (views.length > 0) { + let shouldScroll = false; + + if (pageNumber <= first.id || pageNumber >= last.id) { + shouldScroll = true; + } else { + for (const { + id, + percent + } of views) { + if (id !== pageNumber) { + continue; + } + + shouldScroll = percent < 100; + break; + } + } + + if (shouldScroll) { + (0, _ui_utils.scrollIntoView)(thumbnailView.div, { + top: THUMBNAIL_SCROLL_MARGIN + }); + } + } + + this._currentPageNumber = pageNumber; + } + + get pagesRotation() { + return this._pagesRotation; + } + + set pagesRotation(rotation) { + if (!(0, _ui_utils.isValidRotation)(rotation)) { + throw new Error("Invalid thumbnails rotation angle."); + } + + if (!this.pdfDocument) { + return; + } + + if (this._pagesRotation === rotation) { + return; + } + + this._pagesRotation = rotation; + const updateArgs = { + rotation + }; + + for (const thumbnail of this._thumbnails) { + thumbnail.update(updateArgs); + } + } + + cleanup() { + for (const thumbnail of this._thumbnails) { + if (thumbnail.renderingState !== _ui_utils.RenderingStates.FINISHED) { + thumbnail.reset(); + } + } + + _pdf_thumbnail_view.TempImageFactory.destroyCanvas(); + } + + _resetView() { + this._thumbnails = []; + this._currentPageNumber = 1; + this._pageLabels = null; + this._pagesRotation = 0; + this.container.textContent = ""; + } + + setDocument(pdfDocument) { + if (this.pdfDocument) { + this._cancelRendering(); + + this._resetView(); + } + + this.pdfDocument = pdfDocument; + + if (!pdfDocument) { + return; + } + + const firstPagePromise = pdfDocument.getPage(1); + const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig(); + firstPagePromise.then(firstPdfPage => { + const pagesCount = pdfDocument.numPages; + const viewport = firstPdfPage.getViewport({ + scale: 1 + }); + + for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) { + const thumbnail = new _pdf_thumbnail_view.PDFThumbnailView({ + container: this.container, + id: pageNum, + defaultViewport: viewport.clone(), + optionalContentConfigPromise, + linkService: this.linkService, + renderingQueue: this.renderingQueue, + l10n: this.l10n, + pageColors: this.pageColors + }); + + this._thumbnails.push(thumbnail); + } + + const firstThumbnailView = this._thumbnails[0]; + + if (firstThumbnailView) { + firstThumbnailView.setPdfPage(firstPdfPage); + } + + const thumbnailView = this._thumbnails[this._currentPageNumber - 1]; + thumbnailView.div.classList.add(THUMBNAIL_SELECTED_CLASS); + }).catch(reason => { + console.error("Unable to initialize thumbnail viewer", reason); + }); + } + + _cancelRendering() { + for (const thumbnail of this._thumbnails) { + thumbnail.cancelRendering(); + } + } + + setPageLabels(labels) { + if (!this.pdfDocument) { + return; + } + + if (!labels) { + this._pageLabels = null; + } else if (!(Array.isArray(labels) && this.pdfDocument.numPages === labels.length)) { + this._pageLabels = null; + console.error("PDFThumbnailViewer_setPageLabels: Invalid page labels."); + } else { + this._pageLabels = labels; + } + + for (let i = 0, ii = this._thumbnails.length; i < ii; i++) { + var _this$_pageLabels$i, _this$_pageLabels; + + this._thumbnails[i].setPageLabel((_this$_pageLabels$i = (_this$_pageLabels = this._pageLabels) === null || _this$_pageLabels === void 0 ? void 0 : _this$_pageLabels[i]) !== null && _this$_pageLabels$i !== void 0 ? _this$_pageLabels$i : null); + } + } + + forceRendering() { + const visibleThumbs = this._getVisibleThumbs(); + + const scrollAhead = _classPrivateMethodGet(this, _getScrollAhead, _getScrollAhead2).call(this, visibleThumbs); + + const thumbView = this.renderingQueue.getHighestPriority(visibleThumbs, this._thumbnails, scrollAhead); + + if (thumbView) { + _classPrivateMethodGet(this, _ensurePdfPageLoaded, _ensurePdfPageLoaded2).call(this, thumbView).then(() => { + this.renderingQueue.renderView(thumbView); + }); + + return true; + } + + return false; + } + +} + +exports.PDFThumbnailViewer = PDFThumbnailViewer; + +async function _ensurePdfPageLoaded2(thumbView) { + if (thumbView.pdfPage) { + return thumbView.pdfPage; + } + + try { + const pdfPage = await this.pdfDocument.getPage(thumbView.id); + + if (!thumbView.pdfPage) { + thumbView.setPdfPage(pdfPage); + } + + return pdfPage; + } catch (reason) { + console.error("Unable to get page for thumb view", reason); + return null; + } +} + +function _getScrollAhead2(visible) { + var _visible$first, _visible$last; + + if (((_visible$first = visible.first) === null || _visible$first === void 0 ? void 0 : _visible$first.id) === 1) { + return true; + } else if (((_visible$last = visible.last) === null || _visible$last === void 0 ? void 0 : _visible$last.id) === this._thumbnails.length) { + return false; + } + + return this.scroll.down; +} + +/***/ }), +/* 28 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.TempImageFactory = exports.PDFThumbnailView = void 0; + +var _ui_utils = __webpack_require__(1); + +var _pdfjsLib = __webpack_require__(5); + +function _classStaticPrivateFieldSpecSet(receiver, classConstructor, descriptor, value) { _classCheckPrivateStaticAccess(receiver, classConstructor); _classCheckPrivateStaticFieldDescriptor(descriptor, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } + +function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } + +function _classStaticPrivateFieldSpecGet(receiver, classConstructor, descriptor) { _classCheckPrivateStaticAccess(receiver, classConstructor); _classCheckPrivateStaticFieldDescriptor(descriptor, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classCheckPrivateStaticFieldDescriptor(descriptor, action) { if (descriptor === undefined) { throw new TypeError("attempted to " + action + " private static field before its declaration"); } } + +function _classCheckPrivateStaticAccess(receiver, classConstructor) { if (receiver !== classConstructor) { throw new TypeError("Private static access of wrong provenance"); } } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +const DRAW_UPSCALE_FACTOR = 2; +const MAX_NUM_SCALING_STEPS = 3; +const THUMBNAIL_CANVAS_BORDER_WIDTH = 1; +const THUMBNAIL_WIDTH = 98; + +class TempImageFactory { + static getCanvas(width, height) { + const tempCanvas = _classStaticPrivateFieldSpecGet(this, TempImageFactory, _tempCanvas) || _classStaticPrivateFieldSpecSet(this, TempImageFactory, _tempCanvas, document.createElement("canvas")); + + tempCanvas.width = width; + tempCanvas.height = height; + const ctx = tempCanvas.getContext("2d", { + alpha: false + }); + ctx.save(); + ctx.fillStyle = "rgb(255, 255, 255)"; + ctx.fillRect(0, 0, width, height); + ctx.restore(); + return [tempCanvas, tempCanvas.getContext("2d")]; + } + + static destroyCanvas() { + const tempCanvas = _classStaticPrivateFieldSpecGet(this, TempImageFactory, _tempCanvas); + + if (tempCanvas) { + tempCanvas.width = 0; + tempCanvas.height = 0; + } + + _classStaticPrivateFieldSpecSet(this, TempImageFactory, _tempCanvas, null); + } + +} + +exports.TempImageFactory = TempImageFactory; +var _tempCanvas = { + writable: true, + value: null +}; + +class PDFThumbnailView { + constructor(_ref) { + let { + container, + id, + defaultViewport, + optionalContentConfigPromise, + linkService, + renderingQueue, + l10n, + pageColors + } = _ref; + this.id = id; + this.renderingId = "thumbnail" + id; + this.pageLabel = null; + this.pdfPage = null; + this.rotation = 0; + this.viewport = defaultViewport; + this.pdfPageRotate = defaultViewport.rotation; + this._optionalContentConfigPromise = optionalContentConfigPromise || null; + this.pageColors = pageColors || null; + this.linkService = linkService; + this.renderingQueue = renderingQueue; + this.renderTask = null; + this.renderingState = _ui_utils.RenderingStates.INITIAL; + this.resume = null; + const pageWidth = this.viewport.width, + pageHeight = this.viewport.height, + pageRatio = pageWidth / pageHeight; + this.canvasWidth = THUMBNAIL_WIDTH; + this.canvasHeight = this.canvasWidth / pageRatio | 0; + this.scale = this.canvasWidth / pageWidth; + this.l10n = l10n; + const anchor = document.createElement("a"); + anchor.href = linkService.getAnchorUrl("#page=" + id); + + this._thumbPageTitle.then(msg => { + anchor.title = msg; + }); + + anchor.onclick = function () { + linkService.goToPage(id); + return false; + }; + + this.anchor = anchor; + const div = document.createElement("div"); + div.className = "thumbnail"; + div.setAttribute("data-page-number", this.id); + this.div = div; + const ring = document.createElement("div"); + ring.className = "thumbnailSelectionRing"; + const borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH; + ring.style.width = this.canvasWidth + borderAdjustment + "px"; + ring.style.height = this.canvasHeight + borderAdjustment + "px"; + this.ring = ring; + div.append(ring); + anchor.append(div); + container.append(anchor); + } + + setPdfPage(pdfPage) { + this.pdfPage = pdfPage; + this.pdfPageRotate = pdfPage.rotate; + const totalRotation = (this.rotation + this.pdfPageRotate) % 360; + this.viewport = pdfPage.getViewport({ + scale: 1, + rotation: totalRotation + }); + this.reset(); + } + + reset() { + this.cancelRendering(); + this.renderingState = _ui_utils.RenderingStates.INITIAL; + const pageWidth = this.viewport.width, + pageHeight = this.viewport.height, + pageRatio = pageWidth / pageHeight; + this.canvasHeight = this.canvasWidth / pageRatio | 0; + this.scale = this.canvasWidth / pageWidth; + this.div.removeAttribute("data-loaded"); + const ring = this.ring; + ring.textContent = ""; + const borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH; + ring.style.width = this.canvasWidth + borderAdjustment + "px"; + ring.style.height = this.canvasHeight + borderAdjustment + "px"; + + if (this.canvas) { + this.canvas.width = 0; + this.canvas.height = 0; + delete this.canvas; + } + + if (this.image) { + this.image.removeAttribute("src"); + delete this.image; + } + } + + update(_ref2) { + let { + rotation = null + } = _ref2; + + if (typeof rotation === "number") { + this.rotation = rotation; + } + + const totalRotation = (this.rotation + this.pdfPageRotate) % 360; + this.viewport = this.viewport.clone({ + scale: 1, + rotation: totalRotation + }); + this.reset(); + } + + cancelRendering() { + if (this.renderTask) { + this.renderTask.cancel(); + this.renderTask = null; + } + + this.resume = null; + } + + _getPageDrawContext() { + let upscaleFactor = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1; + const canvas = document.createElement("canvas"); + const ctx = canvas.getContext("2d", { + alpha: false + }); + const outputScale = new _ui_utils.OutputScale(); + canvas.width = upscaleFactor * this.canvasWidth * outputScale.sx | 0; + canvas.height = upscaleFactor * this.canvasHeight * outputScale.sy | 0; + const transform = outputScale.scaled ? [outputScale.sx, 0, 0, outputScale.sy, 0, 0] : null; + return { + ctx, + canvas, + transform + }; + } + + _convertCanvasToImage(canvas) { + if (this.renderingState !== _ui_utils.RenderingStates.FINISHED) { + throw new Error("_convertCanvasToImage: Rendering has not finished."); + } + + const reducedCanvas = this._reduceImage(canvas); + + const image = document.createElement("img"); + image.className = "thumbnailImage"; + + this._thumbPageCanvas.then(msg => { + image.setAttribute("aria-label", msg); + }); + + image.style.width = this.canvasWidth + "px"; + image.style.height = this.canvasHeight + "px"; + image.src = reducedCanvas.toDataURL(); + this.image = image; + this.div.setAttribute("data-loaded", true); + this.ring.append(image); + reducedCanvas.width = 0; + reducedCanvas.height = 0; + } + + draw() { + var _this = this; + + if (this.renderingState !== _ui_utils.RenderingStates.INITIAL) { + console.error("Must be in new state before drawing"); + return Promise.resolve(); + } + + const { + pdfPage + } = this; + + if (!pdfPage) { + this.renderingState = _ui_utils.RenderingStates.FINISHED; + return Promise.reject(new Error("pdfPage is not loaded")); + } + + this.renderingState = _ui_utils.RenderingStates.RUNNING; + + const finishRenderTask = async function () { + let error = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + + if (renderTask === _this.renderTask) { + _this.renderTask = null; + } + + if (error instanceof _pdfjsLib.RenderingCancelledException) { + return; + } + + _this.renderingState = _ui_utils.RenderingStates.FINISHED; + + _this._convertCanvasToImage(canvas); + + if (error) { + throw error; + } + }; + + const { + ctx, + canvas, + transform + } = this._getPageDrawContext(DRAW_UPSCALE_FACTOR); + + const drawViewport = this.viewport.clone({ + scale: DRAW_UPSCALE_FACTOR * this.scale + }); + + const renderContinueCallback = cont => { + if (!this.renderingQueue.isHighestPriority(this)) { + this.renderingState = _ui_utils.RenderingStates.PAUSED; + + this.resume = () => { + this.renderingState = _ui_utils.RenderingStates.RUNNING; + cont(); + }; + + return; + } + + cont(); + }; + + const renderContext = { + canvasContext: ctx, + transform, + viewport: drawViewport, + optionalContentConfigPromise: this._optionalContentConfigPromise, + pageColors: this.pageColors + }; + const renderTask = this.renderTask = pdfPage.render(renderContext); + renderTask.onContinue = renderContinueCallback; + const resultPromise = renderTask.promise.then(function () { + return finishRenderTask(null); + }, function (error) { + return finishRenderTask(error); + }); + resultPromise.finally(() => { + canvas.width = 0; + canvas.height = 0; + const pageCached = this.linkService.isPageCached(this.id); + + if (!pageCached) { + var _this$pdfPage; + + (_this$pdfPage = this.pdfPage) === null || _this$pdfPage === void 0 ? void 0 : _this$pdfPage.cleanup(); + } + }); + return resultPromise; + } + + setImage(pageView) { + if (this.renderingState !== _ui_utils.RenderingStates.INITIAL) { + return; + } + + const { + thumbnailCanvas: canvas, + pdfPage, + scale + } = pageView; + + if (!canvas) { + return; + } + + if (!this.pdfPage) { + this.setPdfPage(pdfPage); + } + + if (scale < this.scale) { + return; + } + + this.renderingState = _ui_utils.RenderingStates.FINISHED; + + this._convertCanvasToImage(canvas); + } + + _reduceImage(img) { + const { + ctx, + canvas + } = this._getPageDrawContext(); + + if (img.width <= 2 * canvas.width) { + ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height); + return canvas; + } + + let reducedWidth = canvas.width << MAX_NUM_SCALING_STEPS; + let reducedHeight = canvas.height << MAX_NUM_SCALING_STEPS; + const [reducedImage, reducedImageCtx] = TempImageFactory.getCanvas(reducedWidth, reducedHeight); + + while (reducedWidth > img.width || reducedHeight > img.height) { + reducedWidth >>= 1; + reducedHeight >>= 1; + } + + reducedImageCtx.drawImage(img, 0, 0, img.width, img.height, 0, 0, reducedWidth, reducedHeight); + + while (reducedWidth > 2 * canvas.width) { + reducedImageCtx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, 0, 0, reducedWidth >> 1, reducedHeight >> 1); + reducedWidth >>= 1; + reducedHeight >>= 1; + } + + ctx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, 0, 0, canvas.width, canvas.height); + return canvas; + } + + get _thumbPageTitle() { + var _this$pageLabel; + + return this.l10n.get("thumb_page_title", { + page: (_this$pageLabel = this.pageLabel) !== null && _this$pageLabel !== void 0 ? _this$pageLabel : this.id + }); + } + + get _thumbPageCanvas() { + var _this$pageLabel2; + + return this.l10n.get("thumb_page_canvas", { + page: (_this$pageLabel2 = this.pageLabel) !== null && _this$pageLabel2 !== void 0 ? _this$pageLabel2 : this.id + }); + } + + setPageLabel(label) { + this.pageLabel = typeof label === "string" ? label : null; + + this._thumbPageTitle.then(msg => { + this.anchor.title = msg; + }); + + if (this.renderingState !== _ui_utils.RenderingStates.FINISHED) { + return; + } + + this._thumbPageCanvas.then(msg => { + var _this$image; + + (_this$image = this.image) === null || _this$image === void 0 ? void 0 : _this$image.setAttribute("aria-label", msg); + }); + } + +} + +exports.PDFThumbnailView = PDFThumbnailView; + +/***/ }), +/* 29 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFViewer = exports.PDFSinglePageViewer = void 0; + +var _ui_utils = __webpack_require__(1); + +var _base_viewer = __webpack_require__(30); + +class PDFViewer extends _base_viewer.BaseViewer {} + +exports.PDFViewer = PDFViewer; + +class PDFSinglePageViewer extends _base_viewer.BaseViewer { + _resetView() { + super._resetView(); + + this._scrollMode = _ui_utils.ScrollMode.PAGE; + this._spreadMode = _ui_utils.SpreadMode.NONE; + } + + set scrollMode(mode) {} + + _updateScrollMode() {} + + set spreadMode(mode) {} + + _updateSpreadMode() {} + +} + +exports.PDFSinglePageViewer = PDFSinglePageViewer; + +/***/ }), +/* 30 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PagesCountLimit = exports.PDFPageViewBuffer = exports.BaseViewer = void 0; + +var _pdfjsLib = __webpack_require__(5); + +var _ui_utils = __webpack_require__(1); + +var _annotation_editor_layer_builder = __webpack_require__(31); + +var _annotation_layer_builder = __webpack_require__(33); + +var _l10n_utils = __webpack_require__(32); + +var _pdf_page_view = __webpack_require__(34); + +var _pdf_rendering_queue = __webpack_require__(23); + +var _pdf_link_service = __webpack_require__(3); + +var _struct_tree_layer_builder = __webpack_require__(36); + +var _text_highlighter = __webpack_require__(37); + +var _text_layer_builder = __webpack_require__(38); + +var _xfa_layer_builder = __webpack_require__(39); + +let _Symbol$iterator; + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } + +function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } + +function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } + +const DEFAULT_CACHE_SIZE = 10; +const ENABLE_PERMISSIONS_CLASS = "enablePermissions"; +const PagesCountLimit = { + FORCE_SCROLL_MODE_PAGE: 15000, + FORCE_LAZY_PAGE_INIT: 7500, + PAUSE_EAGER_PAGE_INIT: 250 +}; +exports.PagesCountLimit = PagesCountLimit; + +function isValidAnnotationEditorMode(mode) { + return Object.values(_pdfjsLib.AnnotationEditorType).includes(mode) && mode !== _pdfjsLib.AnnotationEditorType.DISABLE; +} + +var _buf = /*#__PURE__*/new WeakMap(); + +var _size = /*#__PURE__*/new WeakMap(); + +var _destroyFirstView = /*#__PURE__*/new WeakSet(); + +_Symbol$iterator = Symbol.iterator; + +class PDFPageViewBuffer { + constructor(size) { + _classPrivateMethodInitSpec(this, _destroyFirstView); + + _classPrivateFieldInitSpec(this, _buf, { + writable: true, + value: new Set() + }); + + _classPrivateFieldInitSpec(this, _size, { + writable: true, + value: 0 + }); + + _classPrivateFieldSet(this, _size, size); + } + + push(view) { + const buf = _classPrivateFieldGet(this, _buf); + + if (buf.has(view)) { + buf.delete(view); + } + + buf.add(view); + + if (buf.size > _classPrivateFieldGet(this, _size)) { + _classPrivateMethodGet(this, _destroyFirstView, _destroyFirstView2).call(this); + } + } + + resize(newSize) { + let idsToKeep = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + + _classPrivateFieldSet(this, _size, newSize); + + const buf = _classPrivateFieldGet(this, _buf); + + if (idsToKeep) { + const ii = buf.size; + let i = 1; + + for (const view of buf) { + if (idsToKeep.has(view.id)) { + buf.delete(view); + buf.add(view); + } + + if (++i > ii) { + break; + } + } + } + + while (buf.size > _classPrivateFieldGet(this, _size)) { + _classPrivateMethodGet(this, _destroyFirstView, _destroyFirstView2).call(this); + } + } + + has(view) { + return _classPrivateFieldGet(this, _buf).has(view); + } + + [_Symbol$iterator]() { + return _classPrivateFieldGet(this, _buf).keys(); + } + +} + +exports.PDFPageViewBuffer = PDFPageViewBuffer; + +function _destroyFirstView2() { + const firstView = _classPrivateFieldGet(this, _buf).keys().next().value; + + firstView === null || firstView === void 0 ? void 0 : firstView.destroy(); + + _classPrivateFieldGet(this, _buf).delete(firstView); +} + +var _buffer = /*#__PURE__*/new WeakMap(); + +var _annotationEditorMode = /*#__PURE__*/new WeakMap(); + +var _annotationEditorUIManager = /*#__PURE__*/new WeakMap(); + +var _annotationMode = /*#__PURE__*/new WeakMap(); + +var _enablePermissions = /*#__PURE__*/new WeakMap(); + +var _previousContainerHeight = /*#__PURE__*/new WeakMap(); + +var _scrollModePageState = /*#__PURE__*/new WeakMap(); + +var _onVisibilityChange = /*#__PURE__*/new WeakMap(); + +var _initializePermissions = /*#__PURE__*/new WeakSet(); + +var _onePageRenderedOrForceFetch = /*#__PURE__*/new WeakSet(); + +var _ensurePageViewVisible = /*#__PURE__*/new WeakSet(); + +var _scrollIntoView = /*#__PURE__*/new WeakSet(); + +var _isSameScale = /*#__PURE__*/new WeakSet(); + +var _resetCurrentPageView = /*#__PURE__*/new WeakSet(); + +var _ensurePdfPageLoaded = /*#__PURE__*/new WeakSet(); + +var _getScrollAhead = /*#__PURE__*/new WeakSet(); + +var _toggleLoadingIconSpinner = /*#__PURE__*/new WeakSet(); + +class BaseViewer { + constructor(options) { + var _this$container, _this$viewer, _options$textLayerMod, _options$annotationMo, _options$annotationEd; + + _classPrivateMethodInitSpec(this, _toggleLoadingIconSpinner); + + _classPrivateMethodInitSpec(this, _getScrollAhead); + + _classPrivateMethodInitSpec(this, _ensurePdfPageLoaded); + + _classPrivateMethodInitSpec(this, _resetCurrentPageView); + + _classPrivateMethodInitSpec(this, _isSameScale); + + _classPrivateMethodInitSpec(this, _scrollIntoView); + + _classPrivateMethodInitSpec(this, _ensurePageViewVisible); + + _classPrivateMethodInitSpec(this, _onePageRenderedOrForceFetch); + + _classPrivateMethodInitSpec(this, _initializePermissions); + + _classPrivateFieldInitSpec(this, _buffer, { + writable: true, + value: null + }); + + _classPrivateFieldInitSpec(this, _annotationEditorMode, { + writable: true, + value: _pdfjsLib.AnnotationEditorType.DISABLE + }); + + _classPrivateFieldInitSpec(this, _annotationEditorUIManager, { + writable: true, + value: null + }); + + _classPrivateFieldInitSpec(this, _annotationMode, { + writable: true, + value: _pdfjsLib.AnnotationMode.ENABLE_FORMS + }); + + _classPrivateFieldInitSpec(this, _enablePermissions, { + writable: true, + value: false + }); + + _classPrivateFieldInitSpec(this, _previousContainerHeight, { + writable: true, + value: 0 + }); + + _classPrivateFieldInitSpec(this, _scrollModePageState, { + writable: true, + value: null + }); + + _classPrivateFieldInitSpec(this, _onVisibilityChange, { + writable: true, + value: null + }); + + if (this.constructor === BaseViewer) { + throw new Error("Cannot initialize BaseViewer."); + } + + const viewerVersion = '2.16.105'; + + if (_pdfjsLib.version !== viewerVersion) { + throw new Error(`The API version "${_pdfjsLib.version}" does not match the Viewer version "${viewerVersion}".`); + } + + this.container = options.container; + this.viewer = options.viewer || options.container.firstElementChild; + + if (!(((_this$container = this.container) === null || _this$container === void 0 ? void 0 : _this$container.tagName.toUpperCase()) === "DIV" && ((_this$viewer = this.viewer) === null || _this$viewer === void 0 ? void 0 : _this$viewer.tagName.toUpperCase()) === "DIV")) { + throw new Error("Invalid `container` and/or `viewer` option."); + } + + if (this.container.offsetParent && getComputedStyle(this.container).position !== "absolute") { + throw new Error("The `container` must be absolutely positioned."); + } + + this.eventBus = options.eventBus; + this.linkService = options.linkService || new _pdf_link_service.SimpleLinkService(); + this.downloadManager = options.downloadManager || null; + this.findController = options.findController || null; + this._scriptingManager = options.scriptingManager || null; + this.removePageBorders = options.removePageBorders || false; + this.textLayerMode = (_options$textLayerMod = options.textLayerMode) !== null && _options$textLayerMod !== void 0 ? _options$textLayerMod : _ui_utils.TextLayerMode.ENABLE; + + _classPrivateFieldSet(this, _annotationMode, (_options$annotationMo = options.annotationMode) !== null && _options$annotationMo !== void 0 ? _options$annotationMo : _pdfjsLib.AnnotationMode.ENABLE_FORMS); + + _classPrivateFieldSet(this, _annotationEditorMode, (_options$annotationEd = options.annotationEditorMode) !== null && _options$annotationEd !== void 0 ? _options$annotationEd : _pdfjsLib.AnnotationEditorType.DISABLE); + + this.imageResourcesPath = options.imageResourcesPath || ""; + this.enablePrintAutoRotate = options.enablePrintAutoRotate || false; + this.renderer = options.renderer || _ui_utils.RendererType.CANVAS; + this.useOnlyCssZoom = options.useOnlyCssZoom || false; + this.maxCanvasPixels = options.maxCanvasPixels; + this.l10n = options.l10n || _l10n_utils.NullL10n; + + _classPrivateFieldSet(this, _enablePermissions, options.enablePermissions || false); + + this.pageColors = options.pageColors || null; + + if (this.pageColors && !(CSS.supports("color", this.pageColors.background) && CSS.supports("color", this.pageColors.foreground))) { + if (this.pageColors.background || this.pageColors.foreground) { + console.warn("BaseViewer: Ignoring `pageColors`-option, since the browser doesn't support the values used."); + } + + this.pageColors = null; + } + + this.defaultRenderingQueue = !options.renderingQueue; + + if (this.defaultRenderingQueue) { + this.renderingQueue = new _pdf_rendering_queue.PDFRenderingQueue(); + this.renderingQueue.setViewer(this); + } else { + this.renderingQueue = options.renderingQueue; + } + + this.scroll = (0, _ui_utils.watchScroll)(this.container, this._scrollUpdate.bind(this)); + this.presentationModeState = _ui_utils.PresentationModeState.UNKNOWN; + this._onBeforeDraw = this._onAfterDraw = null; + + this._resetView(); + + if (this.removePageBorders) { + this.viewer.classList.add("removePageBorders"); + } + + this.updateContainerHeightCss(); + } + + get pagesCount() { + return this._pages.length; + } + + getPageView(index) { + return this._pages[index]; + } + + get pageViewsReady() { + if (!this._pagesCapability.settled) { + return false; + } + + return this._pages.every(function (pageView) { + return pageView === null || pageView === void 0 ? void 0 : pageView.pdfPage; + }); + } + + get renderForms() { + return _classPrivateFieldGet(this, _annotationMode) === _pdfjsLib.AnnotationMode.ENABLE_FORMS; + } + + get enableScripting() { + return !!this._scriptingManager; + } + + get currentPageNumber() { + return this._currentPageNumber; + } + + set currentPageNumber(val) { + if (!Number.isInteger(val)) { + throw new Error("Invalid page number."); + } + + if (!this.pdfDocument) { + return; + } + + if (!this._setCurrentPageNumber(val, true)) { + console.error(`currentPageNumber: "${val}" is not a valid page.`); + } + } + + _setCurrentPageNumber(val) { + var _this$_pageLabels, _this$_pageLabels2; + + let resetCurrentPageView = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + if (this._currentPageNumber === val) { + if (resetCurrentPageView) { + _classPrivateMethodGet(this, _resetCurrentPageView, _resetCurrentPageView2).call(this); + } + + return true; + } + + if (!(0 < val && val <= this.pagesCount)) { + return false; + } + + const previous = this._currentPageNumber; + this._currentPageNumber = val; + this.eventBus.dispatch("pagechanging", { + source: this, + pageNumber: val, + pageLabel: (_this$_pageLabels = (_this$_pageLabels2 = this._pageLabels) === null || _this$_pageLabels2 === void 0 ? void 0 : _this$_pageLabels2[val - 1]) !== null && _this$_pageLabels !== void 0 ? _this$_pageLabels : null, + previous + }); + + if (resetCurrentPageView) { + _classPrivateMethodGet(this, _resetCurrentPageView, _resetCurrentPageView2).call(this); + } + + return true; + } + + get currentPageLabel() { + var _this$_pageLabels3, _this$_pageLabels4; + + return (_this$_pageLabels3 = (_this$_pageLabels4 = this._pageLabels) === null || _this$_pageLabels4 === void 0 ? void 0 : _this$_pageLabels4[this._currentPageNumber - 1]) !== null && _this$_pageLabels3 !== void 0 ? _this$_pageLabels3 : null; + } + + set currentPageLabel(val) { + if (!this.pdfDocument) { + return; + } + + let page = val | 0; + + if (this._pageLabels) { + const i = this._pageLabels.indexOf(val); + + if (i >= 0) { + page = i + 1; + } + } + + if (!this._setCurrentPageNumber(page, true)) { + console.error(`currentPageLabel: "${val}" is not a valid page.`); + } + } + + get currentScale() { + return this._currentScale !== _ui_utils.UNKNOWN_SCALE ? this._currentScale : _ui_utils.DEFAULT_SCALE; + } + + set currentScale(val) { + if (isNaN(val)) { + throw new Error("Invalid numeric scale."); + } + + if (!this.pdfDocument) { + return; + } + + this._setScale(val, false); + } + + get currentScaleValue() { + return this._currentScaleValue; + } + + set currentScaleValue(val) { + if (!this.pdfDocument) { + return; + } + + this._setScale(val, false); + } + + get pagesRotation() { + return this._pagesRotation; + } + + set pagesRotation(rotation) { + if (!(0, _ui_utils.isValidRotation)(rotation)) { + throw new Error("Invalid pages rotation angle."); + } + + if (!this.pdfDocument) { + return; + } + + rotation %= 360; + + if (rotation < 0) { + rotation += 360; + } + + if (this._pagesRotation === rotation) { + return; + } + + this._pagesRotation = rotation; + const pageNumber = this._currentPageNumber; + const updateArgs = { + rotation + }; + + for (const pageView of this._pages) { + pageView.update(updateArgs); + } + + if (this._currentScaleValue) { + this._setScale(this._currentScaleValue, true); + } + + this.eventBus.dispatch("rotationchanging", { + source: this, + pagesRotation: rotation, + pageNumber + }); + + if (this.defaultRenderingQueue) { + this.update(); + } + } + + get firstPagePromise() { + return this.pdfDocument ? this._firstPageCapability.promise : null; + } + + get onePageRendered() { + return this.pdfDocument ? this._onePageRenderedCapability.promise : null; + } + + get pagesPromise() { + return this.pdfDocument ? this._pagesCapability.promise : null; + } + + setDocument(pdfDocument) { + if (this.pdfDocument) { + this.eventBus.dispatch("pagesdestroy", { + source: this + }); + + this._cancelRendering(); + + this._resetView(); + + if (this.findController) { + this.findController.setDocument(null); + } + + if (this._scriptingManager) { + this._scriptingManager.setDocument(null); + } + + if (_classPrivateFieldGet(this, _annotationEditorUIManager)) { + _classPrivateFieldGet(this, _annotationEditorUIManager).destroy(); + + _classPrivateFieldSet(this, _annotationEditorUIManager, null); + } + } + + this.pdfDocument = pdfDocument; + + if (!pdfDocument) { + return; + } + + const isPureXfa = pdfDocument.isPureXfa; + const pagesCount = pdfDocument.numPages; + const firstPagePromise = pdfDocument.getPage(1); + const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig(); + const permissionsPromise = _classPrivateFieldGet(this, _enablePermissions) ? pdfDocument.getPermissions() : Promise.resolve(); + + if (pagesCount > PagesCountLimit.FORCE_SCROLL_MODE_PAGE) { + console.warn("Forcing PAGE-scrolling for performance reasons, given the length of the document."); + const mode = this._scrollMode = _ui_utils.ScrollMode.PAGE; + this.eventBus.dispatch("scrollmodechanged", { + source: this, + mode + }); + } + + this._pagesCapability.promise.then(() => { + this.eventBus.dispatch("pagesloaded", { + source: this, + pagesCount + }); + }, () => {}); + + this._onBeforeDraw = evt => { + const pageView = this._pages[evt.pageNumber - 1]; + + if (!pageView) { + return; + } + + _classPrivateFieldGet(this, _buffer).push(pageView); + }; + + this.eventBus._on("pagerender", this._onBeforeDraw); + + this._onAfterDraw = evt => { + if (evt.cssTransform || this._onePageRenderedCapability.settled) { + return; + } + + this._onePageRenderedCapability.resolve({ + timestamp: evt.timestamp + }); + + this.eventBus._off("pagerendered", this._onAfterDraw); + + this._onAfterDraw = null; + + if (_classPrivateFieldGet(this, _onVisibilityChange)) { + document.removeEventListener("visibilitychange", _classPrivateFieldGet(this, _onVisibilityChange)); + + _classPrivateFieldSet(this, _onVisibilityChange, null); + } + }; + + this.eventBus._on("pagerendered", this._onAfterDraw); + + Promise.all([firstPagePromise, permissionsPromise]).then(_ref => { + let [firstPdfPage, permissions] = _ref; + + if (pdfDocument !== this.pdfDocument) { + return; + } + + this._firstPageCapability.resolve(firstPdfPage); + + this._optionalContentConfigPromise = optionalContentConfigPromise; + + const { + annotationEditorMode, + annotationMode, + textLayerMode + } = _classPrivateMethodGet(this, _initializePermissions, _initializePermissions2).call(this, permissions); + + if (annotationEditorMode !== _pdfjsLib.AnnotationEditorType.DISABLE) { + const mode = annotationEditorMode; + + if (isPureXfa) { + console.warn("Warning: XFA-editing is not implemented."); + } else if (isValidAnnotationEditorMode(mode)) { + _classPrivateFieldSet(this, _annotationEditorUIManager, new _pdfjsLib.AnnotationEditorUIManager(this.container, this.eventBus)); + + if (mode !== _pdfjsLib.AnnotationEditorType.NONE) { + _classPrivateFieldGet(this, _annotationEditorUIManager).updateMode(mode); + } + } else { + console.error(`Invalid AnnotationEditor mode: ${mode}`); + } + } + + const viewerElement = this._scrollMode === _ui_utils.ScrollMode.PAGE ? null : this.viewer; + const scale = this.currentScale; + const viewport = firstPdfPage.getViewport({ + scale: scale * _pdfjsLib.PixelsPerInch.PDF_TO_CSS_UNITS + }); + const textLayerFactory = textLayerMode !== _ui_utils.TextLayerMode.DISABLE && !isPureXfa ? this : null; + const annotationLayerFactory = annotationMode !== _pdfjsLib.AnnotationMode.DISABLE ? this : null; + const xfaLayerFactory = isPureXfa ? this : null; + const annotationEditorLayerFactory = _classPrivateFieldGet(this, _annotationEditorUIManager) ? this : null; + + for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) { + const pageView = new _pdf_page_view.PDFPageView({ + container: viewerElement, + eventBus: this.eventBus, + id: pageNum, + scale, + defaultViewport: viewport.clone(), + optionalContentConfigPromise, + renderingQueue: this.renderingQueue, + textLayerFactory, + textLayerMode, + annotationLayerFactory, + annotationMode, + xfaLayerFactory, + annotationEditorLayerFactory, + textHighlighterFactory: this, + structTreeLayerFactory: this, + imageResourcesPath: this.imageResourcesPath, + renderer: this.renderer, + useOnlyCssZoom: this.useOnlyCssZoom, + maxCanvasPixels: this.maxCanvasPixels, + pageColors: this.pageColors, + l10n: this.l10n + }); + + this._pages.push(pageView); + } + + const firstPageView = this._pages[0]; + + if (firstPageView) { + firstPageView.setPdfPage(firstPdfPage); + this.linkService.cachePageRef(1, firstPdfPage.ref); + } + + if (this._scrollMode === _ui_utils.ScrollMode.PAGE) { + _classPrivateMethodGet(this, _ensurePageViewVisible, _ensurePageViewVisible2).call(this); + } else if (this._spreadMode !== _ui_utils.SpreadMode.NONE) { + this._updateSpreadMode(); + } + + _classPrivateMethodGet(this, _onePageRenderedOrForceFetch, _onePageRenderedOrForceFetch2).call(this).then(async () => { + if (this.findController) { + this.findController.setDocument(pdfDocument); + } + + if (this._scriptingManager) { + this._scriptingManager.setDocument(pdfDocument); + } + + if (_classPrivateFieldGet(this, _annotationEditorUIManager)) { + this.eventBus.dispatch("annotationeditormodechanged", { + source: this, + mode: _classPrivateFieldGet(this, _annotationEditorMode) + }); + } + + if (pdfDocument.loadingParams.disableAutoFetch || pagesCount > PagesCountLimit.FORCE_LAZY_PAGE_INIT) { + this._pagesCapability.resolve(); + + return; + } + + let getPagesLeft = pagesCount - 1; + + if (getPagesLeft <= 0) { + this._pagesCapability.resolve(); + + return; + } + + for (let pageNum = 2; pageNum <= pagesCount; ++pageNum) { + const promise = pdfDocument.getPage(pageNum).then(pdfPage => { + const pageView = this._pages[pageNum - 1]; + + if (!pageView.pdfPage) { + pageView.setPdfPage(pdfPage); + } + + this.linkService.cachePageRef(pageNum, pdfPage.ref); + + if (--getPagesLeft === 0) { + this._pagesCapability.resolve(); + } + }, reason => { + console.error(`Unable to get page ${pageNum} to initialize viewer`, reason); + + if (--getPagesLeft === 0) { + this._pagesCapability.resolve(); + } + }); + + if (pageNum % PagesCountLimit.PAUSE_EAGER_PAGE_INIT === 0) { + await promise; + } + } + }); + + this.eventBus.dispatch("pagesinit", { + source: this + }); + pdfDocument.getMetadata().then(_ref2 => { + let { + info + } = _ref2; + + if (pdfDocument !== this.pdfDocument) { + return; + } + + if (info.Language) { + this.viewer.lang = info.Language; + } + }); + + if (this.defaultRenderingQueue) { + this.update(); + } + }).catch(reason => { + console.error("Unable to initialize viewer", reason); + + this._pagesCapability.reject(reason); + }); + } + + setPageLabels(labels) { + if (!this.pdfDocument) { + return; + } + + if (!labels) { + this._pageLabels = null; + } else if (!(Array.isArray(labels) && this.pdfDocument.numPages === labels.length)) { + this._pageLabels = null; + console.error(`setPageLabels: Invalid page labels.`); + } else { + this._pageLabels = labels; + } + + for (let i = 0, ii = this._pages.length; i < ii; i++) { + var _this$_pageLabels$i, _this$_pageLabels5; + + this._pages[i].setPageLabel((_this$_pageLabels$i = (_this$_pageLabels5 = this._pageLabels) === null || _this$_pageLabels5 === void 0 ? void 0 : _this$_pageLabels5[i]) !== null && _this$_pageLabels$i !== void 0 ? _this$_pageLabels$i : null); + } + } + + _resetView() { + this._pages = []; + this._currentPageNumber = 1; + this._currentScale = _ui_utils.UNKNOWN_SCALE; + this._currentScaleValue = null; + this._pageLabels = null; + + _classPrivateFieldSet(this, _buffer, new PDFPageViewBuffer(DEFAULT_CACHE_SIZE)); + + this._location = null; + this._pagesRotation = 0; + this._optionalContentConfigPromise = null; + this._firstPageCapability = (0, _pdfjsLib.createPromiseCapability)(); + this._onePageRenderedCapability = (0, _pdfjsLib.createPromiseCapability)(); + this._pagesCapability = (0, _pdfjsLib.createPromiseCapability)(); + this._scrollMode = _ui_utils.ScrollMode.VERTICAL; + this._previousScrollMode = _ui_utils.ScrollMode.UNKNOWN; + this._spreadMode = _ui_utils.SpreadMode.NONE; + + _classPrivateFieldSet(this, _scrollModePageState, { + previousPageNumber: 1, + scrollDown: true, + pages: [] + }); + + if (this._onBeforeDraw) { + this.eventBus._off("pagerender", this._onBeforeDraw); + + this._onBeforeDraw = null; + } + + if (this._onAfterDraw) { + this.eventBus._off("pagerendered", this._onAfterDraw); + + this._onAfterDraw = null; + } + + if (_classPrivateFieldGet(this, _onVisibilityChange)) { + document.removeEventListener("visibilitychange", _classPrivateFieldGet(this, _onVisibilityChange)); + + _classPrivateFieldSet(this, _onVisibilityChange, null); + } + + this.viewer.textContent = ""; + + this._updateScrollMode(); + + this.viewer.removeAttribute("lang"); + this.viewer.classList.remove(ENABLE_PERMISSIONS_CLASS); + } + + _scrollUpdate() { + if (this.pagesCount === 0) { + return; + } + + this.update(); + } + + _setScaleUpdatePages(newScale, newValue) { + let noScroll = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + let preset = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; + this._currentScaleValue = newValue.toString(); + + if (_classPrivateMethodGet(this, _isSameScale, _isSameScale2).call(this, newScale)) { + if (preset) { + this.eventBus.dispatch("scalechanging", { + source: this, + scale: newScale, + presetValue: newValue + }); + } + + return; + } + + _ui_utils.docStyle.setProperty("--scale-factor", newScale * _pdfjsLib.PixelsPerInch.PDF_TO_CSS_UNITS); + + const updateArgs = { + scale: newScale + }; + + for (const pageView of this._pages) { + pageView.update(updateArgs); + } + + this._currentScale = newScale; + + if (!noScroll) { + let page = this._currentPageNumber, + dest; + + if (this._location && !(this.isInPresentationMode || this.isChangingPresentationMode)) { + page = this._location.pageNumber; + dest = [null, { + name: "XYZ" + }, this._location.left, this._location.top, null]; + } + + this.scrollPageIntoView({ + pageNumber: page, + destArray: dest, + allowNegativeOffset: true + }); + } + + this.eventBus.dispatch("scalechanging", { + source: this, + scale: newScale, + presetValue: preset ? newValue : undefined + }); + + if (this.defaultRenderingQueue) { + this.update(); + } + + this.updateContainerHeightCss(); + } + + get _pageWidthScaleFactor() { + if (this._spreadMode !== _ui_utils.SpreadMode.NONE && this._scrollMode !== _ui_utils.ScrollMode.HORIZONTAL) { + return 2; + } + + return 1; + } + + _setScale(value) { + let noScroll = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + let scale = parseFloat(value); + + if (scale > 0) { + this._setScaleUpdatePages(scale, value, noScroll, false); + } else { + const currentPage = this._pages[this._currentPageNumber - 1]; + + if (!currentPage) { + return; + } + + let hPadding = _ui_utils.SCROLLBAR_PADDING, + vPadding = _ui_utils.VERTICAL_PADDING; + + if (this.isInPresentationMode) { + hPadding = vPadding = 4; + } else if (this.removePageBorders) { + hPadding = vPadding = 0; + } else if (this._scrollMode === _ui_utils.ScrollMode.HORIZONTAL) { + [hPadding, vPadding] = [vPadding, hPadding]; + } + + const pageWidthScale = (this.container.clientWidth - hPadding) / currentPage.width * currentPage.scale / this._pageWidthScaleFactor; + const pageHeightScale = (this.container.clientHeight - vPadding) / currentPage.height * currentPage.scale; + + switch (value) { + case "page-actual": + scale = 1; + break; + + case "page-width": + scale = pageWidthScale; + break; + + case "page-height": + scale = pageHeightScale; + break; + + case "page-fit": + scale = Math.min(pageWidthScale, pageHeightScale); + break; + + case "auto": + const horizontalScale = (0, _ui_utils.isPortraitOrientation)(currentPage) ? pageWidthScale : Math.min(pageHeightScale, pageWidthScale); + scale = Math.min(_ui_utils.MAX_AUTO_SCALE, horizontalScale); + break; + + default: + console.error(`_setScale: "${value}" is an unknown zoom value.`); + return; + } + + this._setScaleUpdatePages(scale, value, noScroll, true); + } + } + + pageLabelToPageNumber(label) { + if (!this._pageLabels) { + return null; + } + + const i = this._pageLabels.indexOf(label); + + if (i < 0) { + return null; + } + + return i + 1; + } + + scrollPageIntoView(_ref3) { + let { + pageNumber, + destArray = null, + allowNegativeOffset = false, + ignoreDestinationZoom = false + } = _ref3; + + if (!this.pdfDocument) { + return; + } + + const pageView = Number.isInteger(pageNumber) && this._pages[pageNumber - 1]; + + if (!pageView) { + console.error(`scrollPageIntoView: "${pageNumber}" is not a valid pageNumber parameter.`); + return; + } + + if (this.isInPresentationMode || !destArray) { + this._setCurrentPageNumber(pageNumber, true); + + return; + } + + let x = 0, + y = 0; + let width = 0, + height = 0, + widthScale, + heightScale; + const changeOrientation = pageView.rotation % 180 !== 0; + const pageWidth = (changeOrientation ? pageView.height : pageView.width) / pageView.scale / _pdfjsLib.PixelsPerInch.PDF_TO_CSS_UNITS; + const pageHeight = (changeOrientation ? pageView.width : pageView.height) / pageView.scale / _pdfjsLib.PixelsPerInch.PDF_TO_CSS_UNITS; + let scale = 0; + + switch (destArray[1].name) { + case "XYZ": + x = destArray[2]; + y = destArray[3]; + scale = destArray[4]; + x = x !== null ? x : 0; + y = y !== null ? y : pageHeight; + break; + + case "Fit": + case "FitB": + scale = "page-fit"; + break; + + case "FitH": + case "FitBH": + y = destArray[2]; + scale = "page-width"; + + if (y === null && this._location) { + x = this._location.left; + y = this._location.top; + } else if (typeof y !== "number" || y < 0) { + y = pageHeight; + } + + break; + + case "FitV": + case "FitBV": + x = destArray[2]; + width = pageWidth; + height = pageHeight; + scale = "page-height"; + break; + + case "FitR": + x = destArray[2]; + y = destArray[3]; + width = destArray[4] - x; + height = destArray[5] - y; + const hPadding = this.removePageBorders ? 0 : _ui_utils.SCROLLBAR_PADDING; + const vPadding = this.removePageBorders ? 0 : _ui_utils.VERTICAL_PADDING; + widthScale = (this.container.clientWidth - hPadding) / width / _pdfjsLib.PixelsPerInch.PDF_TO_CSS_UNITS; + heightScale = (this.container.clientHeight - vPadding) / height / _pdfjsLib.PixelsPerInch.PDF_TO_CSS_UNITS; + scale = Math.min(Math.abs(widthScale), Math.abs(heightScale)); + break; + + default: + console.error(`scrollPageIntoView: "${destArray[1].name}" is not a valid destination type.`); + return; + } + + if (!ignoreDestinationZoom) { + if (scale && scale !== this._currentScale) { + this.currentScaleValue = scale; + } else if (this._currentScale === _ui_utils.UNKNOWN_SCALE) { + this.currentScaleValue = _ui_utils.DEFAULT_SCALE_VALUE; + } + } + + if (scale === "page-fit" && !destArray[4]) { + _classPrivateMethodGet(this, _scrollIntoView, _scrollIntoView2).call(this, pageView); + + return; + } + + const boundingRect = [pageView.viewport.convertToViewportPoint(x, y), pageView.viewport.convertToViewportPoint(x + width, y + height)]; + let left = Math.min(boundingRect[0][0], boundingRect[1][0]); + let top = Math.min(boundingRect[0][1], boundingRect[1][1]); + + if (!allowNegativeOffset) { + left = Math.max(left, 0); + top = Math.max(top, 0); + } + + _classPrivateMethodGet(this, _scrollIntoView, _scrollIntoView2).call(this, pageView, { + left, + top + }); + } + + _updateLocation(firstPage) { + const currentScale = this._currentScale; + const currentScaleValue = this._currentScaleValue; + const normalizedScaleValue = parseFloat(currentScaleValue) === currentScale ? Math.round(currentScale * 10000) / 100 : currentScaleValue; + const pageNumber = firstPage.id; + const currentPageView = this._pages[pageNumber - 1]; + const container = this.container; + const topLeft = currentPageView.getPagePoint(container.scrollLeft - firstPage.x, container.scrollTop - firstPage.y); + const intLeft = Math.round(topLeft[0]); + const intTop = Math.round(topLeft[1]); + let pdfOpenParams = `#page=${pageNumber}`; + + if (!this.isInPresentationMode) { + pdfOpenParams += `&zoom=${normalizedScaleValue},${intLeft},${intTop}`; + } + + this._location = { + pageNumber, + scale: normalizedScaleValue, + top: intTop, + left: intLeft, + rotation: this._pagesRotation, + pdfOpenParams + }; + } + + update() { + const visible = this._getVisiblePages(); + + const visiblePages = visible.views, + numVisiblePages = visiblePages.length; + + if (numVisiblePages === 0) { + return; + } + + const newCacheSize = Math.max(DEFAULT_CACHE_SIZE, 2 * numVisiblePages + 1); + + _classPrivateFieldGet(this, _buffer).resize(newCacheSize, visible.ids); + + this.renderingQueue.renderHighestPriority(visible); + const isSimpleLayout = this._spreadMode === _ui_utils.SpreadMode.NONE && (this._scrollMode === _ui_utils.ScrollMode.PAGE || this._scrollMode === _ui_utils.ScrollMode.VERTICAL); + const currentId = this._currentPageNumber; + let stillFullyVisible = false; + + for (const page of visiblePages) { + if (page.percent < 100) { + break; + } + + if (page.id === currentId && isSimpleLayout) { + stillFullyVisible = true; + break; + } + } + + this._setCurrentPageNumber(stillFullyVisible ? currentId : visiblePages[0].id); + + this._updateLocation(visible.first); + + this.eventBus.dispatch("updateviewarea", { + source: this, + location: this._location + }); + } + + containsElement(element) { + return this.container.contains(element); + } + + focus() { + this.container.focus(); + } + + get _isContainerRtl() { + return getComputedStyle(this.container).direction === "rtl"; + } + + get isInPresentationMode() { + return this.presentationModeState === _ui_utils.PresentationModeState.FULLSCREEN; + } + + get isChangingPresentationMode() { + return this.presentationModeState === _ui_utils.PresentationModeState.CHANGING; + } + + get isHorizontalScrollbarEnabled() { + return this.isInPresentationMode ? false : this.container.scrollWidth > this.container.clientWidth; + } + + get isVerticalScrollbarEnabled() { + return this.isInPresentationMode ? false : this.container.scrollHeight > this.container.clientHeight; + } + + _getVisiblePages() { + const views = this._scrollMode === _ui_utils.ScrollMode.PAGE ? _classPrivateFieldGet(this, _scrollModePageState).pages : this._pages, + horizontal = this._scrollMode === _ui_utils.ScrollMode.HORIZONTAL, + rtl = horizontal && this._isContainerRtl; + return (0, _ui_utils.getVisibleElements)({ + scrollEl: this.container, + views, + sortByVisibility: true, + horizontal, + rtl + }); + } + + isPageVisible(pageNumber) { + if (!this.pdfDocument) { + return false; + } + + if (!(Number.isInteger(pageNumber) && pageNumber > 0 && pageNumber <= this.pagesCount)) { + console.error(`isPageVisible: "${pageNumber}" is not a valid page.`); + return false; + } + + return this._getVisiblePages().ids.has(pageNumber); + } + + isPageCached(pageNumber) { + if (!this.pdfDocument) { + return false; + } + + if (!(Number.isInteger(pageNumber) && pageNumber > 0 && pageNumber <= this.pagesCount)) { + console.error(`isPageCached: "${pageNumber}" is not a valid page.`); + return false; + } + + const pageView = this._pages[pageNumber - 1]; + return _classPrivateFieldGet(this, _buffer).has(pageView); + } + + cleanup() { + for (const pageView of this._pages) { + if (pageView.renderingState !== _ui_utils.RenderingStates.FINISHED) { + pageView.reset(); + } + } + } + + _cancelRendering() { + for (const pageView of this._pages) { + pageView.cancelRendering(); + } + } + + forceRendering(currentlyVisiblePages) { + const visiblePages = currentlyVisiblePages || this._getVisiblePages(); + + const scrollAhead = _classPrivateMethodGet(this, _getScrollAhead, _getScrollAhead2).call(this, visiblePages); + + const preRenderExtra = this._spreadMode !== _ui_utils.SpreadMode.NONE && this._scrollMode !== _ui_utils.ScrollMode.HORIZONTAL; + const pageView = this.renderingQueue.getHighestPriority(visiblePages, this._pages, scrollAhead, preRenderExtra); + + _classPrivateMethodGet(this, _toggleLoadingIconSpinner, _toggleLoadingIconSpinner2).call(this, visiblePages.ids); + + if (pageView) { + _classPrivateMethodGet(this, _ensurePdfPageLoaded, _ensurePdfPageLoaded2).call(this, pageView).then(() => { + this.renderingQueue.renderView(pageView); + }); + + return true; + } + + return false; + } + + createTextLayerBuilder(_ref4) { + let { + textLayerDiv, + pageIndex, + viewport, + enhanceTextSelection = false, + eventBus, + highlighter, + accessibilityManager = null + } = _ref4; + return new _text_layer_builder.TextLayerBuilder({ + textLayerDiv, + eventBus, + pageIndex, + viewport, + enhanceTextSelection: this.isInPresentationMode ? false : enhanceTextSelection, + highlighter, + accessibilityManager + }); + } + + createTextHighlighter(_ref5) { + let { + pageIndex, + eventBus + } = _ref5; + return new _text_highlighter.TextHighlighter({ + eventBus, + pageIndex, + findController: this.isInPresentationMode ? null : this.findController + }); + } + + createAnnotationLayerBuilder(_ref6) { + var _this$pdfDocument, _this$pdfDocument2, _this$_scriptingManag, _this$pdfDocument3; + + let { + pageDiv, + pdfPage, + annotationStorage = (_this$pdfDocument = this.pdfDocument) === null || _this$pdfDocument === void 0 ? void 0 : _this$pdfDocument.annotationStorage, + imageResourcesPath = "", + renderForms = true, + l10n = _l10n_utils.NullL10n, + enableScripting = this.enableScripting, + hasJSActionsPromise = (_this$pdfDocument2 = this.pdfDocument) === null || _this$pdfDocument2 === void 0 ? void 0 : _this$pdfDocument2.hasJSActions(), + mouseState = (_this$_scriptingManag = this._scriptingManager) === null || _this$_scriptingManag === void 0 ? void 0 : _this$_scriptingManag.mouseState, + fieldObjectsPromise = (_this$pdfDocument3 = this.pdfDocument) === null || _this$pdfDocument3 === void 0 ? void 0 : _this$pdfDocument3.getFieldObjects(), + annotationCanvasMap = null, + accessibilityManager = null + } = _ref6; + return new _annotation_layer_builder.AnnotationLayerBuilder({ + pageDiv, + pdfPage, + annotationStorage, + imageResourcesPath, + renderForms, + linkService: this.linkService, + downloadManager: this.downloadManager, + l10n, + enableScripting, + hasJSActionsPromise, + mouseState, + fieldObjectsPromise, + annotationCanvasMap, + accessibilityManager + }); + } + + createAnnotationEditorLayerBuilder(_ref7) { + var _this$pdfDocument4; + + let { + uiManager = _classPrivateFieldGet(this, _annotationEditorUIManager), + pageDiv, + pdfPage, + accessibilityManager = null, + l10n, + annotationStorage = (_this$pdfDocument4 = this.pdfDocument) === null || _this$pdfDocument4 === void 0 ? void 0 : _this$pdfDocument4.annotationStorage + } = _ref7; + return new _annotation_editor_layer_builder.AnnotationEditorLayerBuilder({ + uiManager, + pageDiv, + pdfPage, + annotationStorage, + accessibilityManager, + l10n + }); + } + + createXfaLayerBuilder(_ref8) { + var _this$pdfDocument5; + + let { + pageDiv, + pdfPage, + annotationStorage = (_this$pdfDocument5 = this.pdfDocument) === null || _this$pdfDocument5 === void 0 ? void 0 : _this$pdfDocument5.annotationStorage + } = _ref8; + return new _xfa_layer_builder.XfaLayerBuilder({ + pageDiv, + pdfPage, + annotationStorage, + linkService: this.linkService + }); + } + + createStructTreeLayerBuilder(_ref9) { + let { + pdfPage + } = _ref9; + return new _struct_tree_layer_builder.StructTreeLayerBuilder({ + pdfPage + }); + } + + get hasEqualPageSizes() { + const firstPageView = this._pages[0]; + + for (let i = 1, ii = this._pages.length; i < ii; ++i) { + const pageView = this._pages[i]; + + if (pageView.width !== firstPageView.width || pageView.height !== firstPageView.height) { + return false; + } + } + + return true; + } + + getPagesOverview() { + return this._pages.map(pageView => { + const viewport = pageView.pdfPage.getViewport({ + scale: 1 + }); + + if (!this.enablePrintAutoRotate || (0, _ui_utils.isPortraitOrientation)(viewport)) { + return { + width: viewport.width, + height: viewport.height, + rotation: viewport.rotation + }; + } + + return { + width: viewport.height, + height: viewport.width, + rotation: (viewport.rotation - 90) % 360 + }; + }); + } + + get optionalContentConfigPromise() { + if (!this.pdfDocument) { + return Promise.resolve(null); + } + + if (!this._optionalContentConfigPromise) { + console.error("optionalContentConfigPromise: Not initialized yet."); + return this.pdfDocument.getOptionalContentConfig(); + } + + return this._optionalContentConfigPromise; + } + + set optionalContentConfigPromise(promise) { + if (!(promise instanceof Promise)) { + throw new Error(`Invalid optionalContentConfigPromise: ${promise}`); + } + + if (!this.pdfDocument) { + return; + } + + if (!this._optionalContentConfigPromise) { + return; + } + + this._optionalContentConfigPromise = promise; + const updateArgs = { + optionalContentConfigPromise: promise + }; + + for (const pageView of this._pages) { + pageView.update(updateArgs); + } + + this.update(); + this.eventBus.dispatch("optionalcontentconfigchanged", { + source: this, + promise + }); + } + + get scrollMode() { + return this._scrollMode; + } + + set scrollMode(mode) { + if (this._scrollMode === mode) { + return; + } + + if (!(0, _ui_utils.isValidScrollMode)(mode)) { + throw new Error(`Invalid scroll mode: ${mode}`); + } + + if (this.pagesCount > PagesCountLimit.FORCE_SCROLL_MODE_PAGE) { + return; + } + + this._previousScrollMode = this._scrollMode; + this._scrollMode = mode; + this.eventBus.dispatch("scrollmodechanged", { + source: this, + mode + }); + + this._updateScrollMode(this._currentPageNumber); + } + + _updateScrollMode() { + let pageNumber = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + const scrollMode = this._scrollMode, + viewer = this.viewer; + viewer.classList.toggle("scrollHorizontal", scrollMode === _ui_utils.ScrollMode.HORIZONTAL); + viewer.classList.toggle("scrollWrapped", scrollMode === _ui_utils.ScrollMode.WRAPPED); + + if (!this.pdfDocument || !pageNumber) { + return; + } + + if (scrollMode === _ui_utils.ScrollMode.PAGE) { + _classPrivateMethodGet(this, _ensurePageViewVisible, _ensurePageViewVisible2).call(this); + } else if (this._previousScrollMode === _ui_utils.ScrollMode.PAGE) { + this._updateSpreadMode(); + } + + if (this._currentScaleValue && isNaN(this._currentScaleValue)) { + this._setScale(this._currentScaleValue, true); + } + + this._setCurrentPageNumber(pageNumber, true); + + this.update(); + } + + get spreadMode() { + return this._spreadMode; + } + + set spreadMode(mode) { + if (this._spreadMode === mode) { + return; + } + + if (!(0, _ui_utils.isValidSpreadMode)(mode)) { + throw new Error(`Invalid spread mode: ${mode}`); + } + + this._spreadMode = mode; + this.eventBus.dispatch("spreadmodechanged", { + source: this, + mode + }); + + this._updateSpreadMode(this._currentPageNumber); + } + + _updateSpreadMode() { + let pageNumber = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + + if (!this.pdfDocument) { + return; + } + + const viewer = this.viewer, + pages = this._pages; + + if (this._scrollMode === _ui_utils.ScrollMode.PAGE) { + _classPrivateMethodGet(this, _ensurePageViewVisible, _ensurePageViewVisible2).call(this); + } else { + viewer.textContent = ""; + + if (this._spreadMode === _ui_utils.SpreadMode.NONE) { + for (const pageView of this._pages) { + viewer.append(pageView.div); + } + } else { + const parity = this._spreadMode - 1; + let spread = null; + + for (let i = 0, ii = pages.length; i < ii; ++i) { + if (spread === null) { + spread = document.createElement("div"); + spread.className = "spread"; + viewer.append(spread); + } else if (i % 2 === parity) { + spread = spread.cloneNode(false); + viewer.append(spread); + } + + spread.append(pages[i].div); + } + } + } + + if (!pageNumber) { + return; + } + + if (this._currentScaleValue && isNaN(this._currentScaleValue)) { + this._setScale(this._currentScaleValue, true); + } + + this._setCurrentPageNumber(pageNumber, true); + + this.update(); + } + + _getPageAdvance(currentPageNumber) { + let previous = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + switch (this._scrollMode) { + case _ui_utils.ScrollMode.WRAPPED: + { + const { + views + } = this._getVisiblePages(), + pageLayout = new Map(); + + for (const { + id, + y, + percent, + widthPercent + } of views) { + if (percent === 0 || widthPercent < 100) { + continue; + } + + let yArray = pageLayout.get(y); + + if (!yArray) { + pageLayout.set(y, yArray || (yArray = [])); + } + + yArray.push(id); + } + + for (const yArray of pageLayout.values()) { + const currentIndex = yArray.indexOf(currentPageNumber); + + if (currentIndex === -1) { + continue; + } + + const numPages = yArray.length; + + if (numPages === 1) { + break; + } + + if (previous) { + for (let i = currentIndex - 1, ii = 0; i >= ii; i--) { + const currentId = yArray[i], + expectedId = yArray[i + 1] - 1; + + if (currentId < expectedId) { + return currentPageNumber - expectedId; + } + } + } else { + for (let i = currentIndex + 1, ii = numPages; i < ii; i++) { + const currentId = yArray[i], + expectedId = yArray[i - 1] + 1; + + if (currentId > expectedId) { + return expectedId - currentPageNumber; + } + } + } + + if (previous) { + const firstId = yArray[0]; + + if (firstId < currentPageNumber) { + return currentPageNumber - firstId + 1; + } + } else { + const lastId = yArray[numPages - 1]; + + if (lastId > currentPageNumber) { + return lastId - currentPageNumber + 1; + } + } + + break; + } + + break; + } + + case _ui_utils.ScrollMode.HORIZONTAL: + { + break; + } + + case _ui_utils.ScrollMode.PAGE: + case _ui_utils.ScrollMode.VERTICAL: + { + if (this._spreadMode === _ui_utils.SpreadMode.NONE) { + break; + } + + const parity = this._spreadMode - 1; + + if (previous && currentPageNumber % 2 !== parity) { + break; + } else if (!previous && currentPageNumber % 2 === parity) { + break; + } + + const { + views + } = this._getVisiblePages(), + expectedId = previous ? currentPageNumber - 1 : currentPageNumber + 1; + + for (const { + id, + percent, + widthPercent + } of views) { + if (id !== expectedId) { + continue; + } + + if (percent > 0 && widthPercent === 100) { + return 2; + } + + break; + } + + break; + } + } + + return 1; + } + + nextPage() { + const currentPageNumber = this._currentPageNumber, + pagesCount = this.pagesCount; + + if (currentPageNumber >= pagesCount) { + return false; + } + + const advance = this._getPageAdvance(currentPageNumber, false) || 1; + this.currentPageNumber = Math.min(currentPageNumber + advance, pagesCount); + return true; + } + + previousPage() { + const currentPageNumber = this._currentPageNumber; + + if (currentPageNumber <= 1) { + return false; + } + + const advance = this._getPageAdvance(currentPageNumber, true) || 1; + this.currentPageNumber = Math.max(currentPageNumber - advance, 1); + return true; + } + + increaseScale() { + let steps = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1; + let newScale = this._currentScale; + + do { + newScale = (newScale * _ui_utils.DEFAULT_SCALE_DELTA).toFixed(2); + newScale = Math.ceil(newScale * 10) / 10; + newScale = Math.min(_ui_utils.MAX_SCALE, newScale); + } while (--steps > 0 && newScale < _ui_utils.MAX_SCALE); + + this.currentScaleValue = newScale; + } + + decreaseScale() { + let steps = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1; + let newScale = this._currentScale; + + do { + newScale = (newScale / _ui_utils.DEFAULT_SCALE_DELTA).toFixed(2); + newScale = Math.floor(newScale * 10) / 10; + newScale = Math.max(_ui_utils.MIN_SCALE, newScale); + } while (--steps > 0 && newScale > _ui_utils.MIN_SCALE); + + this.currentScaleValue = newScale; + } + + updateContainerHeightCss() { + const height = this.container.clientHeight; + + if (height !== _classPrivateFieldGet(this, _previousContainerHeight)) { + _classPrivateFieldSet(this, _previousContainerHeight, height); + + _ui_utils.docStyle.setProperty("--viewer-container-height", `${height}px`); + } + } + + get annotationEditorMode() { + return _classPrivateFieldGet(this, _annotationEditorUIManager) ? _classPrivateFieldGet(this, _annotationEditorMode) : _pdfjsLib.AnnotationEditorType.DISABLE; + } + + set annotationEditorMode(mode) { + if (!_classPrivateFieldGet(this, _annotationEditorUIManager)) { + throw new Error(`The AnnotationEditor is not enabled.`); + } + + if (_classPrivateFieldGet(this, _annotationEditorMode) === mode) { + return; + } + + if (!isValidAnnotationEditorMode(mode)) { + throw new Error(`Invalid AnnotationEditor mode: ${mode}`); + } + + if (!this.pdfDocument) { + return; + } + + _classPrivateFieldSet(this, _annotationEditorMode, mode); + + this.eventBus.dispatch("annotationeditormodechanged", { + source: this, + mode + }); + + _classPrivateFieldGet(this, _annotationEditorUIManager).updateMode(mode); + } + + set annotationEditorParams(_ref10) { + let { + type, + value + } = _ref10; + + if (!_classPrivateFieldGet(this, _annotationEditorUIManager)) { + throw new Error(`The AnnotationEditor is not enabled.`); + } + + _classPrivateFieldGet(this, _annotationEditorUIManager).updateParams(type, value); + } + + refresh() { + if (!this.pdfDocument) { + return; + } + + const updateArgs = {}; + + for (const pageView of this._pages) { + pageView.update(updateArgs); + } + + this.update(); + } + +} + +exports.BaseViewer = BaseViewer; + +function _initializePermissions2(permissions) { + const params = { + annotationEditorMode: _classPrivateFieldGet(this, _annotationEditorMode), + annotationMode: _classPrivateFieldGet(this, _annotationMode), + textLayerMode: this.textLayerMode + }; + + if (!permissions) { + return params; + } + + if (!permissions.includes(_pdfjsLib.PermissionFlag.COPY)) { + this.viewer.classList.add(ENABLE_PERMISSIONS_CLASS); + } + + if (!permissions.includes(_pdfjsLib.PermissionFlag.MODIFY_CONTENTS)) { + params.annotationEditorMode = _pdfjsLib.AnnotationEditorType.DISABLE; + } + + if (!permissions.includes(_pdfjsLib.PermissionFlag.MODIFY_ANNOTATIONS) && !permissions.includes(_pdfjsLib.PermissionFlag.FILL_INTERACTIVE_FORMS) && _classPrivateFieldGet(this, _annotationMode) === _pdfjsLib.AnnotationMode.ENABLE_FORMS) { + params.annotationMode = _pdfjsLib.AnnotationMode.ENABLE; + } + + return params; +} + +function _onePageRenderedOrForceFetch2() { + if (document.visibilityState === "hidden" || !this.container.offsetParent || this._getVisiblePages().views.length === 0) { + return Promise.resolve(); + } + + const visibilityChangePromise = new Promise(resolve => { + _classPrivateFieldSet(this, _onVisibilityChange, () => { + if (document.visibilityState !== "hidden") { + return; + } + + resolve(); + document.removeEventListener("visibilitychange", _classPrivateFieldGet(this, _onVisibilityChange)); + + _classPrivateFieldSet(this, _onVisibilityChange, null); + }); + + document.addEventListener("visibilitychange", _classPrivateFieldGet(this, _onVisibilityChange)); + }); + return Promise.race([this._onePageRenderedCapability.promise, visibilityChangePromise]); +} + +function _ensurePageViewVisible2() { + if (this._scrollMode !== _ui_utils.ScrollMode.PAGE) { + throw new Error("#ensurePageViewVisible: Invalid scrollMode value."); + } + + const pageNumber = this._currentPageNumber, + state = _classPrivateFieldGet(this, _scrollModePageState), + viewer = this.viewer; + + viewer.textContent = ""; + state.pages.length = 0; + + if (this._spreadMode === _ui_utils.SpreadMode.NONE && !this.isInPresentationMode) { + const pageView = this._pages[pageNumber - 1]; + viewer.append(pageView.div); + state.pages.push(pageView); + } else { + const pageIndexSet = new Set(), + parity = this._spreadMode - 1; + + if (parity === -1) { + pageIndexSet.add(pageNumber - 1); + } else if (pageNumber % 2 !== parity) { + pageIndexSet.add(pageNumber - 1); + pageIndexSet.add(pageNumber); + } else { + pageIndexSet.add(pageNumber - 2); + pageIndexSet.add(pageNumber - 1); + } + + const spread = document.createElement("div"); + spread.className = "spread"; + + if (this.isInPresentationMode) { + const dummyPage = document.createElement("div"); + dummyPage.className = "dummyPage"; + spread.append(dummyPage); + } + + for (const i of pageIndexSet) { + const pageView = this._pages[i]; + + if (!pageView) { + continue; + } + + spread.append(pageView.div); + state.pages.push(pageView); + } + + viewer.append(spread); + } + + state.scrollDown = pageNumber >= state.previousPageNumber; + state.previousPageNumber = pageNumber; +} + +function _scrollIntoView2(pageView) { + let pageSpot = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + const { + div, + id + } = pageView; + + if (this._scrollMode === _ui_utils.ScrollMode.PAGE) { + this._setCurrentPageNumber(id); + + _classPrivateMethodGet(this, _ensurePageViewVisible, _ensurePageViewVisible2).call(this); + + this.update(); + } + + if (!pageSpot && !this.isInPresentationMode) { + const left = div.offsetLeft + div.clientLeft, + right = left + div.clientWidth; + const { + scrollLeft, + clientWidth + } = this.container; + + if (this._scrollMode === _ui_utils.ScrollMode.HORIZONTAL || left < scrollLeft || right > scrollLeft + clientWidth) { + pageSpot = { + left: 0, + top: 0 + }; + } + } + + (0, _ui_utils.scrollIntoView)(div, pageSpot); +} + +function _isSameScale2(newScale) { + return newScale === this._currentScale || Math.abs(newScale - this._currentScale) < 1e-15; +} + +function _resetCurrentPageView2() { + const pageView = this._pages[this._currentPageNumber - 1]; + + if (this.isInPresentationMode) { + this._setScale(this._currentScaleValue, true); + } + + _classPrivateMethodGet(this, _scrollIntoView, _scrollIntoView2).call(this, pageView); +} + +async function _ensurePdfPageLoaded2(pageView) { + if (pageView.pdfPage) { + return pageView.pdfPage; + } + + try { + var _this$linkService$_ca, _this$linkService; + + const pdfPage = await this.pdfDocument.getPage(pageView.id); + + if (!pageView.pdfPage) { + pageView.setPdfPage(pdfPage); + } + + if (!((_this$linkService$_ca = (_this$linkService = this.linkService)._cachedPageNumber) !== null && _this$linkService$_ca !== void 0 && _this$linkService$_ca.call(_this$linkService, pdfPage.ref))) { + this.linkService.cachePageRef(pageView.id, pdfPage.ref); + } + + return pdfPage; + } catch (reason) { + console.error("Unable to get page for page view", reason); + return null; + } +} + +function _getScrollAhead2(visible) { + var _visible$first, _visible$last; + + if (((_visible$first = visible.first) === null || _visible$first === void 0 ? void 0 : _visible$first.id) === 1) { + return true; + } else if (((_visible$last = visible.last) === null || _visible$last === void 0 ? void 0 : _visible$last.id) === this.pagesCount) { + return false; + } + + switch (this._scrollMode) { + case _ui_utils.ScrollMode.PAGE: + return _classPrivateFieldGet(this, _scrollModePageState).scrollDown; + + case _ui_utils.ScrollMode.HORIZONTAL: + return this.scroll.right; + } + + return this.scroll.down; +} + +function _toggleLoadingIconSpinner2(visibleIds) { + for (const id of visibleIds) { + const pageView = this._pages[id - 1]; + pageView === null || pageView === void 0 ? void 0 : pageView.toggleLoadingIconSpinner(true); + } + + for (const pageView of _classPrivateFieldGet(this, _buffer)) { + if (visibleIds.has(pageView.id)) { + continue; + } + + pageView.toggleLoadingIconSpinner(false); + } +} + +/***/ }), +/* 31 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.AnnotationEditorLayerBuilder = void 0; + +var _pdfjsLib = __webpack_require__(5); + +var _l10n_utils = __webpack_require__(32); + +function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } + +function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } + +function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } + +var _uiManager = /*#__PURE__*/new WeakMap(); + +class AnnotationEditorLayerBuilder { + constructor(options) { + _classPrivateFieldInitSpec(this, _uiManager, { + writable: true, + value: void 0 + }); + + this.pageDiv = options.pageDiv; + this.pdfPage = options.pdfPage; + this.annotationStorage = options.annotationStorage || null; + this.accessibilityManager = options.accessibilityManager; + this.l10n = options.l10n || _l10n_utils.NullL10n; + this.annotationEditorLayer = null; + this.div = null; + this._cancelled = false; + + _classPrivateFieldSet(this, _uiManager, options.uiManager); + } + + async render(viewport) { + let intent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "display"; + + if (intent !== "display") { + return; + } + + if (this._cancelled) { + return; + } + + const clonedViewport = viewport.clone({ + dontFlip: true + }); + + if (this.div) { + this.annotationEditorLayer.update({ + viewport: clonedViewport + }); + this.show(); + return; + } + + this.div = document.createElement("div"); + this.div.className = "annotationEditorLayer"; + this.div.tabIndex = 0; + this.pageDiv.append(this.div); + this.annotationEditorLayer = new _pdfjsLib.AnnotationEditorLayer({ + uiManager: _classPrivateFieldGet(this, _uiManager), + div: this.div, + annotationStorage: this.annotationStorage, + accessibilityManager: this.accessibilityManager, + pageIndex: this.pdfPage._pageIndex, + l10n: this.l10n, + viewport: clonedViewport + }); + const parameters = { + viewport: clonedViewport, + div: this.div, + annotations: null, + intent + }; + this.annotationEditorLayer.render(parameters); + } + + cancel() { + this._cancelled = true; + this.destroy(); + } + + hide() { + if (!this.div) { + return; + } + + this.div.hidden = true; + } + + show() { + if (!this.div) { + return; + } + + this.div.hidden = false; + } + + destroy() { + if (!this.div) { + return; + } + + this.pageDiv = null; + this.annotationEditorLayer.destroy(); + this.div.remove(); + } + +} + +exports.AnnotationEditorLayerBuilder = AnnotationEditorLayerBuilder; + +/***/ }), +/* 32 */ +/***/ ((__unused_webpack_module, exports) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.NullL10n = void 0; +exports.fixupLangCode = fixupLangCode; +exports.getL10nFallback = getL10nFallback; +const DEFAULT_L10N_STRINGS = { + of_pages: "of {{pagesCount}}", + page_of_pages: "({{pageNumber}} of {{pagesCount}})", + document_properties_kb: "{{size_kb}} KB ({{size_b}} bytes)", + document_properties_mb: "{{size_mb}} MB ({{size_b}} bytes)", + document_properties_date_string: "{{date}}, {{time}}", + document_properties_page_size_unit_inches: "in", + document_properties_page_size_unit_millimeters: "mm", + document_properties_page_size_orientation_portrait: "portrait", + document_properties_page_size_orientation_landscape: "landscape", + document_properties_page_size_name_a3: "A3", + document_properties_page_size_name_a4: "A4", + document_properties_page_size_name_letter: "Letter", + document_properties_page_size_name_legal: "Legal", + document_properties_page_size_dimension_string: "{{width}} × {{height}} {{unit}} ({{orientation}})", + document_properties_page_size_dimension_name_string: "{{width}} × {{height}} {{unit}} ({{name}}, {{orientation}})", + document_properties_linearized_yes: "Yes", + document_properties_linearized_no: "No", + print_progress_percent: "{{progress}}%", + "toggle_sidebar.title": "Toggle Sidebar", + "toggle_sidebar_notification2.title": "Toggle Sidebar (document contains outline/attachments/layers)", + additional_layers: "Additional Layers", + page_landmark: "Page {{page}}", + thumb_page_title: "Page {{page}}", + thumb_page_canvas: "Thumbnail of Page {{page}}", + find_reached_top: "Reached top of document, continued from bottom", + find_reached_bottom: "Reached end of document, continued from top", + "find_match_count[one]": "{{current}} of {{total}} match", + "find_match_count[other]": "{{current}} of {{total}} matches", + "find_match_count_limit[one]": "More than {{limit}} match", + "find_match_count_limit[other]": "More than {{limit}} matches", + find_not_found: "Phrase not found", + error_version_info: "PDF.js v{{version}} (build: {{build}})", + error_message: "Message: {{message}}", + error_stack: "Stack: {{stack}}", + error_file: "File: {{file}}", + error_line: "Line: {{line}}", + rendering_error: "An error occurred while rendering the page.", + page_scale_width: "Page Width", + page_scale_fit: "Page Fit", + page_scale_auto: "Automatic Zoom", + page_scale_actual: "Actual Size", + page_scale_percent: "{{scale}}%", + loading: "Loading…", + loading_error: "An error occurred while loading the PDF.", + invalid_file_error: "Invalid or corrupted PDF file.", + missing_file_error: "Missing PDF file.", + unexpected_response_error: "Unexpected server response.", + printing_not_supported: "Warning: Printing is not fully supported by this browser.", + printing_not_ready: "Warning: The PDF is not fully loaded for printing.", + web_fonts_disabled: "Web fonts are disabled: unable to use embedded PDF fonts.", + free_text_default_content: "Enter text…", + editor_free_text_aria_label: "FreeText Editor", + editor_ink_aria_label: "Ink Editor", + editor_ink_canvas_aria_label: "User-created image" +}; + +function getL10nFallback(key, args) { + switch (key) { + case "find_match_count": + key = `find_match_count[${args.total === 1 ? "one" : "other"}]`; + break; + + case "find_match_count_limit": + key = `find_match_count_limit[${args.limit === 1 ? "one" : "other"}]`; + break; + } + + return DEFAULT_L10N_STRINGS[key] || ""; +} + +const PARTIAL_LANG_CODES = { + en: "en-US", + es: "es-ES", + fy: "fy-NL", + ga: "ga-IE", + gu: "gu-IN", + hi: "hi-IN", + hy: "hy-AM", + nb: "nb-NO", + ne: "ne-NP", + nn: "nn-NO", + pa: "pa-IN", + pt: "pt-PT", + sv: "sv-SE", + zh: "zh-CN" +}; + +function fixupLangCode(langCode) { + return PARTIAL_LANG_CODES[langCode === null || langCode === void 0 ? void 0 : langCode.toLowerCase()] || langCode; +} + +function formatL10nValue(text, args) { + if (!args) { + return text; + } + + return text.replace(/\{\{\s*(\w+)\s*\}\}/g, (all, name) => { + return name in args ? args[name] : "{{" + name + "}}"; + }); +} + +const NullL10n = { + async getLanguage() { + return "en-us"; + }, + + async getDirection() { + return "ltr"; + }, + + async get(key) { + let args = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + let fallback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : getL10nFallback(key, args); + return formatL10nValue(fallback, args); + }, + + async translate(element) {} + +}; +exports.NullL10n = NullL10n; + +/***/ }), +/* 33 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.AnnotationLayerBuilder = void 0; + +var _pdfjsLib = __webpack_require__(5); + +var _l10n_utils = __webpack_require__(32); + +class AnnotationLayerBuilder { + constructor(_ref) { + let { + pageDiv, + pdfPage, + linkService, + downloadManager, + annotationStorage = null, + imageResourcesPath = "", + renderForms = true, + l10n = _l10n_utils.NullL10n, + enableScripting = false, + hasJSActionsPromise = null, + fieldObjectsPromise = null, + mouseState = null, + annotationCanvasMap = null, + accessibilityManager = null + } = _ref; + this.pageDiv = pageDiv; + this.pdfPage = pdfPage; + this.linkService = linkService; + this.downloadManager = downloadManager; + this.imageResourcesPath = imageResourcesPath; + this.renderForms = renderForms; + this.l10n = l10n; + this.annotationStorage = annotationStorage; + this.enableScripting = enableScripting; + this._hasJSActionsPromise = hasJSActionsPromise; + this._fieldObjectsPromise = fieldObjectsPromise; + this._mouseState = mouseState; + this._annotationCanvasMap = annotationCanvasMap; + this._accessibilityManager = accessibilityManager; + this.div = null; + this._cancelled = false; + } + + async render(viewport) { + let intent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "display"; + const [annotations, hasJSActions = false, fieldObjects = null] = await Promise.all([this.pdfPage.getAnnotations({ + intent + }), this._hasJSActionsPromise, this._fieldObjectsPromise]); + + if (this._cancelled || annotations.length === 0) { + return; + } + + const parameters = { + viewport: viewport.clone({ + dontFlip: true + }), + div: this.div, + annotations, + page: this.pdfPage, + imageResourcesPath: this.imageResourcesPath, + renderForms: this.renderForms, + linkService: this.linkService, + downloadManager: this.downloadManager, + annotationStorage: this.annotationStorage, + enableScripting: this.enableScripting, + hasJSActions, + fieldObjects, + mouseState: this._mouseState, + annotationCanvasMap: this._annotationCanvasMap, + accessibilityManager: this._accessibilityManager + }; + + if (this.div) { + _pdfjsLib.AnnotationLayer.update(parameters); + } else { + this.div = document.createElement("div"); + this.div.className = "annotationLayer"; + this.pageDiv.append(this.div); + parameters.div = this.div; + + _pdfjsLib.AnnotationLayer.render(parameters); + + this.l10n.translate(this.div); + } + } + + cancel() { + this._cancelled = true; + } + + hide() { + if (!this.div) { + return; + } + + this.div.hidden = true; + } + +} + +exports.AnnotationLayerBuilder = AnnotationLayerBuilder; + +/***/ }), +/* 34 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFPageView = void 0; + +var _pdfjsLib = __webpack_require__(5); + +var _ui_utils = __webpack_require__(1); + +var _app_options = __webpack_require__(2); + +var _l10n_utils = __webpack_require__(32); + +var _text_accessibility = __webpack_require__(35); + +function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } + +function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } + +function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } + +const MAX_CANVAS_PIXELS = _app_options.compatibilityParams.maxCanvasPixels || 16777216; + +var _annotationMode = /*#__PURE__*/new WeakMap(); + +var _useThumbnailCanvas = /*#__PURE__*/new WeakMap(); + +class PDFPageView { + constructor(options) { + var _options$textLayerMod, _options$annotationMo, _options$textHighligh, _this$renderingQueue; + + _classPrivateFieldInitSpec(this, _annotationMode, { + writable: true, + value: _pdfjsLib.AnnotationMode.ENABLE_FORMS + }); + + _classPrivateFieldInitSpec(this, _useThumbnailCanvas, { + writable: true, + value: { + initialOptionalContent: true, + regularAnnotations: true + } + }); + + const container = options.container; + const defaultViewport = options.defaultViewport; + this.id = options.id; + this.renderingId = "page" + this.id; + this.pdfPage = null; + this.pageLabel = null; + this.rotation = 0; + this.scale = options.scale || _ui_utils.DEFAULT_SCALE; + this.viewport = defaultViewport; + this.pdfPageRotate = defaultViewport.rotation; + this._optionalContentConfigPromise = options.optionalContentConfigPromise || null; + this.hasRestrictedScaling = false; + this.textLayerMode = (_options$textLayerMod = options.textLayerMode) !== null && _options$textLayerMod !== void 0 ? _options$textLayerMod : _ui_utils.TextLayerMode.ENABLE; + + _classPrivateFieldSet(this, _annotationMode, (_options$annotationMo = options.annotationMode) !== null && _options$annotationMo !== void 0 ? _options$annotationMo : _pdfjsLib.AnnotationMode.ENABLE_FORMS); + + this.imageResourcesPath = options.imageResourcesPath || ""; + this.useOnlyCssZoom = options.useOnlyCssZoom || false; + this.maxCanvasPixels = options.maxCanvasPixels || MAX_CANVAS_PIXELS; + this.pageColors = options.pageColors || null; + this.eventBus = options.eventBus; + this.renderingQueue = options.renderingQueue; + this.textLayerFactory = options.textLayerFactory; + this.annotationLayerFactory = options.annotationLayerFactory; + this.annotationEditorLayerFactory = options.annotationEditorLayerFactory; + this.xfaLayerFactory = options.xfaLayerFactory; + this.textHighlighter = (_options$textHighligh = options.textHighlighterFactory) === null || _options$textHighligh === void 0 ? void 0 : _options$textHighligh.createTextHighlighter({ + pageIndex: this.id - 1, + eventBus: this.eventBus + }); + this.structTreeLayerFactory = options.structTreeLayerFactory; + this.renderer = options.renderer || _ui_utils.RendererType.CANVAS; + this.l10n = options.l10n || _l10n_utils.NullL10n; + this.paintTask = null; + this.paintedViewportMap = new WeakMap(); + this.renderingState = _ui_utils.RenderingStates.INITIAL; + this.resume = null; + this._renderError = null; + this._isStandalone = !((_this$renderingQueue = this.renderingQueue) !== null && _this$renderingQueue !== void 0 && _this$renderingQueue.hasViewer()); + this._annotationCanvasMap = null; + this.annotationLayer = null; + this.annotationEditorLayer = null; + this.textLayer = null; + this.zoomLayer = null; + this.xfaLayer = null; + this.structTreeLayer = null; + const div = document.createElement("div"); + div.className = "page"; + div.style.width = Math.floor(this.viewport.width) + "px"; + div.style.height = Math.floor(this.viewport.height) + "px"; + div.setAttribute("data-page-number", this.id); + div.setAttribute("role", "region"); + this.l10n.get("page_landmark", { + page: this.id + }).then(msg => { + div.setAttribute("aria-label", msg); + }); + this.div = div; + container === null || container === void 0 ? void 0 : container.append(div); + + if (this._isStandalone) { + const { + optionalContentConfigPromise + } = options; + + if (optionalContentConfigPromise) { + optionalContentConfigPromise.then(optionalContentConfig => { + if (optionalContentConfigPromise !== this._optionalContentConfigPromise) { + return; + } + + _classPrivateFieldGet(this, _useThumbnailCanvas).initialOptionalContent = optionalContentConfig.hasInitialVisibility; + }); + } + } + } + + setPdfPage(pdfPage) { + this.pdfPage = pdfPage; + this.pdfPageRotate = pdfPage.rotate; + const totalRotation = (this.rotation + this.pdfPageRotate) % 360; + this.viewport = pdfPage.getViewport({ + scale: this.scale * _pdfjsLib.PixelsPerInch.PDF_TO_CSS_UNITS, + rotation: totalRotation + }); + this.reset(); + } + + destroy() { + this.reset(); + + if (this.pdfPage) { + this.pdfPage.cleanup(); + } + } + + async _renderAnnotationLayer() { + let error = null; + + try { + await this.annotationLayer.render(this.viewport, "display"); + } catch (ex) { + console.error(`_renderAnnotationLayer: "${ex}".`); + error = ex; + } finally { + this.eventBus.dispatch("annotationlayerrendered", { + source: this, + pageNumber: this.id, + error + }); + } + } + + async _renderAnnotationEditorLayer() { + let error = null; + + try { + await this.annotationEditorLayer.render(this.viewport, "display"); + } catch (ex) { + console.error(`_renderAnnotationEditorLayer: "${ex}".`); + error = ex; + } finally { + this.eventBus.dispatch("annotationeditorlayerrendered", { + source: this, + pageNumber: this.id, + error + }); + } + } + + async _renderXfaLayer() { + let error = null; + + try { + const result = await this.xfaLayer.render(this.viewport, "display"); + + if (this.textHighlighter) { + this._buildXfaTextContentItems(result.textDivs); + } + } catch (ex) { + console.error(`_renderXfaLayer: "${ex}".`); + error = ex; + } finally { + this.eventBus.dispatch("xfalayerrendered", { + source: this, + pageNumber: this.id, + error + }); + } + } + + async _buildXfaTextContentItems(textDivs) { + const text = await this.pdfPage.getTextContent(); + const items = []; + + for (const item of text.items) { + items.push(item.str); + } + + this.textHighlighter.setTextMapping(textDivs, items); + this.textHighlighter.enable(); + } + + _resetZoomLayer() { + let removeFromDOM = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + if (!this.zoomLayer) { + return; + } + + const zoomLayerCanvas = this.zoomLayer.firstChild; + this.paintedViewportMap.delete(zoomLayerCanvas); + zoomLayerCanvas.width = 0; + zoomLayerCanvas.height = 0; + + if (removeFromDOM) { + this.zoomLayer.remove(); + } + + this.zoomLayer = null; + } + + reset() { + var _this$annotationLayer, _this$annotationEdito, _this$xfaLayer; + + let { + keepZoomLayer = false, + keepAnnotationLayer = false, + keepAnnotationEditorLayer = false, + keepXfaLayer = false + } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + this.cancelRendering({ + keepAnnotationLayer, + keepAnnotationEditorLayer, + keepXfaLayer + }); + this.renderingState = _ui_utils.RenderingStates.INITIAL; + const div = this.div; + div.style.width = Math.floor(this.viewport.width) + "px"; + div.style.height = Math.floor(this.viewport.height) + "px"; + const childNodes = div.childNodes, + zoomLayerNode = keepZoomLayer && this.zoomLayer || null, + annotationLayerNode = keepAnnotationLayer && ((_this$annotationLayer = this.annotationLayer) === null || _this$annotationLayer === void 0 ? void 0 : _this$annotationLayer.div) || null, + annotationEditorLayerNode = keepAnnotationEditorLayer && ((_this$annotationEdito = this.annotationEditorLayer) === null || _this$annotationEdito === void 0 ? void 0 : _this$annotationEdito.div) || null, + xfaLayerNode = keepXfaLayer && ((_this$xfaLayer = this.xfaLayer) === null || _this$xfaLayer === void 0 ? void 0 : _this$xfaLayer.div) || null; + + for (let i = childNodes.length - 1; i >= 0; i--) { + const node = childNodes[i]; + + switch (node) { + case zoomLayerNode: + case annotationLayerNode: + case annotationEditorLayerNode: + case xfaLayerNode: + continue; + } + + node.remove(); + } + + div.removeAttribute("data-loaded"); + + if (annotationLayerNode) { + this.annotationLayer.hide(); + } + + if (annotationEditorLayerNode) { + this.annotationEditorLayer.hide(); + } else { + var _this$annotationEdito2; + + (_this$annotationEdito2 = this.annotationEditorLayer) === null || _this$annotationEdito2 === void 0 ? void 0 : _this$annotationEdito2.destroy(); + } + + if (xfaLayerNode) { + this.xfaLayer.hide(); + } + + if (!zoomLayerNode) { + if (this.canvas) { + this.paintedViewportMap.delete(this.canvas); + this.canvas.width = 0; + this.canvas.height = 0; + delete this.canvas; + } + + this._resetZoomLayer(); + } + + if (this.svg) { + this.paintedViewportMap.delete(this.svg); + delete this.svg; + } + + this.loadingIconDiv = document.createElement("div"); + this.loadingIconDiv.className = "loadingIcon notVisible"; + + if (this._isStandalone) { + this.toggleLoadingIconSpinner(true); + } + + this.loadingIconDiv.setAttribute("role", "img"); + this.l10n.get("loading").then(msg => { + var _this$loadingIconDiv; + + (_this$loadingIconDiv = this.loadingIconDiv) === null || _this$loadingIconDiv === void 0 ? void 0 : _this$loadingIconDiv.setAttribute("aria-label", msg); + }); + div.append(this.loadingIconDiv); + } + + update(_ref) { + let { + scale = 0, + rotation = null, + optionalContentConfigPromise = null + } = _ref; + this.scale = scale || this.scale; + + if (typeof rotation === "number") { + this.rotation = rotation; + } + + if (optionalContentConfigPromise instanceof Promise) { + this._optionalContentConfigPromise = optionalContentConfigPromise; + optionalContentConfigPromise.then(optionalContentConfig => { + if (optionalContentConfigPromise !== this._optionalContentConfigPromise) { + return; + } + + _classPrivateFieldGet(this, _useThumbnailCanvas).initialOptionalContent = optionalContentConfig.hasInitialVisibility; + }); + } + + const totalRotation = (this.rotation + this.pdfPageRotate) % 360; + this.viewport = this.viewport.clone({ + scale: this.scale * _pdfjsLib.PixelsPerInch.PDF_TO_CSS_UNITS, + rotation: totalRotation + }); + + if (this._isStandalone) { + _ui_utils.docStyle.setProperty("--scale-factor", this.viewport.scale); + } + + if (this.svg) { + this.cssTransform({ + target: this.svg, + redrawAnnotationLayer: true, + redrawAnnotationEditorLayer: true, + redrawXfaLayer: true + }); + this.eventBus.dispatch("pagerendered", { + source: this, + pageNumber: this.id, + cssTransform: true, + timestamp: performance.now(), + error: this._renderError + }); + return; + } + + let isScalingRestricted = false; + + if (this.canvas && this.maxCanvasPixels > 0) { + const outputScale = this.outputScale; + + if ((Math.floor(this.viewport.width) * outputScale.sx | 0) * (Math.floor(this.viewport.height) * outputScale.sy | 0) > this.maxCanvasPixels) { + isScalingRestricted = true; + } + } + + if (this.canvas) { + if (this.useOnlyCssZoom || this.hasRestrictedScaling && isScalingRestricted) { + this.cssTransform({ + target: this.canvas, + redrawAnnotationLayer: true, + redrawAnnotationEditorLayer: true, + redrawXfaLayer: true + }); + this.eventBus.dispatch("pagerendered", { + source: this, + pageNumber: this.id, + cssTransform: true, + timestamp: performance.now(), + error: this._renderError + }); + return; + } + + if (!this.zoomLayer && !this.canvas.hidden) { + this.zoomLayer = this.canvas.parentNode; + this.zoomLayer.style.position = "absolute"; + } + } + + if (this.zoomLayer) { + this.cssTransform({ + target: this.zoomLayer.firstChild + }); + } + + this.reset({ + keepZoomLayer: true, + keepAnnotationLayer: true, + keepAnnotationEditorLayer: true, + keepXfaLayer: true + }); + } + + cancelRendering() { + let { + keepAnnotationLayer = false, + keepAnnotationEditorLayer = false, + keepXfaLayer = false + } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + if (this.paintTask) { + this.paintTask.cancel(); + this.paintTask = null; + } + + this.resume = null; + + if (this.textLayer) { + this.textLayer.cancel(); + this.textLayer = null; + } + + if (this.annotationLayer && (!keepAnnotationLayer || !this.annotationLayer.div)) { + this.annotationLayer.cancel(); + this.annotationLayer = null; + this._annotationCanvasMap = null; + } + + if (this.annotationEditorLayer && (!keepAnnotationEditorLayer || !this.annotationEditorLayer.div)) { + this.annotationEditorLayer.cancel(); + this.annotationEditorLayer = null; + } + + if (this.xfaLayer && (!keepXfaLayer || !this.xfaLayer.div)) { + var _this$textHighlighter; + + this.xfaLayer.cancel(); + this.xfaLayer = null; + (_this$textHighlighter = this.textHighlighter) === null || _this$textHighlighter === void 0 ? void 0 : _this$textHighlighter.disable(); + } + + if (this._onTextLayerRendered) { + this.eventBus._off("textlayerrendered", this._onTextLayerRendered); + + this._onTextLayerRendered = null; + } + } + + cssTransform(_ref2) { + let { + target, + redrawAnnotationLayer = false, + redrawAnnotationEditorLayer = false, + redrawXfaLayer = false + } = _ref2; + const width = this.viewport.width; + const height = this.viewport.height; + const div = this.div; + target.style.width = target.parentNode.style.width = div.style.width = Math.floor(width) + "px"; + target.style.height = target.parentNode.style.height = div.style.height = Math.floor(height) + "px"; + const relativeRotation = this.viewport.rotation - this.paintedViewportMap.get(target).rotation; + const absRotation = Math.abs(relativeRotation); + let scaleX = 1, + scaleY = 1; + + if (absRotation === 90 || absRotation === 270) { + scaleX = height / width; + scaleY = width / height; + } + + target.style.transform = `rotate(${relativeRotation}deg) scale(${scaleX}, ${scaleY})`; + + if (this.textLayer) { + const textLayerViewport = this.textLayer.viewport; + const textRelativeRotation = this.viewport.rotation - textLayerViewport.rotation; + const textAbsRotation = Math.abs(textRelativeRotation); + let scale = width / textLayerViewport.width; + + if (textAbsRotation === 90 || textAbsRotation === 270) { + scale = width / textLayerViewport.height; + } + + const textLayerDiv = this.textLayer.textLayerDiv; + let transX, transY; + + switch (textAbsRotation) { + case 0: + transX = transY = 0; + break; + + case 90: + transX = 0; + transY = "-" + textLayerDiv.style.height; + break; + + case 180: + transX = "-" + textLayerDiv.style.width; + transY = "-" + textLayerDiv.style.height; + break; + + case 270: + transX = "-" + textLayerDiv.style.width; + transY = 0; + break; + + default: + console.error("Bad rotation value."); + break; + } + + textLayerDiv.style.transform = `rotate(${textAbsRotation}deg) ` + `scale(${scale}) ` + `translate(${transX}, ${transY})`; + textLayerDiv.style.transformOrigin = "0% 0%"; + } + + if (redrawAnnotationLayer && this.annotationLayer) { + this._renderAnnotationLayer(); + } + + if (redrawAnnotationEditorLayer && this.annotationEditorLayer) { + this._renderAnnotationEditorLayer(); + } + + if (redrawXfaLayer && this.xfaLayer) { + this._renderXfaLayer(); + } + } + + get width() { + return this.viewport.width; + } + + get height() { + return this.viewport.height; + } + + getPagePoint(x, y) { + return this.viewport.convertToPdfPoint(x, y); + } + + toggleLoadingIconSpinner() { + var _this$loadingIconDiv2; + + let viewVisible = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + (_this$loadingIconDiv2 = this.loadingIconDiv) === null || _this$loadingIconDiv2 === void 0 ? void 0 : _this$loadingIconDiv2.classList.toggle("notVisible", !viewVisible); + } + + draw() { + var _this$annotationLayer2, + _this$annotationEdito3, + _this$xfaLayer2, + _this = this; + + if (this.renderingState !== _ui_utils.RenderingStates.INITIAL) { + console.error("Must be in new state before drawing"); + this.reset(); + } + + const { + div, + pdfPage + } = this; + + if (!pdfPage) { + this.renderingState = _ui_utils.RenderingStates.FINISHED; + + if (this.loadingIconDiv) { + this.loadingIconDiv.remove(); + delete this.loadingIconDiv; + } + + return Promise.reject(new Error("pdfPage is not loaded")); + } + + this.renderingState = _ui_utils.RenderingStates.RUNNING; + const canvasWrapper = document.createElement("div"); + canvasWrapper.style.width = div.style.width; + canvasWrapper.style.height = div.style.height; + canvasWrapper.classList.add("canvasWrapper"); + const lastDivBeforeTextDiv = ((_this$annotationLayer2 = this.annotationLayer) === null || _this$annotationLayer2 === void 0 ? void 0 : _this$annotationLayer2.div) || ((_this$annotationEdito3 = this.annotationEditorLayer) === null || _this$annotationEdito3 === void 0 ? void 0 : _this$annotationEdito3.div); + + if (lastDivBeforeTextDiv) { + lastDivBeforeTextDiv.before(canvasWrapper); + } else { + div.append(canvasWrapper); + } + + let textLayer = null; + + if (this.textLayerMode !== _ui_utils.TextLayerMode.DISABLE && this.textLayerFactory) { + this._accessibilityManager || (this._accessibilityManager = new _text_accessibility.TextAccessibilityManager()); + const textLayerDiv = document.createElement("div"); + textLayerDiv.className = "textLayer"; + textLayerDiv.style.width = canvasWrapper.style.width; + textLayerDiv.style.height = canvasWrapper.style.height; + + if (lastDivBeforeTextDiv) { + lastDivBeforeTextDiv.before(textLayerDiv); + } else { + div.append(textLayerDiv); + } + + textLayer = this.textLayerFactory.createTextLayerBuilder({ + textLayerDiv, + pageIndex: this.id - 1, + viewport: this.viewport, + enhanceTextSelection: this.textLayerMode === _ui_utils.TextLayerMode.ENABLE_ENHANCE, + eventBus: this.eventBus, + highlighter: this.textHighlighter, + accessibilityManager: this._accessibilityManager + }); + } + + this.textLayer = textLayer; + + if (_classPrivateFieldGet(this, _annotationMode) !== _pdfjsLib.AnnotationMode.DISABLE && this.annotationLayerFactory) { + this._annotationCanvasMap || (this._annotationCanvasMap = new Map()); + this.annotationLayer || (this.annotationLayer = this.annotationLayerFactory.createAnnotationLayerBuilder({ + pageDiv: div, + pdfPage, + imageResourcesPath: this.imageResourcesPath, + renderForms: _classPrivateFieldGet(this, _annotationMode) === _pdfjsLib.AnnotationMode.ENABLE_FORMS, + l10n: this.l10n, + annotationCanvasMap: this._annotationCanvasMap, + accessibilityManager: this._accessibilityManager + })); + } + + if ((_this$xfaLayer2 = this.xfaLayer) !== null && _this$xfaLayer2 !== void 0 && _this$xfaLayer2.div) { + div.append(this.xfaLayer.div); + } + + let renderContinueCallback = null; + + if (this.renderingQueue) { + renderContinueCallback = cont => { + if (!this.renderingQueue.isHighestPriority(this)) { + this.renderingState = _ui_utils.RenderingStates.PAUSED; + + this.resume = () => { + this.renderingState = _ui_utils.RenderingStates.RUNNING; + cont(); + }; + + return; + } + + cont(); + }; + } + + const finishPaintTask = async function () { + let error = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + + if (paintTask === _this.paintTask) { + _this.paintTask = null; + } + + if (error instanceof _pdfjsLib.RenderingCancelledException) { + _this._renderError = null; + return; + } + + _this._renderError = error; + _this.renderingState = _ui_utils.RenderingStates.FINISHED; + + if (_this.loadingIconDiv) { + _this.loadingIconDiv.remove(); + + delete _this.loadingIconDiv; + } + + _this._resetZoomLayer(true); + + _classPrivateFieldGet(_this, _useThumbnailCanvas).regularAnnotations = !paintTask.separateAnnots; + + _this.eventBus.dispatch("pagerendered", { + source: _this, + pageNumber: _this.id, + cssTransform: false, + timestamp: performance.now(), + error: _this._renderError + }); + + if (error) { + throw error; + } + }; + + const paintTask = this.renderer === _ui_utils.RendererType.SVG ? this.paintOnSvg(canvasWrapper) : this.paintOnCanvas(canvasWrapper); + paintTask.onRenderContinue = renderContinueCallback; + this.paintTask = paintTask; + const resultPromise = paintTask.promise.then(() => { + return finishPaintTask(null).then(() => { + if (textLayer) { + const readableStream = pdfPage.streamTextContent({ + includeMarkedContent: true + }); + textLayer.setTextContentStream(readableStream); + textLayer.render(); + } + + if (this.annotationLayer) { + this._renderAnnotationLayer().then(() => { + if (this.annotationEditorLayerFactory) { + this.annotationEditorLayer || (this.annotationEditorLayer = this.annotationEditorLayerFactory.createAnnotationEditorLayerBuilder({ + pageDiv: div, + pdfPage, + l10n: this.l10n, + accessibilityManager: this._accessibilityManager + })); + + this._renderAnnotationEditorLayer(); + } + }); + } + }); + }, function (reason) { + return finishPaintTask(reason); + }); + + if (this.xfaLayerFactory) { + this.xfaLayer || (this.xfaLayer = this.xfaLayerFactory.createXfaLayerBuilder({ + pageDiv: div, + pdfPage + })); + + this._renderXfaLayer(); + } + + if (this.structTreeLayerFactory && this.textLayer && this.canvas) { + this._onTextLayerRendered = event => { + if (event.pageNumber !== this.id) { + return; + } + + this.eventBus._off("textlayerrendered", this._onTextLayerRendered); + + this._onTextLayerRendered = null; + + if (!this.canvas) { + return; + } + + this.pdfPage.getStructTree().then(tree => { + if (!tree) { + return; + } + + if (!this.canvas) { + return; + } + + const treeDom = this.structTreeLayer.render(tree); + treeDom.classList.add("structTree"); + this.canvas.append(treeDom); + }); + }; + + this.eventBus._on("textlayerrendered", this._onTextLayerRendered); + + this.structTreeLayer = this.structTreeLayerFactory.createStructTreeLayerBuilder({ + pdfPage + }); + } + + div.setAttribute("data-loaded", true); + this.eventBus.dispatch("pagerender", { + source: this, + pageNumber: this.id + }); + return resultPromise; + } + + paintOnCanvas(canvasWrapper) { + const renderCapability = (0, _pdfjsLib.createPromiseCapability)(); + const result = { + promise: renderCapability.promise, + + onRenderContinue(cont) { + cont(); + }, + + cancel() { + renderTask.cancel(); + }, + + get separateAnnots() { + return renderTask.separateAnnots; + } + + }; + const viewport = this.viewport; + const canvas = document.createElement("canvas"); + canvas.setAttribute("role", "presentation"); + canvas.hidden = true; + let isCanvasHidden = true; + + const showCanvas = function () { + if (isCanvasHidden) { + canvas.hidden = false; + isCanvasHidden = false; + } + }; + + canvasWrapper.append(canvas); + this.canvas = canvas; + const ctx = canvas.getContext("2d", { + alpha: false + }); + const outputScale = this.outputScale = new _ui_utils.OutputScale(); + + if (this.useOnlyCssZoom) { + const actualSizeViewport = viewport.clone({ + scale: _pdfjsLib.PixelsPerInch.PDF_TO_CSS_UNITS + }); + outputScale.sx *= actualSizeViewport.width / viewport.width; + outputScale.sy *= actualSizeViewport.height / viewport.height; + } + + if (this.maxCanvasPixels > 0) { + const pixelsInViewport = viewport.width * viewport.height; + const maxScale = Math.sqrt(this.maxCanvasPixels / pixelsInViewport); + + if (outputScale.sx > maxScale || outputScale.sy > maxScale) { + outputScale.sx = maxScale; + outputScale.sy = maxScale; + this.hasRestrictedScaling = true; + } else { + this.hasRestrictedScaling = false; + } + } + + const sfx = (0, _ui_utils.approximateFraction)(outputScale.sx); + const sfy = (0, _ui_utils.approximateFraction)(outputScale.sy); + canvas.width = (0, _ui_utils.roundToDivide)(viewport.width * outputScale.sx, sfx[0]); + canvas.height = (0, _ui_utils.roundToDivide)(viewport.height * outputScale.sy, sfy[0]); + canvas.style.width = (0, _ui_utils.roundToDivide)(viewport.width, sfx[1]) + "px"; + canvas.style.height = (0, _ui_utils.roundToDivide)(viewport.height, sfy[1]) + "px"; + this.paintedViewportMap.set(canvas, viewport); + const transform = outputScale.scaled ? [outputScale.sx, 0, 0, outputScale.sy, 0, 0] : null; + const renderContext = { + canvasContext: ctx, + transform, + viewport: this.viewport, + annotationMode: _classPrivateFieldGet(this, _annotationMode), + optionalContentConfigPromise: this._optionalContentConfigPromise, + annotationCanvasMap: this._annotationCanvasMap, + pageColors: this.pageColors + }; + const renderTask = this.pdfPage.render(renderContext); + + renderTask.onContinue = function (cont) { + showCanvas(); + + if (result.onRenderContinue) { + result.onRenderContinue(cont); + } else { + cont(); + } + }; + + renderTask.promise.then(function () { + showCanvas(); + renderCapability.resolve(); + }, function (error) { + showCanvas(); + renderCapability.reject(error); + }); + return result; + } + + paintOnSvg(wrapper) { + let cancelled = false; + + const ensureNotCancelled = () => { + if (cancelled) { + throw new _pdfjsLib.RenderingCancelledException(`Rendering cancelled, page ${this.id}`, "svg"); + } + }; + + const pdfPage = this.pdfPage; + const actualSizeViewport = this.viewport.clone({ + scale: _pdfjsLib.PixelsPerInch.PDF_TO_CSS_UNITS + }); + const promise = pdfPage.getOperatorList({ + annotationMode: _classPrivateFieldGet(this, _annotationMode) + }).then(opList => { + ensureNotCancelled(); + const svgGfx = new _pdfjsLib.SVGGraphics(pdfPage.commonObjs, pdfPage.objs); + return svgGfx.getSVG(opList, actualSizeViewport).then(svg => { + ensureNotCancelled(); + this.svg = svg; + this.paintedViewportMap.set(svg, actualSizeViewport); + svg.style.width = wrapper.style.width; + svg.style.height = wrapper.style.height; + this.renderingState = _ui_utils.RenderingStates.FINISHED; + wrapper.append(svg); + }); + }); + return { + promise, + + onRenderContinue(cont) { + cont(); + }, + + cancel() { + cancelled = true; + }, + + get separateAnnots() { + return false; + } + + }; + } + + setPageLabel(label) { + this.pageLabel = typeof label === "string" ? label : null; + + if (this.pageLabel !== null) { + this.div.setAttribute("data-page-label", this.pageLabel); + } else { + this.div.removeAttribute("data-page-label"); + } + } + + get thumbnailCanvas() { + const { + initialOptionalContent, + regularAnnotations + } = _classPrivateFieldGet(this, _useThumbnailCanvas); + + return initialOptionalContent && regularAnnotations ? this.canvas : null; + } + +} + +exports.PDFPageView = PDFPageView; + +/***/ }), +/* 35 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.TextAccessibilityManager = void 0; + +var _ui_utils = __webpack_require__(1); + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +function _classStaticPrivateMethodGet(receiver, classConstructor, method) { _classCheckPrivateStaticAccess(receiver, classConstructor); return method; } + +function _classCheckPrivateStaticAccess(receiver, classConstructor) { if (receiver !== classConstructor) { throw new TypeError("Private static access of wrong provenance"); } } + +function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } + +function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } + +function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } + +var _enabled = /*#__PURE__*/new WeakMap(); + +var _textChildren = /*#__PURE__*/new WeakMap(); + +var _textNodes = /*#__PURE__*/new WeakMap(); + +var _waitingElements = /*#__PURE__*/new WeakMap(); + +var _addIdToAriaOwns = /*#__PURE__*/new WeakSet(); + +class TextAccessibilityManager { + constructor() { + _classPrivateMethodInitSpec(this, _addIdToAriaOwns); + + _classPrivateFieldInitSpec(this, _enabled, { + writable: true, + value: false + }); + + _classPrivateFieldInitSpec(this, _textChildren, { + writable: true, + value: null + }); + + _classPrivateFieldInitSpec(this, _textNodes, { + writable: true, + value: new Map() + }); + + _classPrivateFieldInitSpec(this, _waitingElements, { + writable: true, + value: new Map() + }); + } + + setTextMapping(textDivs) { + _classPrivateFieldSet(this, _textChildren, textDivs); + } + + enable() { + if (_classPrivateFieldGet(this, _enabled)) { + throw new Error("TextAccessibilityManager is already enabled."); + } + + if (!_classPrivateFieldGet(this, _textChildren)) { + throw new Error("Text divs and strings have not been set."); + } + + _classPrivateFieldSet(this, _enabled, true); + + _classPrivateFieldSet(this, _textChildren, _classPrivateFieldGet(this, _textChildren).slice()); + + _classPrivateFieldGet(this, _textChildren).sort(_classStaticPrivateMethodGet(TextAccessibilityManager, TextAccessibilityManager, _compareElementPositions)); + + if (_classPrivateFieldGet(this, _textNodes).size > 0) { + const textChildren = _classPrivateFieldGet(this, _textChildren); + + for (const [id, nodeIndex] of _classPrivateFieldGet(this, _textNodes)) { + const element = document.getElementById(id); + + if (!element) { + _classPrivateFieldGet(this, _textNodes).delete(id); + + continue; + } + + _classPrivateMethodGet(this, _addIdToAriaOwns, _addIdToAriaOwns2).call(this, id, textChildren[nodeIndex]); + } + } + + for (const [element, isRemovable] of _classPrivateFieldGet(this, _waitingElements)) { + this.addPointerInTextLayer(element, isRemovable); + } + + _classPrivateFieldGet(this, _waitingElements).clear(); + } + + disable() { + if (!_classPrivateFieldGet(this, _enabled)) { + return; + } + + _classPrivateFieldGet(this, _waitingElements).clear(); + + _classPrivateFieldSet(this, _textChildren, null); + + _classPrivateFieldSet(this, _enabled, false); + } + + removePointerInTextLayer(element) { + var _owns; + + if (!_classPrivateFieldGet(this, _enabled)) { + _classPrivateFieldGet(this, _waitingElements).delete(element); + + return; + } + + const children = _classPrivateFieldGet(this, _textChildren); + + if (!children || children.length === 0) { + return; + } + + const { + id + } = element; + + const nodeIndex = _classPrivateFieldGet(this, _textNodes).get(id); + + if (nodeIndex === undefined) { + return; + } + + const node = children[nodeIndex]; + + _classPrivateFieldGet(this, _textNodes).delete(id); + + let owns = node.getAttribute("aria-owns"); + + if ((_owns = owns) !== null && _owns !== void 0 && _owns.includes(id)) { + owns = owns.split(" ").filter(x => x !== id).join(" "); + + if (owns) { + node.setAttribute("aria-owns", owns); + } else { + node.removeAttribute("aria-owns"); + node.setAttribute("role", "presentation"); + } + } + } + + addPointerInTextLayer(element, isRemovable) { + const { + id + } = element; + + if (!id) { + return; + } + + if (!_classPrivateFieldGet(this, _enabled)) { + _classPrivateFieldGet(this, _waitingElements).set(element, isRemovable); + + return; + } + + if (isRemovable) { + this.removePointerInTextLayer(element); + } + + const children = _classPrivateFieldGet(this, _textChildren); + + if (!children || children.length === 0) { + return; + } + + const index = (0, _ui_utils.binarySearchFirstItem)(children, node => _classStaticPrivateMethodGet(TextAccessibilityManager, TextAccessibilityManager, _compareElementPositions).call(TextAccessibilityManager, element, node) < 0); + const nodeIndex = Math.max(0, index - 1); + + _classPrivateMethodGet(this, _addIdToAriaOwns, _addIdToAriaOwns2).call(this, id, children[nodeIndex]); + + _classPrivateFieldGet(this, _textNodes).set(id, nodeIndex); + } + + moveElementInDOM(container, element, contentElement, isRemovable) { + this.addPointerInTextLayer(contentElement, isRemovable); + + if (!container.hasChildNodes()) { + container.append(element); + return; + } + + const children = Array.from(container.childNodes).filter(node => node !== element); + + if (children.length === 0) { + return; + } + + const elementToCompare = contentElement || element; + const index = (0, _ui_utils.binarySearchFirstItem)(children, node => _classStaticPrivateMethodGet(TextAccessibilityManager, TextAccessibilityManager, _compareElementPositions).call(TextAccessibilityManager, elementToCompare, node) < 0); + + if (index === 0) { + children[0].before(element); + } else { + children[index - 1].after(element); + } + } + +} + +exports.TextAccessibilityManager = TextAccessibilityManager; + +function _compareElementPositions(e1, e2) { + const rect1 = e1.getBoundingClientRect(); + const rect2 = e2.getBoundingClientRect(); + + if (rect1.width === 0 && rect1.height === 0) { + return +1; + } + + if (rect2.width === 0 && rect2.height === 0) { + return -1; + } + + const top1 = rect1.y; + const bot1 = rect1.y + rect1.height; + const mid1 = rect1.y + rect1.height / 2; + const top2 = rect2.y; + const bot2 = rect2.y + rect2.height; + const mid2 = rect2.y + rect2.height / 2; + + if (mid1 <= top2 && mid2 >= bot1) { + return -1; + } + + if (mid2 <= top1 && mid1 >= bot2) { + return +1; + } + + const centerX1 = rect1.x + rect1.width / 2; + const centerX2 = rect2.x + rect2.width / 2; + return centerX1 - centerX2; +} + +function _addIdToAriaOwns2(id, node) { + const owns = node.getAttribute("aria-owns"); + + if (!(owns !== null && owns !== void 0 && owns.includes(id))) { + node.setAttribute("aria-owns", owns ? `${owns} ${id}` : id); + } + + node.removeAttribute("role"); +} + +/***/ }), +/* 36 */ +/***/ ((__unused_webpack_module, exports) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.StructTreeLayerBuilder = void 0; +const PDF_ROLE_TO_HTML_ROLE = { + Document: null, + DocumentFragment: null, + Part: "group", + Sect: "group", + Div: "group", + Aside: "note", + NonStruct: "none", + P: null, + H: "heading", + Title: null, + FENote: "note", + Sub: "group", + Lbl: null, + Span: null, + Em: null, + Strong: null, + Link: "link", + Annot: "note", + Form: "form", + Ruby: null, + RB: null, + RT: null, + RP: null, + Warichu: null, + WT: null, + WP: null, + L: "list", + LI: "listitem", + LBody: null, + Table: "table", + TR: "row", + TH: "columnheader", + TD: "cell", + THead: "columnheader", + TBody: null, + TFoot: null, + Caption: null, + Figure: "figure", + Formula: null, + Artifact: null +}; +const HEADING_PATTERN = /^H(\d+)$/; + +class StructTreeLayerBuilder { + constructor(_ref) { + let { + pdfPage + } = _ref; + this.pdfPage = pdfPage; + } + + render(structTree) { + return this._walk(structTree); + } + + _setAttributes(structElement, htmlElement) { + if (structElement.alt !== undefined) { + htmlElement.setAttribute("aria-label", structElement.alt); + } + + if (structElement.id !== undefined) { + htmlElement.setAttribute("aria-owns", structElement.id); + } + + if (structElement.lang !== undefined) { + htmlElement.setAttribute("lang", structElement.lang); + } + } + + _walk(node) { + if (!node) { + return null; + } + + const element = document.createElement("span"); + + if ("role" in node) { + const { + role + } = node; + const match = role.match(HEADING_PATTERN); + + if (match) { + element.setAttribute("role", "heading"); + element.setAttribute("aria-level", match[1]); + } else if (PDF_ROLE_TO_HTML_ROLE[role]) { + element.setAttribute("role", PDF_ROLE_TO_HTML_ROLE[role]); + } + } + + this._setAttributes(node, element); + + if (node.children) { + if (node.children.length === 1 && "id" in node.children[0]) { + this._setAttributes(node.children[0], element); + } else { + for (const kid of node.children) { + element.append(this._walk(kid)); + } + } + } + + return element; + } + +} + +exports.StructTreeLayerBuilder = StructTreeLayerBuilder; + +/***/ }), +/* 37 */ +/***/ ((__unused_webpack_module, exports) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.TextHighlighter = void 0; + +class TextHighlighter { + constructor(_ref) { + let { + findController, + eventBus, + pageIndex + } = _ref; + this.findController = findController; + this.matches = []; + this.eventBus = eventBus; + this.pageIdx = pageIndex; + this._onUpdateTextLayerMatches = null; + this.textDivs = null; + this.textContentItemsStr = null; + this.enabled = false; + } + + setTextMapping(divs, texts) { + this.textDivs = divs; + this.textContentItemsStr = texts; + } + + enable() { + if (!this.textDivs || !this.textContentItemsStr) { + throw new Error("Text divs and strings have not been set."); + } + + if (this.enabled) { + throw new Error("TextHighlighter is already enabled."); + } + + this.enabled = true; + + if (!this._onUpdateTextLayerMatches) { + this._onUpdateTextLayerMatches = evt => { + if (evt.pageIndex === this.pageIdx || evt.pageIndex === -1) { + this._updateMatches(); + } + }; + + this.eventBus._on("updatetextlayermatches", this._onUpdateTextLayerMatches); + } + + this._updateMatches(); + } + + disable() { + if (!this.enabled) { + return; + } + + this.enabled = false; + + if (this._onUpdateTextLayerMatches) { + this.eventBus._off("updatetextlayermatches", this._onUpdateTextLayerMatches); + + this._onUpdateTextLayerMatches = null; + } + } + + _convertMatches(matches, matchesLength) { + if (!matches) { + return []; + } + + const { + textContentItemsStr + } = this; + let i = 0, + iIndex = 0; + const end = textContentItemsStr.length - 1; + const result = []; + + for (let m = 0, mm = matches.length; m < mm; m++) { + let matchIdx = matches[m]; + + while (i !== end && matchIdx >= iIndex + textContentItemsStr[i].length) { + iIndex += textContentItemsStr[i].length; + i++; + } + + if (i === textContentItemsStr.length) { + console.error("Could not find a matching mapping"); + } + + const match = { + begin: { + divIdx: i, + offset: matchIdx - iIndex + } + }; + matchIdx += matchesLength[m]; + + while (i !== end && matchIdx > iIndex + textContentItemsStr[i].length) { + iIndex += textContentItemsStr[i].length; + i++; + } + + match.end = { + divIdx: i, + offset: matchIdx - iIndex + }; + result.push(match); + } + + return result; + } + + _renderMatches(matches) { + if (matches.length === 0) { + return; + } + + const { + findController, + pageIdx + } = this; + const { + textContentItemsStr, + textDivs + } = this; + const isSelectedPage = pageIdx === findController.selected.pageIdx; + const selectedMatchIdx = findController.selected.matchIdx; + const highlightAll = findController.state.highlightAll; + let prevEnd = null; + const infinity = { + divIdx: -1, + offset: undefined + }; + + function beginText(begin, className) { + const divIdx = begin.divIdx; + textDivs[divIdx].textContent = ""; + return appendTextToDiv(divIdx, 0, begin.offset, className); + } + + function appendTextToDiv(divIdx, fromOffset, toOffset, className) { + let div = textDivs[divIdx]; + + if (div.nodeType === Node.TEXT_NODE) { + const span = document.createElement("span"); + div.before(span); + span.append(div); + textDivs[divIdx] = span; + div = span; + } + + const content = textContentItemsStr[divIdx].substring(fromOffset, toOffset); + const node = document.createTextNode(content); + + if (className) { + const span = document.createElement("span"); + span.className = `${className} appended`; + span.append(node); + div.append(span); + return className.includes("selected") ? span.offsetLeft : 0; + } + + div.append(node); + return 0; + } + + let i0 = selectedMatchIdx, + i1 = i0 + 1; + + if (highlightAll) { + i0 = 0; + i1 = matches.length; + } else if (!isSelectedPage) { + return; + } + + for (let i = i0; i < i1; i++) { + const match = matches[i]; + const begin = match.begin; + const end = match.end; + const isSelected = isSelectedPage && i === selectedMatchIdx; + const highlightSuffix = isSelected ? " selected" : ""; + let selectedLeft = 0; + + if (!prevEnd || begin.divIdx !== prevEnd.divIdx) { + if (prevEnd !== null) { + appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset); + } + + beginText(begin); + } else { + appendTextToDiv(prevEnd.divIdx, prevEnd.offset, begin.offset); + } + + if (begin.divIdx === end.divIdx) { + selectedLeft = appendTextToDiv(begin.divIdx, begin.offset, end.offset, "highlight" + highlightSuffix); + } else { + selectedLeft = appendTextToDiv(begin.divIdx, begin.offset, infinity.offset, "highlight begin" + highlightSuffix); + + for (let n0 = begin.divIdx + 1, n1 = end.divIdx; n0 < n1; n0++) { + textDivs[n0].className = "highlight middle" + highlightSuffix; + } + + beginText(end, "highlight end" + highlightSuffix); + } + + prevEnd = end; + + if (isSelected) { + findController.scrollMatchIntoView({ + element: textDivs[begin.divIdx], + selectedLeft, + pageIndex: pageIdx, + matchIndex: selectedMatchIdx + }); + } + } + + if (prevEnd) { + appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset); + } + } + + _updateMatches() { + if (!this.enabled) { + return; + } + + const { + findController, + matches, + pageIdx + } = this; + const { + textContentItemsStr, + textDivs + } = this; + let clearedUntilDivIdx = -1; + + for (let i = 0, ii = matches.length; i < ii; i++) { + const match = matches[i]; + const begin = Math.max(clearedUntilDivIdx, match.begin.divIdx); + + for (let n = begin, end = match.end.divIdx; n <= end; n++) { + const div = textDivs[n]; + div.textContent = textContentItemsStr[n]; + div.className = ""; + } + + clearedUntilDivIdx = match.end.divIdx + 1; + } + + if (!(findController !== null && findController !== void 0 && findController.highlightMatches)) { + return; + } + + const pageMatches = findController.pageMatches[pageIdx] || null; + const pageMatchesLength = findController.pageMatchesLength[pageIdx] || null; + this.matches = this._convertMatches(pageMatches, pageMatchesLength); + + this._renderMatches(this.matches); + } + +} + +exports.TextHighlighter = TextHighlighter; + +/***/ }), +/* 38 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.TextLayerBuilder = void 0; + +var _pdfjsLib = __webpack_require__(5); + +const EXPAND_DIVS_TIMEOUT = 300; + +class TextLayerBuilder { + constructor(_ref) { + let { + textLayerDiv, + eventBus, + pageIndex, + viewport, + highlighter = null, + enhanceTextSelection = false, + accessibilityManager = null + } = _ref; + this.textLayerDiv = textLayerDiv; + this.eventBus = eventBus; + this.textContent = null; + this.textContentItemsStr = []; + this.textContentStream = null; + this.renderingDone = false; + this.pageNumber = pageIndex + 1; + this.viewport = viewport; + this.textDivs = []; + this.textLayerRenderTask = null; + this.highlighter = highlighter; + this.enhanceTextSelection = enhanceTextSelection; + this.accessibilityManager = accessibilityManager; + + this._bindMouse(); + } + + _finishRendering() { + this.renderingDone = true; + + if (!this.enhanceTextSelection) { + const endOfContent = document.createElement("div"); + endOfContent.className = "endOfContent"; + this.textLayerDiv.append(endOfContent); + } + + this.eventBus.dispatch("textlayerrendered", { + source: this, + pageNumber: this.pageNumber, + numTextDivs: this.textDivs.length + }); + } + + render() { + var _this$highlighter, _this$accessibilityMa; + + let timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + + if (!(this.textContent || this.textContentStream) || this.renderingDone) { + return; + } + + this.cancel(); + this.textDivs.length = 0; + (_this$highlighter = this.highlighter) === null || _this$highlighter === void 0 ? void 0 : _this$highlighter.setTextMapping(this.textDivs, this.textContentItemsStr); + (_this$accessibilityMa = this.accessibilityManager) === null || _this$accessibilityMa === void 0 ? void 0 : _this$accessibilityMa.setTextMapping(this.textDivs); + const textLayerFrag = document.createDocumentFragment(); + this.textLayerRenderTask = (0, _pdfjsLib.renderTextLayer)({ + textContent: this.textContent, + textContentStream: this.textContentStream, + container: textLayerFrag, + viewport: this.viewport, + textDivs: this.textDivs, + textContentItemsStr: this.textContentItemsStr, + timeout, + enhanceTextSelection: this.enhanceTextSelection + }); + this.textLayerRenderTask.promise.then(() => { + var _this$highlighter2, _this$accessibilityMa2; + + this.textLayerDiv.append(textLayerFrag); + + this._finishRendering(); + + (_this$highlighter2 = this.highlighter) === null || _this$highlighter2 === void 0 ? void 0 : _this$highlighter2.enable(); + (_this$accessibilityMa2 = this.accessibilityManager) === null || _this$accessibilityMa2 === void 0 ? void 0 : _this$accessibilityMa2.enable(); + }, function (reason) {}); + } + + cancel() { + var _this$highlighter3, _this$accessibilityMa3; + + if (this.textLayerRenderTask) { + this.textLayerRenderTask.cancel(); + this.textLayerRenderTask = null; + } + + (_this$highlighter3 = this.highlighter) === null || _this$highlighter3 === void 0 ? void 0 : _this$highlighter3.disable(); + (_this$accessibilityMa3 = this.accessibilityManager) === null || _this$accessibilityMa3 === void 0 ? void 0 : _this$accessibilityMa3.disable(); + } + + setTextContentStream(readableStream) { + this.cancel(); + this.textContentStream = readableStream; + } + + setTextContent(textContent) { + this.cancel(); + this.textContent = textContent; + } + + _bindMouse() { + const div = this.textLayerDiv; + let expandDivsTimer = null; + div.addEventListener("mousedown", evt => { + if (this.enhanceTextSelection && this.textLayerRenderTask) { + this.textLayerRenderTask.expandTextDivs(true); + + if (expandDivsTimer) { + clearTimeout(expandDivsTimer); + expandDivsTimer = null; + } + + return; + } + + const end = div.querySelector(".endOfContent"); + + if (!end) { + return; + } + + let adjustTop = evt.target !== div; + adjustTop = adjustTop && window.getComputedStyle(end).getPropertyValue("-moz-user-select") !== "none"; + + if (adjustTop) { + const divBounds = div.getBoundingClientRect(); + const r = Math.max(0, (evt.pageY - divBounds.top) / divBounds.height); + end.style.top = (r * 100).toFixed(2) + "%"; + } + + end.classList.add("active"); + }); + div.addEventListener("mouseup", () => { + if (this.enhanceTextSelection && this.textLayerRenderTask) { + expandDivsTimer = setTimeout(() => { + if (this.textLayerRenderTask) { + this.textLayerRenderTask.expandTextDivs(false); + } + + expandDivsTimer = null; + }, EXPAND_DIVS_TIMEOUT); + return; + } + + const end = div.querySelector(".endOfContent"); + + if (!end) { + return; + } + + end.style.top = ""; + end.classList.remove("active"); + }); + } + +} + +exports.TextLayerBuilder = TextLayerBuilder; + +/***/ }), +/* 39 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.XfaLayerBuilder = void 0; + +var _pdfjsLib = __webpack_require__(5); + +class XfaLayerBuilder { + constructor(_ref) { + let { + pageDiv, + pdfPage, + annotationStorage = null, + linkService, + xfaHtml = null + } = _ref; + this.pageDiv = pageDiv; + this.pdfPage = pdfPage; + this.annotationStorage = annotationStorage; + this.linkService = linkService; + this.xfaHtml = xfaHtml; + this.div = null; + this._cancelled = false; + } + + render(viewport) { + let intent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "display"; + + if (intent === "print") { + const parameters = { + viewport: viewport.clone({ + dontFlip: true + }), + div: this.div, + xfaHtml: this.xfaHtml, + annotationStorage: this.annotationStorage, + linkService: this.linkService, + intent + }; + const div = document.createElement("div"); + this.pageDiv.append(div); + parameters.div = div; + + const result = _pdfjsLib.XfaLayer.render(parameters); + + return Promise.resolve(result); + } + + return this.pdfPage.getXfa().then(xfaHtml => { + if (this._cancelled || !xfaHtml) { + return { + textDivs: [] + }; + } + + const parameters = { + viewport: viewport.clone({ + dontFlip: true + }), + div: this.div, + xfaHtml, + annotationStorage: this.annotationStorage, + linkService: this.linkService, + intent + }; + + if (this.div) { + return _pdfjsLib.XfaLayer.update(parameters); + } + + this.div = document.createElement("div"); + this.pageDiv.append(this.div); + parameters.div = this.div; + return _pdfjsLib.XfaLayer.render(parameters); + }).catch(error => { + console.error(error); + }); + } + + cancel() { + this._cancelled = true; + } + + hide() { + if (!this.div) { + return; + } + + this.div.hidden = true; + } + +} + +exports.XfaLayerBuilder = XfaLayerBuilder; + +/***/ }), +/* 40 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.SecondaryToolbar = void 0; + +var _ui_utils = __webpack_require__(1); + +var _pdf_cursor_tools = __webpack_require__(7); + +var _base_viewer = __webpack_require__(30); + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +var _updateUIState = /*#__PURE__*/new WeakSet(); + +var _bindClickListeners = /*#__PURE__*/new WeakSet(); + +var _bindCursorToolsListener = /*#__PURE__*/new WeakSet(); + +var _bindScrollModeListener = /*#__PURE__*/new WeakSet(); + +var _bindSpreadModeListener = /*#__PURE__*/new WeakSet(); + +class SecondaryToolbar { + constructor(options, eventBus) { + _classPrivateMethodInitSpec(this, _bindSpreadModeListener); + + _classPrivateMethodInitSpec(this, _bindScrollModeListener); + + _classPrivateMethodInitSpec(this, _bindCursorToolsListener); + + _classPrivateMethodInitSpec(this, _bindClickListeners); + + _classPrivateMethodInitSpec(this, _updateUIState); + + this.toolbar = options.toolbar; + this.toggleButton = options.toggleButton; + this.buttons = [{ + element: options.presentationModeButton, + eventName: "presentationmode", + close: true + }, { + element: options.printButton, + eventName: "print", + close: true + }, { + element: options.downloadButton, + eventName: "download", + close: true + }, { + element: options.viewBookmarkButton, + eventName: null, + close: true + }, { + element: options.firstPageButton, + eventName: "firstpage", + close: true + }, { + element: options.lastPageButton, + eventName: "lastpage", + close: true + }, { + element: options.pageRotateCwButton, + eventName: "rotatecw", + close: false + }, { + element: options.pageRotateCcwButton, + eventName: "rotateccw", + close: false + }, { + element: options.cursorSelectToolButton, + eventName: "switchcursortool", + eventDetails: { + tool: _pdf_cursor_tools.CursorTool.SELECT + }, + close: true + }, { + element: options.cursorHandToolButton, + eventName: "switchcursortool", + eventDetails: { + tool: _pdf_cursor_tools.CursorTool.HAND + }, + close: true + }, { + element: options.scrollPageButton, + eventName: "switchscrollmode", + eventDetails: { + mode: _ui_utils.ScrollMode.PAGE + }, + close: true + }, { + element: options.scrollVerticalButton, + eventName: "switchscrollmode", + eventDetails: { + mode: _ui_utils.ScrollMode.VERTICAL + }, + close: true + }, { + element: options.scrollHorizontalButton, + eventName: "switchscrollmode", + eventDetails: { + mode: _ui_utils.ScrollMode.HORIZONTAL + }, + close: true + }, { + element: options.scrollWrappedButton, + eventName: "switchscrollmode", + eventDetails: { + mode: _ui_utils.ScrollMode.WRAPPED + }, + close: true + }, { + element: options.spreadNoneButton, + eventName: "switchspreadmode", + eventDetails: { + mode: _ui_utils.SpreadMode.NONE + }, + close: true + }, { + element: options.spreadOddButton, + eventName: "switchspreadmode", + eventDetails: { + mode: _ui_utils.SpreadMode.ODD + }, + close: true + }, { + element: options.spreadEvenButton, + eventName: "switchspreadmode", + eventDetails: { + mode: _ui_utils.SpreadMode.EVEN + }, + close: true + }, { + element: options.documentPropertiesButton, + eventName: "documentproperties", + close: true + }]; + this.buttons.push({ + element: options.openFileButton, + eventName: "openfile", + close: true + }); + this.items = { + firstPage: options.firstPageButton, + lastPage: options.lastPageButton, + pageRotateCw: options.pageRotateCwButton, + pageRotateCcw: options.pageRotateCcwButton + }; + this.eventBus = eventBus; + this.opened = false; + + _classPrivateMethodGet(this, _bindClickListeners, _bindClickListeners2).call(this); + + _classPrivateMethodGet(this, _bindCursorToolsListener, _bindCursorToolsListener2).call(this, options); + + _classPrivateMethodGet(this, _bindScrollModeListener, _bindScrollModeListener2).call(this, options); + + _classPrivateMethodGet(this, _bindSpreadModeListener, _bindSpreadModeListener2).call(this, options); + + this.reset(); + } + + get isOpen() { + return this.opened; + } + + setPageNumber(pageNumber) { + this.pageNumber = pageNumber; + + _classPrivateMethodGet(this, _updateUIState, _updateUIState2).call(this); + } + + setPagesCount(pagesCount) { + this.pagesCount = pagesCount; + + _classPrivateMethodGet(this, _updateUIState, _updateUIState2).call(this); + } + + reset() { + this.pageNumber = 0; + this.pagesCount = 0; + + _classPrivateMethodGet(this, _updateUIState, _updateUIState2).call(this); + + this.eventBus.dispatch("secondarytoolbarreset", { + source: this + }); + } + + open() { + if (this.opened) { + return; + } + + this.opened = true; + this.toggleButton.classList.add("toggled"); + this.toggleButton.setAttribute("aria-expanded", "true"); + this.toolbar.classList.remove("hidden"); + } + + close() { + if (!this.opened) { + return; + } + + this.opened = false; + this.toolbar.classList.add("hidden"); + this.toggleButton.classList.remove("toggled"); + this.toggleButton.setAttribute("aria-expanded", "false"); + } + + toggle() { + if (this.opened) { + this.close(); + } else { + this.open(); + } + } + +} + +exports.SecondaryToolbar = SecondaryToolbar; + +function _updateUIState2() { + this.items.firstPage.disabled = this.pageNumber <= 1; + this.items.lastPage.disabled = this.pageNumber >= this.pagesCount; + this.items.pageRotateCw.disabled = this.pagesCount === 0; + this.items.pageRotateCcw.disabled = this.pagesCount === 0; +} + +function _bindClickListeners2() { + this.toggleButton.addEventListener("click", this.toggle.bind(this)); + + for (const { + element, + eventName, + close, + eventDetails + } of this.buttons) { + element.addEventListener("click", evt => { + if (eventName !== null) { + const details = { + source: this + }; + + for (const property in eventDetails) { + details[property] = eventDetails[property]; + } + + this.eventBus.dispatch(eventName, details); + } + + if (close) { + this.close(); + } + }); + } +} + +function _bindCursorToolsListener2(_ref) { + let { + cursorSelectToolButton, + cursorHandToolButton + } = _ref; + + this.eventBus._on("cursortoolchanged", function (_ref2) { + let { + tool + } = _ref2; + const isSelect = tool === _pdf_cursor_tools.CursorTool.SELECT, + isHand = tool === _pdf_cursor_tools.CursorTool.HAND; + cursorSelectToolButton.classList.toggle("toggled", isSelect); + cursorHandToolButton.classList.toggle("toggled", isHand); + cursorSelectToolButton.setAttribute("aria-checked", isSelect); + cursorHandToolButton.setAttribute("aria-checked", isHand); + }); +} + +function _bindScrollModeListener2(_ref3) { + let { + scrollPageButton, + scrollVerticalButton, + scrollHorizontalButton, + scrollWrappedButton, + spreadNoneButton, + spreadOddButton, + spreadEvenButton + } = _ref3; + + const scrollModeChanged = _ref4 => { + let { + mode + } = _ref4; + const isPage = mode === _ui_utils.ScrollMode.PAGE, + isVertical = mode === _ui_utils.ScrollMode.VERTICAL, + isHorizontal = mode === _ui_utils.ScrollMode.HORIZONTAL, + isWrapped = mode === _ui_utils.ScrollMode.WRAPPED; + scrollPageButton.classList.toggle("toggled", isPage); + scrollVerticalButton.classList.toggle("toggled", isVertical); + scrollHorizontalButton.classList.toggle("toggled", isHorizontal); + scrollWrappedButton.classList.toggle("toggled", isWrapped); + scrollPageButton.setAttribute("aria-checked", isPage); + scrollVerticalButton.setAttribute("aria-checked", isVertical); + scrollHorizontalButton.setAttribute("aria-checked", isHorizontal); + scrollWrappedButton.setAttribute("aria-checked", isWrapped); + const forceScrollModePage = this.pagesCount > _base_viewer.PagesCountLimit.FORCE_SCROLL_MODE_PAGE; + scrollPageButton.disabled = forceScrollModePage; + scrollVerticalButton.disabled = forceScrollModePage; + scrollHorizontalButton.disabled = forceScrollModePage; + scrollWrappedButton.disabled = forceScrollModePage; + spreadNoneButton.disabled = isHorizontal; + spreadOddButton.disabled = isHorizontal; + spreadEvenButton.disabled = isHorizontal; + }; + + this.eventBus._on("scrollmodechanged", scrollModeChanged); + + this.eventBus._on("secondarytoolbarreset", evt => { + if (evt.source === this) { + scrollModeChanged({ + mode: _ui_utils.ScrollMode.VERTICAL + }); + } + }); +} + +function _bindSpreadModeListener2(_ref5) { + let { + spreadNoneButton, + spreadOddButton, + spreadEvenButton + } = _ref5; + + function spreadModeChanged(_ref6) { + let { + mode + } = _ref6; + const isNone = mode === _ui_utils.SpreadMode.NONE, + isOdd = mode === _ui_utils.SpreadMode.ODD, + isEven = mode === _ui_utils.SpreadMode.EVEN; + spreadNoneButton.classList.toggle("toggled", isNone); + spreadOddButton.classList.toggle("toggled", isOdd); + spreadEvenButton.classList.toggle("toggled", isEven); + spreadNoneButton.setAttribute("aria-checked", isNone); + spreadOddButton.setAttribute("aria-checked", isOdd); + spreadEvenButton.setAttribute("aria-checked", isEven); + } + + this.eventBus._on("spreadmodechanged", spreadModeChanged); + + this.eventBus._on("secondarytoolbarreset", evt => { + if (evt.source === this) { + spreadModeChanged({ + mode: _ui_utils.SpreadMode.NONE + }); + } + }); +} + +/***/ }), +/* 41 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.Toolbar = void 0; + +var _ui_utils = __webpack_require__(1); + +var _pdfjsLib = __webpack_require__(5); + +function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); } + +function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } + +function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } + +function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } + +function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; } + +const PAGE_NUMBER_LOADING_INDICATOR = "visiblePageIsLoading"; + +var _wasLocalized = /*#__PURE__*/new WeakMap(); + +var _bindListeners = /*#__PURE__*/new WeakSet(); + +var _bindEditorToolsListener = /*#__PURE__*/new WeakSet(); + +var _updateUIState = /*#__PURE__*/new WeakSet(); + +var _adjustScaleWidth = /*#__PURE__*/new WeakSet(); + +class Toolbar { + constructor(_options, eventBus, _l10n) { + _classPrivateMethodInitSpec(this, _adjustScaleWidth); + + _classPrivateMethodInitSpec(this, _updateUIState); + + _classPrivateMethodInitSpec(this, _bindEditorToolsListener); + + _classPrivateMethodInitSpec(this, _bindListeners); + + _classPrivateFieldInitSpec(this, _wasLocalized, { + writable: true, + value: false + }); + + this.toolbar = _options.container; + this.eventBus = eventBus; + this.l10n = _l10n; + this.buttons = [{ + element: _options.previous, + eventName: "previouspage" + }, { + element: _options.next, + eventName: "nextpage" + }, { + element: _options.zoomIn, + eventName: "zoomin" + }, { + element: _options.zoomOut, + eventName: "zoomout" + }, { + element: _options.print, + eventName: "print" + }, { + element: _options.presentationModeButton, + eventName: "presentationmode" + }, { + element: _options.download, + eventName: "download" + }, { + element: _options.viewBookmark, + eventName: null + }, { + element: _options.editorFreeTextButton, + eventName: "switchannotationeditormode", + eventDetails: { + get mode() { + const { + classList + } = _options.editorFreeTextButton; + return classList.contains("toggled") ? _pdfjsLib.AnnotationEditorType.NONE : _pdfjsLib.AnnotationEditorType.FREETEXT; + } + + } + }, { + element: _options.editorInkButton, + eventName: "switchannotationeditormode", + eventDetails: { + get mode() { + const { + classList + } = _options.editorInkButton; + return classList.contains("toggled") ? _pdfjsLib.AnnotationEditorType.NONE : _pdfjsLib.AnnotationEditorType.INK; + } + + } + }]; + this.buttons.push({ + element: _options.openFile, + eventName: "openfile" + }); + this.items = { + numPages: _options.numPages, + pageNumber: _options.pageNumber, + scaleSelect: _options.scaleSelect, + customScaleOption: _options.customScaleOption, + previous: _options.previous, + next: _options.next, + zoomIn: _options.zoomIn, + zoomOut: _options.zoomOut + }; + + _classPrivateMethodGet(this, _bindListeners, _bindListeners2).call(this, _options); + + this.reset(); + } + + setPageNumber(pageNumber, pageLabel) { + this.pageNumber = pageNumber; + this.pageLabel = pageLabel; + + _classPrivateMethodGet(this, _updateUIState, _updateUIState2).call(this, false); + } + + setPagesCount(pagesCount, hasPageLabels) { + this.pagesCount = pagesCount; + this.hasPageLabels = hasPageLabels; + + _classPrivateMethodGet(this, _updateUIState, _updateUIState2).call(this, true); + } + + setPageScale(pageScaleValue, pageScale) { + this.pageScaleValue = (pageScaleValue || pageScale).toString(); + this.pageScale = pageScale; + + _classPrivateMethodGet(this, _updateUIState, _updateUIState2).call(this, false); + } + + reset() { + this.pageNumber = 0; + this.pageLabel = null; + this.hasPageLabels = false; + this.pagesCount = 0; + this.pageScaleValue = _ui_utils.DEFAULT_SCALE_VALUE; + this.pageScale = _ui_utils.DEFAULT_SCALE; + + _classPrivateMethodGet(this, _updateUIState, _updateUIState2).call(this, true); + + this.updateLoadingIndicatorState(); + this.eventBus.dispatch("toolbarreset", { + source: this + }); + } + + updateLoadingIndicatorState() { + let loading = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + const { + pageNumber + } = this.items; + pageNumber.classList.toggle(PAGE_NUMBER_LOADING_INDICATOR, loading); + } + +} + +exports.Toolbar = Toolbar; + +function _bindListeners2(options) { + const { + pageNumber, + scaleSelect + } = this.items; + const self = this; + + for (const { + element, + eventName, + eventDetails + } of this.buttons) { + element.addEventListener("click", evt => { + if (eventName !== null) { + const details = { + source: this + }; + + if (eventDetails) { + for (const property in eventDetails) { + details[property] = eventDetails[property]; + } + } + + this.eventBus.dispatch(eventName, details); + } + }); + } + + pageNumber.addEventListener("click", function () { + this.select(); + }); + pageNumber.addEventListener("change", function () { + self.eventBus.dispatch("pagenumberchanged", { + source: self, + value: this.value + }); + }); + scaleSelect.addEventListener("change", function () { + if (this.value === "custom") { + return; + } + + self.eventBus.dispatch("scalechanged", { + source: self, + value: this.value + }); + }); + scaleSelect.addEventListener("click", function (evt) { + const target = evt.target; + + if (this.value === self.pageScaleValue && target.tagName.toUpperCase() === "OPTION") { + this.blur(); + } + }); + scaleSelect.oncontextmenu = _ui_utils.noContextMenuHandler; + + this.eventBus._on("localized", () => { + _classPrivateFieldSet(this, _wasLocalized, true); + + _classPrivateMethodGet(this, _adjustScaleWidth, _adjustScaleWidth2).call(this); + + _classPrivateMethodGet(this, _updateUIState, _updateUIState2).call(this, true); + }); + + _classPrivateMethodGet(this, _bindEditorToolsListener, _bindEditorToolsListener2).call(this, options); +} + +function _bindEditorToolsListener2(_ref) { + let { + editorFreeTextButton, + editorFreeTextParamsToolbar, + editorInkButton, + editorInkParamsToolbar + } = _ref; + + const editorModeChanged = function (evt) { + let disableButtons = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + const editorButtons = [{ + mode: _pdfjsLib.AnnotationEditorType.FREETEXT, + button: editorFreeTextButton, + toolbar: editorFreeTextParamsToolbar + }, { + mode: _pdfjsLib.AnnotationEditorType.INK, + button: editorInkButton, + toolbar: editorInkParamsToolbar + }]; + + for (const { + mode, + button, + toolbar + } of editorButtons) { + const checked = mode === evt.mode; + button.classList.toggle("toggled", checked); + button.setAttribute("aria-checked", checked); + button.disabled = disableButtons; + toolbar === null || toolbar === void 0 ? void 0 : toolbar.classList.toggle("hidden", !checked); + } + }; + + this.eventBus._on("annotationeditormodechanged", editorModeChanged); + + this.eventBus._on("toolbarreset", evt => { + if (evt.source === this) { + editorModeChanged({ + mode: _pdfjsLib.AnnotationEditorType.NONE + }, true); + } + }); +} + +function _updateUIState2() { + let resetNumPages = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + if (!_classPrivateFieldGet(this, _wasLocalized)) { + return; + } + + const { + pageNumber, + pagesCount, + pageScaleValue, + pageScale, + items + } = this; + + if (resetNumPages) { + if (this.hasPageLabels) { + items.pageNumber.type = "text"; + } else { + items.pageNumber.type = "number"; + this.l10n.get("of_pages", { + pagesCount + }).then(msg => { + items.numPages.textContent = msg; + }); + } + + items.pageNumber.max = pagesCount; + } + + if (this.hasPageLabels) { + items.pageNumber.value = this.pageLabel; + this.l10n.get("page_of_pages", { + pageNumber, + pagesCount + }).then(msg => { + items.numPages.textContent = msg; + }); + } else { + items.pageNumber.value = pageNumber; + } + + items.previous.disabled = pageNumber <= 1; + items.next.disabled = pageNumber >= pagesCount; + items.zoomOut.disabled = pageScale <= _ui_utils.MIN_SCALE; + items.zoomIn.disabled = pageScale >= _ui_utils.MAX_SCALE; + this.l10n.get("page_scale_percent", { + scale: Math.round(pageScale * 10000) / 100 + }).then(msg => { + let predefinedValueFound = false; + + for (const option of items.scaleSelect.options) { + if (option.value !== pageScaleValue) { + option.selected = false; + continue; + } + + option.selected = true; + predefinedValueFound = true; + } + + if (!predefinedValueFound) { + items.customScaleOption.textContent = msg; + items.customScaleOption.selected = true; + } + }); +} + +async function _adjustScaleWidth2() { + const { + items, + l10n + } = this; + const predefinedValuesPromise = Promise.all([l10n.get("page_scale_auto"), l10n.get("page_scale_actual"), l10n.get("page_scale_fit"), l10n.get("page_scale_width")]); + await _ui_utils.animationStarted; + const style = getComputedStyle(items.scaleSelect), + scaleSelectContainerWidth = parseInt(style.getPropertyValue("--scale-select-container-width"), 10), + scaleSelectOverflow = parseInt(style.getPropertyValue("--scale-select-overflow"), 10); + const canvas = document.createElement("canvas"); + const ctx = canvas.getContext("2d", { + alpha: false + }); + ctx.font = `${style.fontSize} ${style.fontFamily}`; + let maxWidth = 0; + + for (const predefinedValue of await predefinedValuesPromise) { + const { + width + } = ctx.measureText(predefinedValue); + + if (width > maxWidth) { + maxWidth = width; + } + } + + maxWidth += 2 * scaleSelectOverflow; + + if (maxWidth > scaleSelectContainerWidth) { + _ui_utils.docStyle.setProperty("--scale-select-container-width", `${maxWidth}px`); + } + + canvas.width = 0; + canvas.height = 0; +} + +/***/ }), +/* 42 */ +/***/ ((__unused_webpack_module, exports) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.ViewHistory = void 0; +const DEFAULT_VIEW_HISTORY_CACHE_SIZE = 20; + +class ViewHistory { + constructor(fingerprint) { + let cacheSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_VIEW_HISTORY_CACHE_SIZE; + this.fingerprint = fingerprint; + this.cacheSize = cacheSize; + this._initializedPromise = this._readFromStorage().then(databaseStr => { + const database = JSON.parse(databaseStr || "{}"); + let index = -1; + + if (!Array.isArray(database.files)) { + database.files = []; + } else { + while (database.files.length >= this.cacheSize) { + database.files.shift(); + } + + for (let i = 0, ii = database.files.length; i < ii; i++) { + const branch = database.files[i]; + + if (branch.fingerprint === this.fingerprint) { + index = i; + break; + } + } + } + + if (index === -1) { + index = database.files.push({ + fingerprint: this.fingerprint + }) - 1; + } + + this.file = database.files[index]; + this.database = database; + }); + } + + async _writeToStorage() { + const databaseStr = JSON.stringify(this.database); + localStorage.setItem("pdfjs.history", databaseStr); + } + + async _readFromStorage() { + return localStorage.getItem("pdfjs.history"); + } + + async set(name, val) { + await this._initializedPromise; + this.file[name] = val; + return this._writeToStorage(); + } + + async setMultiple(properties) { + await this._initializedPromise; + + for (const name in properties) { + this.file[name] = properties[name]; + } + + return this._writeToStorage(); + } + + async get(name, defaultValue) { + await this._initializedPromise; + const val = this.file[name]; + return val !== undefined ? val : defaultValue; + } + + async getMultiple(properties) { + await this._initializedPromise; + const values = Object.create(null); + + for (const name in properties) { + const val = this.file[name]; + values[name] = val !== undefined ? val : properties[name]; + } + + return values; + } + +} + +exports.ViewHistory = ViewHistory; + +/***/ }), +/* 43 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.GenericCom = void 0; + +var _app = __webpack_require__(4); + +var _preferences = __webpack_require__(44); + +var _download_manager = __webpack_require__(45); + +var _genericl10n = __webpack_require__(46); + +var _generic_scripting = __webpack_require__(48); + +; +const GenericCom = {}; +exports.GenericCom = GenericCom; + +class GenericPreferences extends _preferences.BasePreferences { + async _writeToStorage(prefObj) { + localStorage.setItem("pdfjs.preferences", JSON.stringify(prefObj)); + } + + async _readFromStorage(prefObj) { + return JSON.parse(localStorage.getItem("pdfjs.preferences")); + } + +} + +class GenericExternalServices extends _app.DefaultExternalServices { + static createDownloadManager(options) { + return new _download_manager.DownloadManager(); + } + + static createPreferences() { + return new GenericPreferences(); + } + + static createL10n(_ref) { + let { + locale = "en-US" + } = _ref; + return new _genericl10n.GenericL10n(locale); + } + + static createScripting(_ref2) { + let { + sandboxBundleSrc + } = _ref2; + return new _generic_scripting.GenericScripting(sandboxBundleSrc); + } + +} + +_app.PDFViewerApplication.externalServices = GenericExternalServices; + +/***/ }), +/* 44 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.BasePreferences = void 0; + +var _app_options = __webpack_require__(2); + +function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); } + +function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } } + +function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); } + +function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; } + +function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); } + +function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } } + +var _defaults = /*#__PURE__*/new WeakMap(); + +var _prefs = /*#__PURE__*/new WeakMap(); + +var _initializedPromise = /*#__PURE__*/new WeakMap(); + +class BasePreferences { + constructor() { + _classPrivateFieldInitSpec(this, _defaults, { + writable: true, + value: Object.freeze({ + "annotationEditorMode": -1, + "annotationMode": 2, + "cursorToolOnLoad": 0, + "defaultZoomValue": "", + "disablePageLabels": false, + "enablePermissions": false, + "enablePrintAutoRotate": true, + "enableScripting": true, + "externalLinkTarget": 0, + "historyUpdateUrl": false, + "ignoreDestinationZoom": false, + "forcePageColors": false, + "pageColorsBackground": "Canvas", + "pageColorsForeground": "CanvasText", + "pdfBugEnabled": false, + "sidebarViewOnLoad": -1, + "scrollModeOnLoad": -1, + "spreadModeOnLoad": -1, + "textLayerMode": 1, + "useOnlyCssZoom": false, + "viewerCssTheme": 0, + "viewOnLoad": 0, + "disableAutoFetch": false, + "disableFontFace": false, + "disableRange": false, + "disableStream": false, + "enableXfa": true, + "renderer": "canvas" + }) + }); + + _classPrivateFieldInitSpec(this, _prefs, { + writable: true, + value: Object.create(null) + }); + + _classPrivateFieldInitSpec(this, _initializedPromise, { + writable: true, + value: null + }); + + if (this.constructor === BasePreferences) { + throw new Error("Cannot initialize BasePreferences."); + } + + _classPrivateFieldSet(this, _initializedPromise, this._readFromStorage(_classPrivateFieldGet(this, _defaults)).then(prefs => { + for (const name in _classPrivateFieldGet(this, _defaults)) { + const prefValue = prefs === null || prefs === void 0 ? void 0 : prefs[name]; + + if (typeof prefValue === typeof _classPrivateFieldGet(this, _defaults)[name]) { + _classPrivateFieldGet(this, _prefs)[name] = prefValue; + } + } + })); + } + + async _writeToStorage(prefObj) { + throw new Error("Not implemented: _writeToStorage"); + } + + async _readFromStorage(prefObj) { + throw new Error("Not implemented: _readFromStorage"); + } + + async reset() { + await _classPrivateFieldGet(this, _initializedPromise); + + const prefs = _classPrivateFieldGet(this, _prefs); + + _classPrivateFieldSet(this, _prefs, Object.create(null)); + + return this._writeToStorage(_classPrivateFieldGet(this, _defaults)).catch(reason => { + _classPrivateFieldSet(this, _prefs, prefs); + + throw reason; + }); + } + + async set(name, value) { + await _classPrivateFieldGet(this, _initializedPromise); + + const defaultValue = _classPrivateFieldGet(this, _defaults)[name], + prefs = _classPrivateFieldGet(this, _prefs); + + if (defaultValue === undefined) { + throw new Error(`Set preference: "${name}" is undefined.`); + } else if (value === undefined) { + throw new Error("Set preference: no value is specified."); + } + + const valueType = typeof value, + defaultType = typeof defaultValue; + + if (valueType !== defaultType) { + if (valueType === "number" && defaultType === "string") { + value = value.toString(); + } else { + throw new Error(`Set preference: "${value}" is a ${valueType}, expected a ${defaultType}.`); + } + } else { + if (valueType === "number" && !Number.isInteger(value)) { + throw new Error(`Set preference: "${value}" must be an integer.`); + } + } + + _classPrivateFieldGet(this, _prefs)[name] = value; + return this._writeToStorage(_classPrivateFieldGet(this, _prefs)).catch(reason => { + _classPrivateFieldSet(this, _prefs, prefs); + + throw reason; + }); + } + + async get(name) { + var _classPrivateFieldGet2; + + await _classPrivateFieldGet(this, _initializedPromise); + + const defaultValue = _classPrivateFieldGet(this, _defaults)[name]; + + if (defaultValue === undefined) { + throw new Error(`Get preference: "${name}" is undefined.`); + } + + return (_classPrivateFieldGet2 = _classPrivateFieldGet(this, _prefs)[name]) !== null && _classPrivateFieldGet2 !== void 0 ? _classPrivateFieldGet2 : defaultValue; + } + + async getAll() { + await _classPrivateFieldGet(this, _initializedPromise); + const obj = Object.create(null); + + for (const name in _classPrivateFieldGet(this, _defaults)) { + var _classPrivateFieldGet3; + + obj[name] = (_classPrivateFieldGet3 = _classPrivateFieldGet(this, _prefs)[name]) !== null && _classPrivateFieldGet3 !== void 0 ? _classPrivateFieldGet3 : _classPrivateFieldGet(this, _defaults)[name]; + } + + return obj; + } + +} + +exports.BasePreferences = BasePreferences; + +/***/ }), +/* 45 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.DownloadManager = void 0; + +var _pdfjsLib = __webpack_require__(5); + +; + +function download(blobUrl, filename) { + const a = document.createElement("a"); + + if (!a.click) { + throw new Error('DownloadManager: "a.click()" is not supported.'); + } + + a.href = blobUrl; + a.target = "_parent"; + + if ("download" in a) { + a.download = filename; + } + + (document.body || document.documentElement).append(a); + a.click(); + a.remove(); +} + +class DownloadManager { + constructor() { + this._openBlobUrls = new WeakMap(); + } + + downloadUrl(url, filename) { + if (!(0, _pdfjsLib.createValidAbsoluteUrl)(url, "http://example.com")) { + console.error(`downloadUrl - not a valid URL: ${url}`); + return; + } + + download(url + "#pdfjs.action=download", filename); + } + + downloadData(data, filename, contentType) { + const blobUrl = URL.createObjectURL(new Blob([data], { + type: contentType + })); + download(blobUrl, filename); + } + + openOrDownloadData(element, data, filename) { + const isPdfData = (0, _pdfjsLib.isPdfFile)(filename); + const contentType = isPdfData ? "application/pdf" : ""; + + if (isPdfData) { + let blobUrl = this._openBlobUrls.get(element); + + if (!blobUrl) { + blobUrl = URL.createObjectURL(new Blob([data], { + type: contentType + })); + + this._openBlobUrls.set(element, blobUrl); + } + + let viewerUrl; + viewerUrl = "?file=" + encodeURIComponent(blobUrl + "#" + filename); + + try { + window.open(viewerUrl); + return true; + } catch (ex) { + console.error(`openOrDownloadData: ${ex}`); + URL.revokeObjectURL(blobUrl); + + this._openBlobUrls.delete(element); + } + } + + this.downloadData(data, filename, contentType); + return false; + } + + download(blob, url, filename) { + const blobUrl = URL.createObjectURL(blob); + download(blobUrl, filename); + } + +} + +exports.DownloadManager = DownloadManager; + +/***/ }), +/* 46 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.GenericL10n = void 0; + +__webpack_require__(47); + +var _l10n_utils = __webpack_require__(32); + +const webL10n = document.webL10n; + +class GenericL10n { + constructor(lang) { + this._lang = lang; + this._ready = new Promise((resolve, reject) => { + webL10n.setLanguage((0, _l10n_utils.fixupLangCode)(lang), () => { + resolve(webL10n); + }); + }); + } + + async getLanguage() { + const l10n = await this._ready; + return l10n.getLanguage(); + } + + async getDirection() { + const l10n = await this._ready; + return l10n.getDirection(); + } + + async get(key) { + let args = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + let fallback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : (0, _l10n_utils.getL10nFallback)(key, args); + const l10n = await this._ready; + return l10n.get(key, args, fallback); + } + + async translate(element) { + const l10n = await this._ready; + return l10n.translate(element); + } + +} + +exports.GenericL10n = GenericL10n; + +/***/ }), +/* 47 */ +/***/ (() => { + + + +document.webL10n = function (window, document, undefined) { + var gL10nData = {}; + var gTextData = ''; + var gTextProp = 'textContent'; + var gLanguage = ''; + var gMacros = {}; + var gReadyState = 'loading'; + var gAsyncResourceLoading = true; + + function getL10nResourceLinks() { + return document.querySelectorAll('link[type="application/l10n"]'); + } + + function getL10nDictionary() { + var script = document.querySelector('script[type="application/l10n"]'); + return script ? JSON.parse(script.innerHTML) : null; + } + + function getTranslatableChildren(element) { + return element ? element.querySelectorAll('*[data-l10n-id]') : []; + } + + function getL10nAttributes(element) { + if (!element) return {}; + var l10nId = element.getAttribute('data-l10n-id'); + var l10nArgs = element.getAttribute('data-l10n-args'); + var args = {}; + + if (l10nArgs) { + try { + args = JSON.parse(l10nArgs); + } catch (e) { + console.warn('could not parse arguments for #' + l10nId); + } + } + + return { + id: l10nId, + args: args + }; + } + + function xhrLoadText(url, onSuccess, onFailure) { + onSuccess = onSuccess || function _onSuccess(data) {}; + + onFailure = onFailure || function _onFailure() {}; + + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, gAsyncResourceLoading); + + if (xhr.overrideMimeType) { + xhr.overrideMimeType('text/plain; charset=utf-8'); + } + + xhr.onreadystatechange = function () { + if (xhr.readyState == 4) { + if (xhr.status == 200 || xhr.status === 0) { + onSuccess(xhr.responseText); + } else { + onFailure(); + } + } + }; + + xhr.onerror = onFailure; + xhr.ontimeout = onFailure; + + try { + xhr.send(null); + } catch (e) { + onFailure(); + } + } + + function parseResource(href, lang, successCallback, failureCallback) { + var baseURL = href.replace(/[^\/]*$/, '') || './'; + + function evalString(text) { + if (text.lastIndexOf('\\') < 0) return text; + return text.replace(/\\\\/g, '\\').replace(/\\n/g, '\n').replace(/\\r/g, '\r').replace(/\\t/g, '\t').replace(/\\b/g, '\b').replace(/\\f/g, '\f').replace(/\\{/g, '{').replace(/\\}/g, '}').replace(/\\"/g, '"').replace(/\\'/g, "'"); + } + + function parseProperties(text, parsedPropertiesCallback) { + var dictionary = {}; + var reBlank = /^\s*|\s*$/; + var reComment = /^\s*#|^\s*$/; + var reSection = /^\s*\[(.*)\]\s*$/; + var reImport = /^\s*@import\s+url\((.*)\)\s*$/i; + var reSplit = /^([^=\s]*)\s*=\s*(.+)$/; + + function parseRawLines(rawText, extendedSyntax, parsedRawLinesCallback) { + var entries = rawText.replace(reBlank, '').split(/[\r\n]+/); + var currentLang = '*'; + var genericLang = lang.split('-', 1)[0]; + var skipLang = false; + var match = ''; + + function nextEntry() { + while (true) { + if (!entries.length) { + parsedRawLinesCallback(); + return; + } + + var line = entries.shift(); + if (reComment.test(line)) continue; + + if (extendedSyntax) { + match = reSection.exec(line); + + if (match) { + currentLang = match[1].toLowerCase(); + skipLang = currentLang !== '*' && currentLang !== lang && currentLang !== genericLang; + continue; + } else if (skipLang) { + continue; + } + + match = reImport.exec(line); + + if (match) { + loadImport(baseURL + match[1], nextEntry); + return; + } + } + + var tmp = line.match(reSplit); + + if (tmp && tmp.length == 3) { + dictionary[tmp[1]] = evalString(tmp[2]); + } + } + } + + nextEntry(); + } + + function loadImport(url, callback) { + xhrLoadText(url, function (content) { + parseRawLines(content, false, callback); + }, function () { + console.warn(url + ' not found.'); + callback(); + }); + } + + parseRawLines(text, true, function () { + parsedPropertiesCallback(dictionary); + }); + } + + xhrLoadText(href, function (response) { + gTextData += response; + parseProperties(response, function (data) { + for (var key in data) { + var id, + prop, + index = key.lastIndexOf('.'); + + if (index > 0) { + id = key.substring(0, index); + prop = key.substring(index + 1); + } else { + id = key; + prop = gTextProp; + } + + if (!gL10nData[id]) { + gL10nData[id] = {}; + } + + gL10nData[id][prop] = data[key]; + } + + if (successCallback) { + successCallback(); + } + }); + }, failureCallback); + } + + function loadLocale(lang, callback) { + if (lang) { + lang = lang.toLowerCase(); + } + + callback = callback || function _callback() {}; + + clear(); + gLanguage = lang; + var langLinks = getL10nResourceLinks(); + var langCount = langLinks.length; + + if (langCount === 0) { + var dict = getL10nDictionary(); + + if (dict && dict.locales && dict.default_locale) { + console.log('using the embedded JSON directory, early way out'); + gL10nData = dict.locales[lang]; + + if (!gL10nData) { + var defaultLocale = dict.default_locale.toLowerCase(); + + for (var anyCaseLang in dict.locales) { + anyCaseLang = anyCaseLang.toLowerCase(); + + if (anyCaseLang === lang) { + gL10nData = dict.locales[lang]; + break; + } else if (anyCaseLang === defaultLocale) { + gL10nData = dict.locales[defaultLocale]; + } + } + } + + callback(); + } else { + console.log('no resource to load, early way out'); + } + + gReadyState = 'complete'; + return; + } + + var onResourceLoaded = null; + var gResourceCount = 0; + + onResourceLoaded = function () { + gResourceCount++; + + if (gResourceCount >= langCount) { + callback(); + gReadyState = 'complete'; + } + }; + + function L10nResourceLink(link) { + var href = link.href; + + this.load = function (lang, callback) { + parseResource(href, lang, callback, function () { + console.warn(href + ' not found.'); + console.warn('"' + lang + '" resource not found'); + gLanguage = ''; + callback(); + }); + }; + } + + for (var i = 0; i < langCount; i++) { + var resource = new L10nResourceLink(langLinks[i]); + resource.load(lang, onResourceLoaded); + } + } + + function clear() { + gL10nData = {}; + gTextData = ''; + gLanguage = ''; + } + + function getPluralRules(lang) { + var locales2rules = { + 'af': 3, + 'ak': 4, + 'am': 4, + 'ar': 1, + 'asa': 3, + 'az': 0, + 'be': 11, + 'bem': 3, + 'bez': 3, + 'bg': 3, + 'bh': 4, + 'bm': 0, + 'bn': 3, + 'bo': 0, + 'br': 20, + 'brx': 3, + 'bs': 11, + 'ca': 3, + 'cgg': 3, + 'chr': 3, + 'cs': 12, + 'cy': 17, + 'da': 3, + 'de': 3, + 'dv': 3, + 'dz': 0, + 'ee': 3, + 'el': 3, + 'en': 3, + 'eo': 3, + 'es': 3, + 'et': 3, + 'eu': 3, + 'fa': 0, + 'ff': 5, + 'fi': 3, + 'fil': 4, + 'fo': 3, + 'fr': 5, + 'fur': 3, + 'fy': 3, + 'ga': 8, + 'gd': 24, + 'gl': 3, + 'gsw': 3, + 'gu': 3, + 'guw': 4, + 'gv': 23, + 'ha': 3, + 'haw': 3, + 'he': 2, + 'hi': 4, + 'hr': 11, + 'hu': 0, + 'id': 0, + 'ig': 0, + 'ii': 0, + 'is': 3, + 'it': 3, + 'iu': 7, + 'ja': 0, + 'jmc': 3, + 'jv': 0, + 'ka': 0, + 'kab': 5, + 'kaj': 3, + 'kcg': 3, + 'kde': 0, + 'kea': 0, + 'kk': 3, + 'kl': 3, + 'km': 0, + 'kn': 0, + 'ko': 0, + 'ksb': 3, + 'ksh': 21, + 'ku': 3, + 'kw': 7, + 'lag': 18, + 'lb': 3, + 'lg': 3, + 'ln': 4, + 'lo': 0, + 'lt': 10, + 'lv': 6, + 'mas': 3, + 'mg': 4, + 'mk': 16, + 'ml': 3, + 'mn': 3, + 'mo': 9, + 'mr': 3, + 'ms': 0, + 'mt': 15, + 'my': 0, + 'nah': 3, + 'naq': 7, + 'nb': 3, + 'nd': 3, + 'ne': 3, + 'nl': 3, + 'nn': 3, + 'no': 3, + 'nr': 3, + 'nso': 4, + 'ny': 3, + 'nyn': 3, + 'om': 3, + 'or': 3, + 'pa': 3, + 'pap': 3, + 'pl': 13, + 'ps': 3, + 'pt': 3, + 'rm': 3, + 'ro': 9, + 'rof': 3, + 'ru': 11, + 'rwk': 3, + 'sah': 0, + 'saq': 3, + 'se': 7, + 'seh': 3, + 'ses': 0, + 'sg': 0, + 'sh': 11, + 'shi': 19, + 'sk': 12, + 'sl': 14, + 'sma': 7, + 'smi': 7, + 'smj': 7, + 'smn': 7, + 'sms': 7, + 'sn': 3, + 'so': 3, + 'sq': 3, + 'sr': 11, + 'ss': 3, + 'ssy': 3, + 'st': 3, + 'sv': 3, + 'sw': 3, + 'syr': 3, + 'ta': 3, + 'te': 3, + 'teo': 3, + 'th': 0, + 'ti': 4, + 'tig': 3, + 'tk': 3, + 'tl': 4, + 'tn': 3, + 'to': 0, + 'tr': 0, + 'ts': 3, + 'tzm': 22, + 'uk': 11, + 'ur': 3, + 've': 3, + 'vi': 0, + 'vun': 3, + 'wa': 4, + 'wae': 3, + 'wo': 0, + 'xh': 3, + 'xog': 3, + 'yo': 0, + 'zh': 0, + 'zu': 3 + }; + + function isIn(n, list) { + return list.indexOf(n) !== -1; + } + + function isBetween(n, start, end) { + return start <= n && n <= end; + } + + var pluralRules = { + '0': function (n) { + return 'other'; + }, + '1': function (n) { + if (isBetween(n % 100, 3, 10)) return 'few'; + if (n === 0) return 'zero'; + if (isBetween(n % 100, 11, 99)) return 'many'; + if (n == 2) return 'two'; + if (n == 1) return 'one'; + return 'other'; + }, + '2': function (n) { + if (n !== 0 && n % 10 === 0) return 'many'; + if (n == 2) return 'two'; + if (n == 1) return 'one'; + return 'other'; + }, + '3': function (n) { + if (n == 1) return 'one'; + return 'other'; + }, + '4': function (n) { + if (isBetween(n, 0, 1)) return 'one'; + return 'other'; + }, + '5': function (n) { + if (isBetween(n, 0, 2) && n != 2) return 'one'; + return 'other'; + }, + '6': function (n) { + if (n === 0) return 'zero'; + if (n % 10 == 1 && n % 100 != 11) return 'one'; + return 'other'; + }, + '7': function (n) { + if (n == 2) return 'two'; + if (n == 1) return 'one'; + return 'other'; + }, + '8': function (n) { + if (isBetween(n, 3, 6)) return 'few'; + if (isBetween(n, 7, 10)) return 'many'; + if (n == 2) return 'two'; + if (n == 1) return 'one'; + return 'other'; + }, + '9': function (n) { + if (n === 0 || n != 1 && isBetween(n % 100, 1, 19)) return 'few'; + if (n == 1) return 'one'; + return 'other'; + }, + '10': function (n) { + if (isBetween(n % 10, 2, 9) && !isBetween(n % 100, 11, 19)) return 'few'; + if (n % 10 == 1 && !isBetween(n % 100, 11, 19)) return 'one'; + return 'other'; + }, + '11': function (n) { + if (isBetween(n % 10, 2, 4) && !isBetween(n % 100, 12, 14)) return 'few'; + if (n % 10 === 0 || isBetween(n % 10, 5, 9) || isBetween(n % 100, 11, 14)) return 'many'; + if (n % 10 == 1 && n % 100 != 11) return 'one'; + return 'other'; + }, + '12': function (n) { + if (isBetween(n, 2, 4)) return 'few'; + if (n == 1) return 'one'; + return 'other'; + }, + '13': function (n) { + if (isBetween(n % 10, 2, 4) && !isBetween(n % 100, 12, 14)) return 'few'; + if (n != 1 && isBetween(n % 10, 0, 1) || isBetween(n % 10, 5, 9) || isBetween(n % 100, 12, 14)) return 'many'; + if (n == 1) return 'one'; + return 'other'; + }, + '14': function (n) { + if (isBetween(n % 100, 3, 4)) return 'few'; + if (n % 100 == 2) return 'two'; + if (n % 100 == 1) return 'one'; + return 'other'; + }, + '15': function (n) { + if (n === 0 || isBetween(n % 100, 2, 10)) return 'few'; + if (isBetween(n % 100, 11, 19)) return 'many'; + if (n == 1) return 'one'; + return 'other'; + }, + '16': function (n) { + if (n % 10 == 1 && n != 11) return 'one'; + return 'other'; + }, + '17': function (n) { + if (n == 3) return 'few'; + if (n === 0) return 'zero'; + if (n == 6) return 'many'; + if (n == 2) return 'two'; + if (n == 1) return 'one'; + return 'other'; + }, + '18': function (n) { + if (n === 0) return 'zero'; + if (isBetween(n, 0, 2) && n !== 0 && n != 2) return 'one'; + return 'other'; + }, + '19': function (n) { + if (isBetween(n, 2, 10)) return 'few'; + if (isBetween(n, 0, 1)) return 'one'; + return 'other'; + }, + '20': function (n) { + if ((isBetween(n % 10, 3, 4) || n % 10 == 9) && !(isBetween(n % 100, 10, 19) || isBetween(n % 100, 70, 79) || isBetween(n % 100, 90, 99))) return 'few'; + if (n % 1000000 === 0 && n !== 0) return 'many'; + if (n % 10 == 2 && !isIn(n % 100, [12, 72, 92])) return 'two'; + if (n % 10 == 1 && !isIn(n % 100, [11, 71, 91])) return 'one'; + return 'other'; + }, + '21': function (n) { + if (n === 0) return 'zero'; + if (n == 1) return 'one'; + return 'other'; + }, + '22': function (n) { + if (isBetween(n, 0, 1) || isBetween(n, 11, 99)) return 'one'; + return 'other'; + }, + '23': function (n) { + if (isBetween(n % 10, 1, 2) || n % 20 === 0) return 'one'; + return 'other'; + }, + '24': function (n) { + if (isBetween(n, 3, 10) || isBetween(n, 13, 19)) return 'few'; + if (isIn(n, [2, 12])) return 'two'; + if (isIn(n, [1, 11])) return 'one'; + return 'other'; + } + }; + var index = locales2rules[lang.replace(/-.*$/, '')]; + + if (!(index in pluralRules)) { + console.warn('plural form unknown for [' + lang + ']'); + return function () { + return 'other'; + }; + } + + return pluralRules[index]; + } + + gMacros.plural = function (str, param, key, prop) { + var n = parseFloat(param); + if (isNaN(n)) return str; + if (prop != gTextProp) return str; + + if (!gMacros._pluralRules) { + gMacros._pluralRules = getPluralRules(gLanguage); + } + + var index = '[' + gMacros._pluralRules(n) + ']'; + + if (n === 0 && key + '[zero]' in gL10nData) { + str = gL10nData[key + '[zero]'][prop]; + } else if (n == 1 && key + '[one]' in gL10nData) { + str = gL10nData[key + '[one]'][prop]; + } else if (n == 2 && key + '[two]' in gL10nData) { + str = gL10nData[key + '[two]'][prop]; + } else if (key + index in gL10nData) { + str = gL10nData[key + index][prop]; + } else if (key + '[other]' in gL10nData) { + str = gL10nData[key + '[other]'][prop]; + } + + return str; + }; + + function getL10nData(key, args, fallback) { + var data = gL10nData[key]; + + if (!data) { + console.warn('#' + key + ' is undefined.'); + + if (!fallback) { + return null; + } + + data = fallback; + } + + var rv = {}; + + for (var prop in data) { + var str = data[prop]; + str = substIndexes(str, args, key, prop); + str = substArguments(str, args, key); + rv[prop] = str; + } + + return rv; + } + + function substIndexes(str, args, key, prop) { + var reIndex = /\{\[\s*([a-zA-Z]+)\(([a-zA-Z]+)\)\s*\]\}/; + var reMatch = reIndex.exec(str); + if (!reMatch || !reMatch.length) return str; + var macroName = reMatch[1]; + var paramName = reMatch[2]; + var param; + + if (args && paramName in args) { + param = args[paramName]; + } else if (paramName in gL10nData) { + param = gL10nData[paramName]; + } + + if (macroName in gMacros) { + var macro = gMacros[macroName]; + str = macro(str, param, key, prop); + } + + return str; + } + + function substArguments(str, args, key) { + var reArgs = /\{\{\s*(.+?)\s*\}\}/g; + return str.replace(reArgs, function (matched_text, arg) { + if (args && arg in args) { + return args[arg]; + } + + if (arg in gL10nData) { + return gL10nData[arg]; + } + + console.log('argument {{' + arg + '}} for #' + key + ' is undefined.'); + return matched_text; + }); + } + + function translateElement(element) { + var l10n = getL10nAttributes(element); + if (!l10n.id) return; + var data = getL10nData(l10n.id, l10n.args); + + if (!data) { + console.warn('#' + l10n.id + ' is undefined.'); + return; + } + + if (data[gTextProp]) { + if (getChildElementCount(element) === 0) { + element[gTextProp] = data[gTextProp]; + } else { + var children = element.childNodes; + var found = false; + + for (var i = 0, l = children.length; i < l; i++) { + if (children[i].nodeType === 3 && /\S/.test(children[i].nodeValue)) { + if (found) { + children[i].nodeValue = ''; + } else { + children[i].nodeValue = data[gTextProp]; + found = true; + } + } + } + + if (!found) { + var textNode = document.createTextNode(data[gTextProp]); + element.prepend(textNode); + } + } + + delete data[gTextProp]; + } + + for (var k in data) { + element[k] = data[k]; + } + } + + function getChildElementCount(element) { + if (element.children) { + return element.children.length; + } + + if (typeof element.childElementCount !== 'undefined') { + return element.childElementCount; + } + + var count = 0; + + for (var i = 0; i < element.childNodes.length; i++) { + count += element.nodeType === 1 ? 1 : 0; + } + + return count; + } + + function translateFragment(element) { + element = element || document.documentElement; + var children = getTranslatableChildren(element); + var elementCount = children.length; + + for (var i = 0; i < elementCount; i++) { + translateElement(children[i]); + } + + translateElement(element); + } + + return { + get: function (key, args, fallbackString) { + var index = key.lastIndexOf('.'); + var prop = gTextProp; + + if (index > 0) { + prop = key.substring(index + 1); + key = key.substring(0, index); + } + + var fallback; + + if (fallbackString) { + fallback = {}; + fallback[prop] = fallbackString; + } + + var data = getL10nData(key, args, fallback); + + if (data && prop in data) { + return data[prop]; + } + + return '{{' + key + '}}'; + }, + getData: function () { + return gL10nData; + }, + getText: function () { + return gTextData; + }, + getLanguage: function () { + return gLanguage; + }, + setLanguage: function (lang, callback) { + loadLocale(lang, function () { + if (callback) callback(); + }); + }, + getDirection: function () { + var rtlList = ['ar', 'he', 'fa', 'ps', 'ur']; + var shortCode = gLanguage.split('-', 1)[0]; + return rtlList.indexOf(shortCode) >= 0 ? 'rtl' : 'ltr'; + }, + translate: translateFragment, + getReadyState: function () { + return gReadyState; + }, + ready: function (callback) { + if (!callback) { + return; + } else if (gReadyState == 'complete' || gReadyState == 'interactive') { + window.setTimeout(function () { + callback(); + }); + } else if (document.addEventListener) { + document.addEventListener('localized', function once() { + document.removeEventListener('localized', once); + callback(); + }); + } + } + }; +}(window, document); + +/***/ }), +/* 48 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.GenericScripting = void 0; +exports.docPropertiesLookup = docPropertiesLookup; + +var _pdfjsLib = __webpack_require__(5); + +async function docPropertiesLookup(pdfDocument) { + const url = "", + baseUrl = url.split("#")[0]; + let { + info, + metadata, + contentDispositionFilename, + contentLength + } = await pdfDocument.getMetadata(); + + if (!contentLength) { + const { + length + } = await pdfDocument.getDownloadInfo(); + contentLength = length; + } + + return { ...info, + baseURL: baseUrl, + filesize: contentLength, + filename: contentDispositionFilename || (0, _pdfjsLib.getPdfFilenameFromUrl)(url), + metadata: metadata === null || metadata === void 0 ? void 0 : metadata.getRaw(), + authors: metadata === null || metadata === void 0 ? void 0 : metadata.get("dc:creator"), + numPages: pdfDocument.numPages, + URL: url + }; +} + +class GenericScripting { + constructor(sandboxBundleSrc) { + this._ready = (0, _pdfjsLib.loadScript)(sandboxBundleSrc, true).then(() => { + return window.pdfjsSandbox.QuickJSSandbox(); + }); + } + + async createSandbox(data) { + const sandbox = await this._ready; + sandbox.create(data); + } + + async dispatchEventInSandbox(event) { + const sandbox = await this._ready; + setTimeout(() => sandbox.dispatchEvent(event), 0); + } + + async destroySandbox() { + const sandbox = await this._ready; + sandbox.nukeSandbox(); + } + +} + +exports.GenericScripting = GenericScripting; + +/***/ }), +/* 49 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.PDFPrintService = PDFPrintService; + +var _pdfjsLib = __webpack_require__(5); + +var _app = __webpack_require__(4); + +var _print_utils = __webpack_require__(50); + +let activeService = null; +let dialog = null; +let overlayManager = null; + +function renderPage(activeServiceOnEntry, pdfDocument, pageNumber, size, printResolution, optionalContentConfigPromise, printAnnotationStoragePromise) { + const scratchCanvas = activeService.scratchCanvas; + const PRINT_UNITS = printResolution / _pdfjsLib.PixelsPerInch.PDF; + scratchCanvas.width = Math.floor(size.width * PRINT_UNITS); + scratchCanvas.height = Math.floor(size.height * PRINT_UNITS); + const ctx = scratchCanvas.getContext("2d"); + ctx.save(); + ctx.fillStyle = "rgb(255, 255, 255)"; + ctx.fillRect(0, 0, scratchCanvas.width, scratchCanvas.height); + ctx.restore(); + return Promise.all([pdfDocument.getPage(pageNumber), printAnnotationStoragePromise]).then(function (_ref) { + let [pdfPage, printAnnotationStorage] = _ref; + const renderContext = { + canvasContext: ctx, + transform: [PRINT_UNITS, 0, 0, PRINT_UNITS, 0, 0], + viewport: pdfPage.getViewport({ + scale: 1, + rotation: size.rotation + }), + intent: "print", + annotationMode: _pdfjsLib.AnnotationMode.ENABLE_STORAGE, + optionalContentConfigPromise, + printAnnotationStorage + }; + return pdfPage.render(renderContext).promise; + }); +} + +function PDFPrintService(pdfDocument, pagesOverview, printContainer, printResolution) { + let optionalContentConfigPromise = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null; + let printAnnotationStoragePromise = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : null; + let l10n = arguments.length > 6 ? arguments[6] : undefined; + this.pdfDocument = pdfDocument; + this.pagesOverview = pagesOverview; + this.printContainer = printContainer; + this._printResolution = printResolution || 150; + this._optionalContentConfigPromise = optionalContentConfigPromise || pdfDocument.getOptionalContentConfig(); + this._printAnnotationStoragePromise = printAnnotationStoragePromise || Promise.resolve(); + this.l10n = l10n; + this.currentPage = -1; + this.scratchCanvas = document.createElement("canvas"); +} + +PDFPrintService.prototype = { + layout() { + this.throwIfInactive(); + const body = document.querySelector("body"); + body.setAttribute("data-pdfjsprinting", true); + const hasEqualPageSizes = this.pagesOverview.every(function (size) { + return size.width === this.pagesOverview[0].width && size.height === this.pagesOverview[0].height; + }, this); + + if (!hasEqualPageSizes) { + console.warn("Not all pages have the same size. The printed " + "result may be incorrect!"); + } + + this.pageStyleSheet = document.createElement("style"); + const pageSize = this.pagesOverview[0]; + this.pageStyleSheet.textContent = "@page { size: " + pageSize.width + "pt " + pageSize.height + "pt;}"; + body.append(this.pageStyleSheet); + }, + + destroy() { + if (activeService !== this) { + return; + } + + this.printContainer.textContent = ""; + const body = document.querySelector("body"); + body.removeAttribute("data-pdfjsprinting"); + + if (this.pageStyleSheet) { + this.pageStyleSheet.remove(); + this.pageStyleSheet = null; + } + + this.scratchCanvas.width = this.scratchCanvas.height = 0; + this.scratchCanvas = null; + activeService = null; + ensureOverlay().then(function () { + if (overlayManager.active === dialog) { + overlayManager.close(dialog); + } + }); + }, + + renderPages() { + if (this.pdfDocument.isPureXfa) { + (0, _print_utils.getXfaHtmlForPrinting)(this.printContainer, this.pdfDocument); + return Promise.resolve(); + } + + const pageCount = this.pagesOverview.length; + + const renderNextPage = (resolve, reject) => { + this.throwIfInactive(); + + if (++this.currentPage >= pageCount) { + renderProgress(pageCount, pageCount, this.l10n); + resolve(); + return; + } + + const index = this.currentPage; + renderProgress(index, pageCount, this.l10n); + renderPage(this, this.pdfDocument, index + 1, this.pagesOverview[index], this._printResolution, this._optionalContentConfigPromise, this._printAnnotationStoragePromise).then(this.useRenderedPage.bind(this)).then(function () { + renderNextPage(resolve, reject); + }, reject); + }; + + return new Promise(renderNextPage); + }, + + useRenderedPage() { + this.throwIfInactive(); + const img = document.createElement("img"); + const scratchCanvas = this.scratchCanvas; + + if ("toBlob" in scratchCanvas) { + scratchCanvas.toBlob(function (blob) { + img.src = URL.createObjectURL(blob); + }); + } else { + img.src = scratchCanvas.toDataURL(); + } + + const wrapper = document.createElement("div"); + wrapper.className = "printedPage"; + wrapper.append(img); + this.printContainer.append(wrapper); + return new Promise(function (resolve, reject) { + img.onload = resolve; + img.onerror = reject; + }); + }, + + performPrint() { + this.throwIfInactive(); + return new Promise(resolve => { + setTimeout(() => { + if (!this.active) { + resolve(); + return; + } + + print.call(window); + setTimeout(resolve, 20); + }, 0); + }); + }, + + get active() { + return this === activeService; + }, + + throwIfInactive() { + if (!this.active) { + throw new Error("This print request was cancelled or completed."); + } + } + +}; +const print = window.print; + +window.print = function () { + if (activeService) { + console.warn("Ignored window.print() because of a pending print job."); + return; + } + + ensureOverlay().then(function () { + if (activeService) { + overlayManager.open(dialog); + } + }); + + try { + dispatchEvent("beforeprint"); + } finally { + if (!activeService) { + console.error("Expected print service to be initialized."); + ensureOverlay().then(function () { + if (overlayManager.active === dialog) { + overlayManager.close(dialog); + } + }); + return; + } + + const activeServiceOnEntry = activeService; + activeService.renderPages().then(function () { + return activeServiceOnEntry.performPrint(); + }).catch(function () {}).then(function () { + if (activeServiceOnEntry.active) { + abort(); + } + }); + } +}; + +function dispatchEvent(eventType) { + const event = document.createEvent("CustomEvent"); + event.initCustomEvent(eventType, false, false, "custom"); + window.dispatchEvent(event); +} + +function abort() { + if (activeService) { + activeService.destroy(); + dispatchEvent("afterprint"); + } +} + +function renderProgress(index, total, l10n) { + dialog || (dialog = document.getElementById("printServiceDialog")); + const progress = Math.round(100 * index / total); + const progressBar = dialog.querySelector("progress"); + const progressPerc = dialog.querySelector(".relative-progress"); + progressBar.value = progress; + l10n.get("print_progress_percent", { + progress + }).then(msg => { + progressPerc.textContent = msg; + }); +} + +window.addEventListener("keydown", function (event) { + if (event.keyCode === 80 && (event.ctrlKey || event.metaKey) && !event.altKey && (!event.shiftKey || window.chrome || window.opera)) { + window.print(); + event.preventDefault(); + + if (event.stopImmediatePropagation) { + event.stopImmediatePropagation(); + } else { + event.stopPropagation(); + } + } +}, true); + +if ("onbeforeprint" in window) { + const stopPropagationIfNeeded = function (event) { + if (event.detail !== "custom" && event.stopImmediatePropagation) { + event.stopImmediatePropagation(); + } + }; + + window.addEventListener("beforeprint", stopPropagationIfNeeded); + window.addEventListener("afterprint", stopPropagationIfNeeded); +} + +let overlayPromise; + +function ensureOverlay() { + if (!overlayPromise) { + overlayManager = _app.PDFViewerApplication.overlayManager; + + if (!overlayManager) { + throw new Error("The overlay manager has not yet been initialized."); + } + + dialog || (dialog = document.getElementById("printServiceDialog")); + overlayPromise = overlayManager.register(dialog, true); + document.getElementById("printCancel").onclick = abort; + dialog.addEventListener("close", abort); + } + + return overlayPromise; +} + +_app.PDFPrintServiceFactory.instance = { + supportsPrinting: true, + + createPrintService(pdfDocument, pagesOverview, printContainer, printResolution, optionalContentConfigPromise, printAnnotationStoragePromise, l10n) { + if (activeService) { + throw new Error("The print service is created and active."); + } + + activeService = new PDFPrintService(pdfDocument, pagesOverview, printContainer, printResolution, optionalContentConfigPromise, printAnnotationStoragePromise, l10n); + return activeService; + } + +}; + +/***/ }), +/* 50 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.getXfaHtmlForPrinting = getXfaHtmlForPrinting; + +var _pdfjsLib = __webpack_require__(5); + +var _pdf_link_service = __webpack_require__(3); + +var _xfa_layer_builder = __webpack_require__(39); + +function getXfaHtmlForPrinting(printContainer, pdfDocument) { + const xfaHtml = pdfDocument.allXfaHtml; + const linkService = new _pdf_link_service.SimpleLinkService(); + const scale = Math.round(_pdfjsLib.PixelsPerInch.PDF_TO_CSS_UNITS * 100) / 100; + + for (const xfaPage of xfaHtml.children) { + const page = document.createElement("div"); + page.className = "xfaPrintedPage"; + printContainer.append(page); + const builder = new _xfa_layer_builder.XfaLayerBuilder({ + pageDiv: page, + pdfPage: null, + annotationStorage: pdfDocument.annotationStorage, + linkService, + xfaHtml: xfaPage + }); + const viewport = (0, _pdfjsLib.getXfaPageViewport)(xfaPage, { + scale + }); + builder.render(viewport, "print"); + } +} + +/***/ }) +/******/ ]); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. +(() => { +var exports = __webpack_exports__; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +Object.defineProperty(exports, "PDFViewerApplication", ({ + enumerable: true, + get: function () { + return _app.PDFViewerApplication; + } +})); +exports.PDFViewerApplicationConstants = void 0; +Object.defineProperty(exports, "PDFViewerApplicationOptions", ({ + enumerable: true, + get: function () { + return _app_options.AppOptions; + } +})); + +var _ui_utils = __webpack_require__(1); + +var _app_options = __webpack_require__(2); + +var _pdf_link_service = __webpack_require__(3); + +var _app = __webpack_require__(4); + +var _document$blockUnbloc, _document; + +const pdfjsVersion = '2.16.105'; +const pdfjsBuild = '172ccdbe5'; +const AppConstants = { + LinkTarget: _pdf_link_service.LinkTarget, + RenderingStates: _ui_utils.RenderingStates, + ScrollMode: _ui_utils.ScrollMode, + SpreadMode: _ui_utils.SpreadMode +}; +exports.PDFViewerApplicationConstants = AppConstants; +window.PDFViewerApplication = _app.PDFViewerApplication; +window.PDFViewerApplicationConstants = AppConstants; +window.PDFViewerApplicationOptions = _app_options.AppOptions; +; +; +{ + __webpack_require__(43); +} +; +{ + __webpack_require__(49); +} + +function getViewerConfiguration() { + let errorWrapper = null; + errorWrapper = { + container: document.getElementById("errorWrapper"), + errorMessage: document.getElementById("errorMessage"), + closeButton: document.getElementById("errorClose"), + errorMoreInfo: document.getElementById("errorMoreInfo"), + moreInfoButton: document.getElementById("errorShowMore"), + lessInfoButton: document.getElementById("errorShowLess") + }; + return { + appContainer: document.body, + mainContainer: document.getElementById("viewerContainer"), + viewerContainer: document.getElementById("viewer"), + toolbar: { + container: document.getElementById("toolbarViewer"), + numPages: document.getElementById("numPages"), + pageNumber: document.getElementById("pageNumber"), + scaleSelect: document.getElementById("scaleSelect"), + customScaleOption: document.getElementById("customScaleOption"), + previous: document.getElementById("previous"), + next: document.getElementById("next"), + zoomIn: document.getElementById("zoomIn"), + zoomOut: document.getElementById("zoomOut"), + viewFind: document.getElementById("viewFind"), + openFile: document.getElementById("openFile"), + print: document.getElementById("print"), + editorFreeTextButton: document.getElementById("editorFreeText"), + editorFreeTextParamsToolbar: document.getElementById("editorFreeTextParamsToolbar"), + editorInkButton: document.getElementById("editorInk"), + editorInkParamsToolbar: document.getElementById("editorInkParamsToolbar"), + presentationModeButton: document.getElementById("presentationMode"), + download: document.getElementById("download"), + viewBookmark: document.getElementById("viewBookmark") + }, + secondaryToolbar: { + toolbar: document.getElementById("secondaryToolbar"), + toggleButton: document.getElementById("secondaryToolbarToggle"), + presentationModeButton: document.getElementById("secondaryPresentationMode"), + openFileButton: document.getElementById("secondaryOpenFile"), + printButton: document.getElementById("secondaryPrint"), + downloadButton: document.getElementById("secondaryDownload"), + viewBookmarkButton: document.getElementById("secondaryViewBookmark"), + firstPageButton: document.getElementById("firstPage"), + lastPageButton: document.getElementById("lastPage"), + pageRotateCwButton: document.getElementById("pageRotateCw"), + pageRotateCcwButton: document.getElementById("pageRotateCcw"), + cursorSelectToolButton: document.getElementById("cursorSelectTool"), + cursorHandToolButton: document.getElementById("cursorHandTool"), + scrollPageButton: document.getElementById("scrollPage"), + scrollVerticalButton: document.getElementById("scrollVertical"), + scrollHorizontalButton: document.getElementById("scrollHorizontal"), + scrollWrappedButton: document.getElementById("scrollWrapped"), + spreadNoneButton: document.getElementById("spreadNone"), + spreadOddButton: document.getElementById("spreadOdd"), + spreadEvenButton: document.getElementById("spreadEven"), + documentPropertiesButton: document.getElementById("documentProperties") + }, + sidebar: { + outerContainer: document.getElementById("outerContainer"), + sidebarContainer: document.getElementById("sidebarContainer"), + toggleButton: document.getElementById("sidebarToggle"), + thumbnailButton: document.getElementById("viewThumbnail"), + outlineButton: document.getElementById("viewOutline"), + attachmentsButton: document.getElementById("viewAttachments"), + layersButton: document.getElementById("viewLayers"), + thumbnailView: document.getElementById("thumbnailView"), + outlineView: document.getElementById("outlineView"), + attachmentsView: document.getElementById("attachmentsView"), + layersView: document.getElementById("layersView"), + outlineOptionsContainer: document.getElementById("outlineOptionsContainer"), + currentOutlineItemButton: document.getElementById("currentOutlineItem") + }, + sidebarResizer: { + outerContainer: document.getElementById("outerContainer"), + resizer: document.getElementById("sidebarResizer") + }, + findBar: { + bar: document.getElementById("findbar"), + toggleButton: document.getElementById("viewFind"), + findField: document.getElementById("findInput"), + highlightAllCheckbox: document.getElementById("findHighlightAll"), + caseSensitiveCheckbox: document.getElementById("findMatchCase"), + matchDiacriticsCheckbox: document.getElementById("findMatchDiacritics"), + entireWordCheckbox: document.getElementById("findEntireWord"), + findMsg: document.getElementById("findMsg"), + findResultsCount: document.getElementById("findResultsCount"), + findPreviousButton: document.getElementById("findPrevious"), + findNextButton: document.getElementById("findNext") + }, + passwordOverlay: { + dialog: document.getElementById("passwordDialog"), + label: document.getElementById("passwordText"), + input: document.getElementById("password"), + submitButton: document.getElementById("passwordSubmit"), + cancelButton: document.getElementById("passwordCancel") + }, + documentProperties: { + dialog: document.getElementById("documentPropertiesDialog"), + closeButton: document.getElementById("documentPropertiesClose"), + fields: { + fileName: document.getElementById("fileNameField"), + fileSize: document.getElementById("fileSizeField"), + title: document.getElementById("titleField"), + author: document.getElementById("authorField"), + subject: document.getElementById("subjectField"), + keywords: document.getElementById("keywordsField"), + creationDate: document.getElementById("creationDateField"), + modificationDate: document.getElementById("modificationDateField"), + creator: document.getElementById("creatorField"), + producer: document.getElementById("producerField"), + version: document.getElementById("versionField"), + pageCount: document.getElementById("pageCountField"), + pageSize: document.getElementById("pageSizeField"), + linearized: document.getElementById("linearizedField") + } + }, + annotationEditorParams: { + editorFreeTextFontSize: document.getElementById("editorFreeTextFontSize"), + editorFreeTextColor: document.getElementById("editorFreeTextColor"), + editorInkColor: document.getElementById("editorInkColor"), + editorInkThickness: document.getElementById("editorInkThickness"), + editorInkOpacity: document.getElementById("editorInkOpacity") + }, + errorWrapper, + printContainer: document.getElementById("printContainer"), + openFileInput: document.getElementById("fileInput"), + debuggerScriptPath: "./debugger.js" + }; +} + +function webViewerLoad() { + const config = getViewerConfiguration(); + const event = document.createEvent("CustomEvent"); + event.initCustomEvent("webviewerloaded", true, true, { + source: window + }); + + try { + parent.document.dispatchEvent(event); + } catch (ex) { + console.error(`webviewerloaded: ${ex}`); + document.dispatchEvent(event); + } + + _app.PDFViewerApplication.run(config); +} + +(_document$blockUnbloc = (_document = document).blockUnblockOnload) === null || _document$blockUnbloc === void 0 ? void 0 : _document$blockUnbloc.call(_document, true); + +if (document.readyState === "interactive" || document.readyState === "complete") { + webViewerLoad(); +} else { + document.addEventListener("DOMContentLoaded", webViewerLoad, true); +} +})(); + +/******/ })() +; +//# sourceMappingURL=viewer.js.map \ No newline at end of file diff --git a/frontend/public/pdfjs/web/viewer.js.map b/frontend/public/pdfjs/web/viewer.js.map new file mode 100644 index 0000000..a5c434d --- /dev/null +++ b/frontend/public/pdfjs/web/viewer.js.map @@ -0,0 +1 @@ +{"version":3,"file":"viewer.js","mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAeA,MAAMA,sBAAsB,MAA5B;;AACA,MAAMC,gBAAgB,GAAtB;;AACA,MAAMC,sBAAsB,GAA5B;;AACA,MAAMC,YAAY,GAAlB;;AACA,MAAMC,YAAY,IAAlB;;AACA,MAAMC,gBAAgB,CAAtB;;AACA,MAAMC,iBAAiB,IAAvB;;AACA,MAAMC,oBAAoB,EAA1B;;AACA,MAAMC,mBAAmB,CAAzB;;AAEA,MAAMC,kBAAkB;EACtBC,SAAS,CADa;EAEtBC,SAAS,CAFa;EAGtBC,QAAQ,CAHc;EAItBC,UAAU;AAJY,CAAxB;;AAOA,MAAMC,wBAAwB;EAC5BC,SAAS,CADmB;EAE5BC,QAAQ,CAFoB;EAG5BC,UAAU,CAHkB;EAI5BC,YAAY;AAJgB,CAA9B;;AAOA,MAAMC,cAAc;EAClBJ,SAAS,CAAC,CADQ;EAElBK,MAAM,CAFY;EAGlBC,QAAQ,CAHU;EAIlBC,SAAS,CAJS;EAKlBC,aAAa,CALK;EAMlBC,QAAQ;AANU,CAApB;;AASA,MAAMC,eAEA;EACEC,QAAQ,QADV;EAEEC,KAAK;AAFP,CAFN;;AAQA,MAAMC,gBAAgB;EACpBC,SAAS,CADW;EAEpBC,QAAQ,CAFY;EAGpBC,gBAAgB;AAHI,CAAtB;;AAMA,MAAMC,aAAa;EACjBjB,SAAS,CAAC,CADO;EAEjBkB,UAAU,CAFO;EAGjBC,YAAY,CAHK;EAIjBC,SAAS,CAJQ;EAKjBC,MAAM;AALW,CAAnB;;AAQA,MAAMC,aAAa;EACjBtB,SAAS,CAAC,CADO;EAEjBK,MAAM,CAFW;EAGjBkB,KAAK,CAHY;EAIjBC,MAAM;AAJW,CAAnB;;AAQA,MAAMC,kBAAkB,cAAxB;;;AAKA,MAAMC,WAAN,CAAkB;EAChBC,cAAc;IACZ,MAAMC,aAAaC,OAAOC,gBAAPD,IAA2B,CAA9C;IAKA,KAAKE,EAAL,GAAUH,UAAV;IAKA,KAAKI,EAAL,GAAUJ,UAAV;EAZc;;EAkBhB,IAAIK,MAAJ,GAAa;IACX,OAAO,KAAKF,EAAL,KAAY,CAAZ,IAAiB,KAAKC,EAAL,KAAY,CAApC;EAnBc;;AAAA;;;;AAgClB,SAASE,cAAT,CAAwBC,OAAxB,EAAiCC,IAAjC,EAA8D;EAAA,IAAvBC,aAAuB,uEAAP,KAAO;EAI5D,IAAIC,SAASH,QAAQI,YAArB;;EACA,IAAI,CAACD,MAAL,EAAa;IACXE,QAAQC,KAARD,CAAc,0CAAdA;IACA;EAP0D;;EAS5D,IAAIE,UAAUP,QAAQQ,SAARR,GAAoBA,QAAQS,SAA1C;EACA,IAAIC,UAAUV,QAAQW,UAARX,GAAqBA,QAAQY,UAA3C;;EACA,OACGT,OAAOU,YAAPV,KAAwBA,OAAOW,YAA/BX,IACCA,OAAOY,WAAPZ,KAAuBA,OAAOa,WAD/Bb,IAEAD,kBACEC,OAAOc,SAAPd,CAAiBe,QAAjBf,CAA0B,eAA1BA,KACCgB,iBAAiBhB,MAAjB,EAAyBiB,QAAzBD,KAAsC,QAFzC,CAHH,EAME;IACAZ,WAAWJ,OAAOK,SAAlBD;IACAG,WAAWP,OAAOQ,UAAlBD;IAEAP,SAASA,OAAOC,YAAhBD;;IACA,IAAI,CAACA,MAAL,EAAa;MACX;IANF;EAjB0D;;EA0B5D,IAAIF,IAAJ,EAAU;IACR,IAAIA,KAAKoB,GAALpB,KAAaqB,SAAjB,EAA4B;MAC1Bf,WAAWN,KAAKoB,GAAhBd;IAFM;;IAIR,IAAIN,KAAKsB,IAALtB,KAAcqB,SAAlB,EAA6B;MAC3BZ,WAAWT,KAAKsB,IAAhBb;MACAP,OAAOqB,UAAPrB,GAAoBO,OAApBP;IANM;EA1BkD;;EAmC5DA,OAAOsB,SAAPtB,GAAmBI,OAAnBJ;AAtJF;;AA6JA,SAASuB,WAAT,CAAqBC,eAArB,EAAsCC,QAAtC,EAAgD;EAC9C,MAAMC,iBAAiB,UAAUC,GAAV,EAAe;IACpC,IAAIC,GAAJ,EAAS;MACP;IAFkC;;IAKpCA,MAAMrC,OAAOsC,qBAAPtC,CAA6B,SAASuC,uBAAT,GAAmC;MACpEF,MAAM,IAANA;MAEA,MAAMG,WAAWP,gBAAgBH,UAAjC;MACA,MAAMW,QAAQC,MAAMD,KAApB;;MACA,IAAID,aAAaC,KAAjB,EAAwB;QACtBC,MAAMC,KAAND,GAAcF,WAAWC,KAAzBC;MANkE;;MAQpEA,MAAMD,KAANC,GAAcF,QAAdE;MACA,MAAME,WAAWX,gBAAgBF,SAAjC;MACA,MAAMc,QAAQH,MAAMG,KAApB;;MACA,IAAID,aAAaC,KAAjB,EAAwB;QACtBH,MAAMI,IAANJ,GAAaE,WAAWC,KAAxBH;MAZkE;;MAcpEA,MAAMG,KAANH,GAAcE,QAAdF;MACAR,SAASQ,KAAT;IAfI,EAANL;EALF;;EAwBA,MAAMK,QAAQ;IACZC,OAAO,IADK;IAEZG,MAAM,IAFM;IAGZL,OAAOR,gBAAgBH,UAHX;IAIZe,OAAOZ,gBAAgBF,SAJX;IAKZgB,eAAeZ;EALH,CAAd;EAQA,IAAIE,MAAM,IAAV;EACAJ,gBAAgBe,gBAAhBf,CAAiC,QAAjCA,EAA2CE,cAA3CF,EAA2D,IAA3DA;EACA,OAAOS,KAAP;AAhMF;;AAwMA,SAASO,gBAAT,CAA0BC,KAA1B,EAAiC;EAC/B,MAAMC,SAAS,IAAIC,GAAJ,EAAf;;EACA,WAAW,CAACC,GAAD,EAAMC,KAAN,CAAX,IAA2B,IAAIC,eAAJ,CAAoBL,KAApB,CAA3B,EAAuD;IACrDC,OAAOK,GAAPL,CAAWE,IAAII,WAAJJ,EAAXF,EAA8BG,KAA9BH;EAH6B;;EAK/B,OAAOA,MAAP;AA7MF;;AAgNA,MAAMO,uBAAuB,OAA7B;AACA,MAAMC,4BAA4B,cAAlC;;AAMA,SAASC,oBAAT,CAA8BC,GAA9B,EAA6D;EAAA,IAA1BC,gBAA0B,uEAAP,KAAO;;EAC3D,IAAI,OAAOD,GAAP,KAAe,QAAnB,EAA6B;IAC3BlD,QAAQC,KAARD,CAAe,gCAAfA;IACA,OAAOkD,GAAP;EAHyD;;EAK3D,IAAIC,gBAAJ,EAAsB;IACpBD,MAAMA,IAAIE,OAAJF,CAAYF,yBAAZE,EAAuC,GAAvCA,CAANA;EANyD;;EAQ3D,OAAOA,IAAIE,OAAJF,CAAYH,oBAAZG,EAAkC,EAAlCA,CAAP;AA/NF;;AA2OA,SAASG,qBAAT,CAA+BC,KAA/B,EAAsCC,SAAtC,EAA4D;EAAA,IAAXC,KAAW,uEAAH,CAAG;EAC1D,IAAIC,WAAWD,KAAf;EACA,IAAIE,WAAWJ,MAAMK,MAANL,GAAe,CAA9B;;EAEA,IAAII,WAAW,CAAXA,IAAgB,CAACH,UAAUD,MAAMI,QAAN,CAAV,CAArB,EAAiD;IAC/C,OAAOJ,MAAMK,MAAb;EALwD;;EAO1D,IAAIJ,UAAUD,MAAMG,QAAN,CAAV,CAAJ,EAAgC;IAC9B,OAAOA,QAAP;EARwD;;EAW1D,OAAOA,WAAWC,QAAlB,EAA4B;IAC1B,MAAME,eAAgBH,WAAWC,QAAXD,IAAwB,CAA9C;IACA,MAAMI,cAAcP,MAAMM,YAAN,CAApB;;IACA,IAAIL,UAAUM,WAAV,CAAJ,EAA4B;MAC1BH,WAAWE,YAAXF;IADF,OAEO;MACLD,WAAWG,eAAe,CAA1BH;IANwB;EAX8B;;EAoB1D,OAAOA,QAAP;AA/PF;;AAyQA,SAASK,mBAAT,CAA6BC,CAA7B,EAAgC;EAE9B,IAAIC,KAAKC,KAALD,CAAWD,CAAXC,MAAkBD,CAAtB,EAAyB;IACvB,OAAO,CAACA,CAAD,EAAI,CAAJ,CAAP;EAH4B;;EAK9B,MAAMG,OAAO,IAAIH,CAAjB;EACA,MAAMI,QAAQ,CAAd;;EACA,IAAID,OAAOC,KAAX,EAAkB;IAChB,OAAO,CAAC,CAAD,EAAIA,KAAJ,CAAP;EADF,OAEO,IAAIH,KAAKC,KAALD,CAAWE,IAAXF,MAAqBE,IAAzB,EAA+B;IACpC,OAAO,CAAC,CAAD,EAAIA,IAAJ,CAAP;EAV4B;;EAa9B,MAAME,KAAKL,IAAI,CAAJA,GAAQG,IAARH,GAAeA,CAA1B;EAEA,IAAIM,IAAI,CAAR;EAAA,IACEC,IAAI,CADN;EAAA,IAEEC,IAAI,CAFN;EAAA,IAGEC,IAAI,CAHN;;EAKA,OAAO,IAAP,EAAa;IAEX,MAAMC,IAAIJ,IAAIE,CAAd;IAAA,MACEG,IAAIJ,IAAIE,CADV;;IAEA,IAAIE,IAAIP,KAAR,EAAe;MACb;IALS;;IAOX,IAAIC,MAAMK,IAAIC,CAAd,EAAiB;MACfH,IAAIE,CAAJF;MACAC,IAAIE,CAAJF;IAFF,OAGO;MACLH,IAAII,CAAJJ;MACAC,IAAII,CAAJJ;IAZS;EApBiB;;EAmC9B,IAAIK,MAAJ;;EAEA,IAAIP,KAAKC,IAAIC,CAATF,GAAaG,IAAIC,CAAJD,GAAQH,EAAzB,EAA6B;IAC3BO,SAASP,OAAOL,CAAPK,GAAW,CAACC,CAAD,EAAIC,CAAJ,CAAXF,GAAoB,CAACE,CAAD,EAAID,CAAJ,CAA7BM;EADF,OAEO;IACLA,SAASP,OAAOL,CAAPK,GAAW,CAACG,CAAD,EAAIC,CAAJ,CAAXJ,GAAoB,CAACI,CAAD,EAAID,CAAJ,CAA7BI;EAxC4B;;EA0C9B,OAAOA,MAAP;AAnTF;;AAsTA,SAASC,aAAT,CAAuBb,CAAvB,EAA0Bc,GAA1B,EAA+B;EAC7B,MAAMC,IAAIf,IAAIc,GAAd;EACA,OAAOC,MAAM,CAANA,GAAUf,CAAVe,GAAcd,KAAKe,KAALf,CAAWD,IAAIe,CAAJf,GAAQc,GAAnBb,CAArB;AAxTF;;AA6UA,SAASgB,iBAAT,OAAuD;EAAA,IAA5B;IAAEC,IAAF;IAAQC,QAAR;IAAkBC;EAAlB,CAA4B;EACrD,MAAM,CAACC,EAAD,EAAKC,EAAL,EAASC,EAAT,EAAaC,EAAb,IAAmBN,IAAzB;EAEA,MAAMO,oBAAoBL,SAAS,GAATA,KAAiB,CAA3C;EAEA,MAAMM,QAAU,MAAKL,EAAL,IAAW,EAAX,GAAiBF,QAAjC;EACA,MAAMQ,SAAW,MAAKL,EAAL,IAAW,EAAX,GAAiBH,QAAlC;EAEA,OAAO;IACLO,OAAOD,oBAAoBE,MAApB,GAA6BD,KAD/B;IAELC,QAAQF,oBAAoBC,KAApB,GAA4BC;EAF/B,CAAP;AArVF;;AAsWA,SAASC,iCAAT,CAA2CC,KAA3C,EAAkDC,KAAlD,EAAyD7E,GAAzD,EAA8D;EAa5D,IAAI4E,QAAQ,CAAZ,EAAe;IACb,OAAOA,KAAP;EAd0D;;EAwC5D,IAAIE,MAAMD,MAAMD,KAAN,EAAaf,GAAvB;EACA,IAAIkB,UAAUD,IAAI3F,SAAJ2F,GAAgBA,IAAI1F,SAAlC;;EAEA,IAAI2F,WAAW/E,GAAf,EAAoB;IAMlB8E,MAAMD,MAAMD,QAAQ,CAAd,EAAiBf,GAAvBiB;IACAC,UAAUD,IAAI3F,SAAJ2F,GAAgBA,IAAI1F,SAA9B2F;EAlD0D;;EA6D5D,KAAK,IAAIC,IAAIJ,QAAQ,CAArB,EAAwBI,KAAK,CAA7B,EAAgC,EAAEA,CAAlC,EAAqC;IACnCF,MAAMD,MAAMG,CAAN,EAASnB,GAAfiB;;IACA,IAAIA,IAAI3F,SAAJ2F,GAAgBA,IAAI1F,SAApB0F,GAAgCA,IAAItF,YAApCsF,IAAoDC,OAAxD,EAAiE;MAI/D;IANiC;;IAQnCH,QAAQI,CAARJ;EArE0D;;EAuE5D,OAAOA,KAAP;AA7aF;;AAmdA,SAASK,kBAAT,QAMG;EAAA,IANyB;IAC1BC,QAD0B;IAE1BL,KAF0B;IAG1BM,mBAAmB,KAHO;IAI1BC,aAAa,KAJa;IAK1BC,MAAM;EALoB,CAMzB;EACD,MAAMrF,MAAMkF,SAAS9E,SAArB;EAAA,MACEkF,SAAStF,MAAMkF,SAAS1F,YAD1B;EAEA,MAAMU,OAAOgF,SAAS/E,UAAtB;EAAA,MACEa,QAAQd,OAAOgF,SAASxF,WAD1B;;EAaA,SAAS6F,2BAAT,CAAqCtB,IAArC,EAA2C;IACzC,MAAMtF,UAAUsF,KAAKJ,GAArB;IACA,MAAM2B,gBACJ7G,QAAQQ,SAARR,GAAoBA,QAAQS,SAA5BT,GAAwCA,QAAQa,YADlD;IAEA,OAAOgG,gBAAgBxF,GAAvB;EApBD;;EAsBD,SAASyF,kCAAT,CAA4CxB,IAA5C,EAAkD;IAChD,MAAMtF,UAAUsF,KAAKJ,GAArB;IACA,MAAM6B,cAAc/G,QAAQW,UAARX,GAAqBA,QAAQY,UAAjD;IACA,MAAMoG,eAAeD,cAAc/G,QAAQe,WAA3C;IACA,OAAO2F,MAAMK,cAAc1E,KAApB,GAA4B2E,eAAezF,IAAlD;EA1BD;;EA6BD,MAAM0F,UAAU,EAAhB;EAAA,MACEC,MAAM,IAAIC,GAAJ,EADR;EAAA,MAEEC,WAAWlB,MAAMlC,MAFnB;EAGA,IAAIqD,yBAAyB3D,sBAC3BwC,KAD2B,EAE3BO,aACIK,kCADJ,GAEIF,2BAJuB,CAA7B;;EASA,IACES,yBAAyB,CAAzBA,IACAA,yBAAyBD,QADzBC,IAEA,CAACZ,UAHH,EAIE;IAMAY,yBAAyBrB,kCACvBqB,sBADuB,EAEvBnB,KAFuB,EAGvB7E,GAHuB,CAAzBgG;EAnDD;;EAkED,IAAIC,WAAWb,aAAapE,KAAb,GAAqB,CAAC,CAArC;;EAEA,KAAK,IAAIgE,IAAIgB,sBAAb,EAAqChB,IAAIe,QAAzC,EAAmDf,GAAnD,EAAwD;IACtD,MAAMf,OAAOY,MAAMG,CAAN,CAAb;IAAA,MACErG,UAAUsF,KAAKJ,GADjB;IAEA,MAAMqC,eAAevH,QAAQW,UAARX,GAAqBA,QAAQY,UAAlD;IACA,MAAM4G,gBAAgBxH,QAAQQ,SAARR,GAAoBA,QAAQS,SAAlD;IACA,MAAMgH,YAAYzH,QAAQe,WAA1B;IAAA,MACE2G,aAAa1H,QAAQa,YADvB;IAEA,MAAM8G,YAAYJ,eAAeE,SAAjC;IACA,MAAMG,aAAaJ,gBAAgBE,UAAnC;;IAEA,IAAIJ,aAAa,CAAC,CAAlB,EAAqB;MAKnB,IAAIM,cAAcjB,MAAlB,EAA0B;QACxBW,WAAWM,UAAXN;MANiB;IAArB,OAQO,IAAK,cAAaC,YAAb,GAA4BC,aAA5B,IAA6CF,QAAlD,EAA4D;MACjE;IAnBoD;;IAsBtD,IACEM,cAAcvG,GAAduG,IACAJ,iBAAiBb,MADjBiB,IAEAD,aAAapG,IAFbqG,IAGAL,gBAAgBlF,KAJlB,EAKE;MACA;IA5BoD;;IA+BtD,MAAMwF,eACJxD,KAAKyD,GAALzD,CAAS,CAATA,EAAYhD,MAAMmG,aAAlBnD,IAAmCA,KAAKyD,GAALzD,CAAS,CAATA,EAAYuD,aAAajB,MAAzBtC,CADrC;IAEA,MAAM0D,cACJ1D,KAAKyD,GAALzD,CAAS,CAATA,EAAY9C,OAAOgG,YAAnBlD,IAAmCA,KAAKyD,GAALzD,CAAS,CAATA,EAAYsD,YAAYtF,KAAxBgC,CADrC;IAGA,MAAM2D,iBAAkB,cAAaH,YAAb,IAA6BH,UAArD;IAAA,MACEO,gBAAiB,aAAYF,WAAZ,IAA2BN,SAD9C;IAEA,MAAMS,UAAWF,iBAAiBC,aAAjBD,GAAiC,GAAjCA,GAAwC,CAAzD;IAEAf,QAAQkB,IAARlB,CAAa;MACXmB,IAAI9C,KAAK8C,EADE;MAEXhE,GAAGmD,YAFQ;MAGXc,GAAGb,aAHQ;MAIXlC,IAJW;MAKX4C,OALW;MAMXI,cAAeL,gBAAgB,GAAhBA,GAAuB;IAN3B,CAAbhB;IAQAC,IAAIqB,GAAJrB,CAAQ5B,KAAK8C,EAAblB;EApHD;;EAuHD,MAAMsB,QAAQvB,QAAQ,CAAR,CAAd;EAAA,MACEwB,OAAOxB,QAAQyB,EAARzB,CAAW,CAAC,CAAZA,CADT;;EAGA,IAAIT,gBAAJ,EAAsB;IACpBS,QAAQ0B,IAAR1B,CAAa,UAAUvC,CAAV,EAAaC,CAAb,EAAgB;MAC3B,MAAMiE,KAAKlE,EAAEwD,OAAFxD,GAAYC,EAAEuD,OAAzB;;MACA,IAAI7D,KAAKwE,GAALxE,CAASuE,EAATvE,IAAe,KAAnB,EAA0B;QACxB,OAAO,CAACuE,EAAR;MAHyB;;MAK3B,OAAOlE,EAAE0D,EAAF1D,GAAOC,EAAEyD,EAAhB;IALF;EA3HD;;EAmID,OAAO;IAAEI,KAAF;IAASC,IAAT;IAAevC,OAAOe,OAAtB;IAA+BC;EAA/B,CAAP;AA5lBF;;AAkmBA,SAAS4B,oBAAT,CAA8BhH,GAA9B,EAAmC;EACjCA,IAAIiH,cAAJjH;AAnmBF;;AAsmBA,SAASkH,4BAAT,CAAsClH,GAAtC,EAA2C;EACzC,IAAImH,QAAQ5E,KAAK6E,KAAL7E,CAAWvC,IAAIqH,MAAf9E,EAAuBvC,IAAIsH,MAA3B/E,CAAZ;EACA,MAAMgF,QAAQhF,KAAKiF,KAALjF,CAAWvC,IAAIsH,MAAf/E,EAAuBvC,IAAIqH,MAA3B9E,CAAd;;EACA,IAAI,CAAC,IAAD,GAAQA,KAAKkF,EAAb,GAAkBF,KAAlB,IAA2BA,QAAQ,OAAOhF,KAAKkF,EAAnD,EAAuD;IAErDN,QAAQ,CAACA,KAATA;EALuC;;EAOzC,OAAOA,KAAP;AA7mBF;;AAgnBA,SAASO,wBAAT,CAAkC1H,GAAlC,EAAuC;EACrC,IAAImH,QAAQD,6BAA6BlH,GAA7B,CAAZ;EAEA,MAAM2H,6BAA6B,CAAnC;EACA,MAAMC,4BAA4B,CAAlC;EACA,MAAMC,wBAAwB,EAA9B;EACA,MAAMC,uBAAuB,EAA7B;;EAGA,IAAI9H,IAAI+H,SAAJ/H,KAAkB2H,0BAAtB,EAAkD;IAChDR,SAASU,wBAAwBC,oBAAjCX;EADF,OAEO,IAAInH,IAAI+H,SAAJ/H,KAAkB4H,yBAAtB,EAAiD;IACtDT,SAASW,oBAATX;EAZmC;;EAcrC,OAAOA,KAAP;AA9nBF;;AAioBA,SAASa,eAAT,CAAyBT,KAAzB,EAAgC;EAC9B,OAAOU,OAAOC,SAAPD,CAAiBV,KAAjBU,KAA2BV,QAAQ,EAARA,KAAe,CAAjD;AAloBF;;AAqoBA,SAASY,iBAAT,CAA2BC,IAA3B,EAAiC;EAC/B,OACEH,OAAOC,SAAPD,CAAiBG,IAAjBH,KACAI,OAAOC,MAAPD,CAAcrL,UAAdqL,EAA0BE,QAA1BF,CAAmCD,IAAnCC,CADAJ,IAEAG,SAASpL,WAAWjB,OAHtB;AAtoBF;;AA6oBA,SAASyM,iBAAT,CAA2BJ,IAA3B,EAAiC;EAC/B,OACEH,OAAOC,SAAPD,CAAiBG,IAAjBH,KACAI,OAAOC,MAAPD,CAAchL,UAAdgL,EAA0BE,QAA1BF,CAAmCD,IAAnCC,CADAJ,IAEAG,SAAS/K,WAAWtB,OAHtB;AA9oBF;;AAqpBA,SAAS0M,qBAAT,CAA+BC,IAA/B,EAAqC;EACnC,OAAOA,KAAK1E,KAAL0E,IAAcA,KAAKzE,MAA1B;AAtpBF;;AA4pBA,MAAM0E,mBAAmB,IAAIC,OAAJ,CAAY,UAAUC,OAAV,EAAmB;EAWtDjL,OAAOsC,qBAAPtC,CAA6BiL,OAA7BjL;AAXuB,EAAzB;;AAcA,MAAMkL,WAKAC,SAASC,eAATD,CAAyBE,KAL/B;;;AAOA,SAASC,KAAT,CAAeC,CAAf,EAAkBC,GAAlB,EAAuBpD,GAAvB,EAA4B;EAC1B,OAAOzD,KAAK6G,GAAL7G,CAASA,KAAKyD,GAALzD,CAAS4G,CAAT5G,EAAY6G,GAAZ7G,CAATA,EAA2ByD,GAA3BzD,CAAP;AAlrBF;;;;;;;;AAqrBA,MAAM8G,WAAN,CAAkB;EAOhB3L,YAAY4I,EAAZ,EAAgB;IAAA;MAAA;MAAA,OANH;IAMG;;IAAA;MAAA;MAAA,OAJL;IAIK;;IAAA;MAAA;MAAA,OAFL;IAEK;;IACd,IAEEgD,UAAUpH,MAAVoH,GAAmB,CAFrB,EAGE;MACA,MAAM,IAAIC,KAAJ,CACJ,2DACE,wDAFE,CAAN;IALY;;IAUd,MAAMC,MAAMT,SAASU,cAATV,CAAwBzC,EAAxByC,CAAZ;;IACA,wCAAkBS,IAAIrK,SAAtB;EAlBc;;EAqBhB,IAAIiH,OAAJ,GAAc;IACZ,6BAAO,IAAP;EAtBc;;EAyBhB,IAAIA,OAAJ,CAAYsD,GAAZ,EAAiB;IACf,sCAAgBR,MAAMQ,GAAN,EAAW,CAAX,EAAc,GAAd,CAAhB;;IAEA,IAAIC,MAAMD,GAAN,CAAJ,EAAgB;MACd,wCAAgBjD,GAAhB,CAAoB,eAApB;;MACA;IALa;;IAOf,wCAAgBmD,MAAhB,CAAuB,eAAvB;;IAEAd,SAASe,WAATf,CAAqB,uBAArBA,EAA8C,yBAAG,IAAH,WAAiB,GAA/DA;EAlCc;;EAqChBgB,SAASC,MAAT,EAAiB;IACf,IAAI,CAACA,MAAL,EAAa;MACX;IAFa;;IAIf,MAAMC,YAAYD,OAAOE,UAAzB;IACA,MAAMC,iBAAiBF,UAAUG,WAAVH,GAAwBD,OAAOI,WAAtD;;IACA,IAAID,iBAAiB,CAArB,EAAwB;MACtBpB,SAASe,WAATf,CAAqB,0BAArBA,EAAiD,GAAGoB,cAAe,IAAnEpB;IAPa;EArCD;;EAgDhBsB,OAAO;IACL,IAAI,uBAAC,IAAD,WAAJ,EAAoB;MAClB;IAFG;;IAIL,sCAAgB,KAAhB;;IACA,wCAAgB3D,GAAhB,CAAoB,QAApB;EArDc;;EAwDhB4D,OAAO;IACL,0BAAI,IAAJ,aAAmB;MACjB;IAFG;;IAIL,sCAAgB,IAAhB;;IACA,wCAAgBT,MAAhB,CAAuB,QAAvB;EA7Dc;;AAAA;;;;AAyElB,SAASU,yBAAT,GAAqC;EACnC,IAAIC,UAAUxB,QAAd;EACA,IAAIyB,qBACFD,QAAQE,aAARF,IAAyBA,QAAQG,aAARH,CAAsB,QAAtBA,CAD3B;;EAGA,8BAAOC,kBAAP,gDAAOA,oBAAoBG,UAA3B,EAAuC;IAAA;;IACrCJ,UAAUC,mBAAmBG,UAA7BJ;IACAC,qBACED,QAAQE,aAARF,IAAyBA,QAAQG,aAARH,CAAsB,QAAtBA,CAD3BC;EAPiC;;EAWnC,OAAOA,kBAAP;AAzwBF;;AAoxBA,SAASI,0BAAT,CAAoCC,MAApC,EAA4C;EAC1C,IAAIC,aAAa9N,WAAWC,QAA5B;EAAA,IACE8N,aAAa1N,WAAWjB,IAD1B;;EAGA,QAAQyO,MAAR;IACE,KAAK,YAAL;MACEC,aAAa9N,WAAWI,IAAxB0N;MACA;;IACF,KAAK,WAAL;MACE;;IACF,KAAK,aAAL;MACEA,aAAa9N,WAAWI,IAAxB0N;;IAEF,KAAK,eAAL;MACEC,aAAa1N,WAAWC,GAAxByN;MACA;;IACF,KAAK,cAAL;MACED,aAAa9N,WAAWI,IAAxB0N;;IAEF,KAAK,gBAAL;MACEC,aAAa1N,WAAWE,IAAxBwN;MACA;EAjBJ;;EAmBA,OAAO;IAAED,UAAF;IAAcC;EAAd,CAAP;AA3yBF;;AAszBA,SAASC,wBAAT,CAAkC5C,IAAlC,EAAwC;EACtC,QAAQA,IAAR;IACE,KAAK,SAAL;MACE,OAAOjM,YAAYC,IAAnB;;IACF,KAAK,WAAL;MACE,OAAOD,YAAYE,MAAnB;;IACF,KAAK,aAAL;MACE,OAAOF,YAAYG,OAAnB;;IACF,KAAK,gBAAL;MACE,OAAOH,YAAYI,WAAnB;;IACF,KAAK,OAAL;MACE,OAAOJ,YAAYK,MAAnB;EAVJ;;EAYA,OAAOL,YAAYC,IAAnB;AAn0BF;;;;;;;;;;;;ACeA,MAAM6O,sBAAsB5C,OAAO6C,MAAP7C,CAAc,IAAdA,CAA5B;;AACiE;EAQ/D,MAAM8C,YAAYC,UAAUD,SAAVC,IAAuB,EAAzC;EACA,MAAMC,WAAWD,UAAUC,QAAVD,IAAsB,EAAvC;EACA,MAAME,iBAAiBF,UAAUE,cAAVF,IAA4B,CAAnD;EAEA,MAAMG,YAAY,UAAUC,IAAV,CAAeL,SAAf,CAAlB;EACA,MAAMM,QACJ,4BAA4BD,IAA5B,CAAiCL,SAAjC,KACCE,aAAa,UAAbA,IAA2BC,iBAAiB,CAF/C;;EAMC,UAASI,yBAAT,GAAqC;IACpC,IAAID,SAASF,SAAb,EAAwB;MACtBN,oBAAoBU,eAApBV,GAAsC,OAAtCA;IAFkC;EAAtC,CAAC,GAAD;AAnCF;AA0CA,MAAMW,aAAa;EACjBC,QAAQ,IADS;EAEjBC,KAAK,IAFY;EAGjBC,QAAQ,IAHS;EAIjBC,YAAY;AAJK,CAAnB;;AAYA,MAAMC,iBAAiB;EACrBC,sBAAsB;IAEpBhL,OAGM,CAAC,CALa;IAMpBiL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EANjB,CADD;EASrBI,gBAAgB;IAEdlL,OAAO,CAFO;IAGdiL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EAHvB,CATK;EAcrBK,kBAAkB;IAEhBnL,OAAO,CAFS;IAGhBiL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EAHrB,CAdG;EAmBrBM,kBAAkB;IAEhBpL,OAAO,EAFS;IAGhBiL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EAHrB,CAnBG;EAwBrBO,gBAAgB;IAEdrL,OAAO,KAFO;IAGdiL,MAAMP,WAAWC;EAHH,CAxBK;EA6BrBW,mBAAmB;IAEjBtL,OAAO,KAFU;IAGjBiL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EAHpB,CA7BE;EAkCrBS,mBAAmB;IAEjBvL,OAAO,KAFU;IAGjBiL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EAHpB,CAlCE;EAuCrBU,uBAAuB;IAErBxL,OAAO,IAFc;IAGrBiL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EAHhB,CAvCF;EA4CrBW,iBAAiB;IAEfzL,OAA0C,IAF3B;IAGfiL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EAHtB,CA5CI;EAiDrBY,iBAAiB;IAEf1L,OAAO,8BAFQ;IAGfiL,MAAMP,WAAWC;EAHF,CAjDI;EAsDrBgB,oBAAoB;IAElB3L,OAAO,CAFW;IAGlBiL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EAHnB,CAtDC;EA2DrBc,kBAAkB;IAEhB5L,OAAO,KAFS;IAGhBiL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EAHrB,CA3DG;EAgErBe,uBAAuB;IAErB7L,OAAO,KAFc;IAGrBiL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EAHhB,CAhEF;EAqErBgB,oBAAoB;IAElB9L,OAAO,WAFW;IAGlBiL,MAAMP,WAAWC;EAHC,CArEC;EA0ErBF,iBAAiB;IAEfzK,OAAO,QAFQ;IAGfiL,MAAMP,WAAWC;EAHF,CA1EI;EA+ErBoB,iBAAiB;IAEf/L,OAAO,KAFQ;IAGfiL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EAHtB,CA/EI;EAoFrBkB,sBAAsB;IAEpBhM,OAAO,QAFa;IAGpBiL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EAHjB,CApFD;EAyFrBmB,sBAAsB;IAEpBjM,OAAO,YAFa;IAGpBiL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EAHjB,CAzFD;EA8FrBoB,eAAe;IAEblM,OAA0C,KAF7B;IAGbiL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EAHxB,CA9FM;EAmGrBqB,iBAAiB;IAEfnM,OAAO,GAFQ;IAGfiL,MAAMP,WAAWC;EAHF,CAnGI;EAwGrByB,mBAAmB;IAEjBpM,OAAO,CAAC,CAFS;IAGjBiL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EAHpB,CAxGE;EA6GrBuB,kBAAkB;IAEhBrM,OAAO,CAAC,CAFQ;IAGhBiL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EAHrB,CA7GG;EAkHrBwB,kBAAkB;IAEhBtM,OAAO,CAAC,CAFQ;IAGhBiL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EAHrB,CAlHG;EAuHrByB,eAAe;IAEbvM,OAAO,CAFM;IAGbiL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EAHxB,CAvHM;EA4HrB0B,gBAAgB;IAEdxM,OAAO,KAFO;IAGdiL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EAHvB,CA5HK;EAiIrB2B,gBAAgB;IAEdzM,OAAwE,CAF1D;IAGdiL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EAHvB,CAjIK;EAsIrB4B,YAAY;IAEV1M,OAAO,CAFG;IAGViL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EAH3B,CAtIS;EA4IrB6B,YAAY;IAEV3M,OAAO,IAFG;IAGViL,MAAMP,WAAWE;EAHP,CA5IS;EAiJrBgC,SAAS;IAEP5M,OAGM,eALC;IAMPiL,MAAMP,WAAWE;EANV,CAjJY;EAyJrBiC,kBAAkB;IAEhB7M,OAAO,KAFS;IAGhBiL,MAAMP,WAAWE,GAAXF,GAAiBA,WAAWI;EAHlB,CAzJG;EA8JrBgC,iBAAiB;IAEf9M,OAAO,KAFQ;IAGfiL,MAAMP,WAAWE,GAAXF,GAAiBA,WAAWI;EAHnB,CA9JI;EAmKrBiC,cAAc;IAEZ/M,OAAO,KAFK;IAGZiL,MAAMP,WAAWE,GAAXF,GAAiBA,WAAWI;EAHtB,CAnKO;EAwKrBkC,eAAe;IAEbhN,OAAO,KAFM;IAGbiL,MAAMP,WAAWE,GAAXF,GAAiBA,WAAWI;EAHrB,CAxKM;EA6KrBmC,YAAY;IAEVjN,OAAO,EAFG;IAGViL,MAAMP,WAAWE;EAHP,CA7KS;EAkLrBsC,WAAW;IAETlN,OAAO,IAFE;IAGTiL,MAAMP,WAAWE,GAAXF,GAAiBA,WAAWI;EAHzB,CAlLU;EAuLrBqC,qBAAqB;IAEnBnN,OAAO,KAFY;IAGnBiL,MAAMP,WAAWE;EAHE,CAvLA;EA4LrBwC,iBAAiB;IAEfpN,OAAO,IAFQ;IAGfiL,MAAMP,WAAWE;EAHF,CA5LI;EAiMrByC,cAAc;IAEZrN,OAAO,CAAC,CAFI;IAGZiL,MAAMP,WAAWE;EAHL,CAjMO;EAsMrB0C,QAAQ;IAENtN,OAAO,KAFD;IAGNiL,MAAMP,WAAWE;EAHX,CAtMa;EA2MrB2C,qBAAqB;IAEnBvN,OAGM,wBALa;IAMnBiL,MAAMP,WAAWE;EANE,CA3MA;EAmNrB4C,WAAW;IAETxN,OAAO,CAFE;IAGTiL,MAAMP,WAAWE;EAHR,CAnNU;EAyNrB6C,YAAY;IAEVzN,OAAO,IAFG;IAGViL,MAAMP,WAAWG;EAHP,CAzNS;EA8NrB6C,WAAW;IAET1N,OAGM,wBALG;IAMTiL,MAAMP,WAAWG;EANR;AA9NU,CAAvB;AA0OE;EACAE,eAAe4C,UAAf5C,GAA4B;IAE1B/K,OAAO,oCAFmB;IAG1BiL,MAAMP,WAAWC;EAHS,CAA5BI;EAKAA,eAAe6C,kBAAf7C,GAAoC;IAElC/K,OAA0C,KAFR;IAGlCiL,MAAMP,WAAWC;EAHiB,CAApCI;EAKAA,eAAe8C,MAAf9C,GAAwB;IAEtB/K,OAAOkK,UAAU4D,QAAV5D,IAAsB,OAFP;IAGtBe,MAAMP,WAAWC;EAHK,CAAxBI;EAKAA,eAAegD,QAAfhD,GAA0B;IAExB/K,OAAO,QAFiB;IAGxBiL,MAAMP,WAAWC,MAAXD,GAAoBA,WAAWI;EAHb,CAA1BC;EAKAA,eAAeiD,gBAAfjD,GAAkC;IAEhC/K,OAGM,yBAL0B;IAMhCiL,MAAMP,WAAWC;EANe,CAAlCI;AArTF;AA+UA,MAAMkD,cAAc9G,OAAO6C,MAAP7C,CAAc,IAAdA,CAApB;;AAEA,MAAM+G,UAAN,CAAiB;EACf1R,cAAc;IACZ,MAAM,IAAI6L,KAAJ,CAAU,+BAAV,CAAN;EAFa;;EAKf,OAAO8F,GAAP,CAAWC,IAAX,EAAiB;IACf,MAAMC,aAAaJ,YAAYG,IAAZ,CAAnB;;IACA,IAAIC,eAAe/P,SAAnB,EAA8B;MAC5B,OAAO+P,UAAP;IAHa;;IAKf,MAAMC,gBAAgBvD,eAAeqD,IAAf,CAAtB;;IACA,IAAIE,kBAAkBhQ,SAAtB,EAAiC;MAAA;;MAC/B,gCAAOyL,oBAAoBqE,IAApB,CAAP,yEAAoCE,cAActO,KAAlD;IAPa;;IASf,OAAO1B,SAAP;EAda;;EAiBf,OAAOiQ,MAAP,GAA2B;IAAA,IAAbtD,IAAa,uEAAN,IAAM;IACzB,MAAMuD,UAAUrH,OAAO6C,MAAP7C,CAAc,IAAdA,CAAhB;;IACA,WAAWiH,IAAX,IAAmBrD,cAAnB,EAAmC;MAAA;;MACjC,MAAMuD,gBAAgBvD,eAAeqD,IAAf,CAAtB;;MACA,IAAInD,IAAJ,EAAU;QACR,IAAK,QAAOqD,cAAcrD,IAArB,MAA+B,CAApC,EAAuC;UACrC;QAFM;;QAIR,IAAIA,SAASP,WAAWI,UAAxB,EAAoC;UAClC,MAAM9K,QAAQsO,cAActO,KAA5B;UAAA,MACEyO,YAAY,OAAOzO,KADrB;;UAGA,IACEyO,cAAc,SAAdA,IACAA,cAAc,QADdA,IAECA,cAAc,QAAdA,IAA0B1H,OAAOC,SAAPD,CAAiB/G,KAAjB+G,CAH7B,EAIE;YACAyH,QAAQJ,IAAR,IAAgBpO,KAAhBwO;YACA;UAVgC;;UAYlC,MAAM,IAAInG,KAAJ,CAAW,gCAA+B+F,IAAhC,EAAV,CAAN;QAhBM;MAFuB;;MAqBjC,MAAMC,aAAaJ,YAAYG,IAAZ,CAAnB;MACAI,QAAQJ,IAAR,IACEC,eAAe/P,SAAf+P,GACIA,UADJA,6BAEItE,oBAAoBqE,IAApB,CAFJC,2EAEiCC,cAActO,KAHjDwO;IAxBuB;;IA6BzB,OAAOA,OAAP;EA9Ca;;EAiDf,OAAOtO,GAAP,CAAWkO,IAAX,EAAiBpO,KAAjB,EAAwB;IACtBiO,YAAYG,IAAZ,IAAoBpO,KAApBiO;EAlDa;;EAqDf,OAAOS,MAAP,CAAcF,OAAd,EAAuB;IACrB,WAAWJ,IAAX,IAAmBI,OAAnB,EAA4B;MAC1BP,YAAYG,IAAZ,IAAoBI,QAAQJ,IAAR,CAApBH;IAFmB;EArDR;;EA2Df,OAAOvF,MAAP,CAAc0F,IAAd,EAAoB;IAClB,OAAOH,YAAYG,IAAZ,CAAP;EA5Da;;EAkEf,OAAOO,eAAP,GAAyB;IACvB,OAAOxH,OAAOyH,IAAPzH,CAAY8G,WAAZ9G,EAAyBnG,MAAzBmG,GAAkC,CAAzC;EAnEa;;AAAA;;;;;;;;;;;;;;;AC/TjB;;;;;;;;;;;;;;;;;;;;AAEA,MAAM0H,mBAAmB,8BAAzB;AAEA,MAAMC,aAAa;EACjB5T,MAAM,CADW;EAEjB6T,MAAM,CAFW;EAGjBC,OAAO,CAHU;EAIjBC,QAAQ,CAJS;EAKjBC,KAAK;AALY,CAAnB;;;AAwBA,SAASC,iBAAT,CAA2BC,IAA3B,EAA4E;EAAA,IAA3C;IAAEC,GAAF;IAAOC,MAAP;IAAeC,GAAf;IAAoBC,UAAU;EAA9B,CAA2C,uEAAJ,EAAI;;EAC1E,IAAI,CAACH,GAAD,IAAQ,OAAOA,GAAP,KAAe,QAA3B,EAAqC;IACnC,MAAM,IAAIhH,KAAJ,CAAU,wCAAV,CAAN;EAFwE;;EAK1E,MAAMoH,iBAAiBnP,oCAAqB+O,GAArB/O,CAAvB;;EACA,IAAIkP,OAAJ,EAAa;IACXJ,KAAKM,IAALN,GAAYA,KAAKO,KAALP,GAAaK,cAAzBL;EADF,OAEO;IACLA,KAAKM,IAALN,GAAY,EAAZA;IACAA,KAAKO,KAALP,GAAc,aAAYK,cAAb,EAAbL;;IACAA,KAAKQ,OAALR,GAAe,MAAM;MACnB,OAAO,KAAP;IADF;EAXwE;;EAgB1E,IAAIS,YAAY,EAAhB;;EACA,QAAQP,MAAR;IACE,KAAKR,WAAW5T,IAAhB;MACE;;IACF,KAAK4T,WAAWC,IAAhB;MACEc,YAAY,OAAZA;MACA;;IACF,KAAKf,WAAWE,KAAhB;MACEa,YAAY,QAAZA;MACA;;IACF,KAAKf,WAAWG,MAAhB;MACEY,YAAY,SAAZA;MACA;;IACF,KAAKf,WAAWI,GAAhB;MACEW,YAAY,MAAZA;MACA;EAdJ;;EAgBAT,KAAKE,MAALF,GAAcS,SAAdT;EAEAA,KAAKG,GAALH,GAAW,OAAOG,GAAP,KAAe,QAAf,GAA0BA,GAA1B,GAAgCV,gBAA3CO;AAjFF;;;;;;AAsGA,MAAMU,cAAN,CAAqB;EAMnBtT,cAKQ;IAAA,IALI;MACVuT,QADU;MAEVpE,qBAAqB,IAFX;MAGVD,kBAAkB,IAHR;MAIVG,wBAAwB;IAJd,CAKJ,uEAAJ,EAAI;;IAAA;;IAAA;MAAA;MAAA,OAVS,IAAI/L,GAAJ;IAUT;;IACN,KAAKiQ,QAAL,GAAgBA,QAAhB;IACA,KAAKpE,kBAAL,GAA0BA,kBAA1B;IACA,KAAKD,eAAL,GAAuBA,eAAvB;IACA,KAAKsE,mBAAL,GAA2B,IAA3B;IACA,KAAKC,sBAAL,GAA8BpE,qBAA9B;IAEA,KAAKqE,OAAL,GAAe,IAAf;IACA,KAAKC,WAAL,GAAmB,IAAnB;IACA,KAAKC,SAAL,GAAiB,IAAjB;IACA,KAAKC,UAAL,GAAkB,IAAlB;EArBiB;;EAwBnBC,YAAYH,WAAZ,EAAyC;IAAA,IAAhBD,OAAgB,uEAAN,IAAM;IACvC,KAAKA,OAAL,GAAeA,OAAf;IACA,KAAKC,WAAL,GAAmBA,WAAnB;;IACA,4CAAoBI,KAApB;EA3BiB;;EA8BnBC,UAAUJ,SAAV,EAAqB;IACnB,KAAKA,SAAL,GAAiBA,SAAjB;EA/BiB;;EAkCnBK,WAAWJ,UAAX,EAAuB;IACrB,KAAKA,UAAL,GAAkBA,UAAlB;EAnCiB;;EAyCnB,IAAIK,UAAJ,GAAiB;IACf,OAAO,KAAKP,WAAL,GAAmB,KAAKA,WAAL,CAAiBQ,QAApC,GAA+C,CAAtD;EA1CiB;;EAgDnB,IAAIC,IAAJ,GAAW;IACT,OAAO,KAAKR,SAAL,CAAeS,iBAAtB;EAjDiB;;EAuDnB,IAAID,IAAJ,CAAS5Q,KAAT,EAAgB;IACd,KAAKoQ,SAAL,CAAeS,iBAAf,GAAmC7Q,KAAnC;EAxDiB;;EA8DnB,IAAI8Q,QAAJ,GAAe;IACb,OAAO,KAAKV,SAAL,CAAeW,aAAtB;EA/DiB;;EAqEnB,IAAID,QAAJ,CAAa9Q,KAAb,EAAoB;IAClB,KAAKoQ,SAAL,CAAeW,aAAf,GAA+B/Q,KAA/B;EAtEiB;;EAsInB,MAAMgR,eAAN,CAAsBC,IAAtB,EAA4B;IAC1B,IAAI,CAAC,KAAKd,WAAV,EAAuB;MACrB;IAFwB;;IAI1B,IAAIe,SAAJ,EAAeC,YAAf;;IACA,IAAI,OAAOF,IAAP,KAAgB,QAApB,EAA8B;MAC5BC,YAAYD,IAAZC;MACAC,eAAe,MAAM,KAAKhB,WAAL,CAAiBiB,cAAjB,CAAgCH,IAAhC,CAArBE;IAFF,OAGO;MACLD,YAAY,IAAZA;MACAC,eAAe,MAAMF,IAArBE;IAVwB;;IAY1B,IAAI,CAACE,MAAMC,OAAND,CAAcF,YAAdE,CAAL,EAAkC;MAChChU,QAAQC,KAARD,CACG,oCAAmC8T,YAAa,WAAjD,GACG,wCAAuCF,IAAK,IAFjD5T;MAIA;IAjBwB;;IAmB1B,yFAA4B4T,IAA5B,EAAkCC,SAAlC,EAA6CC,YAA7C;EAzJiB;;EAiKnBI,SAAS/I,GAAT,EAAc;IACZ,IAAI,CAAC,KAAK2H,WAAV,EAAuB;MACrB;IAFU;;IAIZ,MAAMqB,aACH,OAAOhJ,GAAP,KAAe,QAAf,IAA2B,KAAK4H,SAAL,CAAeqB,qBAAf,CAAqCjJ,GAArC,CAA3B,IACDA,MAAM,CAFR;;IAGA,IACE,EACEzB,OAAOC,SAAPD,CAAiByK,UAAjBzK,KACAyK,aAAa,CADbzK,IAEAyK,cAAc,KAAKd,UAHrB,CADF,EAME;MACArT,QAAQC,KAARD,CAAe,6BAA4BmL,GAAI,wBAA/CnL;MACA;IAfU;;IAkBZ,IAAI,KAAKgT,UAAT,EAAqB;MAGnB,KAAKA,UAAL,CAAgBqB,mBAAhB;MACA,KAAKrB,UAAL,CAAgBsB,QAAhB,CAAyBH,UAAzB;IAtBU;;IAyBZ,KAAKpB,SAAL,CAAewB,kBAAf,CAAkC;MAAEJ;IAAF,CAAlC;EA1LiB;;EAmMnBrC,kBAAkBC,IAAlB,EAAwBC,GAAxB,EAAgD;IAAA,IAAnBwC,SAAmB,uEAAP,KAAO;IAC9C1C,kBAAkBC,IAAlB,EAAwB;MACtBC,GADsB;MAEtBC,QAAQuC,YAAY/C,WAAWE,KAAvB,GAA+B,KAAKrD,kBAFtB;MAGtB4D,KAAK,KAAK7D,eAHY;MAItB8D,SAAS,KAAKQ;IAJQ,CAAxB;EApMiB;;EAgNnB8B,mBAAmBb,IAAnB,EAAyB;IACvB,IAAI,OAAOA,IAAP,KAAgB,QAApB,EAA8B;MAC5B,IAAIA,KAAKjQ,MAALiQ,GAAc,CAAlB,EAAqB;QACnB,OAAO,KAAKc,YAAL,CAAkB,MAAMC,OAAOf,IAAP,CAAxB,CAAP;MAF0B;IAA9B,OAIO,IAAII,MAAMC,OAAND,CAAcJ,IAAdI,CAAJ,EAAyB;MAC9B,MAAM9Q,MAAM0R,KAAKC,SAALD,CAAehB,IAAfgB,CAAZ;;MACA,IAAI1R,IAAIS,MAAJT,GAAa,CAAjB,EAAoB;QAClB,OAAO,KAAKwR,YAAL,CAAkB,MAAMC,OAAOzR,GAAP,CAAxB,CAAP;MAH4B;IALT;;IAWvB,OAAO,KAAKwR,YAAL,CAAkB,EAAlB,CAAP;EA3NiB;;EAoOnBA,aAAaI,MAAb,EAAqB;IACnB,OAAQ,MAAKjC,OAAL,IAAgB,EAAhB,IAAsBiC,MAA9B;EArOiB;;EA2OnBC,QAAQC,IAAR,EAAc;IACZ,IAAI,CAAC,KAAKlC,WAAV,EAAuB;MACrB;IAFU;;IAIZ,IAAIqB,UAAJ,EAAgBP,IAAhB;;IACA,IAAIoB,KAAKhL,QAALgL,CAAc,GAAdA,CAAJ,EAAwB;MACtB,MAAMxS,SAASF,gCAAiB0S,IAAjB1S,CAAf;;MACA,IAAIE,OAAOyS,GAAPzS,CAAW,QAAXA,CAAJ,EAA0B;QACxB,KAAKkQ,QAAL,CAAcwC,QAAd,CAAuB,iBAAvB,EAA0C;UACxCC,QAAQ,IADgC;UAExC5S,OAAOC,OAAOsO,GAAPtO,CAAW,QAAXA,EAAqBY,OAArBZ,CAA6B,IAA7BA,EAAmC,EAAnCA,CAFiC;UAGxC4S,cAAc5S,OAAOsO,GAAPtO,CAAW,QAAXA,MAAyB;QAHC,CAA1C;MAHoB;;MAUtB,IAAIA,OAAOyS,GAAPzS,CAAW,MAAXA,CAAJ,EAAwB;QACtB2R,aAAa3R,OAAOsO,GAAPtO,CAAW,MAAXA,IAAqB,CAArBA,IAA0B,CAAvC2R;MAXoB;;MAatB,IAAI3R,OAAOyS,GAAPzS,CAAW,MAAXA,CAAJ,EAAwB;QAEtB,MAAM6S,WAAW7S,OAAOsO,GAAPtO,CAAW,MAAXA,EAAmB8S,KAAnB9S,CAAyB,GAAzBA,CAAjB;QACA,MAAM+S,UAAUF,SAAS,CAAT,CAAhB;QACA,MAAMG,gBAAgBC,WAAWF,OAAX,CAAtB;;QAEA,IAAI,CAACA,QAAQvL,QAARuL,CAAiB,KAAjBA,CAAL,EAA8B;UAG5B3B,OAAO,CACL,IADK,EAEL;YAAE7C,MAAM;UAAR,CAFK,EAGLsE,SAAS1R,MAAT0R,GAAkB,CAAlBA,GAAsBA,SAAS,CAAT,IAAc,CAApCA,GAAwC,IAHnC,EAILA,SAAS1R,MAAT0R,GAAkB,CAAlBA,GAAsBA,SAAS,CAAT,IAAc,CAApCA,GAAwC,IAJnC,EAKLG,gBAAgBA,gBAAgB,GAAhC,GAAsCD,OALjC,CAAP3B;QAHF,OAUO;UACL,IAAI2B,YAAY,KAAZA,IAAqBA,YAAY,MAArC,EAA6C;YAC3C3B,OAAO,CAAC,IAAD,EAAO;cAAE7C,MAAMwE;YAAR,CAAP,CAAP3B;UADF,OAEO,IACL2B,YAAY,MAAZA,IACAA,YAAY,OADZA,IAEAA,YAAY,MAFZA,IAGAA,YAAY,OAJP,EAKL;YACA3B,OAAO,CACL,IADK,EAEL;cAAE7C,MAAMwE;YAAR,CAFK,EAGLF,SAAS1R,MAAT0R,GAAkB,CAAlBA,GAAsBA,SAAS,CAAT,IAAc,CAApCA,GAAwC,IAHnC,CAAPzB;UANK,OAWA,IAAI2B,YAAY,MAAhB,EAAwB;YAC7B,IAAIF,SAAS1R,MAAT0R,KAAoB,CAAxB,EAA2B;cACzBrV,QAAQC,KAARD,CACE,2DADFA;YADF,OAIO;cACL4T,OAAO,CACL,IADK,EAEL;gBAAE7C,MAAMwE;cAAR,CAFK,EAGLF,SAAS,CAAT,IAAc,CAHT,EAILA,SAAS,CAAT,IAAc,CAJT,EAKLA,SAAS,CAAT,IAAc,CALT,EAMLA,SAAS,CAAT,IAAc,CANT,CAAPzB;YAN2B;UAAxB,OAeA;YACL5T,QAAQC,KAARD,CACG,4BAA2BuV,OAAQ,8BADtCvV;UA9BG;QAhBe;MAbF;;MAiEtB,IAAI4T,IAAJ,EAAU;QACR,KAAKb,SAAL,CAAewB,kBAAf,CAAkC;UAChCJ,YAAYA,cAAc,KAAKZ,IADC;UAEhCmC,WAAW9B,IAFqB;UAGhC+B,qBAAqB;QAHW,CAAlC;MADF,OAMO,IAAIxB,UAAJ,EAAgB;QACrB,KAAKZ,IAAL,GAAYY,UAAZ;MAxEoB;;MA0EtB,IAAI3R,OAAOyS,GAAPzS,CAAW,UAAXA,CAAJ,EAA4B;QAC1B,KAAKkQ,QAAL,CAAcwC,QAAd,CAAuB,UAAvB,EAAmC;UACjCC,QAAQ,IADyB;UAEjCtL,MAAMrH,OAAOsO,GAAPtO,CAAW,UAAXA;QAF2B,CAAnC;MA3EoB;;MAkFtB,IAAIA,OAAOyS,GAAPzS,CAAW,WAAXA,CAAJ,EAA6B;QAC3B,KAAKmR,eAAL,CAAqBnR,OAAOsO,GAAPtO,CAAW,WAAXA,CAArB;MAnFoB;IAAxB,OAqFO;MAELoR,OAAOgC,SAASZ,IAAT,CAAPpB;;MACA,IAAI;QACFA,OAAOgB,KAAKiB,KAALjB,CAAWhB,IAAXgB,CAAPhB;;QAEA,IAAI,CAACI,MAAMC,OAAND,CAAcJ,IAAdI,CAAL,EAA0B;UAGxBJ,OAAOA,KAAKkC,QAALlC,EAAPA;QANA;MAAJ,EAQE,OAAOmC,EAAP,EAAW,CAXR;;MAaL,IACE,OAAOnC,IAAP,KAAgB,QAAhB,iCACAnB,cADA,EAnVFA,cAmVE,oCACAA,cADA,EAC2CmB,IAD3C,CADF,EAGE;QACA,KAAKD,eAAL,CAAqBC,IAArB;QACA;MAlBG;;MAoBL5T,QAAQC,KAARD,CACG,4BAA2B4V,SAC1BZ,IAD0B,CAE1B,+BAHJhV;IA9GU;EA3OK;;EAoWnBgW,mBAAmBC,MAAnB,EAA2B;IAAA;;IAEzB,QAAQA,MAAR;MACE,KAAK,QAAL;QACE,yBAAKjD,UAAL,sEAAiBkD,IAAjB;QACA;;MAEF,KAAK,WAAL;QACE,0BAAKlD,UAAL,wEAAiBmD,OAAjB;QACA;;MAEF,KAAK,UAAL;QACE,KAAKpD,SAAL,CAAeqD,QAAf;QACA;;MAEF,KAAK,UAAL;QACE,KAAKrD,SAAL,CAAesD,YAAf;QACA;;MAEF,KAAK,UAAL;QACE,KAAK9C,IAAL,GAAY,KAAKF,UAAjB;QACA;;MAEF,KAAK,WAAL;QACE,KAAKE,IAAL,GAAY,CAAZ;QACA;;MAEF;QACE;IA1BJ;;IA6BA,KAAKb,QAAL,CAAcwC,QAAd,CAAuB,aAAvB,EAAsC;MACpCC,QAAQ,IAD4B;MAEpCc;IAFoC,CAAtC;EAnYiB;;EA6YnBK,aAAaC,OAAb,EAAsBC,OAAtB,EAA+B;IAC7B,IAAI,CAACA,OAAL,EAAc;MACZ;IAF2B;;IAI7B,MAAMC,SACJD,QAAQE,GAARF,KAAgB,CAAhBA,GAAoB,GAAGA,QAAQG,GAAI,GAAnCH,GAAwC,GAAGA,QAAQG,GAAI,IAAGH,QAAQE,GAA1B,EAD1C;;IAEA,4CAAoB7T,GAApB,CAAwB4T,MAAxB,EAAgCF,OAAhC;EAnZiB;;EAyZnBK,kBAAkBJ,OAAlB,EAA2B;IACzB,IAAI,CAACA,OAAL,EAAc;MACZ,OAAO,IAAP;IAFuB;;IAIzB,MAAMC,SACJD,QAAQE,GAARF,KAAgB,CAAhBA,GAAoB,GAAGA,QAAQG,GAAI,GAAnCH,GAAwC,GAAGA,QAAQG,GAAI,IAAGH,QAAQE,GAA1B,EAD1C;IAEA,OAAO,4CAAoB5F,GAApB,CAAwB2F,MAAxB,KAAmC,IAA1C;EA/ZiB;;EAqanBI,cAAc1C,UAAd,EAA0B;IACxB,OAAO,KAAKpB,SAAL,CAAe8D,aAAf,CAA6B1C,UAA7B,CAAP;EAtaiB;;EA4anB2C,aAAa3C,UAAb,EAAyB;IACvB,OAAO,KAAKpB,SAAL,CAAe+D,YAAf,CAA4B3C,UAA5B,CAAP;EA7aiB;;AAAA;;;;iCAyEI4C,SAAyC;EAAA,IAAhClD,SAAgC,uEAApB,IAAoB;EAAA,IAAdC,YAAc;EAE9D,MAAMkD,UAAUlD,aAAa,CAAb,CAAhB;EACA,IAAIK,UAAJ;;EAEA,IAAI,OAAO6C,OAAP,KAAmB,QAAnB,IAA+BA,YAAY,IAA/C,EAAqD;IACnD7C,aAAa,KAAKyC,iBAAL,CAAuBI,OAAvB,CAAb7C;;IAEA,IAAI,CAACA,UAAL,EAAiB;MAGf,KAAKrB,WAAL,CACGmE,YADH,CACgBD,OADhB,EAEGE,IAFH,CAEQC,aAAa;QACjB,KAAKb,YAAL,CAAkBa,YAAY,CAA9B,EAAiCH,OAAjC;;QACA,yFAA4BD,OAA5B,EAAqClD,SAArC,EAAgDC,YAAhD;MAJJ,GAMGsD,KANH,CAMS,MAAM;QACXpX,QAAQC,KAARD,CACG,2CAA0CgX,OAAQ,WAAnD,GACG,qCAAoCD,OAAQ,IAFjD/W;MAPJ;MAYA;IAlBiD;EAArD,OAoBO,IAAI0J,OAAOC,SAAPD,CAAiBsN,OAAjBtN,CAAJ,EAA+B;IACpCyK,aAAa6C,UAAU,CAAvB7C;EADK,OAEA;IACLnU,QAAQC,KAARD,CACG,2CAA0CgX,OAAQ,WAAnD,GACG,4CAA2CD,OAAQ,IAFxD/W;IAIA;EAhC4D;;EAkC9D,IAAI,CAACmU,UAAD,IAAeA,aAAa,CAA5B,IAAiCA,aAAa,KAAKd,UAAvD,EAAmE;IACjErT,QAAQC,KAARD,CACG,2CAA0CmU,UAAW,WAAtD,GACG,kCAAiC4C,OAAQ,IAF9C/W;IAIA;EAvC4D;;EA0C9D,IAAI,KAAKgT,UAAT,EAAqB;IAGnB,KAAKA,UAAL,CAAgBqB,mBAAhB;IACA,KAAKrB,UAAL,CAAgBlL,IAAhB,CAAqB;MAAE+L,SAAF;MAAaC,YAAb;MAA2BK;IAA3B,CAArB;EA9C4D;;EAiD9D,KAAKpB,SAAL,CAAewB,kBAAf,CAAkC;IAChCJ,UADgC;IAEhCuB,WAAW5B,YAFqB;IAGhCtF,uBAAuB,KAAKoE;EAHI,CAAlC;AA1HiB;;qCAgbgBgB,MAAM;EACvC,IAAI,CAACI,MAAMC,OAAND,CAAcJ,IAAdI,CAAL,EAA0B;IACxB,OAAO,KAAP;EAFqC;;EAIvC,MAAMqD,aAAazD,KAAKjQ,MAAxB;;EACA,IAAI0T,aAAa,CAAjB,EAAoB;IAClB,OAAO,KAAP;EANqC;;EAQvC,MAAM9D,OAAOK,KAAK,CAAL,CAAb;;EACA,IACE,EACE,OAAOL,IAAP,KAAgB,QAAhB,IACA7J,OAAOC,SAAPD,CAAiB6J,KAAKoD,GAAtBjN,CADA,IAEAA,OAAOC,SAAPD,CAAiB6J,KAAKmD,GAAtBhN,CAHF,KAKA,EAAEA,OAAOC,SAAPD,CAAiB6J,IAAjB7J,KAA0B6J,QAAQ,CAApC,CANF,EAOE;IACA,OAAO,KAAP;EAjBqC;;EAmBvC,MAAM+D,OAAO1D,KAAK,CAAL,CAAb;;EACA,IAAI,EAAE,OAAO0D,IAAP,KAAgB,QAAhB,IAA4B,OAAOA,KAAKvG,IAAZ,KAAqB,QAAnD,CAAJ,EAAkE;IAChE,OAAO,KAAP;EArBqC;;EAuBvC,IAAIwG,YAAY,IAAhB;;EACA,QAAQD,KAAKvG,IAAb;IACE,KAAK,KAAL;MACE,IAAIsG,eAAe,CAAnB,EAAsB;QACpB,OAAO,KAAP;MAFJ;;MAIE;;IACF,KAAK,KAAL;IACA,KAAK,MAAL;MACE,OAAOA,eAAe,CAAtB;;IACF,KAAK,MAAL;IACA,KAAK,OAAL;IACA,KAAK,MAAL;IACA,KAAK,OAAL;MACE,IAAIA,eAAe,CAAnB,EAAsB;QACpB,OAAO,KAAP;MAFJ;;MAIE;;IACF,KAAK,MAAL;MACE,IAAIA,eAAe,CAAnB,EAAsB;QACpB,OAAO,KAAP;MAFJ;;MAIEE,YAAY,KAAZA;MACA;;IACF;MACE,OAAO,KAAP;EAxBJ;;EA0BA,KAAK,IAAIvR,IAAI,CAAb,EAAgBA,IAAIqR,UAApB,EAAgCrR,GAAhC,EAAqC;IACnC,MAAMwR,QAAQ5D,KAAK5N,CAAL,CAAd;;IACA,IAAI,EAAE,OAAOwR,KAAP,KAAiB,QAAjB,IAA8BD,aAAaC,UAAU,IAAvD,CAAJ,EAAmE;MACjE,OAAO,KAAP;IAHiC;EAlDE;;EAwDvC,OAAO,IAAP;AAxeiB;;AA+erB,MAAMC,iBAAN,CAAwB;EACtBtY,cAAc;IACZ,KAAKwT,mBAAL,GAA2B,IAA3B;EAFoB;;EAQtB,IAAIU,UAAJ,GAAiB;IACf,OAAO,CAAP;EAToB;;EAetB,IAAIE,IAAJ,GAAW;IACT,OAAO,CAAP;EAhBoB;;EAsBtB,IAAIA,IAAJ,CAAS5Q,KAAT,EAAgB,CAtBM;;EA2BtB,IAAI8Q,QAAJ,GAAe;IACb,OAAO,CAAP;EA5BoB;;EAkCtB,IAAIA,QAAJ,CAAa9Q,KAAb,EAAoB,CAlCE;;EAuCtB,MAAMgR,eAAN,CAAsBC,IAAtB,EAA4B,CAvCN;;EA4CtBM,SAAS/I,GAAT,EAAc,CA5CQ;;EAmDtB2G,kBAAkBC,IAAlB,EAAwBC,GAAxB,EAAgD;IAAA,IAAnBwC,SAAmB,uEAAP,KAAO;IAC9C1C,kBAAkBC,IAAlB,EAAwB;MAAEC,GAAF;MAAOG,SAAS,KAAKQ;IAArB,CAAxB;EApDoB;;EA2DtB8B,mBAAmBb,IAAnB,EAAyB;IACvB,OAAO,GAAP;EA5DoB;;EAmEtBc,aAAaM,IAAb,EAAmB;IACjB,OAAO,GAAP;EApEoB;;EA0EtBD,QAAQC,IAAR,EAAc,CA1EQ;;EA+EtBgB,mBAAmBC,MAAnB,EAA2B,CA/EL;;EAqFtBK,aAAaC,OAAb,EAAsBC,OAAtB,EAA+B,CArFT;;EA0FtBK,cAAc1C,UAAd,EAA0B;IACxB,OAAO,IAAP;EA3FoB;;EAiGtB2C,aAAa3C,UAAb,EAAyB;IACvB,OAAO,IAAP;EAlGoB;;AAAA;;;;;;;;;;;;;;;ACtkBxB;;AAqBA;;AAmBA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AAEA,MAAMuD,yCAAyC,IAA/C;AACA,MAAMC,6BAA6B,KAAnC;AACA,MAAMC,8BAA8B,IAApC;AAEA,MAAMC,aAAa;EACjBra,SAAS,CAAC,CADO;EAEjBsa,UAAU,CAFO;EAGjB3a,SAAS;AAHQ,CAAnB;AAMA,MAAM4a,iBAAiB;EACrBC,WAAW,CADU;EAErBC,OAAO,CAFc;EAGrBC,MAAM;AAHe,CAAvB;AAOA,MAAMC,iBAAiB,CACrB,KADqB,EAErB,KAFqB,EAGrB,KAHqB,EAIrB,KAJqB,EAKrB,KALqB,EAMrB,KANqB,EAOrB,KAPqB,EAQrB,KARqB,EASrB,KATqB,EAUrB,KAVqB,EAWrB,KAXqB,EAYrB,KAZqB,EAarB,KAbqB,EAcrB,KAdqB,CAAvB;AAiBA,MAAMC,mBAAmB,CACvB,mBADuB,EAEvB,mBAFuB,EAGvB,iBAHuB,EAIvB,mBAJuB,EAKvB,iBALuB,EAMvB,aANuB,EAOvB,OAPuB,EAQvB,OARuB,EASvB,SATuB,EAUvB,OAVuB,EAWvB,QAXuB,EAYvB,QAZuB,EAavB,OAbuB,EAcvB,QAduB,EAevB,aAfuB,EAgBvB,UAhBuB,EAiBvB,WAjBuB,EAkBvB,YAlBuB,EAmBvB,QAnBuB,EAoBvB,cApBuB,EAqBvB,aArBuB,EAsBvB,eAtBuB,EAuBvB,cAvBuB,EAwBvB,MAxBuB,CAAzB;;AA2BA,MAAMC,uBAAN,CAA8B;EAC5BlZ,cAAc;IACZ,MAAM,IAAI6L,KAAJ,CAAU,4CAAV,CAAN;EAF0B;;EAK5B,OAAOsN,sBAAP,CAA8BC,IAA9B,EAAoC,CALR;;EAO5B,OAAOC,sBAAP,CAA8BD,IAA9B,EAAoC,CAPR;;EAS5B,OAAOE,kBAAP,CAA0BC,SAA1B,EAAqC,CATT;;EAW5B,OAAOC,eAAP,CAAuBJ,IAAvB,EAA6B,CAXD;;EAa5B,OAAOK,qBAAP,CAA6BzH,OAA7B,EAAsC;IACpC,MAAM,IAAInG,KAAJ,CAAU,wCAAV,CAAN;EAd0B;;EAiB5B,OAAO6N,iBAAP,GAA2B;IACzB,MAAM,IAAI7N,KAAJ,CAAU,oCAAV,CAAN;EAlB0B;;EAqB5B,OAAO8N,UAAP,CAAkB3H,OAAlB,EAA2B;IACzB,MAAM,IAAInG,KAAJ,CAAU,6BAAV,CAAN;EAtB0B;;EAyB5B,OAAO+N,eAAP,CAAuB5H,OAAvB,EAAgC;IAC9B,MAAM,IAAInG,KAAJ,CAAU,kCAAV,CAAN;EA1B0B;;EA6B5B,WAAWgO,sBAAX,GAAoC;IAClC,OAAOC,sBAAO,IAAPA,EAAa,wBAAbA,EAAuC,KAAvCA,CAAP;EA9B0B;;EAiC5B,WAAWC,qBAAX,GAAmC;IACjC,OAAOD,sBAAO,IAAPA,EAAa,uBAAbA,EAAsC,IAAtCA,CAAP;EAlC0B;;EAqC5B,WAAWE,mCAAX,GAAiD;IAC/C,OAAOF,sBAAO,IAAPA,EAAa,qCAAbA,EAAoD;MACzDG,SAAS,IADgD;MAEzDC,SAAS;IAFgD,CAApDJ,CAAP;EAtC0B;;EA4C5B,WAAWK,cAAX,GAA4B;IAC1B,OAAOL,sBAAO,IAAPA,EAAa,gBAAbA,EAA+B,KAA/BA,CAAP;EA7C0B;;EAgD5B,OAAOM,kBAAP,CAA0BhB,IAA1B,EAAgC;IAC9B,MAAM,IAAIvN,KAAJ,CAAU,qCAAV,CAAN;EAjD0B;;AAAA;;;AAqD9B,MAAMwO,uBAAuB;EAC3BC,iBAAiBjP,SAASkP,QAATlP,CAAkBwK,IAAlBxK,CAAuBmP,SAAvBnP,CAAiC,CAAjCA,CADU;EAE3BoP,wBAAwBC,wCAFG;EAG3BC,WAAW,IAHgB;EAI3BhH,aAAa,IAJc;EAK3BiH,gBAAgB,IALW;EAM3BC,cAAc,IANa;EAQ3BjH,WAAW,IARgB;EAU3BkH,oBAAoB,IAVO;EAY3BC,mBAAmB,IAZQ;EAc3BC,qBAAqB,IAdM;EAgB3BC,uBAAuB,IAhBI;EAkB3BC,gBAAgB,IAlBW;EAoB3BrH,YAAY,IApBe;EAsB3BsH,YAAY,IAtBe;EAwB3BC,mBAAmB,IAxBQ;EA0B3BC,kBAAkB,IA1BS;EA4B3BC,qBAAqB,IA5BM;EA8B3BC,gBAAgB,IA9BW;EAgC3BC,gBAAgB,IAhCW;EAkC3BC,qBAAqB,IAlCM;EAoC3BC,OAAO,IApCoB;EAsC3BC,iBAAiB,IAtCU;EAwC3BC,gBAAgB,IAxCW;EA0C3BC,aAAa,IA1Cc;EA4C3BC,SAAS,IA5CkB;EA8C3BC,kBAAkB,IA9CS;EAgD3BxI,UAAU,IAhDiB;EAkD3ByI,MAAM,IAlDqB;EAoD3BC,wBAAwB,IApDG;EAqD3BC,kBAAkB,KArDS;EAsD3BC,kBAAkB,KAtDS;EAuD3BC,kBAAkBlc,OAAOS,MAAPT,KAAkBA,MAvDT;EAwD3B2S,KAAK,EAxDsB;EAyD3Ba,SAAS,EAzDkB;EA0D3B2I,cAAc,EA1Da;EA2D3BC,kBAAkBpD,uBA3DS;EA4D3BqD,cAAc5R,OAAO6C,MAAP7C,CAAc,IAAdA,CA5Da;EA6D3B6R,cAAc,IA7Da;EA8D3BC,UAAU,IA9DiB;EA+D3BC,6BAA6B,IA/DF;EAgE3BC,gBAAgB,IAhEW;EAiE3BC,iBAAiB,KAjEU;EAkE3BC,WAAW,IAlEgB;EAmE3BC,mBAAmB,CAnEQ;EAoE3BC,gBAAgB,IAAIpV,GAAJ,EApEW;EAqE3BqV,SAAS,IArEkB;EAsE3BC,uBAAuB,KAtEI;EAuE3BC,QAAQ7R,SAAS8H,KAvEU;EAwE3BgK,gCAAgC,IAxEL;;EA2E3B,MAAMC,UAAN,CAAiBzC,SAAjB,EAA4B;IAC1B,KAAKkB,WAAL,GAAmB,KAAKS,gBAAL,CAAsB5C,iBAAtB,EAAnB;IACA,KAAKiB,SAAL,GAAiBA,SAAjB;IAEA,MAAM,KAAK0C,gBAAL,EAAN;IACA,MAAM,KAAKC,oBAAL,EAAN;;IACA,KAAKC,cAAL;;IACA,MAAM,KAAKC,eAAL,EAAN;;IAEA,IACE,KAAKpB,gBAAL,IACA1K,wBAAWC,GAAXD,CAAe,oBAAfA,MAAyCY,6BAAW5T,IAFtD,EAGE;MAGAgT,wBAAWhO,GAAXgO,CAAe,oBAAfA,EAAqCY,6BAAWI,GAAhDhB;IAfwB;;IAiB1B,MAAM,KAAK+L,2BAAL,EAAN;IAIA,KAAKC,UAAL;IACA,KAAKC,gBAAL;IAGA,MAAMC,eAAejD,UAAUiD,YAAVjD,IAA0BtP,SAASC,eAAxD;IACA,KAAK0Q,IAAL,CAAU6B,SAAV,CAAoBD,YAApB,EAAkC7F,IAAlC,CAAuC,MAAM;MAG3C,KAAKxE,QAAL,CAAcwC,QAAd,CAAuB,WAAvB,EAAoC;QAAEC,QAAQ;MAAV,CAApC;IAHF;;IAMA,KAAKyE,sBAAL,CAA4BtP,OAA5B;EA3GyB;;EAiH3B,MAAMkS,gBAAN,GAAyB;IAKrB,IAAI3L,wBAAWC,GAAXD,CAAe,oBAAfA,CAAJ,EAA0C;MAGxC;IARmB;;IAUrB,IAAIA,wBAAWS,eAAXT,EAAJ,EAAkC;MAChC7Q,QAAQid,IAARjd,CACE,6EACE,sEAFJA;IAXmB;;IAiBvB,IAAI;MACF6Q,wBAAWQ,MAAXR,CAAkB,MAAM,KAAKmK,WAAL,CAAiB9J,MAAjB,EAAxBL;IADF,EAEE,OAAOqM,MAAP,EAAe;MACfld,QAAQC,KAARD,CAAe,sBAAqBkd,MAAtB,aAAsBA,MAAtB,uBAAsBA,OAAQC,OAAQ,IAApDnd;IApBqB;EAjHE;;EA6I3B,MAAMyc,oBAAN,GAA6B;IAC3B,IAAI,CAAC5L,wBAAWC,GAAXD,CAAe,eAAfA,CAAL,EAAsC;MACpC;IAFyB;;IAI3B,MAAMmE,OAAOxK,SAASkP,QAATlP,CAAkBwK,IAAlBxK,CAAuBmP,SAAvBnP,CAAiC,CAAjCA,CAAb;;IACA,IAAI,CAACwK,IAAL,EAAW;MACT;IANyB;;IAQ3B,MAAM;MAAEoI,aAAF;MAAiBC;IAAjB,IAAqC,KAAKvD,SAAhD;IAAA,MACEtX,SAASF,gCAAiB0S,IAAjB1S,CADX;;IAGA,IAAIE,OAAOsO,GAAPtO,CAAW,eAAXA,MAAgC,MAApC,EAA4C;MAC1C,IAAI;QACF,MAAM8a,gBAAN;MADF,EAEE,OAAOvH,EAAP,EAAW;QACX/V,QAAQC,KAARD,CAAe,0BAAyB+V,GAAGoH,OAAQ,IAAnDnd;MAJwC;IAXjB;;IAkB3B,IAAIwC,OAAOyS,GAAPzS,CAAW,cAAXA,CAAJ,EAAgC;MAC9BqO,wBAAWhO,GAAXgO,CAAe,cAAfA,EAA+BrO,OAAOsO,GAAPtO,CAAW,cAAXA,MAA+B,MAA9DqO;IAnByB;;IAqB3B,IAAIrO,OAAOyS,GAAPzS,CAAW,eAAXA,CAAJ,EAAiC;MAC/BqO,wBAAWhO,GAAXgO,CAAe,eAAfA,EAAgCrO,OAAOsO,GAAPtO,CAAW,eAAXA,MAAgC,MAAhEqO;IAtByB;;IAwB3B,IAAIrO,OAAOyS,GAAPzS,CAAW,kBAAXA,CAAJ,EAAoC;MAClCqO,wBAAWhO,GAAXgO,CACE,kBADFA,EAEErO,OAAOsO,GAAPtO,CAAW,kBAAXA,MAAmC,MAFrCqO;IAzByB;;IA8B3B,IAAIrO,OAAOyS,GAAPzS,CAAW,iBAAXA,CAAJ,EAAmC;MACjCqO,wBAAWhO,GAAXgO,CACE,iBADFA,EAEErO,OAAOsO,GAAPtO,CAAW,iBAAXA,MAAkC,MAFpCqO;IA/ByB;;IAoC3B,IAAIrO,OAAOyS,GAAPzS,CAAW,gBAAXA,CAAJ,EAAkC;MAChCqO,wBAAWhO,GAAXgO,CAAe,gBAAfA,EAAiCrO,OAAOsO,GAAPtO,CAAW,gBAAXA,MAAiC,MAAlEqO;IArCyB;;IAuC3B,IAAIrO,OAAOyS,GAAPzS,CAAW,WAAXA,CAAJ,EAA6B;MAC3BqO,wBAAWhO,GAAXgO,CAAe,WAAfA,EAA4BrO,OAAOsO,GAAPtO,CAAW,WAAXA,IAA0B,CAAtDqO;IAxCyB;;IA0C3B,IAAIrO,OAAOyS,GAAPzS,CAAW,WAAXA,CAAJ,EAA6B;MAC3B,QAAQA,OAAOsO,GAAPtO,CAAW,WAAXA,CAAR;QACE,KAAK,KAAL;UACEqO,wBAAWhO,GAAXgO,CAAe,eAAfA,EAAgCxS,wBAAcC,OAA9CuS;;UACA;;QACF,KAAK,SAAL;QACA,KAAK,QAAL;QACA,KAAK,OAAL;UACEwM,gBAAgBzc,SAAhByc,CAA0BnV,GAA1BmV,CAA+B,aAAY7a,OAAOsO,GAAPtO,CAAW,WAAXA,CAAb,EAA9B6a;;UACA,IAAI;YACF,MAAME,WAAW,IAAX,CAAN;;YACA,KAAKpB,OAAL,CAAaqB,OAAb;UAFF,EAGE,OAAOzH,EAAP,EAAW;YACX/V,QAAQC,KAARD,CAAe,0BAAyB+V,GAAGoH,OAAQ,IAAnDnd;UANJ;;UAQE;MAdJ;IA3CyB;;IA4D3B,IAAIwC,OAAOyS,GAAPzS,CAAW,QAAXA,CAAJ,EAA0B;MACxBqO,wBAAWhO,GAAXgO,CAAe,QAAfA,EAAyB,IAAzBA;;MACAA,wBAAWhO,GAAXgO,CAAe,qBAAfA,EAAsC,IAAtCA;;MAEA,MAAMsB,UAAU3P,OAAOsO,GAAPtO,CAAW,QAAXA,EAAqB8S,KAArB9S,CAA2B,GAA3BA,CAAhB;;MACA,IAAI;QACF,MAAM+a,WAAW,IAAX,CAAN;;QACA,KAAKpB,OAAL,CAAasB,IAAb,CAAkB;UAAEC,GAAF,EAAEA;QAAF,CAAlB,EAA2BN,aAA3B,EAA0CjL,OAA1C;MAFF,EAGE,OAAO4D,EAAP,EAAW;QACX/V,QAAQC,KAARD,CAAe,0BAAyB+V,GAAGoH,OAAQ,IAAnDnd;MATsB;IA5DC;;IAyE3B,IAGEwC,OAAOyS,GAAPzS,CAAW,QAAXA,CAHF,EAIE;MACAqO,wBAAWhO,GAAXgO,CAAe,QAAfA,EAAyBrO,OAAOsO,GAAPtO,CAAW,QAAXA,CAAzBqO;IA9EyB;EA7IF;;EAkO3B,MAAM8L,eAAN,GAAwB;IACtB,KAAKxB,IAAL,GAAY,KAAKM,gBAAL,CAAsB3C,UAAtB,CAEN;MAAEtI,QAAQK,wBAAWC,GAAXD,CAAe,QAAfA;IAAV,CAFM,CAAZ;IAKA,MAAM8M,MAAM,MAAM,KAAKxC,IAAL,CAAUyC,YAAV,EAAlB;IACApT,SAASqT,oBAATrT,CAA8B,MAA9BA,EAAsC,CAAtCA,EAAyCmT,GAAzCnT,GAA+CmT,GAA/CnT;EAzOyB;;EA+O3BkS,iBAAiB;IACf,MAAMoB,WAAWjN,wBAAWC,GAAXD,CAAe,gBAAfA,CAAjB;;IACA,IACEiN,aAAa/F,eAAeC,SAA5B8F,IACA,CAAChU,OAAOC,MAAPD,CAAciO,cAAdjO,EAA8BE,QAA9BF,CAAuCgU,QAAvChU,CAFH,EAGE;MACA;IANa;;IAQf,IAAI;MACF,MAAMiU,aAAavT,SAASwT,WAATxT,CAAqB,CAArBA,CAAnB;MACA,MAAMyT,WAAWF,oEAAYE,QAAZF,KAAwB,EAAzC;;MACA,KAAK,IAAI/X,IAAI,CAAR,EAAWkY,KAAKD,SAASta,MAA9B,EAAsCqC,IAAIkY,EAA1C,EAA8ClY,GAA9C,EAAmD;QAAA;;QACjD,MAAMmY,OAAOF,SAASjY,CAAT,CAAb;;QACA,IACEmY,gBAAgBC,YAAhBD,IACAA,qBAAKE,KAALF,4DAAa,CAAbA,OAAoB,8BAFtB,EAGE;UACA,IAAIL,aAAa/F,eAAeE,KAAhC,EAAuC;YACrC8F,WAAWO,UAAXP,CAAsB/X,CAAtB+X;YACA;UAHF;;UAMA,MAAMQ,YACJ,yEAAyEC,IAAzE,CACEL,KAAKM,OADP,CADF;;UAIA,IAAIF,SAAJ,aAAIA,SAAJ,eAAIA,UAAY,CAAZ,CAAJ,EAAoB;YAClBR,WAAWO,UAAXP,CAAsB/X,CAAtB+X;YACAA,WAAWW,UAAXX,CAAsBQ,UAAU,CAAV,CAAtBR,EAAoC/X,CAApC+X;UAZF;;UAcA;QAnB+C;MAHjD;IAAJ,EAyBE,OAAOb,MAAP,EAAe;MACfld,QAAQC,KAARD,CAAe,oBAAmBkd,MAApB,aAAoBA,MAApB,uBAAoBA,OAAQC,OAAQ,IAAlDnd;IAlCa;EA/OU;;EAwR3B,MAAM4c,2BAAN,GAAoC;IAClC,MAAM;MAAE9C,SAAF;MAAa2B;IAAb,IAAkC,IAAxC;IAEA,MAAM/I,WAAW+I,iBAAiBnC,cAAjBmC,GACb,IAAIkD,+BAAJ,EADalD,GAEb,IAAImD,qBAAJ,EAFJ;IAGA,KAAKlM,QAAL,GAAgBA,QAAhB;IAEA,KAAKqI,cAAL,GAAsB,IAAI8D,+BAAJ,EAAtB;IAEA,MAAM3E,oBAAoB,IAAI4E,sCAAJ,EAA1B;IACA5E,kBAAkB6E,MAAlB7E,GAA2B,KAAK8E,QAAL,CAAcC,IAAd,CAAmB,IAAnB,CAA3B/E;IACA,KAAKA,iBAAL,GAAyBA,iBAAzB;IAEA,MAAMG,iBAAiB,IAAI5H,gCAAJ,CAAmB;MACxCC,QADwC;MAExCpE,oBAAoBuC,wBAAWC,GAAXD,CAAe,oBAAfA,CAFoB;MAGxCxC,iBAAiBwC,wBAAWC,GAAXD,CAAe,iBAAfA,CAHuB;MAIxCrC,uBAAuBqC,wBAAWC,GAAXD,CAAe,uBAAfA;IAJiB,CAAnB,CAAvB;IAMA,KAAKwJ,cAAL,GAAsBA,cAAtB;IAEA,MAAMS,kBAAkBW,iBAAiB7C,qBAAjB6C,EAAxB;IACA,KAAKX,eAAL,GAAuBA,eAAvB;IAEA,MAAMoE,iBAAiB,IAAIC,sCAAJ,CAAsB;MAC3CC,aAAa/E,cAD8B;MAE3C3H;IAF2C,CAAtB,CAAvB;IAIA,KAAKwM,cAAL,GAAsBA,cAAtB;IAEA,MAAMtE,sBAAsB,IAAIyE,0CAAJ,CAAwB;MAClD3M,QADkD;MAElD/B,kBAGME,wBAAWC,GAAXD,CAAe,kBAAfA,CAL4C;MAOlDyO,kBAAkB7D,gBAPgC;MAQlD8D,qBAAqB,KAAKC,uBAAL,CAA6BP,IAA7B,CAAkC,IAAlC;IAR6B,CAAxB,CAA5B;IAUA,KAAKrE,mBAAL,GAA2BA,mBAA3B;IAEA,MAAMnP,YAAYqO,UAAUsD,aAA5B;IAAA,MACE5R,SAASsO,UAAUuD,eADrB;;IAEA,MAAM1P,uBAAuBkD,wBAAWC,GAAXD,CAAe,sBAAfA,CAA7B;;IACA,MAAM4O,aACJ5O,wBAAWC,GAAXD,CAAe,iBAAfA,KACAxR,OAAOqgB,UAAPrgB,CAAkB,yBAAlBA,EAA6CsgB,OAD7C9O,GAEI;MACE+O,YAAY/O,wBAAWC,GAAXD,CAAe,sBAAfA,CADd;MAEEgP,YAAYhP,wBAAWC,GAAXD,CAAe,sBAAfA;IAFd,CAFJA,GAMI,IAPN;IASA,KAAKkC,SAAL,GAAiB,IAAI+M,qBAAJ,CAAc;MAC7BrU,SAD6B;MAE7BD,MAF6B;MAG7BkH,QAH6B;MAI7BqN,gBAAgB7F,iBAJa;MAK7BkF,aAAa/E,cALgB;MAM7BS,eAN6B;MAO7BoE,cAP6B;MAQ7Bc,kBACEnP,wBAAWC,GAAXD,CAAe,iBAAfA,KAAqC+J,mBATV;MAU7BlK,UAGMG,wBAAWC,GAAXD,CAAe,UAAfA,CAbuB;MAe7BsK,MAAM,KAAKA,IAfkB;MAgB7BjM,eAAe2B,wBAAWC,GAAXD,CAAe,eAAfA,CAhBc;MAiB7BhD,gBAAgBgD,wBAAWC,GAAXD,CAAe,gBAAfA,CAjBa;MAkB7BlD,oBAlB6B;MAmB7Bc,oBAAoBoC,wBAAWC,GAAXD,CAAe,oBAAfA,CAnBS;MAoB7B1C,uBAAuB0C,wBAAWC,GAAXD,CAAe,uBAAfA,CApBM;MAqB7B1B,gBAAgB0B,wBAAWC,GAAXD,CAAe,gBAAfA,CArBa;MAsB7BzD,iBAAiByD,wBAAWC,GAAXD,CAAe,iBAAfA,CAtBY;MAuB7B3C,mBAAmB2C,wBAAWC,GAAXD,CAAe,mBAAfA,CAvBU;MAwB7B4O;IAxB6B,CAAd,CAAjB;IA0BAvF,kBAAkB/G,SAAlB+G,CAA4B,KAAKnH,SAAjCmH;IACAG,eAAelH,SAAfkH,CAAyB,KAAKtH,SAA9BsH;IACAO,oBAAoBzH,SAApByH,CAA8B,KAAK7H,SAAnC6H;IAEA,KAAKX,kBAAL,GAA0B,IAAIgG,wCAAJ,CAAuB;MAC/CxU,WAAWqO,UAAUoG,OAAVpG,CAAkBqG,aADkB;MAE/CzN,QAF+C;MAG/CqN,gBAAgB7F,iBAH+B;MAI/CkF,aAAa/E,cAJkC;MAK/Cc,MAAM,KAAKA,IALoC;MAM/CsE;IAN+C,CAAvB,CAA1B;IAQAvF,kBAAkBkG,kBAAlBlG,CAAqC,KAAKD,kBAA1CC;;IAIA,IAAI,CAAC,KAAKqB,gBAAN,IAA0B,CAAC1K,wBAAWC,GAAXD,CAAe,gBAAfA,CAA/B,EAAiE;MAC/D,KAAKmC,UAAL,GAAkB,IAAIqN,uBAAJ,CAAe;QAC/BjB,aAAa/E,cADkB;QAE/B3H;MAF+B,CAAf,CAAlB;MAIA2H,eAAejH,UAAfiH,CAA0B,KAAKrH,UAA/BqH;IAtGgC;;IAyGlC,IAAI,CAAC,KAAKrB,sBAAV,EAAkC;MAChC,KAAKsH,OAAL,GAAe,IAAIC,wBAAJ,CAAezG,UAAUwG,OAAzB,EAAkC5N,QAAlC,EAA4C,KAAKyI,IAAjD,CAAf;IA1GgC;;IA6GlC,IAAIxN,yBAAyB6S,+BAAqBliB,OAAlD,EAA2D;MACzD,KAAK8c,sBAAL,GAA8B,IAAIqF,gDAAJ,CAC5B3G,UAAUsB,sBADkB,EAE5B1I,QAF4B,CAA9B;;MAIA,WAAW/S,OAAX,IAAsB,CACpB6K,SAASU,cAATV,CAAwB,mBAAxBA,CADoB,EAEpBA,SAASU,cAATV,CAAwB,qBAAxBA,CAFoB,CAAtB,EAGG;QACD7K,QAAQiB,SAARjB,CAAkB0L,MAAlB1L,CAAyB,QAAzBA;MATuD;IA7GzB;;IA0HlC,KAAKya,qBAAL,GAA6B,IAAIsG,8CAAJ,CAC3B5G,UAAU6G,kBADiB,EAE3B,KAAK5F,cAFsB,EAG3BrI,QAH2B,EAI3B,KAAKyI,IAJsB,EAKJ,MAAM;MAC3B,OAAO,KAAKyF,YAAZ;IANyB,EAA7B;IAUA,KAAKjG,cAAL,GAAsB,IAAIkG,gCAAJ,CAAmB;MACvCpV,SADuC;MAEvCiH,QAFuC;MAGvC5E,kBAAkB+C,wBAAWC,GAAXD,CAAe,kBAAfA;IAHqB,CAAnB,CAAtB;IAMA,KAAKoK,OAAL,GAAe,IAAI6F,gBAAJ,CAAYhH,UAAUmB,OAAtB,EAA+BvI,QAA/B,EAAyC,KAAKyI,IAA9C,CAAf;IAEA,KAAKD,gBAAL,GAAwB,IAAI6F,mCAAJ,CACtBjH,UAAUoB,gBADY,EAEtBxI,QAFsB,CAAxB;;IAKA,IAAI,KAAKsO,kBAAT,EAA6B;MAC3B,KAAK7G,mBAAL,GAA2B,IAAI8G,0CAAJ,CAAwB;QACjDxV,SADiD;QAEjDsH,WAAW,KAAKA,SAFiC;QAGjDL;MAHiD,CAAxB,CAA3B;IAlJgC;;IAyJlC,KAAKwO,cAAL,GAAsB,IAAIC,+BAAJ,CACpBrH,UAAUsH,eADU,EAEpB,KAAKrG,cAFe,EAGpB,KAAKI,IAHe,EAIpB,KAAKI,gBAJe,CAAtB;IAOA,KAAKf,gBAAL,GAAwB,IAAI6G,oCAAJ,CAAqB;MAC3C5V,WAAWqO,UAAUoG,OAAVpG,CAAkBwH,WADc;MAE3C5O,QAF2C;MAG3C0M,aAAa/E;IAH8B,CAArB,CAAxB;IAMA,KAAKI,mBAAL,GAA2B,IAAI8G,0CAAJ,CAAwB;MACjD9V,WAAWqO,UAAUoG,OAAVpG,CAAkB0H,eADoB;MAEjD9O,QAFiD;MAGjDoI;IAHiD,CAAxB,CAA3B;IAMA,KAAKJ,cAAL,GAAsB,IAAI+G,gCAAJ,CAAmB;MACvChW,WAAWqO,UAAUoG,OAAVpG,CAAkB4H,UADU;MAEvChP,QAFuC;MAGvCyI,MAAM,KAAKA;IAH4B,CAAnB,CAAtB;IAMA,KAAKb,UAAL,GAAkB,IAAIqH,uBAAJ,CAAe;MAC/BC,UAAU9H,UAAUoG,OADW;MAE/BnN,WAAW,KAAKA,SAFe;MAG/BkH,oBAAoB,KAAKA,kBAHM;MAI/BvH,QAJ+B;MAK/ByI,MAAM,KAAKA;IALoB,CAAf,CAAlB;IAOA,KAAKb,UAAL,CAAgBuH,SAAhB,GAA4B,KAAKC,cAAL,CAAoB7C,IAApB,CAAyB,IAAzB,CAA5B;IAEA,KAAK1E,iBAAL,GAAyB,IAAIwH,sCAAJ,CACvBjI,UAAUkI,cADa,EAEvBtP,QAFuB,EAGvB,KAAKyI,IAHkB,CAAzB;EAndyB;;EA0d3B8G,IAAIC,MAAJ,EAAY;IACV,KAAK3F,UAAL,CAAgB2F,MAAhB,EAAwBhL,IAAxB,CAA6BiL,oBAA7B;EA3dyB;;EA8d3B,IAAIC,WAAJ,GAAkB;IAChB,OAAO,KAAKxI,sBAAL,CAA4ByI,OAAnC;EA/dyB;;EAke3B,IAAIC,kBAAJ,GAAyB;IACvB,OAAO,KAAK1I,sBAAL,CAA4B2I,OAAnC;EAneyB;;EAse3BC,OAAOC,KAAP,EAAc;IACZ,IAAI,KAAK1P,SAAL,CAAe2P,oBAAnB,EAAyC;MACvC;IAFU;;IAIZ,KAAK3P,SAAL,CAAe4P,aAAf,CAA6BF,KAA7B;EA1eyB;;EA6e3BG,QAAQH,KAAR,EAAe;IACb,IAAI,KAAK1P,SAAL,CAAe2P,oBAAnB,EAAyC;MACvC;IAFW;;IAIb,KAAK3P,SAAL,CAAe8P,aAAf,CAA6BJ,KAA7B;EAjfyB;;EAof3BK,YAAY;IACV,IAAI,KAAK/P,SAAL,CAAe2P,oBAAnB,EAAyC;MACvC;IAFQ;;IAIV,KAAK3P,SAAL,CAAegQ,iBAAf,GAAmCtmB,6BAAnC;EAxfyB;;EA2f3B,IAAI4W,UAAJ,GAAiB;IACf,OAAO,KAAKP,WAAL,GAAmB,KAAKA,WAAL,CAAiBQ,QAApC,GAA+C,CAAtD;EA5fyB;;EA+f3B,IAAIC,IAAJ,GAAW;IACT,OAAO,KAAKR,SAAL,CAAeS,iBAAtB;EAhgByB;;EAmgB3B,IAAID,IAAJ,CAASpI,GAAT,EAAc;IACZ,KAAK4H,SAAL,CAAeS,iBAAf,GAAmCrI,GAAnC;EApgByB;;EAugB3B,IAAI6X,gBAAJ,GAAuB;IACrB,OAAOC,uBAAuBC,QAAvBD,CAAgCD,gBAAvC;EAxgByB;;EA2gB3B,IAAIhC,kBAAJ,GAAyB;IACvB,OAAO/H,sBAAO,IAAPA,EAAa,oBAAbA,EAAmCzO,SAAS2Y,iBAA5ClK,CAAP;EA5gByB;;EA+gB3B,IAAID,sBAAJ,GAA6B;IAC3B,OAAO,KAAKyC,gBAAL,CAAsBzC,sBAA7B;EAhhByB;;EAmhB3B,IAAIE,qBAAJ,GAA4B;IAC1B,OAAO,KAAKuC,gBAAL,CAAsBvC,qBAA7B;EAphByB;;EAuhB3B,IAAIkK,UAAJ,GAAiB;IACf,MAAMnY,MAAM,IAAIH,qBAAJ,CAAgB,YAAhB,CAAZ;IACA,OAAOmO,sBAAO,IAAPA,EAAa,YAAbA,EAA2BhO,GAA3BgO,CAAP;EAzhByB;;EA4hB3B,IAAIE,mCAAJ,GAA0C;IACxC,OAAO,KAAKsC,gBAAL,CAAsBtC,mCAA7B;EA7hByB;;EAgiB3BV,qBAAqB;IAKjB,MAAM,IAAIzN,KAAJ,CAAU,qCAAV,CAAN;EAriBuB;;EAkkB3BqY,mBAA+C;IAAA,IAA9BrR,GAA8B,uEAAxB,EAAwB;IAAA,IAApBsR,WAAoB,uEAAN,IAAM;IAC7C,KAAKtR,GAAL,GAAWA,GAAX;IACA,KAAKa,OAAL,GAAeb,IAAIsD,KAAJtD,CAAU,GAAVA,EAAe,CAAfA,CAAf;;IACA,IAAIsR,WAAJ,EAAiB;MACf,KAAK9H,YAAL,GACE8H,gBAAgBtR,GAAhBsR,GAAsB,KAAKzQ,OAA3ByQ,GAAqCA,YAAYhO,KAAZgO,CAAkB,GAAlBA,EAAuB,CAAvBA,CADvC;IAJ2C;;IAO7C,IAAIhR,QAAQiR,qCAAsBvR,GAAtBuR,EAA2B,EAA3BA,CAAZ;;IACA,IAAI,CAACjR,KAAL,EAAY;MACV,IAAI;QACFA,QAAQkR,mBAAmBC,kCAAmBzR,GAAnByR,CAAnB,KAA+CzR,GAAvDM;MADF,EAEE,OAAOyD,EAAP,EAAW;QAGXzD,QAAQN,GAARM;MANQ;IARiC;;IAiB7C,KAAKoR,QAAL,CAAcpR,KAAd;EAnlByB;;EAslB3BoR,WAA8B;IAAA,IAArBpR,KAAqB,uEAAb,KAAK+J,MAAQ;IAC5B,KAAKA,MAAL,GAAc/J,KAAd;;IAEA,IAAI,KAAKiJ,gBAAT,EAA2B;MAEzB;IAL0B;;IAO5B/Q,SAAS8H,KAAT9H,GAAiB,GAAG,KAAK4R,qBAAL,GAA6B,IAA7B,GAAoC,EAAvC,GAA4C9J,KAA5C,EAAjB9H;EA7lByB;;EAgmB3B,IAAIoW,YAAJ,GAAmB;IAGjB,OAAO,KAAK/E,2BAAL,IAAoC0H,qCAAsB,KAAKvR,GAA3BuR,CAA3C;EAnmByB;;EAymB3BI,oBAAoB;IAElB,MAAM;MAAE1I,OAAF;MAAWC;IAAX,IAAgC,KAAKpB,SAA3C;IACAmB,QAAQ2I,YAAR3I,CAAqB4I,MAArB5I,GAA8B,IAA9BA;IACAC,iBAAiB4I,kBAAjB5I,CAAoC2I,MAApC3I,GAA6C,IAA7CA;EA7mByB;;EAmnB3B6I,uBAAuB;IACrB,IAAI,CAAC,KAAK7H,cAAL,CAAoB/R,IAAzB,EAA+B;MAC7B;IAFmB;;IAIrB,WAAW5I,QAAX,IAAuB,KAAK2a,cAA5B,EAA4C;MAC1C7c,OAAO2kB,kBAAP3kB,CAA0BkC,QAA1BlC;IALmB;;IAOrB,KAAK6c,cAAL,CAAoBhJ,KAApB;EA1nByB;;EAkoB3B,MAAM+Q,KAAN,GAAc;IAAA;;IACZ,KAAKC,yBAAL;;IACA,KAAKP,iBAAL;;IAGE,MAAM;MAAElY;IAAF,IAAgB,KAAKqO,SAAL,CAAeqK,YAArC;IACA1Y,UAAUoY,MAAVpY,GAAmB,IAAnBA;;IAGF,IAAI,CAAC,KAAKsO,cAAV,EAA0B;MACxB;IAVU;;IAYZ,IAEE,2BAAKjH,WAAL,wEAAkBsR,iBAAlB,CAAoCja,IAApC,IAA2C,CAA3C,IACA,KAAKka,0BAHP,EAIE;MACA,IAAI;QAEF,MAAM,KAAKC,IAAL,EAAN;MAFF,EAGE,OAAOpH,MAAP,EAAe,CAJjB;IAhBU;;IAwBZ,MAAMqH,WAAW,EAAjB;IAEAA,SAASzc,IAATyc,CAAc,KAAKxK,cAAL,CAAoByK,OAApB,EAAdD;IACA,KAAKxK,cAAL,GAAsB,IAAtB;;IAEA,IAAI,KAAKjH,WAAT,EAAsB;MACpB,KAAKA,WAAL,GAAmB,IAAnB;MAEA,KAAKmH,kBAAL,CAAwBhH,WAAxB,CAAoC,IAApC;MACA,KAAKF,SAAL,CAAeE,WAAf,CAA2B,IAA3B;MACA,KAAKoH,cAAL,CAAoBpH,WAApB,CAAgC,IAAhC;MACA,KAAKmH,qBAAL,CAA2BnH,WAA3B,CAAuC,IAAvC;IAnCU;;IAqCZ,KAAKoH,cAAL,CAAoB1H,mBAApB,GAA0C,IAA1C;IACA,KAAKkI,KAAL,GAAa,IAAb;IACA,KAAKQ,gBAAL,GAAwB,KAAxB;IACA,KAAKC,gBAAL,GAAwB,KAAxB;IACA,KAAKtJ,GAAL,GAAW,EAAX;IACA,KAAKa,OAAL,GAAe,EAAf;IACA,KAAK2I,YAAL,GAAoB,EAApB;IACA,KAAKG,YAAL,GAAoB,IAApB;IACA,KAAKC,QAAL,GAAgB,IAAhB;IACA,KAAKC,2BAAL,GAAmC,IAAnC;IACA,KAAKC,cAAL,GAAsB,IAAtB;IACA,KAAKC,eAAL,GAAuB,KAAvB;IACA,KAAKC,SAAL,GAAiB,IAAjB;IACA,KAAKI,qBAAL,GAA6B,KAA7B;;IAEA,KAAK2H,oBAAL;;IACAQ,SAASzc,IAATyc,CAAc,KAAK3J,mBAAL,CAAyB6J,cAAvCF;IAEA,KAAKb,QAAL;IACA,KAAKpJ,UAAL,CAAgBoK,KAAhB;IACA,KAAKlK,gBAAL,CAAsBkK,KAAtB;IACA,KAAKjK,mBAAL,CAAyBiK,KAAzB;IACA,KAAKhK,cAAL,CAAoBgK,KAApB;IAEA,yBAAK1R,UAAL,sEAAiB0R,KAAjB;IACA,sBAAKpE,OAAL,gEAAcoE,KAAd;IACA,KAAKzJ,OAAL,CAAayJ,KAAb;IACA,KAAKxJ,gBAAL,CAAsBwJ,KAAtB;IACA,sBAAKvI,OAAL,gEAAcwI,OAAd;IAEA,MAAMta,QAAQua,GAARva,CAAYka,QAAZla,CAAN;EArsByB;;EAitB3B,MAAMwa,IAAN,CAAWC,IAAX,EAAiBC,IAAjB,EAAuB;IACrB,IAAI,KAAKhL,cAAT,EAAyB;MAEvB,MAAM,KAAKkK,KAAL,EAAN;IAHmB;;IAMrB,MAAMe,mBAAmBnU,wBAAWK,MAAXL,CAAkBxD,wBAAWG,MAA7BqD,CAAzB;;IACA,WAAWnO,GAAX,IAAkBsiB,gBAAlB,EAAoC;MAClCC,8BAAoBviB,GAApBuiB,IAA2BD,iBAAiBtiB,GAAjB,CAA3BuiB;IARmB;;IAWrB,MAAMC,aAAapb,OAAO6C,MAAP7C,CAAc,IAAdA,CAAnB;;IACA,IAAI,OAAOgb,IAAP,KAAgB,QAApB,EAA8B;MAE5B,KAAKzB,gBAAL,CAAsByB,IAAtB,EAAgDA,IAAhD;MACAI,WAAWlT,GAAXkT,GAAiBJ,IAAjBI;IAHF,OAIO,IAAIJ,QAAQ,gBAAgBA,IAA5B,EAAkC;MAEvCI,WAAW3M,IAAX2M,GAAkBJ,IAAlBI;IAFK,OAGA,IAAIJ,KAAK9S,GAAL8S,IAAYA,KAAKK,WAArB,EAAkC;MACvC,KAAK9B,gBAAL,CAAsByB,KAAKK,WAA3B,EAA4DL,KAAK9S,GAAjE;MACAkT,WAAWlT,GAAXkT,GAAiBJ,KAAK9S,GAAtBkT;IArBmB;;IAwBrB,MAAME,gBAAgBvU,wBAAWK,MAAXL,CAAkBxD,wBAAWE,GAA7BsD,CAAtB;;IACA,WAAWnO,GAAX,IAAkB0iB,aAAlB,EAAiC;MAC/B,IAAIziB,QAAQyiB,cAAc1iB,GAAd,CAAZ;;MAEA,IAAIA,QAAQ,YAARA,IAAwB,CAACC,KAA7B,EAAoC,CAHL;;MAU/BuiB,WAAWxiB,GAAX,IAAkBC,KAAlBuiB;IAnCmB;;IAsCrB,IAAIH,IAAJ,EAAU;MACR,WAAWriB,GAAX,IAAkBqiB,IAAlB,EAAwB;QACtBG,WAAWxiB,GAAX,IAAkBqiB,KAAKriB,GAAL,CAAlBwiB;MAFM;IAtCW;;IA4CrB,MAAMG,cAAcC,2BAAYJ,UAAZI,CAApB;IACA,KAAKvL,cAAL,GAAsBsL,WAAtB;;IAEAA,YAAYE,UAAZF,GAAyB,CAACG,cAAD,EAAiBtI,MAAjB,KAA4B;MACnD,KAAK7C,cAAL,CAAoB1H,mBAApB,GAA0C,KAA1C;MACA,KAAKuO,cAAL,CAAoBuE,iBAApB,CAAsCD,cAAtC,EAAsDtI,MAAtD;MACA,KAAKgE,cAAL,CAAoB2D,IAApB;IAHF;;IAMAQ,YAAYK,UAAZL,GAAyB,QAAuB;MAAA,IAAtB;QAAEM,MAAF;QAAUC;MAAV,CAAsB;MAC9C,KAAKC,QAAL,CAAcF,SAASC,KAAvB;IADF;;IAKAP,YAAYS,oBAAZT,GAAmC,KAAKU,QAAL,CAAc9G,IAAd,CAAmB,IAAnB,CAAnCoG;IAEA,OAAOA,YAAY9C,OAAZ8C,CAAoBnO,IAApBmO,CACLvS,eAAe;MACb,KAAKkT,IAAL,CAAUlT,WAAV;IAFG,GAILoK,UAAU;MACR,IAAImI,gBAAgB,KAAKtL,cAAzB,EAAyC;QACvC,OAAO9Y,SAAP;MAFM;;MAKR,IAAIyB,MAAM,eAAV;;MACA,IAAIwa,kBAAkB+I,6BAAtB,EAA2C;QACzCvjB,MAAM,oBAANA;MADF,OAEO,IAAIwa,kBAAkBgJ,6BAAtB,EAA2C;QAChDxjB,MAAM,oBAANA;MADK,OAEA,IAAIwa,kBAAkBiJ,qCAAtB,EAAmD;QACxDzjB,MAAM,2BAANA;MAXM;;MAaR,OAAO,KAAKyY,IAAL,CAAUrK,GAAV,CAAcpO,GAAd,EAAmBwU,IAAnB,CAAwBkP,OAAO;QACpC,KAAKC,cAAL,CAAoBD,GAApB,EAAyB;UAAEjJ,SAASD,MAAT,aAASA,MAAT,uBAASA,OAAQC;QAAnB,CAAzB;;QACA,MAAMD,MAAN;MAFK,EAAP;IAjBG,EAAP;EA7wByB;;EAyyB3BoJ,0BAA0B;IACxB,IAAI,KAAKxT,WAAL,IAAoB,KAAKwI,gBAA7B,EAA+C;MAC7C;IAFsB;;IAIxB,MAAM,IAAItQ,KAAJ,CAAU,8BAAV,CAAN;EA7yByB;;EAgzB3B,MAAMub,QAAN,GAAiB;IACf,MAAMvU,MAAM,KAAKwJ,YAAjB;IAAA,MACEgL,WAAW,KAAK5F,YADlB;;IAEA,IAAI;MACF,KAAK0F,uBAAL;;MAEA,MAAM/N,OAAO,MAAM,KAAKzF,WAAL,CAAiB2T,OAAjB,EAAnB;MACA,MAAMC,OAAO,IAAIC,IAAJ,CAAS,CAACpO,IAAD,CAAT,EAAiB;QAAEqO,MAAM;MAAR,CAAjB,CAAb;MAEA,MAAM,KAAK9L,eAAL,CAAqByL,QAArB,CAA8BG,IAA9B,EAAoC1U,GAApC,EAAyCwU,QAAzC,CAAN;IANF,EAOE,OAAOtJ,MAAP,EAAe;MAGf,MAAM,KAAKpC,eAAL,CAAqBwI,WAArB,CAAiCtR,GAAjC,EAAsCwU,QAAtC,CAAN;IAba;EAhzBU;;EAi0B3B,MAAMlC,IAAN,GAAa;IACX,IAAI,KAAKvI,eAAT,EAA0B;MACxB;IAFS;;IAIX,KAAKA,eAAL,GAAuB,IAAvB;IACA,MAAM,KAAKnB,mBAAL,CAAyBiM,gBAAzB,EAAN;IAEA,MAAM7U,MAAM,KAAKwJ,YAAjB;IAAA,MACEgL,WAAW,KAAK5F,YADlB;;IAEA,IAAI;MACF,KAAK0F,uBAAL;;MAEA,MAAM/N,OAAO,MAAM,KAAKzF,WAAL,CAAiBgU,YAAjB,EAAnB;MACA,MAAMJ,OAAO,IAAIC,IAAJ,CAAS,CAACpO,IAAD,CAAT,EAAiB;QAAEqO,MAAM;MAAR,CAAjB,CAAb;MAEA,MAAM,KAAK9L,eAAL,CAAqByL,QAArB,CAA8BG,IAA9B,EAAoC1U,GAApC,EAAyCwU,QAAzC,CAAN;IANF,EAOE,OAAOtJ,MAAP,EAAe;MAGfld,QAAQC,KAARD,CAAe,mCAAkCkd,OAAOC,OAA1C,EAAdnd;MACA,MAAM,KAAKumB,QAAL,EAAN;IAXF,UAYU;MACR,MAAM,KAAK3L,mBAAL,CAAyBmM,eAAzB,EAAN;MACA,KAAKhL,eAAL,GAAuB,KAAvB;IAvBS;;IA0BX,IAAI,KAAKK,qBAAT,EAAgC;MAC9B,KAAKX,gBAAL,CAAsB9C,eAAtB,CAAsC;QACpCiO,MAAM,SAD8B;QAEpCrO,MAAM;UAAEqO,MAAM;QAAR;MAF8B,CAAtC;IA3BS;EAj0Bc;;EAm2B3BI,iBAAiB;IAAA;;IACf,IAAI,4BAAKlU,WAAL,0EAAkBsR,iBAAlB,CAAoCja,IAApC,IAA2C,CAA/C,EAAkD;MAChD,KAAKma,IAAL;IADF,OAEO;MACL,KAAKiC,QAAL;IAJa;EAn2BU;;EA22B3BR,SAASkB,SAAT,EAAoB;IAClB,KAAKxL,gBAAL,CAAsB9C,eAAtB,CAAsC;MACpCiO,MAAM,oBAD8B;MAEpCK;IAFoC,CAAtC;EA52ByB;;EAs3B3BZ,eAAelJ,OAAf,EAAyC;IAAA;;IAAA,IAAjB+J,QAAiB,uEAAN,IAAM;;IACvC,KAAKhD,yBAAL;;IAEA,KAAKiD,WAAL,CAAiBhK,OAAjB,EAA0B+J,QAA1B;;IAEA,KAAKxU,QAAL,CAAcwC,QAAd,CAAuB,eAAvB,EAAwC;MACtCC,QAAQ,IAD8B;MAEtCgI,OAFsC;MAGtCD,6BAAQgK,QAAR,aAAQA,QAAR,uBAAQA,SAAU/J,OAAlB,iEAA6B;IAHS,CAAxC;EA33ByB;;EA04B3BgK,YAAYhK,OAAZ,EAAsC;IAAA,IAAjB+J,QAAiB,uEAAN,IAAM;IACpC,MAAME,eAAe,CACnB,KAAKjM,IAAL,CAAUrK,GAAV,CAAc,oBAAd,EAAoC;MAClCuW,SAASA,qBAAW,GADc;MAElCC,OAAOA,mBAAS;IAFkB,CAApC,CADmB,CAArB;;IAMA,IAAIJ,QAAJ,EAAc;MACZE,aAAatf,IAAbsf,CACE,KAAKjM,IAAL,CAAUrK,GAAV,CAAc,eAAd,EAA+B;QAAEqM,SAAS+J,SAAS/J;MAApB,CAA/B,CADFiK;;MAGA,IAAIF,SAASK,KAAb,EAAoB;QAClBH,aAAatf,IAAbsf,CACE,KAAKjM,IAAL,CAAUrK,GAAV,CAAc,aAAd,EAA6B;UAAEyW,OAAOL,SAASK;QAAlB,CAA7B,CADFH;MADF,OAIO;QACL,IAAIF,SAASV,QAAb,EAAuB;UACrBY,aAAatf,IAAbsf,CACE,KAAKjM,IAAL,CAAUrK,GAAV,CAAc,YAAd,EAA4B;YAAEgU,MAAMoC,SAASV;UAAjB,CAA5B,CADFY;QAFG;;QAML,IAAIF,SAASM,UAAb,EAAyB;UACvBJ,aAAatf,IAAbsf,CACE,KAAKjM,IAAL,CAAUrK,GAAV,CAAc,YAAd,EAA4B;YAAE2W,MAAMP,SAASM;UAAjB,CAA5B,CADFJ;QAPG;MARK;IAPsB;;IA8BlC,MAAMM,qBAAqB,KAAK5N,SAAL,CAAeqK,YAA1C;IACA,MAAMA,eAAeuD,mBAAmBjc,SAAxC;IACA0Y,aAAaN,MAAbM,GAAsB,KAAtBA;IAEA,MAAMwD,eAAeD,mBAAmBC,YAAxC;IACAA,aAAaC,WAAbD,GAA2BxK,OAA3BwK;IAEA,MAAME,cAAcH,mBAAmBG,WAAvC;;IACAA,YAAYtV,OAAZsV,GAAsB,YAAY;MAChC1D,aAAaN,MAAbM,GAAsB,IAAtBA;IADF;;IAIA,MAAM2D,gBAAgBJ,mBAAmBI,aAAzC;IACA,MAAMC,iBAAiBL,mBAAmBK,cAA1C;IACA,MAAMC,iBAAiBN,mBAAmBM,cAA1C;;IACAD,eAAexV,OAAfwV,GAAyB,YAAY;MACnCD,cAAcjE,MAAdiE,GAAuB,KAAvBA;MACAC,eAAelE,MAAfkE,GAAwB,IAAxBA;MACAC,eAAenE,MAAfmE,GAAwB,KAAxBA;MACAF,cAAcpd,KAAdod,CAAoBpiB,MAApBoiB,GAA6BA,cAAcrnB,YAAdqnB,GAA6B,IAA1DA;IAJF;;IAMAE,eAAezV,OAAfyV,GAAyB,YAAY;MACnCF,cAAcjE,MAAdiE,GAAuB,IAAvBA;MACAC,eAAelE,MAAfkE,GAAwB,KAAxBA;MACAC,eAAenE,MAAfmE,GAAwB,IAAxBA;IAHF;;IAKAD,eAAeE,aAAfF,GAA+Btf,8BAA/Bsf;IACAC,eAAeC,aAAfD,GAA+Bvf,8BAA/Buf;IACAH,YAAYI,aAAZJ,GAA4Bpf,8BAA5Bof;IACAE,eAAelE,MAAfkE,GAAwB,KAAxBA;IACAC,eAAenE,MAAfmE,GAAwB,IAAxBA;IACA3d,QAAQua,GAARva,CAAY+c,YAAZ/c,EAA0B6M,IAA1B7M,CAA+B6d,SAAS;MACtCJ,cAAcnlB,KAAdmlB,GAAsBI,MAAMC,IAAND,CAAW,IAAXA,CAAtBJ;IADF;EAv8BuB;;EAk9B3BjC,SAASuC,KAAT,EAAgB;IAAA;;IACd,IAAI,KAAK9M,gBAAT,EAA2B;MAGzB;IAJY;;IAMd,MAAMzT,UAAU7D,KAAKe,KAALf,CAAWokB,QAAQ,GAAnBpkB,CAAhB;;IAKA,IAAI6D,WAAW,KAAKub,UAAL,CAAgBvb,OAA/B,EAAwC;MACtC;IAZY;;IAcd,KAAKub,UAAL,CAAgBvb,OAAhB,GAA0BA,OAA1B;IAOA,MAAM2H,kEACJ,KAAKsD,WADD,uDACJ,mBAAkBuV,aAAlB,CAAgC7Y,gBAD5B,yEAEJqB,wBAAWC,GAAXD,CAAe,kBAAfA,CAFF;;IAIA,IAAI,CAACrB,gBAAD,IAAqBpE,MAAMvD,OAAN,CAAzB,EAAyC;MACvC;IA1BY;;IA4Bd,IAAI,KAAKygB,iCAAT,EAA4C;MAC1CC,aAAa,KAAKD,iCAAlB;MACA,KAAKA,iCAAL,GAAyC,IAAzC;IA9BY;;IAgCd,KAAKlF,UAAL,CAAgBtX,IAAhB;IAEA,KAAKwc,iCAAL,GAAyCE,WAAW,MAAM;MACxD,KAAKpF,UAAL,CAAgBvX,IAAhB;MACA,KAAKyc,iCAAL,GAAyC,IAAzC;IAFuC,GAGtC5Q,sCAHsC,CAAzC;EAp/ByB;;EA0/B3BsO,KAAKlT,WAAL,EAAkB;IAChB,KAAKA,WAAL,GAAmBA,WAAnB;IAEAA,YAAY2V,eAAZ3V,GAA8BoE,IAA9BpE,CAAmC,SAAgB;MAAA,IAAf;QAAEnP;MAAF,CAAe;MACjD,KAAKmY,cAAL,GAAsBnY,MAAtB;MACA,KAAK2X,gBAAL,GAAwB,IAAxB;MACA,KAAK8H,UAAL,CAAgBvX,IAAhB;MAEA6c,iBAAiBxR,IAAjBwR,CAAsB,MAAM;QAC1B,KAAKhW,QAAL,CAAcwC,QAAd,CAAuB,gBAAvB,EAAyC;UAAEC,QAAQ;QAAV,CAAzC;MADF;IALF;IAYA,MAAMwT,oBAAoB7V,YAAY8V,aAAZ9V,GAA4BsE,KAA5BtE,CAAkC,YAAY,CAA9C,EAA1B;IAGA,MAAM+V,kBAAkB/V,YAAYgW,WAAZhW,GAA0BsE,KAA1BtE,CAAgC,YAAY,CAA5C,EAAxB;IAGA,MAAMiW,oBAAoBjW,YAAYkW,aAAZlW,GAA4BsE,KAA5BtE,CAAkC,YAAY,CAA9C,EAA1B;IAIA,KAAKmI,OAAL,CAAagO,aAAb,CAA2BnW,YAAYQ,QAAvC,EAAiD,KAAjD;IACA,KAAK4H,gBAAL,CAAsB+N,aAAtB,CAAoCnW,YAAYQ,QAAhD;IAEA,IAAI4V,eAAJ;IAEEA,kBAAkB,IAAlBA;IAMF,KAAK7O,cAAL,CAAoBpH,WAApB,CAAgCH,WAAhC,EAA6CoW,eAA7C;IACA,KAAK9O,qBAAL,CAA2BnH,WAA3B,CAAuCH,WAAvC;IAEA,MAAMC,YAAY,KAAKA,SAAvB;IACAA,UAAUE,WAAVF,CAAsBD,WAAtBC;IACA,MAAM;MAAE2V,gBAAF;MAAoBS,eAApB;MAAqCC;IAArC,IAAsDrW,SAA5D;IAEA,MAAMkH,qBAAqB,KAAKA,kBAAhC;IACAA,mBAAmBhH,WAAnBgH,CAA+BnH,WAA/BmH;IAEA,MAAMoP,gBAAiB,MAAKxO,KAAL,GAAa,IAAIyO,yBAAJ,CAClCxW,YAAYyW,YAAZzW,CAAyB,CAAzBA,CADkC,CAAb,EAGpB0W,WAHoB,CAGR;MACXjW,MAAM,IADK;MAEX+D,MAAM7a,6BAFK;MAGX0E,YAAY,GAHD;MAIXC,WAAW,GAJA;MAKXqS,UAAU,IALC;MAMXgW,aAAa7rB,sBAAYJ,OANd;MAOX+O,YAAY9N,qBAAWjB,OAPZ;MAQXgP,YAAY1N,qBAAWtB;IARZ,CAHQ,EAapB4Z,KAboB,CAad,MAAM;MAEX,OAAOtN,OAAO6C,MAAP7C,CAAc,IAAdA,CAAP;IAfkB,CAAC,CAAvB;IAkBA4e,iBAAiBxR,IAAjBwR,CAAsBgB,WAAW;MAC/B,KAAKtG,UAAL,CAAgB7X,QAAhB,CAAyB,KAAKuO,SAAL,CAAeuD,eAAxC;;MACA,KAAKsM,qCAAL,CAA2C7W,WAA3C;;MAEAzI,QAAQua,GAARva,CAAY,CACVD,0BADU,EAEVif,aAFU,EAGVV,iBAHU,EAIVE,eAJU,EAKVE,iBALU,CAAZ1e,EAOG6M,IAPH7M,CAOQ,eAAiE;QAAA,IAA1D,CAACuf,SAAD,EAAYC,MAAZ,EAAoBC,UAApB,EAAgCC,QAAhC,EAA0CC,UAA1C,CAA0D;;QACrE,MAAM3a,aAAawB,wBAAWC,GAAXD,CAAe,YAAfA,CAAnB;;QAEA,KAAKoZ,qBAAL,CAA2B;UACzBC,aAAapX,YAAYyW,YAAZzW,CAAyB,CAAzBA,CADY;UAEzBzD,UAFyB;UAGzB8a,aAAaH,UAAb,aAAaA,UAAb,uBAAaA,WAAYpW;QAHA,CAA3B;;QAKA,MAAM6F,kBAAkB,KAAKA,eAA7B;;QAGA,MAAMnC,OAAOzG,wBAAWC,GAAXD,CAAe,kBAAfA,CAAb;;QACA,IAAImE,OAAOsC,OAAQ,QAAOA,IAAR,EAAP,GAAwB,IAAnC;QAEA,IAAI7D,WAAW,IAAf;;QACA,IAAIgW,cAAc5Y,wBAAWC,GAAXD,CAAe,mBAAfA,CAAlB;;QACA,IAAItE,aAAasE,wBAAWC,GAAXD,CAAe,kBAAfA,CAAjB;;QACA,IAAIrE,aAAaqE,wBAAWC,GAAXD,CAAe,kBAAfA,CAAjB;;QAEA,IAAIgZ,OAAOtW,IAAPsW,IAAexa,eAAewI,WAAW1a,OAA7C,EAAsD;UACpD6X,OACG,QAAO6U,OAAOtW,IAAK,SAAQ+D,QAAQuS,OAAOvS,IAAK,GAAhD,GACA,GAAGuS,OAAO1oB,UAAW,IAAG0oB,OAAOzoB,SAA/B,EAFF4T;UAIAvB,WAAW2W,SAASP,OAAOpW,QAAhB,EAA0B,EAA1B,CAAXA;;UAEA,IAAIgW,gBAAgB7rB,sBAAYJ,OAAhC,EAAyC;YACvCisB,cAAcI,OAAOJ,WAAPI,GAAqB,CAAnCJ;UARkD;;UAUpD,IAAIld,eAAe9N,qBAAWjB,OAA9B,EAAuC;YACrC+O,aAAasd,OAAOtd,UAAPsd,GAAoB,CAAjCtd;UAXkD;;UAapD,IAAIC,eAAe1N,qBAAWtB,OAA9B,EAAuC;YACrCgP,aAAaqd,OAAOrd,UAAPqd,GAAoB,CAAjCrd;UAdkD;QAnBe;;QAqCrE,IAAIud,YAAYN,gBAAgB7rB,sBAAYJ,OAA5C,EAAqD;UACnDisB,cAAchd,wCAAyBsd,QAAzBtd,CAAdgd;QAtCmE;;QAwCrE,IACEK,cACAvd,eAAe9N,qBAAWjB,OAD1BssB,IAEAtd,eAAe1N,qBAAWtB,OAH5B,EAIE;UACA,MAAM6sB,QAAQhe,0CAA2Byd,UAA3Bzd,CAAd;UAIAG,aAAa6d,MAAM7d,UAAnBA;QAjDmE;;QAoDrE,KAAK8d,cAAL,CAAoBtV,IAApB,EAA0B;UACxBvB,QADwB;UAExBgW,WAFwB;UAGxBld,UAHwB;UAIxBC;QAJwB,CAA1B;QAMA,KAAKkG,QAAL,CAAcwC,QAAd,CAAuB,cAAvB,EAAuC;UAAEC,QAAQ;QAAV,CAAvC;;QAGA,IAAI,CAAC,KAAKoG,gBAAV,EAA4B;UAC1BxI,UAAUwX,KAAVxX;QA9DmE;;QAsErE,MAAM1I,QAAQmgB,IAARngB,CAAa,CACjB+e,YADiB,EAEjB,IAAI/e,OAAJ,CAAYC,WAAW;UACrBke,WAAWle,OAAX,EAAoBqN,0BAApB;QADF,EAFiB,CAAbtN,CAAN;;QAMA,IAAI,CAACoP,eAAD,IAAoB,CAACzE,IAAzB,EAA+B;UAC7B;QA7EmE;;QA+ErE,IAAIjC,UAAU0X,iBAAd,EAAiC;UAC/B;QAhFmE;;QAkFrE,KAAKhR,eAAL,GAAuBA,eAAvB;QAGA1G,UAAUgQ,iBAAVhQ,GAA8BA,UAAUgQ,iBAAxChQ;QAEA,KAAKuX,cAAL,CAAoBtV,IAApB;MA9FJ,GAgGGoC,KAhGH/M,CAgGS,MAAM;QAGX,KAAKigB,cAAL;MAnGJ,GAqGGpT,IArGH7M,CAqGQ,YAAY;QAKhB0I,UAAU2X,MAAV3X;MA1GJ;IAJF;IAkHAqW,aAAalS,IAAbkS,CACE,MAAM;MACJ,KAAKlF,yBAAL;;MAEA,KAAKyG,oBAAL,CAA0B7X,WAA1B,EAAuCiW,iBAAvC;IAJJ,GAME7L,UAAU;MACR,KAAK/B,IAAL,CAAUrK,GAAV,CAAc,eAAd,EAA+BoG,IAA/B,CAAoCkP,OAAO;QACzC,KAAKC,cAAL,CAAoBD,GAApB,EAAyB;UAAEjJ,SAASD,MAAT,aAASA,MAAT,uBAASA,OAAQC;QAAnB,CAAzB;MADF;IAPJ;IAaAgM,gBAAgBjS,IAAhBiS,CAAqB5Q,QAAQ;MAC3B,KAAKkD,gBAAL,CAAsB9C,eAAtB,CAAsC;QACpCiO,MAAM,UAD8B;QAEpCgE,WAAWrS,KAAKqS;MAFoB,CAAtC;MAKA9X,YAAY+X,UAAZ/X,GAAyBoE,IAAzBpE,CAA8BgY,WAAW;QACvC,IAAIhY,gBAAgB,KAAKA,WAAzB,EAAsC;UACpC;QAFqC;;QAIvC,KAAK0H,gBAAL,CAAsBuQ,MAAtB,CAA6B;UAAED,OAAF;UAAWhY;QAAX,CAA7B;MAJF;MAMAA,YAAYkY,cAAZlY,GAA6BoE,IAA7BpE,CAAkCmY,eAAe;QAC/C,IAAInY,gBAAgB,KAAKA,WAAzB,EAAsC;UACpC;QAF6C;;QAI/C,KAAK2H,mBAAL,CAAyBsQ,MAAzB,CAAgC;UAAEE;QAAF,CAAhC;MAJF;MAQAlY,UAAUmY,4BAAVnY,CAAuCmE,IAAvCnE,CAA4CoY,yBAAyB;QACnE,IAAIrY,gBAAgB,KAAKA,WAAzB,EAAsC;UACpC;QAFiE;;QAInE,KAAK4H,cAAL,CAAoBqQ,MAApB,CAA2B;UAAEI,qBAAF;UAAyBrY;QAAzB,CAA3B;MAJF;;MAMA,IAEE,yBAAyBzT,MAF3B,EAGE;QACA,MAAMkC,WAAWlC,OAAO+rB,mBAAP/rB,CACf,MAAM;UACJ,KAAKgsB,iBAAL,CAAuBvY,WAAvB;;UACA,KAAKoJ,cAAL,CAAoBoP,MAApB,CAA2B/pB,QAA3B;QAHa,GAKf;UAAEgqB,SAAS;QAAX,CALelsB,CAAjB;;QAOA,KAAK6c,cAAL,CAAoBhU,GAApB,CAAwB3G,QAAxB;MArCyB;IAA7B;;IAyCA,KAAKiqB,qBAAL,CAA2B1Y,WAA3B;;IACA,KAAK2Y,mBAAL,CAAyB3Y,WAAzB;EAnuCyB;;EAyuC3B,MAAM0M,uBAAN,CAA8B1M,WAA9B,EAA2C;IAAA;;IACzC,IAAI,CAAC,KAAK6I,YAAV,EAAwB;MAGtB,MAAM,IAAItR,OAAJ,CAAYC,WAAW;QAC3B,KAAKoI,QAAL,CAAcgZ,GAAd,CAAkB,gBAAlB,EAAoCphB,OAApC,EAA6C;UAAEqhB,MAAM;QAAR,CAA7C;MADI,EAAN;;MAGA,IAAI7Y,gBAAgB,KAAKA,WAAzB,EAAsC;QACpC,OAAO,IAAP;MAPoB;IADiB;;IAWzC,IAAI,CAAC,KAAKgJ,cAAV,EAA0B;MAMxB,MAAM,IAAIzR,OAAJ,CAAYC,WAAW;QAC3B,KAAKoI,QAAL,CAAcgZ,GAAd,CAAkB,gBAAlB,EAAoCphB,OAApC,EAA6C;UAAEqhB,MAAM;QAAR,CAA7C;MADI,EAAN;;MAGA,IAAI7Y,gBAAgB,KAAKA,WAAzB,EAAsC;QACpC,OAAO,IAAP;MAVsB;IAXe;;IAyBzC,OAAO,EACL,GAAG,KAAK6I,YADH;MAELiQ,SAAS,KAAK/Y,OAFT;MAGLgZ,UAAU,KAAK/P,cAHV;MAIL0K,UAAU,KAAK5F,YAJV;MAKLhF,4BAAU,KAAKA,QAAf,mDAAU,eAAekQ,MAAf,EALL;MAMLC,4BAAS,KAAKnQ,QAAd,oDAAS,gBAAe9K,GAAf,CAAmB,YAAnB,CANJ;MAOLwC,UAAU,KAAKD,UAPV;MAQL2Y,KAAK,KAAKha;IARL,CAAP;EAlwCyB;;EAmxC3B,MAAMqZ,iBAAN,CAAwBvY,WAAxB,EAAqC;IACnC,MAAMmZ,WAAW,MAAM,KAAKnZ,WAAL,CAAiBoZ,WAAjB,EAAvB;;IACA,IAAIpZ,gBAAgB,KAAKA,WAAzB,EAAsC;MACpC;IAHiC;;IAKnC,MAAMqZ,SAASF,8DAAUG,MAAVH,KAAoB,KAAnC;IACA,KAAKxQ,gBAAL,CAAsB9C,eAAtB,CAAsC;MACpCiO,MAAM,QAD8B;MAEpCuF;IAFoC,CAAtC;EAzxCyB;;EAkyC3B,MAAMxB,oBAAN,CAA2B7X,WAA3B,EAAwCiW,iBAAxC,EAA2D;IACzD,MAAM,CAACiB,UAAD,EAAaqC,UAAb,IAA2B,MAAMhiB,QAAQua,GAARva,CAAY,CACjD0e,iBADiD,EAEjD,CAAC,KAAKhW,SAAL,CAAe3E,eAAhB,GAAkC0E,YAAYwZ,aAAZxZ,EAAlC,GAAgE,IAFf,CAAZzI,CAAvC;;IAKA,IAAIyI,gBAAgB,KAAKA,WAAzB,EAAsC;MACpC;IAPuD;;IASzD,IAAIyZ,mBAAmB,KAAvB;;IAEA,IAAIvC,oEAAY/T,MAAZ+T,MAAuB,OAA3B,EAAoC;MAClCuC,mBAAmB,IAAnBA;IAZuD;;IAczD,IAAIF,UAAJ,EAAgB;MACdA,WAAWG,IAAXH,CAAgBI,MAAM;QACpB,IAAI,CAACA,EAAL,EAAS;UAEP,OAAO,KAAP;QAHkB;;QAKpBzsB,QAAQid,IAARjd,CAAa,4CAAbA;QACA,KAAK+lB,QAAL,CAAc2G,+BAAqBL,UAAnC;QACA,OAAO,IAAP;MAPF;;MAUA,IAAI,CAACE,gBAAL,EAAuB;QAErB,WAAWE,EAAX,IAAiBJ,UAAjB,EAA6B;UAC3B,IAAII,MAAMxtB,0BAAgBgO,IAAhBhO,CAAqBwtB,EAArBxtB,CAAV,EAAoC;YAClCstB,mBAAmB,IAAnBA;YACA;UAHyB;QAFR;MAXT;IAdyC;;IAoCzD,IAAIA,gBAAJ,EAAsB;MACpB,KAAKI,eAAL;IArCuD;EAlyChC;;EA80C3B,MAAMlB,mBAAN,CAA0B3Y,WAA1B,EAAuC;IAAA;;IACrC,MAAM;MAAE8Z,IAAF;MAAQhR,QAAR;MAAkBiR,0BAAlB;MAA8CC;IAA9C,IACJ,MAAMha,YAAYia,WAAZja,EADR;;IAGA,IAAIA,gBAAgB,KAAKA,WAAzB,EAAsC;MACpC;IALmC;;IAOrC,KAAK6I,YAAL,GAAoBiR,IAApB;IACA,KAAKhR,QAAL,GAAgBA,QAAhB;IACA,8BAAKC,2BAAL,8EAAKA,2BAAL,GAAqCgR,0BAArC;IACA,6BAAK/Q,cAAL,4EAAKA,cAAL,GAAwBgR,aAAxB;IAGA9sB,QAAQgtB,GAARhtB,CACG,OAAM8S,YAAYyW,YAAZzW,CAAyB,CAAzBA,CAA4B,KAAI8Z,KAAKK,gBAAiB,GAA7D,GACE,GAAI,MAAKC,QAALN,IAAiB,GAAjB,EAAsBO,IAAtB,EAA6B,MAAM,MAAKC,OAALR,IAAgB,GAAhB,EAAqBO,IAArB,EAA4B,IADrE,GAEG,YAAW9F,qBAAW,GAAI,GAH/BrnB;IAKA,IAAIqtB,WAAWT,KAAKU,KAApB;IAEA,MAAMC,gBAAgB3R,QAAhB,aAAgBA,QAAhB,uBAAgBA,SAAU9K,GAAV8K,CAAc,UAAdA,CAAtB;;IACA,IAAI2R,aAAJ,EAAmB;MAMjB,IACEA,kBAAkB,UAAlBA,IACA,CAAC,mBAAmBtgB,IAAnB,CAAwBsgB,aAAxB,CAFH,EAGE;QACAF,WAAWE,aAAXF;MAVe;IArBkB;;IAkCrC,IAAIA,QAAJ,EAAc;MACZ,KAAK3J,QAAL,CACE,GAAG2J,QAAS,MAAK,KAAKxR,2BAAL,IAAoC,KAAKQ,MAA1D,EADF;IADF,OAIO,IAAI,KAAKR,2BAAT,EAAsC;MAC3C,KAAK6H,QAAL,CAAc,KAAK7H,2BAAnB;IAvCmC;;IA0CrC,IACE+Q,KAAKY,YAALZ,IACA,CAACA,KAAKa,iBADNb,IAEA,CAAC9Z,YAAY4a,SAHf,EAIE;MACA,IAAI5a,YAAYuV,aAAZvV,CAA0BjD,SAA9B,EAAyC;QACvC7P,QAAQid,IAARjd,CAAa,qDAAbA;MADF,OAEO;QACLA,QAAQid,IAARjd,CAAa,qCAAbA;MAJF;;MAMA,KAAK+lB,QAAL,CAAc2G,+BAAqBiB,KAAnC;IAVF,OAWO,IACJ,MAAKF,iBAALb,IAA0BA,KAAKY,YAA/B,KACD,CAAC,KAAKza,SAAL,CAAe6a,WAFX,EAGL;MACA5tB,QAAQid,IAARjd,CAAa,kDAAbA;MACA,KAAK+lB,QAAL,CAAc2G,+BAAqBiB,KAAnC;IA1DmC;;IA6DrC,IAAIf,KAAKiB,mBAAT,EAA8B;MAC5B7tB,QAAQid,IAARjd,CAAa,yDAAbA;MACA,KAAK+lB,QAAL,CAAc2G,+BAAqBoB,UAAnC;IA/DmC;;IAmErC,IAAIC,YAAY,OAAhB;;IACA,IAAI5V,eAAenO,QAAfmO,CAAwByU,KAAKK,gBAA7B9U,CAAJ,EAAoD;MAClD4V,YAAa,IAAGnB,KAAKK,gBAALL,CAAsBxpB,OAAtBwpB,CAA8B,GAA9BA,EAAmC,GAAnCA,CAAJ,EAAZmB;IArEmC;;IAuErC,IAAIC,cAAc,OAAlB;;IACA,IAAIpB,KAAKM,QAAT,EAAmB;MACjB,MAAMe,WAAWrB,KAAKM,QAALN,CAAc9pB,WAAd8pB,EAAjB;MACAxU,iBAAiBoU,IAAjBpU,CAAsB,UAAU8V,SAAV,EAAqB;QACzC,IAAI,CAACD,SAASjkB,QAATikB,CAAkBC,SAAlBD,CAAL,EAAmC;UACjC,OAAO,KAAP;QAFuC;;QAIzCD,cAAcE,UAAU9qB,OAAV8qB,CAAkB,QAAlBA,EAA4B,GAA5BA,CAAdF;QACA,OAAO,IAAP;MALF;IA1EmC;;IAkFrC,IAAIG,WAAW,IAAf;;IACA,IAAIvB,KAAKY,YAAT,EAAuB;MACrBW,WAAW,KAAXA;IADF,OAEO,IAAIvB,KAAKa,iBAAT,EAA4B;MACjCU,WAAW,UAAXA;IAtFmC;;IAwFrC,KAAK1S,gBAAL,CAAsB9C,eAAtB,CAAsC;MACpCiO,MAAM,cAD8B;MAEpCS,SAAS0G,SAF2B;MAGpCG,WAAWF,WAHyB;MAIpCG;IAJoC,CAAtC;IAOA,KAAKzb,QAAL,CAAcwC,QAAd,CAAuB,gBAAvB,EAAyC;MAAEC,QAAQ;IAAV,CAAzC;EA76CyB;;EAm7C3B,MAAMqW,qBAAN,CAA4B1Y,WAA5B,EAAyC;IACvC,MAAMsb,SAAS,MAAMtb,YAAYub,aAAZvb,EAArB;;IAEA,IAAIA,gBAAgB,KAAKA,WAAzB,EAAsC;MACpC;IAJqC;;IAMvC,IAAI,CAACsb,MAAD,IAAWvd,wBAAWC,GAAXD,CAAe,mBAAfA,CAAf,EAAoD;MAClD;IAPqC;;IASvC,MAAMyd,YAAYF,OAAOzqB,MAAzB;IAGA,IAAI4qB,iBAAiB,CAArB;IAAA,IACEC,cAAc,CADhB;;IAEA,KAAK,IAAIxoB,IAAI,CAAb,EAAgBA,IAAIsoB,SAApB,EAA+BtoB,GAA/B,EAAoC;MAClC,MAAMyoB,QAAQL,OAAOpoB,CAAP,CAAd;;MACA,IAAIyoB,UAAW,KAAI,CAAJ,EAAO3Y,QAAP,EAAf,EAAkC;QAChCyY;MADF,OAEO,IAAIE,UAAU,EAAd,EAAkB;QACvBD;MADK,OAEA;QACL;MAPgC;IAdG;;IAwBvC,IAAID,kBAAkBD,SAAlBC,IAA+BC,eAAeF,SAAlD,EAA6D;MAC3D;IAzBqC;;IA2BvC,MAAM;MAAEvb,SAAF;MAAakH,kBAAb;MAAiCgB;IAAjC,IAA6C,IAAnD;IAEAlI,UAAU2b,aAAV3b,CAAwBqb,MAAxBrb;IACAkH,mBAAmByU,aAAnBzU,CAAiCmU,MAAjCnU;IAIAgB,QAAQgO,aAARhO,CAAsBqT,SAAtBrT,EAAiC,IAAjCA;IACAA,QAAQ0T,aAAR1T,CACElI,UAAUS,iBADZyH,EAEElI,UAAU6b,gBAFZ3T;EAt9CyB;;EA+9C3BgP,6BAAuE;IAAA,IAAjD;MAAEC,WAAF;MAAe7a,UAAf;MAA2B8a,cAAc;IAAzC,CAAiD;;IACrE,IAAI,CAAC,KAAKnX,UAAV,EAAsB;MACpB;IAFmE;;IAIrE,KAAKA,UAAL,CAAgBuJ,UAAhB,CAA2B;MACzB2N,WADyB;MAEzB2E,cAAcxf,eAAewI,WAAW1a,OAFf;MAGzB2xB,WAAWje,wBAAWC,GAAXD,CAAe,kBAAfA;IAHc,CAA3B;;IAMA,IAAI,KAAKmC,UAAL,CAAgByG,eAApB,EAAqC;MACnC,KAAKA,eAAL,GAAuB,KAAKzG,UAAL,CAAgByG,eAAvC;MAEA,KAAKsV,eAAL,GAAuB,KAAK/b,UAAL,CAAgB+b,eAAvC;IAbmE;;IAiBrE,IACE5E,eACA,CAAC,KAAK1Q,eADN0Q,IAEA9a,eAAewI,WAAWra,OAH5B,EAIE;MACA,KAAKic,eAAL,GAAuB7E,KAAKC,SAALD,CAAeuV,WAAfvV,CAAvB;MAGA,KAAK5B,UAAL,CAAgBlL,IAAhB,CAAqB;QAAEgM,cAAcqW,WAAhB;QAA6BhW,YAAY;MAAzC,CAArB;IAzBmE;EA/9C5C;;EA+/C3BwV,sCAAsC7W,WAAtC,EAAmD;IACjD,IAAIA,gBAAgB,KAAKA,WAAzB,EAAsC;MACpC;IAF+C;;IAIjD,MAAM;MAAEsR;IAAF,IAAwBtR,WAA9B;;IAEAsR,kBAAkB4K,aAAlB5K,GAAkC,MAAM;MACtC/kB,OAAOgD,gBAAPhD,CAAwB,cAAxBA,EAAwC4vB,YAAxC5vB;MAGE,KAAKglB,0BAAL,GAAkC,IAAlC;IAJJ;;IAOAD,kBAAkB8K,eAAlB9K,GAAoC,MAAM;MACxC/kB,OAAO8vB,mBAAP9vB,CAA2B,cAA3BA,EAA2C4vB,YAA3C5vB;MAGE,OAAO,KAAKglB,0BAAZ;IAJJ;;IAOAD,kBAAkBgL,kBAAlBhL,GAAuCiL,WAAW;MAChD,KAAKjT,qBAAL,GAA6B,CAAC,CAACiT,OAA/B;MACA,KAAK3L,QAAL;;MAEA,IAAI2L,OAAJ,EAAa;QACX,KAAK5T,gBAAL,CAAsB9C,eAAtB,CAAsC;UACpCiO,MAAM,SAD8B;UAEpCrO,MAAM;YAAEqO,MAAMyI;UAAR;QAF8B,CAAtC;MAL8C;IAAlD;EAnhDyB;;EAgiD3B/E,eACEgF,UADF,EAGE;IAAA,IADA;MAAE7b,QAAF;MAAYgW,WAAZ;MAAyBld,UAAzB;MAAqCC;IAArC,CACA,uEADoD,EACpD;;IACA,MAAM+iB,cAAcvmB,SAAS;MAC3B,IAAIS,+BAAgBT,KAAhBS,CAAJ,EAA4B;QAC1B,KAAKsJ,SAAL,CAAeW,aAAf,GAA+B1K,KAA/B;MAFyB;IAA7B;;IAKA,MAAMwmB,iBAAiB,CAACC,MAAD,EAASC,MAAT,KAAoB;MACzC,IAAI9lB,iCAAkB6lB,MAAlB7lB,CAAJ,EAA+B;QAC7B,KAAKmJ,SAAL,CAAexG,UAAf,GAA4BkjB,MAA5B;MAFuC;;MAIzC,IAAIxlB,iCAAkBylB,MAAlBzlB,CAAJ,EAA+B;QAC7B,KAAK8I,SAAL,CAAevG,UAAf,GAA4BkjB,MAA5B;MALuC;IAA3C;;IAQA,KAAKrU,gBAAL,GAAwB,IAAxB;IACA,KAAKf,UAAL,CAAgBgQ,cAAhB,CAA+Bb,WAA/B;IAEA+F,eAAejjB,UAAf,EAA2BC,UAA3B;;IAEA,IAAI,KAAKiN,eAAT,EAA0B;MACxB8V,YAAY,KAAKR,eAAjB;MACA,OAAO,KAAKA,eAAZ;MAEA,KAAK1U,cAAL,CAAoBtF,OAApB,CAA4B,KAAK0E,eAAjC;MACA,KAAKA,eAAL,GAAuB,IAAvB;IALF,OAMO,IAAI6V,UAAJ,EAAgB;MACrBC,YAAY9b,QAAZ;MAEA,KAAK4G,cAAL,CAAoBtF,OAApB,CAA4Bua,UAA5B;IA5BF;;IAiCA,KAAKrU,OAAL,CAAa0T,aAAb,CACE,KAAK5b,SAAL,CAAeS,iBADjB,EAEE,KAAKT,SAAL,CAAe6b,gBAFjB;IAIA,KAAK1T,gBAAL,CAAsByT,aAAtB,CAAoC,KAAK5b,SAAL,CAAeS,iBAAnD;;IAEA,IAAI,CAAC,KAAKT,SAAL,CAAegQ,iBAApB,EAAuC;MAGrC,KAAKhQ,SAAL,CAAegQ,iBAAf,GAAmCtmB,6BAAnC;IA1CF;EAniDyB;;EAolD3BuiB,WAAW;IACT,IAAI,CAAC,KAAKlM,WAAV,EAAuB;MACrB;IAFO;;IAIT,KAAKC,SAAL,CAAe4R,OAAf;IACA,KAAK1K,kBAAL,CAAwB0K,OAAxB;IAOE,KAAK7R,WAAL,CAAiB6R,OAAjB,CAC0B,KAAK5R,SAAL,CAAerC,QAAf,KAA4BxS,uBAAaE,GADnE;EAhmDuB;;EAwmD3B0jB,iBAAiB;IACf,KAAK5H,iBAAL,CAAuByV,QAAvB,GAAkC,CAAC,CAAC,KAAK3V,YAAzC;IACA,KAAKE,iBAAL,CAAuB0V,sBAAvB,GACE,KAAKtV,UAAL,CAAgBuV,WAAhB,KAAgCjyB,sBAAYE,MAD9C;IAEA,KAAKoc,iBAAL,CAAuB4V,qBAAvB;EA5mDyB;;EA+mD3BC,cAAc;IACZ,KAAKzT,8BAAL,GAAsC,KAAK1B,mBAAL,CACnCoV,iBADmC,GAEnC5Y,KAFmC,CAE7B,MAAM,CAFuB,GAKnCF,IALmC,CAK9B,MAAM;MAAA;;MACV,6BAAO,KAAKpE,WAAZ,uDAAO,mBAAkBsR,iBAAlB,CAAoC6L,KAA3C;IANkC,EAAtC;;IASA,IAAI,KAAKjW,YAAT,EAAuB;MAIrB;IAdU;;IAiBZ,IAAI,CAAC,KAAKgJ,gBAAV,EAA4B;MAC1B,KAAK7H,IAAL,CAAUrK,GAAV,CAAc,wBAAd,EAAwCoG,IAAxC,CAA6CkP,OAAO;QAClD,KAAKe,WAAL,CAAiBf,GAAjB;MADF;MAGA;IArBU;;IA0BZ,IAAI,CAAC,KAAKrT,SAAL,CAAemd,cAApB,EAAoC;MAClC,KAAK/U,IAAL,CAAUrK,GAAV,CAAc,oBAAd,EAAoCoG,IAApC,CAAyCkP,OAAO;QAE9C/mB,OAAO8wB,KAAP9wB,CAAa+mB,GAAb/mB;MAFF;MAIA;IA/BU;;IAkCZ,MAAM+wB,gBAAgB,KAAKrd,SAAL,CAAesd,gBAAf,EAAtB;IACA,MAAMC,iBAAiB,KAAKxW,SAAL,CAAewW,cAAtC;;IACA,MAAMxhB,kBAAkB+B,wBAAWC,GAAXD,CAAe,iBAAfA,CAAxB;;IACA,MAAMqa,+BACJ,KAAKnY,SAAL,CAAemY,4BADjB;IAGA,MAAMlR,eAAeiJ,uBAAuBC,QAAvBD,CAAgCsN,kBAAhCtN,CACnB,KAAKnQ,WADcmQ,EAEnBmN,aAFmBnN,EAGnBqN,cAHmBrN,EAInBnU,eAJmBmU,EAKnBiI,4BALmBjI,EAMnB,KAAK3G,8BANc2G,EAOnB,KAAK9H,IAPc8H,CAArB;IASA,KAAKjJ,YAAL,GAAoBA,YAApB;IACA,KAAK8H,cAAL;IAEA9H,aAAa1N,MAAb0N;IAEA,KAAKyB,gBAAL,CAAsB9C,eAAtB,CAAsC;MACpCiO,MAAM;IAD8B,CAAtC;;IAIA,IAAI,KAAKxK,qBAAT,EAAgC;MAC9B,KAAKX,gBAAL,CAAsB9C,eAAtB,CAAsC;QACpCiO,MAAM,SAD8B;QAEpCrO,MAAM;UAAEqO,MAAM;QAAR;MAF8B,CAAtC;IA3DU;EA/mDa;;EAirD3B4J,aAAa;IACX,IAAI,KAAKlU,8BAAT,EAAyC;MACvC,KAAKA,8BAAL,CAAoCpF,IAApC,CAAyC,MAAM;QAC7C,KAAK0D,mBAAL,CAAyB6V,gBAAzB;MADF;;MAGA,KAAKnU,8BAAL,GAAsC,IAAtC;IALS;;IAQX,IAAI,KAAKtC,YAAT,EAAuB;MAAA;;MACrB,KAAKA,YAAL,CAAkBwK,OAAlB;MACA,KAAKxK,YAAL,GAAoB,IAApB;MAEA,2BAAKlH,WAAL,0EAAkBsR,iBAAlB,CAAoCsM,aAApC;IAZS;;IAcX,KAAK5O,cAAL;EA/rDyB;;EAksD3B6O,YAAY/nB,KAAZ,EAAmB;IACjB,KAAKmK,SAAL,CAAeW,aAAf,IAAgC9K,KAAhC;EAnsDyB;;EAwsD3BgoB,0BAA0B;IAAA;;IACxB,8BAAKzW,mBAAL,gFAA0B0W,OAA1B;EAzsDyB;;EA4sD3BlE,kBAAkB;IAChB,IAAI,CAAC,KAAK3J,gBAAV,EAA4B;MAC1B;IAFc;;IAIhB3jB,OAAO4wB,KAAP5wB;EAhtDyB;;EAmtD3Bwd,aAAa;IACX,MAAM;MAAEnK,QAAF;MAAYgJ;IAAZ,IAA6B,IAAnC;IAEAA,aAAaqU,WAAbrU,GAA2B,KAAKqU,WAAL,CAAiB9Q,IAAjB,CAAsB,IAAtB,CAA3BvD;IACAA,aAAa8U,UAAb9U,GAA0B,KAAK8U,UAAL,CAAgBvR,IAAhB,CAAqB,IAArB,CAA1BvD;;IAEAhJ,SAASgZ,GAAThZ,CAAa,QAAbA,EAAuBoe,eAAvBpe;;IACAA,SAASgZ,GAAThZ,CAAa,YAAbA,EAA2Bqe,mBAA3Bre;;IACAA,SAASgZ,GAAThZ,CAAa,aAAbA,EAA4BgJ,aAAaqU,WAAzCrd;;IACAA,SAASgZ,GAAThZ,CAAa,YAAbA,EAA2BgJ,aAAa8U,UAAxC9d;;IACAA,SAASgZ,GAAThZ,CAAa,cAAbA,EAA6Bse,qBAA7Bte;;IACAA,SAASgZ,GAAThZ,CAAa,gBAAbA,EAA+Bue,uBAA/Bve;;IACAA,SAASgZ,GAAThZ,CAAa,cAAbA,EAA6Bwe,qBAA7Bxe;;IACAA,SAASgZ,GAAThZ,CAAa,eAAbA,EAA8Bye,sBAA9Bze;;IACAA,SAASgZ,GAAThZ,CAAa,kBAAbA,EAAiC0e,yBAAjC1e;;IACAA,SAASgZ,GAAThZ,CAAa,oBAAbA,EAAmC2e,2BAAnC3e;;IACAA,SAASgZ,GAAThZ,CAAa,UAAbA,EAAyB4e,iBAAzB5e;;IACAA,SAASgZ,GAAThZ,CAAa,aAAbA,EAA4B6e,oBAA5B7e;;IACAA,SAASgZ,GAAThZ,CAAa,yBAAbA,EAAwC8e,gCAAxC9e;;IACAA,SAASgZ,GAAThZ,CAAa,kBAAbA,EAAiC+e,yBAAjC/e;;IACAA,SAASgZ,GAAThZ,CACE,4BADFA,EAEEgf,mCAFFhf;;IAIAA,SAASgZ,GAAThZ,CACE,8BADFA,EAEEif,qCAFFjf;;IAIAA,SAASgZ,GAAThZ,CAAa,OAAbA,EAAsBkf,cAAtBlf;;IACAA,SAASgZ,GAAThZ,CAAa,UAAbA,EAAyBmf,iBAAzBnf;;IACAA,SAASgZ,GAAThZ,CAAa,WAAbA,EAA0Bof,kBAA1Bpf;;IACAA,SAASgZ,GAAThZ,CAAa,UAAbA,EAAyBqf,iBAAzBrf;;IACAA,SAASgZ,GAAThZ,CAAa,UAAbA,EAAyBsf,iBAAzBtf;;IACAA,SAASgZ,GAAThZ,CAAa,cAAbA,EAA6Buf,qBAA7Bvf;;IACAA,SAASgZ,GAAThZ,CAAa,QAAbA,EAAuBwf,eAAvBxf;;IACAA,SAASgZ,GAAThZ,CAAa,SAAbA,EAAwByf,gBAAxBzf;;IACAA,SAASgZ,GAAThZ,CAAa,WAAbA,EAA0B0f,kBAA1B1f;;IACAA,SAASgZ,GAAThZ,CAAa,mBAAbA,EAAkC2f,0BAAlC3f;;IACAA,SAASgZ,GAAThZ,CAAa,cAAbA,EAA6B4f,qBAA7B5f;;IACAA,SAASgZ,GAAThZ,CAAa,UAAbA,EAAyB6f,iBAAzB7f;;IACAA,SAASgZ,GAAThZ,CAAa,WAAbA,EAA0B8f,kBAA1B9f;;IACAA,SAASgZ,GAAThZ,CAAa,uBAAbA,EAAsC+f,8BAAtC/f;;IACAA,SAASgZ,GAAThZ,CAAa,kBAAbA,EAAiCggB,yBAAjChgB;;IACAA,SAASgZ,GAAThZ,CAAa,mBAAbA,EAAkCigB,0BAAlCjgB;;IACAA,SAASgZ,GAAThZ,CAAa,kBAAbA,EAAiCkgB,yBAAjClgB;;IACAA,SAASgZ,GAAThZ,CAAa,mBAAbA,EAAkCmgB,0BAAlCngB;;IACAA,SAASgZ,GAAThZ,CAAa,oBAAbA,EAAmCogB,2BAAnCpgB;;IACAA,SAASgZ,GAAThZ,CAAa,iBAAbA,EAAgCqgB,wBAAhCrgB;;IACAA,SAASgZ,GAAThZ,CAAa,wBAAbA,EAAuCsgB,+BAAvCtgB;;IACAA,SAASgZ,GAAThZ,CAAa,wBAAbA,EAAuCugB,+BAAvCvgB;;IAEA,IAAI7B,wBAAWC,GAAXD,CAAe,QAAfA,CAAJ,EAA8B;MAC5B6K,aAAawX,qBAAbxX,GAAqCwX,qBAArCxX;;MAEAhJ,SAASgZ,GAAThZ,CAAa,cAAbA,EAA6BgJ,aAAawX,qBAA1CxgB;;MACAA,SAASgZ,GAAThZ,CAAa,cAAbA,EAA6BgJ,aAAawX,qBAA1CxgB;IAvDS;;IA0DTA,SAASgZ,GAAThZ,CAAa,iBAAbA,EAAgCygB,wBAAhCzgB;;IACAA,SAASgZ,GAAThZ,CAAa,UAAbA,EAAyB0gB,iBAAzB1gB;EA9wDuB;;EAwxD3BoK,mBAAmB;IACjB,MAAM;MAAEpK,QAAF;MAAYgJ;IAAZ,IAA6B,IAAnC;;IAEA,SAAS2X,yBAAT,GAA+C;MAAA,IAAZ5xB,GAAY,uEAAN,IAAM;;MAC7C,IAAIA,GAAJ,EAAS;QACP6xB,0BAA0B7xB,GAA1B;MAF2C;;MAI7C,MAAM8xB,iBAAiBl0B,OAAOqgB,UAAPrgB,CACpB,gBAAeA,OAAOC,gBAAPD,IAA2B,CAAE,OADxBA,CAAvB;MAGAk0B,eAAelxB,gBAAfkxB,CAAgC,QAAhCA,EAA0CF,yBAA1CE,EAAqE;QACnE5H,MAAM;MAD6D,CAArE4H;MAOA7X,aAAa8X,4BAAb9X,kBAAa8X,4BAAb9X,GAA8C,YAAY;QACxD6X,eAAepE,mBAAfoE,CAAmC,QAAnCA,EAA6CF,yBAA7CE;QACA7X,aAAa8X,4BAAb9X,GAA4C,IAA5CA;MAFF;IAjBe;;IAsBjB2X;;IAEA3X,aAAa+X,YAAb/X,GAA4B,MAAM;MAChChJ,SAASwC,QAATxC,CAAkB,QAAlBA,EAA4B;QAAEyC,QAAQ9V;MAAV,CAA5BqT;IADF;;IAGAgJ,aAAagY,gBAAbhY,GAAgC,MAAM;MACpChJ,SAASwC,QAATxC,CAAkB,YAAlBA,EAAgC;QAC9ByC,QAAQ9V,MADsB;QAE9B2V,MAAMxK,SAASkP,QAATlP,CAAkBwK,IAAlBxK,CAAuBmP,SAAvBnP,CAAiC,CAAjCA;MAFwB,CAAhCkI;IADF;;IAMAgJ,aAAaiY,iBAAbjY,GAAiC,MAAM;MACrChJ,SAASwC,QAATxC,CAAkB,aAAlBA,EAAiC;QAAEyC,QAAQ9V;MAAV,CAAjCqT;IADF;;IAGAgJ,aAAakY,gBAAblY,GAAgC,MAAM;MACpChJ,SAASwC,QAATxC,CAAkB,YAAlBA,EAAgC;QAAEyC,QAAQ9V;MAAV,CAAhCqT;IADF;;IAGAgJ,aAAamY,uBAAbnY,GAAuCoY,SAAS;MAC9CphB,SAASwC,QAATxC,CAAkB,mBAAlBA,EAAuC;QACrCyC,QAAQ9V,MAD6B;QAErC00B,QAAQD,MAAMC;MAFuB,CAAvCrhB;IADF;;IAOArT,OAAOgD,gBAAPhD,CAAwB,kBAAxBA,EAA4C20B,yBAA5C30B;IACAA,OAAOgD,gBAAPhD,CAAwB,OAAxBA,EAAiC40B,cAAjC50B,EAAiD;MAAE60B,SAAS;IAAX,CAAjD70B;IACAA,OAAOgD,gBAAPhD,CAAwB,YAAxBA,EAAsC80B,mBAAtC90B,EAA2D;MACzD60B,SAAS;IADgD,CAA3D70B;IAGAA,OAAOgD,gBAAPhD,CAAwB,OAAxBA,EAAiC+0B,cAAjC/0B;IACAA,OAAOgD,gBAAPhD,CAAwB,SAAxBA,EAAmCg1B,gBAAnCh1B;IACAA,OAAOgD,gBAAPhD,CAAwB,QAAxBA,EAAkCqc,aAAa+X,YAA/Cp0B;IACAA,OAAOgD,gBAAPhD,CAAwB,YAAxBA,EAAsCqc,aAAagY,gBAAnDr0B;IACAA,OAAOgD,gBAAPhD,CAAwB,aAAxBA,EAAuCqc,aAAaiY,iBAApDt0B;IACAA,OAAOgD,gBAAPhD,CAAwB,YAAxBA,EAAsCqc,aAAakY,gBAAnDv0B;IACAA,OAAOgD,gBAAPhD,CACE,mBADFA,EAEEqc,aAAamY,uBAFfx0B;EAj1DyB;;EAu1D3Bi1B,eAAe;IAIb,MAAM;MAAE5hB,QAAF;MAAYgJ;IAAZ,IAA6B,IAAnC;;IAEAhJ,SAAS6hB,IAAT7hB,CAAc,QAAdA,EAAwBoe,eAAxBpe;;IACAA,SAAS6hB,IAAT7hB,CAAc,YAAdA,EAA4Bqe,mBAA5Bre;;IACAA,SAAS6hB,IAAT7hB,CAAc,aAAdA,EAA6BgJ,aAAaqU,WAA1Crd;;IACAA,SAAS6hB,IAAT7hB,CAAc,YAAdA,EAA4BgJ,aAAa8U,UAAzC9d;;IACAA,SAAS6hB,IAAT7hB,CAAc,cAAdA,EAA8Bse,qBAA9Bte;;IACAA,SAAS6hB,IAAT7hB,CAAc,gBAAdA,EAAgCue,uBAAhCve;;IACAA,SAAS6hB,IAAT7hB,CAAc,cAAdA,EAA8Bwe,qBAA9Bxe;;IACAA,SAAS6hB,IAAT7hB,CAAc,eAAdA,EAA+Bye,sBAA/Bze;;IACAA,SAAS6hB,IAAT7hB,CAAc,kBAAdA,EAAkC0e,yBAAlC1e;;IACAA,SAAS6hB,IAAT7hB,CAAc,oBAAdA,EAAoC2e,2BAApC3e;;IACAA,SAAS6hB,IAAT7hB,CAAc,UAAdA,EAA0B4e,iBAA1B5e;;IACAA,SAAS6hB,IAAT7hB,CAAc,aAAdA,EAA6B6e,oBAA7B7e;;IACAA,SAAS6hB,IAAT7hB,CAAc,yBAAdA,EAAyC8e,gCAAzC9e;;IACAA,SAAS6hB,IAAT7hB,CAAc,kBAAdA,EAAkC+e,yBAAlC/e;;IACAA,SAAS6hB,IAAT7hB,CAAc,OAAdA,EAAuBkf,cAAvBlf;;IACAA,SAAS6hB,IAAT7hB,CAAc,UAAdA,EAA0Bmf,iBAA1Bnf;;IACAA,SAAS6hB,IAAT7hB,CAAc,WAAdA,EAA2Bof,kBAA3Bpf;;IACAA,SAAS6hB,IAAT7hB,CAAc,UAAdA,EAA0Bqf,iBAA1Brf;;IACAA,SAAS6hB,IAAT7hB,CAAc,UAAdA,EAA0Bsf,iBAA1Btf;;IACAA,SAAS6hB,IAAT7hB,CAAc,cAAdA,EAA8Buf,qBAA9Bvf;;IACAA,SAAS6hB,IAAT7hB,CAAc,QAAdA,EAAwBwf,eAAxBxf;;IACAA,SAAS6hB,IAAT7hB,CAAc,SAAdA,EAAyByf,gBAAzBzf;;IACAA,SAAS6hB,IAAT7hB,CAAc,WAAdA,EAA2B0f,kBAA3B1f;;IACAA,SAAS6hB,IAAT7hB,CAAc,mBAAdA,EAAmC2f,0BAAnC3f;;IACAA,SAAS6hB,IAAT7hB,CAAc,cAAdA,EAA8B4f,qBAA9B5f;;IACAA,SAAS6hB,IAAT7hB,CAAc,UAAdA,EAA0B6f,iBAA1B7f;;IACAA,SAAS6hB,IAAT7hB,CAAc,WAAdA,EAA2B8f,kBAA3B9f;;IACAA,SAAS6hB,IAAT7hB,CAAc,uBAAdA,EAAuC+f,8BAAvC/f;;IACAA,SAAS6hB,IAAT7hB,CAAc,kBAAdA,EAAkCggB,yBAAlChgB;;IACAA,SAAS6hB,IAAT7hB,CAAc,mBAAdA,EAAmCigB,0BAAnCjgB;;IACAA,SAAS6hB,IAAT7hB,CAAc,kBAAdA,EAAkCkgB,yBAAlClgB;;IACAA,SAAS6hB,IAAT7hB,CAAc,mBAAdA,EAAmCmgB,0BAAnCngB;;IACAA,SAAS6hB,IAAT7hB,CAAc,oBAAdA,EAAoCogB,2BAApCpgB;;IACAA,SAAS6hB,IAAT7hB,CAAc,iBAAdA,EAAiCqgB,wBAAjCrgB;;IACAA,SAAS6hB,IAAT7hB,CAAc,wBAAdA,EAAwCsgB,+BAAxCtgB;;IACAA,SAAS6hB,IAAT7hB,CAAc,wBAAdA,EAAwCugB,+BAAxCvgB;;IAEA,IAAIgJ,aAAawX,qBAAjB,EAAwC;MACtCxgB,SAAS6hB,IAAT7hB,CAAc,cAAdA,EAA8BgJ,aAAawX,qBAA3CxgB;;MACAA,SAAS6hB,IAAT7hB,CAAc,cAAdA,EAA8BgJ,aAAawX,qBAA3CxgB;;MAEAgJ,aAAawX,qBAAbxX,GAAqC,IAArCA;IA/CW;;IAkDXhJ,SAAS6hB,IAAT7hB,CAAc,iBAAdA,EAAiCygB,wBAAjCzgB;;IACAA,SAAS6hB,IAAT7hB,CAAc,UAAdA,EAA0B0gB,iBAA1B1gB;;IAGFgJ,aAAaqU,WAAbrU,GAA2B,IAA3BA;IACAA,aAAa8U,UAAb9U,GAA0B,IAA1BA;EA94DyB;;EAi5D3B8Y,qBAAqB;IAAA;;IAInB,MAAM;MAAE9Y;IAAF,IAAmB,IAAzB;IAEArc,OAAO8vB,mBAAP9vB,CAA2B,kBAA3BA,EAA+C20B,yBAA/C30B;IACAA,OAAO8vB,mBAAP9vB,CAA2B,OAA3BA,EAAoC40B,cAApC50B,EAAoD;MAAE60B,SAAS;IAAX,CAApD70B;IACAA,OAAO8vB,mBAAP9vB,CAA2B,YAA3BA,EAAyC80B,mBAAzC90B,EAA8D;MAC5D60B,SAAS;IADmD,CAA9D70B;IAGAA,OAAO8vB,mBAAP9vB,CAA2B,OAA3BA,EAAoC+0B,cAApC/0B;IACAA,OAAO8vB,mBAAP9vB,CAA2B,SAA3BA,EAAsCg1B,gBAAtCh1B;IACAA,OAAO8vB,mBAAP9vB,CAA2B,QAA3BA,EAAqCqc,aAAa+X,YAAlDp0B;IACAA,OAAO8vB,mBAAP9vB,CAA2B,YAA3BA,EAAyCqc,aAAagY,gBAAtDr0B;IACAA,OAAO8vB,mBAAP9vB,CAA2B,aAA3BA,EAA0Cqc,aAAaiY,iBAAvDt0B;IACAA,OAAO8vB,mBAAP9vB,CAA2B,YAA3BA,EAAyCqc,aAAakY,gBAAtDv0B;IACAA,OAAO8vB,mBAAP9vB,CACE,mBADFA,EAEEqc,aAAamY,uBAFfx0B;IAKAqc,sCAAa8X,4BAAb9X;IACAA,aAAa+X,YAAb/X,GAA4B,IAA5BA;IACAA,aAAagY,gBAAbhY,GAAgC,IAAhCA;IACAA,aAAaiY,iBAAbjY,GAAiC,IAAjCA;IACAA,aAAakY,gBAAblY,GAAgC,IAAhCA;IACAA,aAAamY,uBAAbnY,GAAuC,IAAvCA;EA56DyB;;EA+6D3B+Y,qBAAqBC,KAArB,EAA4B;IAE1B,IACG,KAAKzY,iBAAL,GAAyB,CAAzB,IAA8ByY,QAAQ,CAAtC,IACA,KAAKzY,iBAAL,GAAyB,CAAzB,IAA8ByY,QAAQ,CAFzC,EAGE;MACA,KAAKzY,iBAAL,GAAyB,CAAzB;IANwB;;IAQ1B,KAAKA,iBAAL,IAA0ByY,KAA1B;IACA,MAAMC,aACJ3wB,KAAK4wB,IAAL5wB,CAAU,KAAKiY,iBAAfjY,IACAA,KAAKC,KAALD,CAAWA,KAAKwE,GAALxE,CAAS,KAAKiY,iBAAdjY,CAAXA,CAFF;IAGA,KAAKiY,iBAAL,IAA0B0Y,UAA1B;IACA,OAAOA,UAAP;EA57DyB;;EAo8D3BzQ,4BAA4B;IAAA;;IAC1B1Z,gDAASqqB,kBAATrqB,gGAA8B,KAA9BA;;IAGA,KAAK0Z,yBAAL,GAAiC,MAAM,CAAvC;EAx8DyB;;EA88D3B4Q,gCAAgC;IAC9B,MAAM;MAAEC;IAAF,IAAY,KAAKjiB,WAAvB;;IACA,IAAIiiB,UAAU,KAAK/Y,SAAnB,EAA8B;MAC5B,KAAKA,SAAL,GAAiB+Y,KAAjB;MAEA,KAAKtZ,gBAAL,CAAsB9C,eAAtB,CAAsC;QACpCiO,MAAM,eAD8B;QAEpCmO;MAFoC,CAAtC;IAL4B;EA98DL;;EA89D3B,IAAIC,cAAJ,GAAqB;IACnB,OAAO,KAAKpa,mBAAL,CAAyBqa,KAAhC;EA/9DyB;;AAAA,CAA7B;;AAm+DA,IAAIC,eAAJ;AACiE;EAC/D,MAAMC,wBAAwB,CAC5B,MAD4B,EAE5B,0BAF4B,EAG5B,2BAH4B,CAA9B;;EAKAD,kBAAkB,UAAUpQ,IAAV,EAAgB;IAChC,IAAI,CAACA,IAAL,EAAW;MACT;IAF8B;;IAIhC,IAAI;MACF,MAAMsQ,eAAe,IAAIpJ,GAAJ,CAAQ3sB,OAAOqa,QAAPra,CAAgBgT,IAAxB,EAA8BgjB,MAA9B,IAAwC,MAA7D;;MACA,IAAIF,sBAAsBnrB,QAAtBmrB,CAA+BC,YAA/BD,CAAJ,EAAkD;QAEhD;MAJA;;MAMF,MAAMG,aAAa,IAAItJ,GAAJ,CAAQlH,IAAR,EAAczlB,OAAOqa,QAAPra,CAAgBgT,IAA9B,EAAoCgjB,MAAvD;;MAIA,IAAIC,eAAeF,YAAnB,EAAiC;QAC/B,MAAM,IAAIpqB,KAAJ,CAAU,qCAAV,CAAN;MAXA;IAAJ,EAaE,OAAO+K,EAAP,EAAW;MACXyD,qBAAqB2B,IAArB3B,CAA0B1I,GAA1B0I,CAA8B,eAA9BA,EAA+CtC,IAA/CsC,CAAoD4M,OAAO;QACzD5M,qBAAqB6M,cAArB7M,CAAoC4M,GAApC5M,EAAyC;UAAE2D,SAASpH,EAAT,aAASA,EAAT,uBAASA,GAAIoH;QAAf,CAAzC3D;MADF;MAGA,MAAMzD,EAAN;IArB8B;EAAlC;AA5qEF;;AAssEA,eAAeuH,cAAf,GAAgC;EAC9B2H,8BAAoB5U,SAApB4U,mCAAoB5U,SAApB4U,GAAkCpU,wBAAWC,GAAXD,CAAe,WAAfA,CAAlCoU;EAMA,MAAMsQ,0BAAWC,oBAAUnlB,SAArBklB,CAAN;AA7sEF;;AAgtEA,eAAehY,UAAf,CAA0BkY,IAA1B,EAAgC;EAC9B,MAAM;IAAEC;EAAF,IAAyBD,KAAK3b,SAApC;EACA,MAAM;IAAE6b;EAAF,IAGA,MAAMC,uBAAuBF,kBAAvB,CAHZ;EAKAD,KAAKtZ,OAALsZ,GAAeE,MAAfF;AAvtEF;;AA0tEA,SAASvC,qBAAT,QAA+C;EAAA;;EAAA,IAAhB;IAAE/e;EAAF,CAAgB;;EAC7C,IAAI,uBAAC0hB,WAAWC,KAAZ,8CAACD,kBAAkB1jB,OAAnB,CAAJ,EAAgC;IAC9B;EAF2C;;EAI7C,MAAM4jB,WAAWvc,qBAAqBzG,SAArByG,CAA+Bwc,WAA/Bxc,CACDrF,aAAa,CADZqF,CAAjB;EAGAqc,WAAWC,KAAXD,CAAiB3tB,GAAjB2tB,CAAqB1hB,UAArB0hB,EAAiCE,QAAjCF,aAAiCE,QAAjCF,4CAAiCE,SAAUrM,OAA3CmM,sDAAiCE,kBAAmBhB,KAApDc;AAjuEF;;AAouEA,SAAS1T,oBAAT,GAAgC;EAAA;;EAC9B,MAAM;IAAErI,SAAF;IAAapH;EAAb,IAA0B8G,oBAAhC;EACA,IAAIsL,IAAJ;EAEE,MAAMmR,cAAczrB,SAASkP,QAATlP,CAAkB0rB,MAAlB1rB,CAAyBmP,SAAzBnP,CAAmC,CAAnCA,CAApB;EACA,MAAMhI,SAASF,gCAAiB2zB,WAAjB3zB,CAAf;EACAwiB,sBAAOtiB,OAAOsO,GAAPtO,CAAW,MAAXA,CAAP,qDAA6BqO,wBAAWC,GAAXD,CAAe,YAAfA,CAA7BiU;EACAoQ,gBAAgBpQ,IAAhB;EAQA,MAAMqR,YAAYrc,UAAUsc,aAA5B;EACAD,UAAUxzB,KAAVwzB,GAAkB,IAAlBA;EAEAA,UAAU9zB,gBAAV8zB,CAA2B,QAA3BA,EAAqC,UAAU10B,GAAV,EAAe;IAClD,MAAM;MAAE40B;IAAF,IAAY50B,IAAIwQ,MAAtB;;IACA,IAAI,CAACokB,KAAD,IAAUA,MAAM1yB,MAAN0yB,KAAiB,CAA/B,EAAkC;MAChC;IAHgD;;IAKlD3jB,SAASwC,QAATxC,CAAkB,iBAAlBA,EAAqC;MACnCyC,QAAQ,IAD2B;MAEnCghB,WAAW10B,IAAIwQ;IAFoB,CAArCS;EALF;EAYAoH,UAAUsD,aAAVtD,CAAwBzX,gBAAxByX,CAAyC,UAAzCA,EAAqD,UAAUrY,GAAV,EAAe;IAClEA,IAAIiH,cAAJjH;IAEAA,IAAI60B,YAAJ70B,CAAiB80B,UAAjB90B,GACEA,IAAI60B,YAAJ70B,CAAiB+0B,aAAjB/0B,KAAmC,MAAnCA,GAA4C,MAA5CA,GAAqD,MADvDA;EAHF;EAMAqY,UAAUsD,aAAVtD,CAAwBzX,gBAAxByX,CAAyC,MAAzCA,EAAiD,UAAUrY,GAAV,EAAe;IAC9DA,IAAIiH,cAAJjH;IAEA,MAAM;MAAE40B;IAAF,IAAY50B,IAAI60B,YAAtB;;IACA,IAAI,CAACD,KAAD,IAAUA,MAAM1yB,MAAN0yB,KAAiB,CAA/B,EAAkC;MAChC;IAL4D;;IAO9D3jB,SAASwC,QAATxC,CAAkB,iBAAlBA,EAAqC;MACnCyC,QAAQ,IAD2B;MAEnCghB,WAAW10B,IAAI60B;IAFoB,CAArC5jB;EAPF;;EAcF,IAAI,CAAC8G,qBAAqBN,qBAA1B,EAAiD;IAC/CrI,wBAAWhO,GAAXgO,CAAe,iBAAfA,EAAkC,IAAlCA;;IACA2I,qBAAqB2B,IAArB3B,CAA0B1I,GAA1B0I,CAA8B,oBAA9BA,EAAoDtC,IAApDsC,CAAyD4M,OAAO;MAC9DpmB,QAAQid,IAARjd,CAAaomB,GAAbpmB;IADF;EApD4B;;EAyD9B,IAAI,CAACwZ,qBAAqBwJ,gBAA1B,EAA4C;IAC1ClJ,UAAUmB,OAAVnB,CAAkBmW,KAAlBnW,CAAwBlZ,SAAxBkZ,CAAkC5R,GAAlC4R,CAAsC,QAAtCA;IACAA,UAAUoB,gBAAVpB,CAA2B2c,WAA3B3c,CAAuClZ,SAAvCkZ,CAAiD5R,GAAjD4R,CAAqD,QAArDA;EA3D4B;;EA8D9B,IAAI,CAACN,qBAAqBwH,kBAA1B,EAA8C;IAC5ClH,UAAUmB,OAAVnB,CAAkB4c,sBAAlB5c,CAAyClZ,SAAzCkZ,CAAmD5R,GAAnD4R,CAAuD,QAAvDA;IACAA,UAAUoB,gBAAVpB,CAA2B4c,sBAA3B5c,CAAkDlZ,SAAlDkZ,CAA4D5R,GAA5D4R,CAAgE,QAAhEA;EAhE4B;;EAmE9B,IAAIN,qBAAqBR,sBAAzB,EAAiD;IAC/Cc,UAAUmB,OAAVnB,CAAkB6c,QAAlB7c,CAA2BlZ,SAA3BkZ,CAAqC5R,GAArC4R,CAAyC,QAAzCA;EApE4B;;EAuE9BA,UAAUsD,aAAVtD,CAAwBzX,gBAAxByX,CACE,eADFA,EAEE,UAAUrY,GAAV,EAAe;IACb,IAAIA,IAAIwQ,MAAJxQ,KAAmC,IAAvC,EAA6C;MAC3CiR,SAASwC,QAATxC,CAAkB,QAAlBA,EAA4B;QAAEyC,QAAQ;MAAV,CAA5BzC;IAFW;EAFjB,GAOE,IAPFoH;;EAUA,IAAI;IAEA,IAAIgL,IAAJ,EAAU;MACRtL,qBAAqBqL,IAArBrL,CAA0BsL,IAA1BtL;IADF,OAEO;MACLA,qBAAqBmK,iBAArBnK;IALF;EAAJ,EAaE,OAAO0D,MAAP,EAAe;IACf1D,qBAAqB2B,IAArB3B,CAA0B1I,GAA1B0I,CAA8B,eAA9BA,EAA+CtC,IAA/CsC,CAAoD4M,OAAO;MACzD5M,qBAAqB6M,cAArB7M,CAAoC4M,GAApC5M,EAAyC0D,MAAzC1D;IADF;EA/F4B;AApuEhC;;AAy0EA,SAASwX,qBAAT,QAAsD;EAAA,IAAvB;IAAE7c,UAAF;IAAclU;EAAd,CAAuB;;EAGpD,IAAIkU,eAAeqF,qBAAqBjG,IAAxC,EAA8C;IAC5CiG,qBAAqByB,OAArBzB,CAA6Bod,2BAA7Bpd,CAAyD,KAAzDA;EAJkD;;EAQpD,IAAIA,qBAAqBc,UAArBd,CAAgCqW,WAAhCrW,KAAgD5b,sBAAYE,MAAhE,EAAwE;IACtE,MAAMi4B,WAAWvc,qBAAqBzG,SAArByG,CAA+Bwc,WAA/Bxc,CACDrF,aAAa,CADZqF,CAAjB;IAGA,MAAM2G,gBAAgB3G,qBAAqBS,kBAArBT,CAAwCqd,YAAxCrd,CACNrF,aAAa,CADPqF,CAAtB;;IAGA,IAAIuc,YAAY5V,aAAhB,EAA+B;MAC7BA,cAAc2W,QAAd3W,CAAuB4V,QAAvB5V;IARoE;EARpB;;EAoBpD,IAAIlgB,KAAJ,EAAW;IACTuZ,qBAAqB2B,IAArB3B,CAA0B1I,GAA1B0I,CAA8B,iBAA9BA,EAAiDtC,IAAjDsC,CAAsD4M,OAAO;MAC3D5M,qBAAqB2N,WAArB3N,CAAiC4M,GAAjC5M,EAAsCvZ,KAAtCuZ;IADF;EArBkD;;EA2BpDA,qBAAqBsb,6BAArBtb;AAp2EF;;AAu2EA,SAAS8X,iBAAT,QAAqC;EAAA,IAAV;IAAEznB;EAAF,CAAU;EAEnC,IAAI5E,IAAJ;;EACA,QAAQ4E,IAAR;IACE,KAAK,QAAL;MACE5E,OAAOrH,sBAAYE,MAAnBmH;MACA;;IACF,KAAK,WAAL;IACA,KAAK,SAAL;MACEA,OAAOrH,sBAAYG,OAAnBkH;MACA;;IACF,KAAK,aAAL;MACEA,OAAOrH,sBAAYI,WAAnBiH;MACA;;IACF,KAAK,QAAL;MACEA,OAAOrH,sBAAYK,MAAnBgH;MACA;;IACF,KAAK,MAAL;MACEA,OAAOrH,sBAAYC,IAAnBoH;MACA;;IACF;MACEjF,QAAQC,KAARD,CAAc,wCAAwC6J,IAAtD7J;MACA;EAnBJ;;EAqBAwZ,qBAAqBc,UAArBd,CAAgCud,UAAhCvd,CAA2CvU,IAA3CuU,EAAmE,IAAnEA;AA/3EF;;AAk4EA,SAAS+X,oBAAT,CAA8B9vB,GAA9B,EAAmC;EAGjC,QAAQA,IAAIwU,MAAZ;IACE,KAAK,UAAL;MACEuD,qBAAqBM,SAArBN,CAA+ByB,OAA/BzB,CAAuCrF,UAAvCqF,CAAkDwd,MAAlDxd;MACA;;IAEF,KAAK,MAAL;MACE,IAAI,CAACA,qBAAqBR,sBAA1B,EAAkD;QAChDQ,qBAAqB8G,OAArB9G,CAA6Byd,MAA7Bzd;MAFJ;;MAIE;;IAEF,KAAK,OAAL;MACEA,qBAAqBmT,eAArBnT;MACA;;IAEF,KAAK,QAAL;MACEA,qBAAqBwN,cAArBxN;MACA;EAjBJ;AAr4EF;;AA05EA,SAASgY,gCAAT,CAA0C/vB,GAA1C,EAA+C;EAC7C+X,qBAAqBzG,SAArByG,CAA+B0d,qBAA/B1d,GAAuD/X,IAAIM,KAA3DyX;AA35EF;;AA85EA,SAAS6X,2BAAT,QAA+C;EAAA,IAAV;IAAEpsB;EAAF,CAAU;EAC7CuU,qBAAqBU,iBAArBV,CAAuCoW,sBAAvCpW,GACEvU,SAASrH,sBAAYE,MADvB0b;;EAGA,IAAIA,qBAAqB6B,gBAAzB,EAA2C;IAAA;;IAEzC7B,8CAAqBqB,KAArBrB,gFAA4B3W,GAA5B2W,CAAgC,aAAhCA,EAA+CvU,IAA/CuU,EAAqDpC,KAArDoC,CAA2D,MAAM,CAAjE;EAN2C;AA95E/C;;AA06EA,SAASyX,uBAAT,QAA+C;EAAA,IAAd;IAAEvX;EAAF,CAAc;;EAC7C,IAAIF,qBAAqB6B,gBAAzB,EAA2C;IAAA;;IAEzC7B,+CAAqBqB,KAArBrB,kFACI2d,WADJ3d,CACgB;MACZjG,MAAMmG,SAASvF,UADH;MAEZmD,MAAMoC,SAAS0d,KAFH;MAGZj2B,YAAYuY,SAASxY,IAHT;MAIZE,WAAWsY,SAAS1Y,GAJR;MAKZyS,UAAUiG,SAASjG;IALP,CADhB+F,EAQGpC,KARHoC,CAQS,MAAM,CARf;EAH2C;;EAe7C,MAAMnH,OAAOmH,qBAAqBa,cAArBb,CAAoC9E,YAApC8E,CACXE,SAAS2d,aADE7d,CAAb;EAGAA,qBAAqBM,SAArBN,CAA+ByB,OAA/BzB,CAAuCoK,YAAvCpK,CAAoDnH,IAApDmH,GAA2DnH,IAA3DmH;EACAA,qBAAqBM,SAArBN,CAA+B0B,gBAA/B1B,CAAgDsK,kBAAhDtK,CAAmEnH,IAAnEmH,GACEnH,IADFmH;EAIA,MAAM8d,cAAc9d,qBAAqBzG,SAArByG,CAA+Bwc,WAA/Bxc,CACJA,qBAAqBjG,IAArBiG,GAA4B,CADxBA,CAApB;EAGA,MAAM+d,UAAUD,uEAAaE,cAAbF,MAAgCp6B,0BAAgBI,QAAhE;EACAkc,qBAAqByB,OAArBzB,CAA6Bod,2BAA7Bpd,CAAyD+d,OAAzD/d;AAr8EF;;AAw8EA,SAASmZ,0BAAT,CAAoClxB,GAApC,EAAyC;EACvC,IAAI+X,qBAAqB6B,gBAAzB,EAA2C;IAAA;;IAEzC7B,+CAAqBqB,KAArBrB,kFAA4B3W,GAA5B2W,CAAgC,YAAhCA,EAA8C/X,IAAIoI,IAAlD2P,EAAwDpC,KAAxDoC,CAA8D,MAAM,CAApE;EAHqC;AAx8EzC;;AAi9EA,SAASqZ,0BAAT,CAAoCpxB,GAApC,EAAyC;EACvC,IAAI+X,qBAAqB6B,gBAAzB,EAA2C;IAAA;;IAEzC7B,+CAAqBqB,KAArBrB,kFAA4B3W,GAA5B2W,CAAgC,YAAhCA,EAA8C/X,IAAIoI,IAAlD2P,EAAwDpC,KAAxDoC,CAA8D,MAAM,CAApE;EAHqC;AAj9EzC;;AA09EA,SAASsX,eAAT,GAA2B;EACzB,MAAM;IAAEhe,WAAF;IAAeC,SAAf;IAA0BmH;EAA1B,IAAgDV,oBAAtD;;EAEA,IAAIU,kBAAkByV,QAAlBzV,IAA8B7a,OAAOqgB,UAAPrgB,CAAkB,OAAlBA,EAA2BsgB,OAA7D,EAAsE;IAEpE;EALuB;;EAOzB5M,UAAU0kB,wBAAV1kB;;EAEA,IAAI,CAACD,WAAL,EAAkB;IAChB;EAVuB;;EAYzB,MAAMiQ,oBAAoBhQ,UAAUgQ,iBAApC;;EACA,IACEA,sBAAsB,MAAtBA,IACAA,sBAAsB,UADtBA,IAEAA,sBAAsB,YAHxB,EAIE;IAEAhQ,UAAUgQ,iBAAVhQ,GAA8BgQ,iBAA9BhQ;EAnBuB;;EAqBzBA,UAAU2X,MAAV3X;AA/+EF;;AAk/EA,SAASge,mBAAT,CAA6BtvB,GAA7B,EAAkC;EAAA;;EAChC,MAAMuT,OAAOvT,IAAIuT,IAAjB;;EACA,IAAI,CAACA,IAAL,EAAW;IACT;EAH8B;;EAKhC,IAAI,CAACwE,qBAAqB6B,gBAA1B,EAA4C;IAC1C7B,qBAAqBC,eAArBD,GAAuCxE,IAAvCwE;EADF,OAEO,IAAI,4BAACA,qBAAqBxG,UAAtB,mDAACwG,uBAAiCke,kBAAlC,CAAJ,EAA0D;IAC/Dle,qBAAqBa,cAArBb,CAAoCzE,OAApCyE,CAA4CxE,IAA5CwE;EAR8B;AAl/ElC;;AA8/EiE;EAE/D,IAAI2Z,2BAA2B,UAAU1xB,GAAV,EAAe;IAAA;;IAC5C,8BAAI+X,qBAAqBzG,SAAzB,mDAAIyG,uBAAgCkJ,oBAApC,EAA0D;MACxD;IAF0C;;IAI5C,MAAMoC,OAAOrjB,IAAI00B,SAAJ10B,CAAc40B,KAAd50B,CAAoB,CAApBA,CAAb;IAEA,IAAIuQ,MAAMga,IAAI2L,eAAJ3L,CAAoBlH,IAApBkH,CAAV;;IACA,IAAIlH,KAAK/T,IAAT,EAAe;MACbiB,MAAM;QAAEA,GAAF;QAAOmT,aAAaL,KAAK/T;MAAzB,CAANiB;IAR0C;;IAU5CwH,qBAAqBqL,IAArBrL,CAA0BxH,GAA1BwH;EAVF;;EAcA,IAAI4Z,oBAAoB,UAAU3xB,GAAV,EAAe;IACrC,MAAM00B,YAAY3c,qBAAqBM,SAArBN,CAA+B4c,aAAjD;IACAD,UAAUyB,KAAVzB;EAFF;AA9gFF;;AAohFA,SAAS1E,yBAAT,GAAqC;EACnCjY,qBAAqBoX,uBAArBpX;AArhFF;;AAuhFA,SAASkY,mCAAT,CAA6CjwB,GAA7C,EAAkD;EAChD+X,qBAAqBzG,SAArByG,CAA+B7L,oBAA/B6L,GAAsD/X,IAAIoI,IAA1D2P;AAxhFF;;AA0hFA,SAASmY,qCAAT,CAA+ClwB,GAA/C,EAAoD;EAClD+X,qBAAqBzG,SAArByG,CAA+B4B,sBAA/B5B,GAAwD/X,GAAxD+X;AA3hFF;;AA6hFA,SAASoY,cAAT,GAA0B;EACxBpY,qBAAqBmT,eAArBnT;AA9hFF;;AAgiFA,SAASqY,iBAAT,GAA6B;EAC3BrY,qBAAqBwN,cAArBxN;AAjiFF;;AAmiFA,SAASsY,kBAAT,GAA8B;EAC5B,IAAItY,qBAAqB1G,WAAzB,EAAsC;IACpC0G,qBAAqBjG,IAArBiG,GAA4B,CAA5BA;EAF0B;AAniF9B;;AAwiFA,SAASuY,iBAAT,GAA6B;EAC3B,IAAIvY,qBAAqB1G,WAAzB,EAAsC;IACpC0G,qBAAqBjG,IAArBiG,GAA4BA,qBAAqBnG,UAAjDmG;EAFyB;AAxiF7B;;AA6iFA,SAASwY,iBAAT,GAA6B;EAC3BxY,qBAAqBzG,SAArByG,CAA+BpD,QAA/BoD;AA9iFF;;AAgjFA,SAASyY,qBAAT,GAAiC;EAC/BzY,qBAAqBzG,SAArByG,CAA+BnD,YAA/BmD;AAjjFF;;AAmjFA,SAAS0Y,eAAT,GAA2B;EACzB1Y,qBAAqBgJ,MAArBhJ;AApjFF;;AAsjFA,SAAS2Y,gBAAT,GAA4B;EAC1B3Y,qBAAqBoJ,OAArBpJ;AAvjFF;;AAyjFA,SAAS4Y,kBAAT,GAA8B;EAC5B5Y,qBAAqBsJ,SAArBtJ;AA1jFF;;AA4jFA,SAAS6Y,0BAAT,CAAoC5wB,GAApC,EAAyC;EACvC,MAAMsR,YAAYyG,qBAAqBzG,SAAvC;;EAGA,IAAItR,IAAIkB,KAAJlB,KAAc,EAAlB,EAAsB;IACpB+X,qBAAqBa,cAArBb,CAAoCtF,QAApCsF,CAA6C/X,IAAIkB,KAAjD6W;EALqC;;EAUvC,IACE/X,IAAIkB,KAAJlB,KAAcsR,UAAUS,iBAAVT,CAA4B+C,QAA5B/C,EAAdtR,IACAA,IAAIkB,KAAJlB,KAAcsR,UAAU6b,gBAF1B,EAGE;IACApV,qBAAqByB,OAArBzB,CAA6BmV,aAA7BnV,CACEzG,UAAUS,iBADZgG,EAEEzG,UAAU6b,gBAFZpV;EAdqC;AA5jFzC;;AAglFA,SAAS8Y,qBAAT,CAA+B7wB,GAA/B,EAAoC;EAClC+X,qBAAqBzG,SAArByG,CAA+BuJ,iBAA/BvJ,GAAmD/X,IAAIkB,KAAvD6W;AAjlFF;;AAmlFA,SAAS+Y,iBAAT,GAA6B;EAC3B/Y,qBAAqBmX,WAArBnX,CAAiC,EAAjCA;AAplFF;;AAslFA,SAASgZ,kBAAT,GAA8B;EAC5BhZ,qBAAqBmX,WAArBnX,CAAiC,CAAC,EAAlCA;AAvlFF;;AAylFA,SAASiZ,8BAAT,CAAwChxB,GAAxC,EAA6C;EAC3C+X,qBAAqBzG,SAArByG,CAA+B0R,4BAA/B1R,GAA8D/X,IAAI8gB,OAAlE/I;AA1lFF;;AA4lFA,SAASkZ,yBAAT,CAAmCjxB,GAAnC,EAAwC;EACtC+X,qBAAqBzG,SAArByG,CAA+BjN,UAA/BiN,GAA4C/X,IAAIoI,IAAhD2P;AA7lFF;;AA+lFA,SAASoZ,yBAAT,CAAmCnxB,GAAnC,EAAwC;EACtC+X,qBAAqBzG,SAArByG,CAA+BhN,UAA/BgN,GAA4C/X,IAAIoI,IAAhD2P;AAhmFF;;AAkmFA,SAASsZ,2BAAT,GAAuC;EACrCtZ,qBAAqBY,qBAArBZ,CAA2CqL,IAA3CrL;AAnmFF;;AAsmFA,SAASuZ,wBAAT,CAAkCtxB,GAAlC,EAAuC;EACrC+X,qBAAqB9G,QAArB8G,CAA8BtE,QAA9BsE,CAAuC,MAAvCA,EAA+C;IAC7CrE,QAAQ1T,IAAI0T,MADiC;IAE7CyR,MAAM,EAFuC;IAG7CrkB,OAAOd,IAAIc,KAHkC;IAI7C6S,cAAc3T,IAAI2T,YAJ2B;IAK7CyiB,eAAe,KAL8B;IAM7CC,YAAY,KANiC;IAO7CC,cAAc,IAP+B;IAQ7CC,cAAc,KAR+B;IAS7CC,iBAAiB;EAT4B,CAA/Cze;AAvmFF;;AAonFA,SAASwZ,+BAAT,SAA2D;EAAA,IAAlB;IAAEkF;EAAF,CAAkB;;EACzD,IAAI1e,qBAAqBR,sBAAzB,EAAiD;IAC/CQ,qBAAqBiC,gBAArBjC,CAAsChB,sBAAtCgB,CAA6D0e,YAA7D1e;EADF,OAEO;IACLA,qBAAqB8G,OAArB9G,CAA6B2e,kBAA7B3e,CAAgD0e,YAAhD1e;EAJuD;AApnF3D;;AA4nFA,SAASyZ,+BAAT,SAKG;EAAA,IALsC;IACvClxB,KADuC;IAEvCq2B,QAFuC;IAGvCF,YAHuC;IAIvCG;EAJuC,CAKtC;;EACD,IAAI7e,qBAAqBR,sBAAzB,EAAiD;IAC/CQ,qBAAqBiC,gBAArBjC,CAAsClB,sBAAtCkB,CAA6D;MAC3D7U,QAAQ5C,KADmD;MAE3Di2B,cAAcI,QAF6C;MAG3DF,YAH2D;MAI3DG;IAJ2D,CAA7D7e;EADF,OAOO;IACLA,qBAAqB8G,OAArB9G,CAA6B8e,aAA7B9e,CAA2CzX,KAA3CyX,EAAkD4e,QAAlD5e,EAA4D0e,YAA5D1e;EATD;AAjoFH;;AA8oFA,SAAS2X,sBAAT,CAAgC1vB,GAAhC,EAAqC;EACnC+X,qBAAqByB,OAArBzB,CAA6B+e,YAA7B/e,CAA0C/X,IAAI+2B,WAA9Chf,EAA2D/X,IAAI21B,KAA/D5d;EAEAA,qBAAqBzG,SAArByG,CAA+BkR,MAA/BlR;AAjpFF;;AAopFA,SAAS4X,yBAAT,CAAmC3vB,GAAnC,EAAwC;EACtC+X,qBAAqBS,kBAArBT,CAAwC9F,aAAxC8F,GAAwD/X,IAAIiS,aAA5D8F;EAEAA,qBAAqBsI,cAArBtI;EAEAA,qBAAqBzG,SAArByG,CAA+BhG,iBAA/BgG,GAAmD/X,IAAI0S,UAAvDqF;AAzpFF;;AA4pFA,SAAS0X,qBAAT,SAA0D;EAAA,IAA3B;IAAE/c,UAAF;IAAcskB;EAAd,CAA2B;EACxDjf,qBAAqByB,OAArBzB,CAA6BmV,aAA7BnV,CAA2CrF,UAA3CqF,EAAuDif,SAAvDjf;EACAA,qBAAqB0B,gBAArB1B,CAAsCmV,aAAtCnV,CAAoDrF,UAApDqF;;EAEA,IAAIA,qBAAqBc,UAArBd,CAAgCqW,WAAhCrW,KAAgD5b,sBAAYE,MAAhE,EAAwE;IACtE0b,qBAAqBS,kBAArBT,CAAwCkf,uBAAxClf,CAAgErF,UAAhEqF;EALsD;AA5pF1D;;AAqqFA,SAAS8Z,yBAAT,CAAmC7xB,GAAnC,EAAwC;EACtC+X,qBAAqBzG,SAArByG,CAA+Bmf,OAA/Bnf;AAtqFF;;AAyqFA,SAASwa,yBAAT,CAAmCvyB,GAAnC,EAAwC;EACtC,IAAI+I,SAASouB,eAATpuB,KAA6B,SAAjC,EAA4C;IAE1CquB;EAHoC;AAzqFxC;;AAgrFA,IAAIC,sBAAsB,IAA1B;;AACA,SAASD,sBAAT,GAAkC;EAChC,IAAIC,mBAAJ,EAAyB;IACvBvQ,aAAauQ,mBAAb;EAF8B;;EAIhCA,sBAAsBtQ,WAAW,YAAY;IAC3CsQ,sBAAsB,IAAtBA;EADoB,GAEnBlhB,2BAFmB,CAAtBkhB;AArrFF;;AA0rFA,SAAS7E,cAAT,CAAwBxyB,GAAxB,EAA6B;EAC3B,MAAM;IAAEsR,SAAF;IAAaoG;EAAb,IACJK,oBADF;;EAGA,IAAIzG,UAAU2P,oBAAd,EAAoC;IAClC;EALyB;;EAQ3B,IACGjhB,IAAI2X,OAAJ3X,IAAe0X,oCAAoCC,OAAnD3X,IACAA,IAAI4X,OAAJ5X,IAAe0X,oCAAoCE,OAFtD,EAGE;IAEA5X,IAAIiH,cAAJjH;;IAEA,IAAIq3B,uBAAuBtuB,SAASouB,eAATpuB,KAA6B,QAAxD,EAAkE;MAChE;IALF;;IAWA,MAAMhB,YAAY/H,IAAI+H,SAAtB;IACA,MAAMZ,QAAQD,4CAA6BlH,GAA7BkH,CAAd;IACA,MAAMowB,gBAAgBhmB,UAAUimB,YAAhC;IAEA,IAAItE,QAAQ,CAAZ;;IACA,IACElrB,cAAcyvB,WAAWC,cAAzB1vB,IACAA,cAAcyvB,WAAWE,cAF3B,EAGE;MAKA,IAAIn1B,KAAKwE,GAALxE,CAAS4E,KAAT5E,KAAmB,CAAvB,EAA0B;QACxB0wB,QAAQ1wB,KAAK4wB,IAAL5wB,CAAU4E,KAAV5E,CAAR0wB;MADF,OAEO;QAGLA,QAAQlb,qBAAqBib,oBAArBjb,CAA0C5Q,KAA1C4Q,CAARkb;MAVF;IAHF,OAeO;MAEL,MAAM0E,wBAAwB,EAA9B;MACA1E,QAAQlb,qBAAqBib,oBAArBjb,CACN5Q,QAAQwwB,qBADF5f,CAARkb;IAlCF;;IAuCA,IAAIA,QAAQ,CAAZ,EAAe;MACblb,qBAAqBoJ,OAArBpJ,CAA6B,CAACkb,KAA9Blb;IADF,OAEO,IAAIkb,QAAQ,CAAZ,EAAe;MACpBlb,qBAAqBgJ,MAArBhJ,CAA4Bkb,KAA5Blb;IA1CF;;IA6CA,MAAMwf,eAAejmB,UAAUimB,YAA/B;;IACA,IAAID,kBAAkBC,YAAtB,EAAoC;MAIlC,MAAMK,wBAAwBL,eAAeD,aAAfC,GAA+B,CAA7D;MACA,MAAMM,OAAOvmB,UAAUtH,SAAVsH,CAAoBwmB,qBAApBxmB,EAAb;MACA,MAAMymB,KAAK/3B,IAAIg4B,OAAJh4B,GAAc63B,KAAKp4B,IAA9B;MACA,MAAMw4B,KAAKj4B,IAAIk4B,OAAJl4B,GAAc63B,KAAKt4B,GAA9B;MACA+R,UAAUtH,SAAVsH,CAAoB5R,UAApB4R,IAAkCymB,KAAKH,qBAAvCtmB;MACAA,UAAUtH,SAAVsH,CAAoB3R,SAApB2R,IAAiC2mB,KAAKL,qBAAtCtmB;IAvDF;EAHF,OA4DO;IACL8lB;EArEyB;AA1rF7B;;AAmwFA,SAAS1E,mBAAT,CAA6B1yB,GAA7B,EAAkC;EAChC,IAAIA,IAAIm4B,OAAJn4B,CAAYkC,MAAZlC,GAAqB,CAAzB,EAA4B;IAS1BA,IAAIiH,cAAJjH;EAV8B;AAnwFlC;;AAixFA,SAAS2yB,cAAT,CAAwB3yB,GAAxB,EAA6B;EAC3B,IAAI,CAAC+X,qBAAqB0B,gBAArB1B,CAAsCqgB,MAA3C,EAAmD;IACjD;EAFyB;;EAI3B,MAAM/f,YAAYN,qBAAqBM,SAAvC;;EACA,IACEN,qBAAqBzG,SAArByG,CAA+BsgB,eAA/BtgB,CAA+C/X,IAAIwQ,MAAnDuH,KACCM,UAAUmB,OAAVnB,CAAkBrO,SAAlBqO,CAA4BjZ,QAA5BiZ,CAAqCrY,IAAIwQ,MAAzC6H,KACCrY,IAAIwQ,MAAJxQ,KAAeqY,UAAUoB,gBAAVpB,CAA2BigB,YAH9C,EAIE;IACAvgB,qBAAqB0B,gBAArB1B,CAAsCyK,KAAtCzK;EAVyB;AAjxF7B;;AA+xFA,SAAS6a,gBAAT,CAA0B5yB,GAA1B,EAA+B;EAC7B,IAAI+X,qBAAqBuB,cAArBvB,CAAoCwgB,MAAxC,EAAgD;IAC9C;EAF2B;;EAI7B,MAAM;IAAEtnB,QAAF;IAAYK;EAAZ,IAA0ByG,oBAAhC;EACA,MAAMygB,6BAA6BlnB,UAAU2P,oBAA7C;EAEA,IAAIwX,UAAU,KAAd;EAAA,IACEC,sBAAsB,KADxB;EAEA,MAAMC,MACH,KAAIhhB,OAAJ3X,GAAc,CAAdA,GAAkB,CAAlB,KACAA,IAAI44B,MAAJ54B,GAAa,CAAbA,GAAiB,CADjB,KAEAA,IAAI64B,QAAJ74B,GAAe,CAAfA,GAAmB,CAFnB,KAGAA,IAAI4X,OAAJ5X,GAAc,CAAdA,GAAkB,CAHlB,CADH;;EAQA,IAAI24B,QAAQ,CAARA,IAAaA,QAAQ,CAArBA,IAA0BA,QAAQ,CAAlCA,IAAuCA,QAAQ,EAAnD,EAAuD;IAErD,QAAQ34B,IAAI84B,OAAZ;MACE,KAAK,EAAL;QACE,IAAI,CAAC/gB,qBAAqBR,sBAAtB,IAAgD,CAACvX,IAAI64B,QAAzD,EAAmE;UACjE9gB,qBAAqB8G,OAArB9G,CAA6BqL,IAA7BrL;UACA0gB,UAAU,IAAVA;QAHJ;;QAKE;;MACF,KAAK,EAAL;QACE,IAAI,CAAC1gB,qBAAqBR,sBAA1B,EAAkD;UAChD,MAAM;YAAEjX;UAAF,IAAYyX,qBAAqB0F,cAAvC;;UACA,IAAInd,KAAJ,EAAW;YACT,MAAMy4B,aAAa1wB,OAAO2wB,MAAP3wB,CAAcA,OAAO6C,MAAP7C,CAAc,IAAdA,CAAdA,EAAmC/H,KAAnC+H,EAA0C;cAC3DqL,QAAQ9V,MADmD;cAE3DunB,MAAM,OAFqD;cAG3DoR,cAAcoC,QAAQ,CAARA,IAAaA,QAAQ;YAHwB,CAA1CtwB,CAAnB;YAKA4I,SAASwC,QAATxC,CAAkB,MAAlBA,EAA0B8nB,UAA1B9nB;UAR8C;;UAUhDwnB,UAAU,IAAVA;QAXJ;;QAaE;;MACF,KAAK,EAAL;MACA,KAAK,GAAL;MACA,KAAK,GAAL;MACA,KAAK,GAAL;QACE,IAAI,CAACD,0BAAL,EAAiC;UAC/BzgB,qBAAqBgJ,MAArBhJ;QAFJ;;QAIE0gB,UAAU,IAAVA;QACA;;MACF,KAAK,GAAL;MACA,KAAK,GAAL;MACA,KAAK,GAAL;QACE,IAAI,CAACD,0BAAL,EAAiC;UAC/BzgB,qBAAqBoJ,OAArBpJ;QAFJ;;QAIE0gB,UAAU,IAAVA;QACA;;MACF,KAAK,EAAL;MACA,KAAK,EAAL;QACE,IAAI,CAACD,0BAAL,EAAiC;UAE/BzR,WAAW,YAAY;YAErBhP,qBAAqBsJ,SAArBtJ;UAFF;UAIA0gB,UAAU,KAAVA;QAPJ;;QASE;;MAEF,KAAK,EAAL;QACE,IAAID,8BAA8BzgB,qBAAqBjG,IAArBiG,GAA4B,CAA9D,EAAiE;UAC/DA,qBAAqBjG,IAArBiG,GAA4B,CAA5BA;UACA0gB,UAAU,IAAVA;UACAC,sBAAsB,IAAtBA;QAJJ;;QAME;;MACF,KAAK,EAAL;QACE,IACEF,8BACAzgB,qBAAqBjG,IAArBiG,GAA4BA,qBAAqBnG,UAFnD,EAGE;UACAmG,qBAAqBjG,IAArBiG,GAA4BA,qBAAqBnG,UAAjDmG;UACA0gB,UAAU,IAAVA;UACAC,sBAAsB,IAAtBA;QAPJ;;QASE;IAlEJ;EAnB2B;;EA2F3B,IAAIC,QAAQ,CAARA,IAAaA,QAAQ,CAAzB,EAA4B;IAC1B,QAAQ34B,IAAI84B,OAAZ;MACE,KAAK,EAAL;QACE7nB,SAASwC,QAATxC,CAAkB,UAAlBA,EAA8B;UAAEyC,QAAQ9V;QAAV,CAA9BqT;QACAwnB,UAAU,IAAVA;QACA;;MAEF,KAAK,EAAL;QACmE;UAC/DxnB,SAASwC,QAATxC,CAAkB,UAAlBA,EAA8B;YAAEyC,QAAQ9V;UAAV,CAA9BqT;UACAwnB,UAAU,IAAVA;QAHJ;QAKE;IAXJ;EA5FyB;;EA6G7B,IAAIE,QAAQ,CAARA,IAAaA,QAAQ,EAAzB,EAA6B;IAC3B,QAAQ34B,IAAI84B,OAAZ;MACE,KAAK,EAAL;QACE/gB,qBAAqBoX,uBAArBpX;QACA0gB,UAAU,IAAVA;QACA;;MACF,KAAK,EAAL;QAEE1gB,qBAAqBM,SAArBN,CAA+ByB,OAA/BzB,CAAuCrF,UAAvCqF,CAAkDwd,MAAlDxd;QACA0gB,UAAU,IAAVA;QACA;IATJ;EA9G2B;;EA2H7B,IAAIA,OAAJ,EAAa;IACX,IAAIC,uBAAuB,CAACF,0BAA5B,EAAwD;MACtDlnB,UAAUwX,KAAVxX;IAFS;;IAIXtR,IAAIiH,cAAJjH;IACA;EAhI2B;;EAqI7B,MAAMi5B,aAAa3uB,0CAAnB;EACA,MAAM4uB,oBAAoBD,UAApB,aAAoBA,UAApB,uBAAoBA,WAAYE,OAAZF,CAAoBG,WAApBH,EAA1B;;EACA,IACEC,sBAAsB,OAAtBA,IACAA,sBAAsB,UADtBA,IAEAA,sBAAsB,QAFtBA,IAGAD,UAHAC,aAGAD,UAHAC,eAGAD,WAAYI,iBAJd,EAKE;IAEA,IAAIr5B,IAAI84B,OAAJ94B,KAA4B,EAAhC,EAAoC;MAClC;IAHF;EA5I2B;;EAoJ7B,IAAI24B,QAAQ,CAAZ,EAAe;IACb,IAAIW,WAAW,CAAf;IAAA,IACEC,oBAAoB,KADtB;;IAEA,QAAQv5B,IAAI84B,OAAZ;MACE,KAAK,EAAL;MACA,KAAK,EAAL;QAEE,IAAIxnB,UAAUkoB,0BAAd,EAA0C;UACxCD,oBAAoB,IAApBA;QAHJ;;QAKED,WAAW,CAAC,CAAZA;QACA;;MACF,KAAK,CAAL;QACE,IAAI,CAACd,0BAAL,EAAiC;UAC/Be,oBAAoB,IAApBA;QAFJ;;QAIED,WAAW,CAAC,CAAZA;QACA;;MACF,KAAK,EAAL;QAEE,IAAIhoB,UAAUmoB,4BAAd,EAA4C;UAC1CF,oBAAoB,IAApBA;QAlBN;;MAqBE,KAAK,EAAL;MACA,KAAK,EAAL;QACED,WAAW,CAAC,CAAZA;QACA;;MACF,KAAK,EAAL;QACE,IAAIvhB,qBAAqB0B,gBAArB1B,CAAsCqgB,MAA1C,EAAkD;UAChDrgB,qBAAqB0B,gBAArB1B,CAAsCyK,KAAtCzK;UACA0gB,UAAU,IAAVA;QAHJ;;QAKE,IACE,CAAC1gB,qBAAqBR,sBAAtB,IACAQ,qBAAqB8G,OAArB9G,CAA6B2hB,MAF/B,EAGE;UACA3hB,qBAAqB8G,OAArB9G,CAA6ByK,KAA7BzK;UACA0gB,UAAU,IAAVA;QAVJ;;QAYE;;MACF,KAAK,EAAL;MACA,KAAK,EAAL;QAEE,IAAInnB,UAAUkoB,0BAAd,EAA0C;UACxCD,oBAAoB,IAApBA;QAHJ;;QAKED,WAAW,CAAXA;QACA;;MACF,KAAK,EAAL;MACA,KAAK,EAAL;QACE,IAAI,CAACd,0BAAL,EAAiC;UAC/Be,oBAAoB,IAApBA;QAFJ;;QAIED,WAAW,CAAXA;QACA;;MACF,KAAK,EAAL;QAEE,IAAIhoB,UAAUmoB,4BAAd,EAA4C;UAC1CF,oBAAoB,IAApBA;QAxDN;;MA2DE,KAAK,EAAL;MACA,KAAK,EAAL;QACED,WAAW,CAAXA;QACA;;MAEF,KAAK,EAAL;QACE,IAAId,8BAA8BzgB,qBAAqBjG,IAArBiG,GAA4B,CAA9D,EAAiE;UAC/DA,qBAAqBjG,IAArBiG,GAA4B,CAA5BA;UACA0gB,UAAU,IAAVA;UACAC,sBAAsB,IAAtBA;QAJJ;;QAME;;MACF,KAAK,EAAL;QACE,IACEF,8BACAzgB,qBAAqBjG,IAArBiG,GAA4BA,qBAAqBnG,UAFnD,EAGE;UACAmG,qBAAqBjG,IAArBiG,GAA4BA,qBAAqBnG,UAAjDmG;UACA0gB,UAAU,IAAVA;UACAC,sBAAsB,IAAtBA;QAPJ;;QASE;;MAEF,KAAK,EAAL;QACE3gB,qBAAqBmB,cAArBnB,CAAoC4hB,UAApC5hB,CAA+C6hB,6BAAWC,MAA1D9hB;QACA;;MACF,KAAK,EAAL;QACEA,qBAAqBmB,cAArBnB,CAAoC4hB,UAApC5hB,CAA+C6hB,6BAAWE,IAA1D/hB;QACA;;MAEF,KAAK,EAAL;QACEA,qBAAqBmX,WAArBnX,CAAiC,EAAjCA;QACA;;MAEF,KAAK,GAAL;QACEA,qBAAqBc,UAArBd,CAAgCyd,MAAhCzd;QACA;IA/FJ;;IAkGA,IACEuhB,aAAa,CAAbA,KACC,CAACC,iBAAD,IAAsBjoB,UAAUgQ,iBAAVhQ,KAAgC,UADvDgoB,CADF,EAGE;MACA,IAAIA,WAAW,CAAf,EAAkB;QAChBhoB,UAAUqD,QAAVrD;MADF,OAEO;QACLA,UAAUsD,YAAVtD;MAJF;;MAMAmnB,UAAU,IAAVA;IA9GW;EApJc;;EAuQ7B,IAAIE,QAAQ,CAAZ,EAAe;IACb,QAAQ34B,IAAI84B,OAAZ;MACE,KAAK,EAAL;MACA,KAAK,EAAL;QACE,IACE,CAACN,0BAAD,IACAlnB,UAAUgQ,iBAAVhQ,KAAgC,UAFlC,EAGE;UACA;QALJ;;QAOEA,UAAUsD,YAAVtD;QAEAmnB,UAAU,IAAVA;QACA;;MAEF,KAAK,EAAL;QACE1gB,qBAAqBmX,WAArBnX,CAAiC,CAAC,EAAlCA;QACA;IAhBJ;EAxQ2B;;EA4R7B,IAAI,CAAC0gB,OAAD,IAAY,CAACD,0BAAjB,EAA6C;IAI3C,IACGx4B,IAAI84B,OAAJ94B,IAAe,EAAfA,IAAqBA,IAAI84B,OAAJ94B,IAAe,EAApCA,IACAA,IAAI84B,OAAJ94B,KAAgB,EAAhBA,IAAsBk5B,sBAAsB,QAF/C,EAGE;MACAR,sBAAsB,IAAtBA;IARyC;EA5RhB;;EAwS7B,IAAIA,uBAAuB,CAACpnB,UAAU+mB,eAAV/mB,CAA0B2nB,UAA1B3nB,CAA5B,EAAmE;IAIjEA,UAAUwX,KAAVxX;EA5S2B;;EA+S7B,IAAImnB,OAAJ,EAAa;IACXz4B,IAAIiH,cAAJjH;EAhT2B;AA/xF/B;;AAmlGA,SAASwtB,YAAT,CAAsBxtB,GAAtB,EAA2B;EACzBA,IAAIiH,cAAJjH;EACAA,IAAI+5B,WAAJ/5B,GAAkB,EAAlBA;EACA,OAAO,KAAP;AAtlGF;;AAylGA,SAASg6B,sCAAT,CAAgDljB,IAAhD,EAAsD;EACpDiB,qBAAqBiC,gBAArBjC,CAAsCD,kBAAtCC,CAAyDjB,IAAzDiB;AA1lGF;;AA8lGA,MAAMyJ,yBAAyB;EAC7BC,UAAU;IACRF,kBAAkB,KADV;;IAERuN,qBAAqB;MACnB,MAAM,IAAIvlB,KAAJ,CAAU,qCAAV,CAAN;IAHM;;EAAA;AADmB,CAA/B;;;;;;;AC9kGa;;AAEb,IAAI0wB,QAAJ;;AACA,IAAI,OAAOr8B,MAAP,KAAkB,WAAlB,IAAiCA,OAAO,sBAAP,CAArC,EAAqE;EACnEq8B,WAAWr8B,OAAO,sBAAP,CAAXq8B;AADF,OAEO;EACLA,WAAWC,OAAuBA,CAAC,iBAAxB,CAAXD;AAtBF;;AAwBAE,OAAOC,OAAPD,GAAiBF,QAAjBE;;;;;;;;;;;;;ACTA,MAAME,aAAa;EACjBC,OAAO,OADU;EAEjBC,SAAS;AAFQ,CAAnB;;;AAsBA,SAASC,oBAAT,OAA2D;EAAA,IAA7B;IAAEhqB,MAAF;IAAUlB,IAAV;IAAgBmrB,QAAQ;EAAxB,CAA6B;EACzD,OAAO,IAAI7xB,OAAJ,CAAY,UAAUC,OAAV,EAAmB6xB,MAAnB,EAA2B;IAC5C,IACE,OAAOlqB,MAAP,KAAkB,QAAlB,IACA,EAAElB,QAAQ,OAAOA,IAAP,KAAgB,QAA1B,CADA,IAEA,EAAErH,OAAOC,SAAPD,CAAiBwyB,KAAjBxyB,KAA2BwyB,SAAS,CAAtC,CAHF,EAIE;MACA,MAAM,IAAIlxB,KAAJ,CAAU,4CAAV,CAAN;IAN0C;;IAS5C,SAASoxB,OAAT,CAAiBxV,IAAjB,EAAuB;MACrB,IAAI3U,kBAAkB2M,QAAtB,EAAgC;QAC9B3M,OAAOsiB,IAAPtiB,CAAYlB,IAAZkB,EAAkBoqB,YAAlBpqB;MADF,OAEO;QACLA,OAAOkd,mBAAPld,CAA2BlB,IAA3BkB,EAAiCoqB,YAAjCpqB;MAJmB;;MAOrB,IAAIsZ,OAAJ,EAAa;QACXhD,aAAagD,OAAb;MARmB;;MAUrBjhB,QAAQsc,IAAR;IAnB0C;;IAsB5C,MAAMyV,eAAeD,QAAQnd,IAARmd,CAAa,IAAbA,EAAmBN,WAAWC,KAA9BK,CAArB;;IACA,IAAInqB,kBAAkB2M,QAAtB,EAAgC;MAC9B3M,OAAOyZ,GAAPzZ,CAAWlB,IAAXkB,EAAiBoqB,YAAjBpqB;IADF,OAEO;MACLA,OAAO5P,gBAAP4P,CAAwBlB,IAAxBkB,EAA8BoqB,YAA9BpqB;IA1B0C;;IA6B5C,MAAMqqB,iBAAiBF,QAAQnd,IAARmd,CAAa,IAAbA,EAAmBN,WAAWE,OAA9BI,CAAvB;IACA,MAAM7Q,UAAU/C,WAAW8T,cAAX,EAA2BJ,KAA3B,CAAhB;EA9BK,EAAP;AAtCF;;AA4EA,MAAMtd,QAAN,CAAe;EACbzf,cAAc;IACZ,KAAKo9B,UAAL,GAAkBzyB,OAAO6C,MAAP7C,CAAc,IAAdA,CAAlB;EAFW;;EAUb0yB,GAAGC,SAAH,EAAcC,QAAd,EAAwC;IAAA,IAAhBvrB,OAAgB,uEAAN,IAAM;;IACtC,KAAKua,GAAL,CAAS+Q,SAAT,EAAoBC,QAApB,EAA8B;MAC5BC,UAAU,IADkB;MAE5BhR,MAAMxa,OAAN,aAAMA,OAAN,uBAAMA,QAASwa;IAFa,CAA9B;EAXW;;EAsBbiR,IAAIH,SAAJ,EAAeC,QAAf,EAAyC;IAAA,IAAhBvrB,OAAgB,uEAAN,IAAM;;IACvC,KAAKojB,IAAL,CAAUkI,SAAV,EAAqBC,QAArB,EAA+B;MAC7BC,UAAU,IADmB;MAE7BhR,MAAMxa,OAAN,aAAMA,OAAN,uBAAMA,QAASwa;IAFc,CAA/B;EAvBW;;EAiCbzW,SAASunB,SAAT,EAAoBlkB,IAApB,EAA0B;IACxB,MAAMskB,iBAAiB,KAAKN,UAAL,CAAgBE,SAAhB,CAAvB;;IACA,IAAI,CAACI,cAAD,IAAmBA,eAAel5B,MAAfk5B,KAA0B,CAAjD,EAAoD;MAClD;IAHsB;;IAKxB,IAAIC,iBAAJ;;IAGA,WAAW;MAAEJ,QAAF;MAAYC,QAAZ;MAAsBhR;IAAtB,CAAX,IAA2CkR,eAAeE,KAAfF,CAAqB,CAArBA,CAA3C,EAAoE;MAClE,IAAIlR,IAAJ,EAAU;QACR,KAAK4I,IAAL,CAAUkI,SAAV,EAAqBC,QAArB;MAFgE;;MAIlE,IAAIC,QAAJ,EAAc;QACX,2CAAsB,EAAtB,GAA0B70B,IAA1B,CAA+B40B,QAA/B;QACD;MANgE;;MAQlEA,SAASnkB,IAAT;IAhBsB;;IAoBxB,IAAIukB,iBAAJ,EAAuB;MACrB,WAAWJ,QAAX,IAAuBI,iBAAvB,EAA0C;QACxCJ,SAASnkB,IAAT;MAFmB;;MAIrBukB,oBAAoB,IAApBA;IAxBsB;EAjCb;;EAgEbpR,IAAI+Q,SAAJ,EAAeC,QAAf,EAAyC;IAAA;;IAAA,IAAhBvrB,OAAgB,uEAAN,IAAM;IACvC,MAAM0rB,iBAAkB,yBAAKN,UAAL,EAAgBE,SAAhB,CAAlB,KAAkB,iBAAgBA,SAAhB,CAAlB,GAAiD,EAAjD,CAAN;IACAI,eAAe/0B,IAAf+0B,CAAoB;MAClBH,QADkB;MAElBC,UAAUxrB,2DAASwrB,QAATxrB,MAAsB,IAFd;MAGlBwa,MAAMxa,2DAASwa,IAATxa,MAAkB;IAHN,CAApB0rB;EAlEW;;EA4EbtI,KAAKkI,SAAL,EAAgBC,QAAhB,EAA0C;IAAA,IAAhBvrB,OAAgB,uEAAN,IAAM;IACxC,MAAM0rB,iBAAiB,KAAKN,UAAL,CAAgBE,SAAhB,CAAvB;;IACA,IAAI,CAACI,cAAL,EAAqB;MACnB;IAHsC;;IAKxC,KAAK,IAAI72B,IAAI,CAAR,EAAWkY,KAAK2e,eAAel5B,MAApC,EAA4CqC,IAAIkY,EAAhD,EAAoDlY,GAApD,EAAyD;MACvD,IAAI62B,eAAe72B,CAAf,EAAkB02B,QAAlBG,KAA+BH,QAAnC,EAA6C;QAC3CG,eAAeG,MAAfH,CAAsB72B,CAAtB62B,EAAyB,CAAzBA;QACA;MAHqD;IALjB;EA5E7B;;AAAA;;;;AA6Ff,MAAMle,kBAAN,SAAiCC,QAAjC,CAA0C;EACxC1J,SAASunB,SAAT,EAAoBlkB,IAApB,EAA0B;IAEtB,MAAM,IAAIvN,KAAJ,CAAU,8CAAV,CAAN;EAHoC;;AAAA;;;;;;;;;;;;;;;AC1J1C;;AACA;;;;;;;;AAEA,MAAMqwB,aAAa;EACjBC,QAAQ,CADS;EAEjBC,MAAM,CAFW;EAGjB0B,MAAM;AAHW,CAAnB;;;;;;;AAeA,MAAMpc,cAAN,CAAqB;EAInB1hB,kBAA2E;IAAA,IAA/D;MAAEsM,SAAF;MAAaiH,QAAb;MAAuB5E,mBAAmButB,WAAWC;IAArD,CAA+D;;IAAA;;IAAA;;IACzE,KAAK7vB,SAAL,GAAiBA,SAAjB;IACA,KAAKiH,QAAL,GAAgBA,QAAhB;IAEA,KAAKsnB,MAAL,GAAcqB,WAAWC,MAAzB;IACA,KAAK4B,4BAAL,GAAoC,IAApC;IAEA,KAAKC,QAAL,GAAgB,IAAIC,sBAAJ,CAAc;MAC5Bz9B,SAAS,KAAK8L;IADc,CAAd,CAAhB;;IAIA;;IAIApB,QAAQC,OAARD,GAAkB6M,IAAlB7M,CAAuB,MAAM;MAC3B,KAAK+wB,UAAL,CAAgBttB,gBAAhB;IADF;EAnBiB;;EA2BnB,IAAIuvB,UAAJ,GAAiB;IACf,OAAO,KAAKrD,MAAZ;EA5BiB;;EAoCnBoB,WAAWkC,IAAX,EAAiB;IACf,IAAI,KAAKJ,4BAAL,KAAsC,IAA1C,EAAgD;MAC9C;IAFa;;IAIf,IAAII,SAAS,KAAKtD,MAAlB,EAA0B;MACxB;IALa;;IAQf,MAAMuD,oBAAoB,MAAM;MAC9B,QAAQ,KAAKvD,MAAb;QACE,KAAKqB,WAAWC,MAAhB;UACE;;QACF,KAAKD,WAAWE,IAAhB;UACE,KAAK4B,QAAL,CAAcK,UAAd;UACA;;QACF,KAAKnC,WAAW4B,IAAhB;MANF;IADF;;IAaA,QAAQK,IAAR;MACE,KAAKjC,WAAWC,MAAhB;QACEiC;QACA;;MACF,KAAKlC,WAAWE,IAAhB;QACEgC;QACA,KAAKJ,QAAL,CAAcM,QAAd;QACA;;MACF,KAAKpC,WAAW4B,IAAhB;MAEA;QACEj9B,QAAQC,KAARD,CAAe,gBAAes9B,IAAK,4BAAnCt9B;QACA;IAZJ;;IAgBA,KAAKg6B,MAAL,GAAcsD,IAAd;;IAEA;EA3EiB;;AAAA;;;;2BA8EF;EACf,KAAK5qB,QAAL,CAAcwC,QAAd,CAAuB,mBAAvB,EAA4C;IAC1CC,QAAQ,IADkC;IAE1CmoB,MAAM,KAAKtD;EAF+B,CAA5C;AA/EiB;;+BAqFE;EACnB,KAAKtnB,QAAL,CAAcgZ,GAAd,CAAkB,kBAAlB,EAAsCjqB,OAAO;IAC3C,KAAK25B,UAAL,CAAgB35B,IAAI67B,IAApB;EADF;;EAIA,KAAK5qB,QAAL,CAAcgZ,GAAd,CAAkB,yBAAlB,EAA6CjqB,OAAO;IAClD,QAAQA,IAAIM,KAAZ;MACE,KAAKxE,gCAAsBI,UAA3B;QAAuC;UACrC,MAAM+/B,mBAAmB,KAAK1D,MAA9B;UAEA,KAAKoB,UAAL,CAAgBC,WAAWC,MAA3B;UACA,KAAK4B,4BAAL,GAAoCQ,gBAApC;UACA;QANJ;;MAQE,KAAKngC,gCAAsBE,MAA3B;QAAmC;UACjC,MAAMigC,mBAAmB,KAAKR,4BAA9B;UAEA,KAAKA,4BAAL,GAAoC,IAApC;UACA,KAAK9B,UAAL,CAAgBsC,gBAAhB;UACA;QAbJ;IAAA;EADF;AA1FiB;;;;;;;;;;;;;;;;;;;AChBrB,MAAMC,iBAAiB,kBAAvB;;;;;;;;AAEA,MAAMP,SAAN,CAAgB;EASdj+B,YAAYgS,OAAZ,EAAqB;IAAA;;IAAA;;IAAA;;IACnB,KAAKxR,OAAL,GAAewR,QAAQxR,OAAvB;IACA,KAAK6K,QAAL,GAAgB2G,QAAQxR,OAARwR,CAAgBysB,aAAhC;;IACA,IAAI,OAAOzsB,QAAQ0sB,YAAf,KAAgC,UAApC,EAAgD;MAC9C,KAAKA,YAAL,GAAoB1sB,QAAQ0sB,YAA5B;IAJiB;;IAMnB,KAAKC,eAAL,GAAuB3sB,QAAQ2sB,eAA/B;IAIA,KAAKL,QAAL,GAAgB,KAAKA,QAAL,CAAcxe,IAAd,CAAmB,IAAnB,CAAhB;IACA,KAAKue,UAAL,GAAkB,KAAKA,UAAL,CAAgBve,IAAhB,CAAqB,IAArB,CAAlB;IACA,KAAKgY,MAAL,GAAc,KAAKA,MAAL,CAAYhY,IAAZ,CAAiB,IAAjB,CAAd;IACA,KAAK8e,YAAL,GAAoB,0DAAkB9e,IAAlB,CAAuB,IAAvB,CAApB;IACA,KAAK+e,YAAL,GAAoB,0DAAkB/e,IAAlB,CAAuB,IAAvB,CAApB;IACA,KAAKgf,OAAL,GAAe,gDAAahf,IAAb,CAAkB,IAAlB,CAAf;IAIA,MAAMif,UAAW,KAAKA,OAAL,GAAe1zB,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAhC;IACA0zB,QAAQE,SAARF,GAAoB,sBAApBA;EA7BY;;EAmCdT,WAAW;IACT,IAAI,CAAC,KAAKzD,MAAV,EAAkB;MAAA;;MAChB,KAAKA,MAAL,GAAc,IAAd;MACA,KAAKr6B,OAAL,CAAa0C,gBAAb,CAA8B,WAA9B,EAA2C,KAAK07B,YAAhD,EAA8D,IAA9D;MACA,KAAKp+B,OAAL,CAAaiB,SAAb,CAAuBsH,GAAvB,CAA2By1B,cAA3B;MAEA,8BAAKG,eAAL,2FAAuB,IAAvB;IANO;EAnCG;;EAgDdN,aAAa;IACX,IAAI,KAAKxD,MAAT,EAAiB;MAAA;;MACf,KAAKA,MAAL,GAAc,KAAd;MACA,KAAKr6B,OAAL,CAAawvB,mBAAb,CAAiC,WAAjC,EAA8C,KAAK4O,YAAnD,EAAiE,IAAjE;;MACA,KAAKE,OAAL;;MACA,KAAKt+B,OAAL,CAAaiB,SAAb,CAAuByK,MAAvB,CAA8BsyB,cAA9B;MAEA,+BAAKG,eAAL,6FAAuB,KAAvB;IAPS;EAhDC;;EA2Dd7G,SAAS;IACP,IAAI,KAAK+C,MAAT,EAAiB;MACf,KAAKwD,UAAL;IADF,OAEO;MACL,KAAKC,QAAL;IAJK;EA3DK;;EA0EdI,aAAaQ,IAAb,EAAmB;IAEjB,OAAOA,KAAK1e,OAAL0e,CACL,uEADKA,CAAP;EA5EY;;AAAA;;;;uBAiFDvK,OAAO;EAClB,IAAIA,MAAMwK,MAANxK,KAAiB,CAAjBA,IAAsB,KAAK+J,YAAL,CAAkB/J,MAAM7hB,MAAxB,CAA1B,EAA2D;IACzD;EAFgB;;EAIlB,IAAI6hB,MAAMyK,cAAV,EAA0B;IACxB,IAAI;MAEFzK,MAAMyK,cAANzK,CAAqB8G,OAArB9G;IAFF,EAGE,OAAO0K,CAAP,EAAU;MAEV;IANsB;EAJR;;EAclB,KAAKC,eAAL,GAAuB,KAAK9+B,OAAL,CAAawB,UAApC;EACA,KAAKu9B,cAAL,GAAsB,KAAK/+B,OAAL,CAAayB,SAAnC;EACA,KAAKu9B,YAAL,GAAoB7K,MAAM2F,OAA1B;EACA,KAAKmF,YAAL,GAAoB9K,MAAM6F,OAA1B;EACA,KAAKnvB,QAAL,CAAcnI,gBAAd,CAA+B,WAA/B,EAA4C,KAAK27B,YAAjD,EAA+D,IAA/D;EACA,KAAKxzB,QAAL,CAAcnI,gBAAd,CAA+B,SAA/B,EAA0C,KAAK47B,OAA/C,EAAwD,IAAxD;EAIA,KAAKt+B,OAAL,CAAa0C,gBAAb,CAA8B,QAA9B,EAAwC,KAAK47B,OAA7C,EAAsD,IAAtD;EACAnK,MAAMprB,cAANorB;EACAA,MAAM+K,eAAN/K;EAEA,MAAMgL,iBAAiBt0B,SAAS0B,aAAhC;;EACA,IAAI4yB,kBAAkB,CAACA,eAAej+B,QAAfi+B,CAAwBhL,MAAM7hB,MAA9B6sB,CAAvB,EAA8D;IAC5DA,eAAeC,IAAfD;EA7BgB;AAjFN;;uBAkHDhL,OAAO;EAClB,KAAKn0B,OAAL,CAAawvB,mBAAb,CAAiC,QAAjC,EAA2C,KAAK8O,OAAhD,EAAyD,IAAzD;;EACA,IAAI,EAAEnK,MAAMkL,OAANlL,GAAgB,CAAlB,CAAJ,EAA0B;IAExB,KAAKmK,OAAL;;IACA;EALgB;;EAOlB,MAAMgB,QAAQnL,MAAM2F,OAAN3F,GAAgB,KAAK6K,YAAnC;EACA,MAAMO,QAAQpL,MAAM6F,OAAN7F,GAAgB,KAAK8K,YAAnC;EACA,MAAMx9B,YAAY,KAAKs9B,cAAL,GAAsBQ,KAAxC;EACA,MAAM/9B,aAAa,KAAKs9B,eAAL,GAAuBQ,KAA1C;;EACA,IAAI,KAAKt/B,OAAL,CAAaw/B,QAAjB,EAA2B;IACzB,KAAKx/B,OAAL,CAAaw/B,QAAb,CAAsB;MACpBn+B,KAAKI,SADe;MAEpBF,MAAMC,UAFc;MAGpBi+B,UAAU;IAHU,CAAtB;EADF,OAMO;IACL,KAAKz/B,OAAL,CAAayB,SAAb,GAAyBA,SAAzB;IACA,KAAKzB,OAAL,CAAawB,UAAb,GAA0BA,UAA1B;EAnBgB;;EAqBlB,IAAI,CAAC,KAAK+8B,OAAL,CAAaxyB,UAAlB,EAA8B;IAC5BlB,SAAS60B,IAAT70B,CAAc80B,MAAd90B,CAAqB,KAAK0zB,OAA1B1zB;EAtBgB;AAlHN;;oBA4IJ;EACR,KAAK7K,OAAL,CAAawvB,mBAAb,CAAiC,QAAjC,EAA2C,KAAK8O,OAAhD,EAAyD,IAAzD;EACA,KAAKzzB,QAAL,CAAc2kB,mBAAd,CAAkC,WAAlC,EAA+C,KAAK6O,YAApD,EAAkE,IAAlE;EACA,KAAKxzB,QAAL,CAAc2kB,mBAAd,CAAkC,SAAlC,EAA6C,KAAK8O,OAAlD,EAA2D,IAA3D;EAEA,KAAKC,OAAL,CAAa7yB,MAAb;AAjJY;;;;;;;;;;;;;ACJhB;;;;;;;;;;AAEA,MAAMoV,sBAAN,CAA6B;EAK3BthB,YAAYgS,OAAZ,EAAqBuB,QAArB,EAA+B;IAAA;;IAC7B,KAAKA,QAAL,GAAgBA,QAAhB;;IACA,yEAAoBvB,OAApB;EAPyB;;AAAA;;;;+BAgBxB;EAAA,IANY;IACbouB,sBADa;IAEbC,mBAFa;IAGbC,cAHa;IAIbC,kBAJa;IAKbC;EALa,CAMZ;EACDJ,uBAAuBl9B,gBAAvBk9B,CAAwC,OAAxCA,EAAiD99B,OAAO;IACtD,KAAKiR,QAAL,CAAcwC,QAAd,CAAuB,8BAAvB,EAAuD;MACrDC,QAAQ,IAD6C;MAErDyR,MAAMgZ,qCAA2BC,aAFoB;MAGrDl9B,OAAO48B,uBAAuBO;IAHuB,CAAvD;EADF;EAOAN,oBAAoBn9B,gBAApBm9B,CAAqC,OAArCA,EAA8C/9B,OAAO;IACnD,KAAKiR,QAAL,CAAcwC,QAAd,CAAuB,8BAAvB,EAAuD;MACrDC,QAAQ,IAD6C;MAErDyR,MAAMgZ,qCAA2BG,cAFoB;MAGrDp9B,OAAO68B,oBAAoB78B;IAH0B,CAAvD;EADF;EAOA88B,eAAep9B,gBAAfo9B,CAAgC,OAAhCA,EAAyCh+B,OAAO;IAC9C,KAAKiR,QAAL,CAAcwC,QAAd,CAAuB,8BAAvB,EAAuD;MACrDC,QAAQ,IAD6C;MAErDyR,MAAMgZ,qCAA2BI,SAFoB;MAGrDr9B,OAAO88B,eAAe98B;IAH+B,CAAvD;EADF;EAOA+8B,mBAAmBr9B,gBAAnBq9B,CAAoC,OAApCA,EAA6Cj+B,OAAO;IAClD,KAAKiR,QAAL,CAAcwC,QAAd,CAAuB,8BAAvB,EAAuD;MACrDC,QAAQ,IAD6C;MAErDyR,MAAMgZ,qCAA2BK,aAFoB;MAGrDt9B,OAAO+8B,mBAAmBI;IAH2B,CAAvD;EADF;EAOAH,iBAAiBt9B,gBAAjBs9B,CAAkC,OAAlCA,EAA2Cl+B,OAAO;IAChD,KAAKiR,QAAL,CAAcwC,QAAd,CAAuB,8BAAvB,EAAuD;MACrDC,QAAQ,IAD6C;MAErDyR,MAAMgZ,qCAA2BM,WAFoB;MAGrDv9B,OAAOg9B,iBAAiBG;IAH6B,CAAvD;EADF;;EAQA,KAAKptB,QAAL,CAAcgZ,GAAd,CAAkB,+BAAlB,EAAmDjqB,OAAO;IACxD,WAAW,CAACmlB,IAAD,EAAOjkB,KAAP,CAAX,IAA4BlB,IAAI0+B,OAAhC,EAAyC;MACvC,QAAQvZ,IAAR;QACE,KAAKgZ,qCAA2BC,aAAhC;UACEN,uBAAuB58B,KAAvB48B,GAA+B58B,KAA/B48B;UACA;;QACF,KAAKK,qCAA2BG,cAAhC;UACEP,oBAAoB78B,KAApB68B,GAA4B78B,KAA5B68B;UACA;;QACF,KAAKI,qCAA2BI,SAAhC;UACEP,eAAe98B,KAAf88B,GAAuB98B,KAAvB88B;UACA;;QACF,KAAKG,qCAA2BK,aAAhC;UACEP,mBAAmB/8B,KAAnB+8B,GAA2B/8B,KAA3B+8B;UACA;;QACF,KAAKE,qCAA2BM,WAAhC;UACEP,iBAAiBh9B,KAAjBg9B,GAAyBh9B,KAAzBg9B;UACA;MAfJ;IAFsD;EAA1D;AArDyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACF7B,MAAM9gB,cAAN,CAAqB;EAAA;IAAA;MAAA;MAAA,OACP,IAAIuhB,OAAJ;IADO;;IAAA;MAAA;MAAA,OAGT;IAHS;EAAA;;EAKnB,IAAIpG,MAAJ,GAAa;IACX,6BAAO,IAAP;EANiB;;EAgBnB,MAAMqG,QAAN,CAAeC,MAAf,EAA8C;IAAA,IAAvBC,aAAuB,uEAAP,KAAO;;IAC5C,IAAI,OAAOD,MAAP,KAAkB,QAAtB,EAAgC;MAC9B,MAAM,IAAIt1B,KAAJ,CAAU,wBAAV,CAAN;IADF,OAEO,IAAI,uCAAeiK,GAAf,CAAmBqrB,MAAnB,CAAJ,EAAgC;MACrC,MAAM,IAAIt1B,KAAJ,CAAU,oCAAV,CAAN;IAJ0C;;IAM5C,uCAAenI,GAAf,CAAmBy9B,MAAnB,EAA2B;MAAEC;IAAF,CAA3B;;IAEA,IAGE,CAACD,OAAOE,SAHV,EAIE;MACA,MAAMC,iBAAiBC,mBAAOA,CAAC,EAAR,CAAvB;;MACAD,eAAeE,cAAfF,CAA8BH,MAA9BG;;MAEA,IAAI,CAAC,KAAKG,kBAAV,EAA8B;QAC5B,KAAKA,kBAAL,GAA0B,IAA1B;QAEA,MAAMl2B,QAAQF,SAAS2zB,aAAT3zB,CAAuB,OAAvBA,CAAd;QACAE,MAAMkd,WAANld,GAAoB,kqBAApBA;QAEAF,SAASq2B,IAATr2B,CAAcs2B,OAAdt2B,CAAsBE,KAAtBF;MAVF;IAZ0C;;IA0B5C81B,OAAOj+B,gBAAPi+B,CAAwB,QAAxBA,EAAkC7+B,OAAO;MACvC,qCAAe,IAAf;IADF;EA1CiB;;EAoDnB,MAAMs/B,UAAN,CAAiBT,MAAjB,EAAyB;IACvB,IAAI,CAAC,uCAAerrB,GAAf,CAAmBqrB,MAAnB,CAAL,EAAiC;MAC/B,MAAM,IAAIt1B,KAAJ,CAAU,6BAAV,CAAN;IADF,OAEO,IAAI,yCAAiBs1B,MAArB,EAA6B;MAClC,MAAM,IAAIt1B,KAAJ,CAAU,mDAAV,CAAN;IAJqB;;IAMvB,uCAAesgB,MAAf,CAAsBgV,MAAtB;EA1DiB;;EAkEnB,MAAMzb,IAAN,CAAWyb,MAAX,EAAmB;IACjB,IAAI,CAAC,uCAAerrB,GAAf,CAAmBqrB,MAAnB,CAAL,EAAiC;MAC/B,MAAM,IAAIt1B,KAAJ,CAAU,6BAAV,CAAN;IADF,OAEO,0BAAI,IAAJ,YAAkB;MACvB,IAAI,yCAAiBs1B,MAArB,EAA6B;QAC3B,MAAM,IAAIt1B,KAAJ,CAAU,gCAAV,CAAN;MADF,OAEO,IAAI,uCAAe8F,GAAf,CAAmBwvB,MAAnB,EAA2BC,aAA/B,EAA8C;QACnD,MAAM,KAAKtc,KAAL,EAAN;MADK,OAEA;QACL,MAAM,IAAIjZ,KAAJ,CAAU,sCAAV,CAAN;MANqB;IAHR;;IAYjB,qCAAes1B,MAAf;;IACAA,OAAOE,SAAPF;EA/EiB;;EAuFnB,MAAMrc,KAAN,GAAmC;IAAA,IAAvBqc,MAAuB,6FAAd,IAAc;;IACjC,IAAI,CAAC,uCAAerrB,GAAf,CAAmBqrB,MAAnB,CAAL,EAAiC;MAC/B,MAAM,IAAIt1B,KAAJ,CAAU,6BAAV,CAAN;IADF,OAEO,IAAI,uBAAC,IAAD,UAAJ,EAAmB;MACxB,MAAM,IAAIA,KAAJ,CAAU,sCAAV,CAAN;IADK,OAEA,IAAI,yCAAiBs1B,MAArB,EAA6B;MAClC,MAAM,IAAIt1B,KAAJ,CAAU,sCAAV,CAAN;IAN+B;;IAQjCs1B,OAAOrc,KAAPqc;;IACA,qCAAe,IAAf;EAhGiB;;AAAA;;;;;;;;;;ACfpB,WAAUU,MAAV,EAAkBC,OAAlB,EAA2B;EAC1B,QAA+DrF,OAAOC,OAAPD,GAAiBqF,SAAhF,GACA,CADA;AADD,WAIO,YAAY;EAAE;;EAGpB,IAAIG,qBAAqB/hC,OAAOgiC,WAAhC;;EACA,IAAI,CAACD,kBAAD,IAAuB,OAAOA,kBAAP,KAA8B,QAAzD,EAAmE;IACjEA,qBAAqB,SAASC,WAAT,CAAqBvN,KAArB,EAA4B/vB,CAA5B,EAA+B;MAClDA,IAAIA,KAAK,EAATA;MACA,IAAIu9B,KAAK92B,SAAS+2B,WAAT/2B,CAAqB,aAArBA,CAAT;MACA82B,GAAGE,eAAHF,CAAmBxN,KAAnBwN,EAA0B,CAAC,CAACv9B,EAAE09B,OAA9BH,EAAuC,CAAC,CAACv9B,EAAE29B,UAA3CJ,EAAuDv9B,EAAEgwB,MAAFhwB,IAAY,IAAnEu9B;MACA,OAAOA,EAAP;IAJF;;IAMAF,mBAAmBO,SAAnBP,GAA+B/hC,OAAOuiC,KAAPviC,CAAasiC,SAA5CP;EAXgB;;EAsBlB,SAASS,iBAAT,CAA2B5vB,MAA3B,EAAmC6hB,KAAnC,EAA0C;IACxC,IAAIgO,QAAQ,OAAOhO,MAAMlN,IAANkN,CAAWhxB,WAAXgxB,EAAnB;;IACA,IAAI,OAAO7hB,OAAO6vB,KAAP,CAAP,KAAyB,UAA7B,EAAyC;MACvC7vB,OAAO6vB,KAAP,EAAchO,KAAd7hB;IAHsC;;IAKxC,OAAOA,OAAO8vB,aAAP9vB,CAAqB6hB,KAArB7hB,CAAP;EA3BgB;;EAkClB,SAAS+vB,sBAAT,CAAgCC,EAAhC,EAAoC;IAClC,OAAOA,MAAMA,OAAOz3B,SAAS60B,IAA7B,EAAmC;MACjC,IAAI6C,IAAI7iC,OAAOyB,gBAAPzB,CAAwB4iC,EAAxB5iC,CAAR;;MACA,IAAI8iC,UAAU,UAASC,CAAT,EAAYC,EAAZ,EAAgB;QAC5B,OAAO,EAAEH,EAAEE,CAAF,MAASnhC,SAATihC,IAAsBA,EAAEE,CAAF,MAASC,EAAjC,CAAP;MADF;;MAIA,IAAIH,EAAEI,OAAFJ,GAAY,CAAZA,IACAC,QAAQ,QAAR,EAAkB,MAAlB,CADAD,IAEAC,QAAQ,WAAR,EAAqB,MAArB,CAFAD,IAGAC,QAAQ,cAAR,EAAwB,QAAxB,CAHAD,IAIAC,QAAQ,QAAR,EAAkB,MAAlB,CAJAD,IAKAC,QAAQ,aAAR,EAAuB,MAAvB,CALAD,IAMAA,EAAE,WAAF,MAAmB,SANnBA,IAOAA,EAAEK,QAAFL,KAAe,OAPfA,IAQAA,EAAEM,uBAAFN,KAA8B,OARlC,EAQ2C;QACzC,OAAO,IAAP;MAf+B;;MAiBjCD,KAAKA,GAAGQ,aAARR;IAlBgC;;IAoBlC,OAAO,KAAP;EAtDgB;;EA+DlB,SAASS,iBAAT,CAA2BT,EAA3B,EAA+B;IAC7B,OAAOA,EAAP,EAAW;MACT,IAAIA,GAAGU,SAAHV,KAAiB,QAArB,EAA+B;QAC7B,OAAyCA,EAAzC;MAFO;;MAIT,IAAIA,GAAGQ,aAAP,EAAsB;QACpBR,KAAKA,GAAGQ,aAARR;MADF,OAEO,IAAIA,GAAGv2B,UAAP,EAAmB;QACxBu2B,KAAKA,GAAGv2B,UAAHu2B,CAAcW,IAAnBX;MADK,OAEA;QACLA,KAAK,IAALA;MATO;IADkB;;IAa7B,OAAO,IAAP;EA5EgB;;EAsFlB,SAASY,QAAT,CAAkBZ,EAAlB,EAAsB;IAEpB,OAAOA,MAAMA,GAAG71B,UAAT61B,IAAuBA,GAAG71B,UAAH61B,CAAc/1B,aAA5C,EAA2D;MACzD+1B,KAAKA,GAAG71B,UAAH61B,CAAc/1B,aAAnB+1B;IAHkB;;IAMpB,IAAIA,MAAMA,GAAGlD,IAATkD,IAAiBA,OAAOz3B,SAAS60B,IAArC,EAA2C;MACzC4C,GAAGlD,IAAHkD;IAPkB;EAtFJ;;EAsGlB,SAASa,UAAT,CAAoBC,QAApB,EAA8B1E,IAA9B,EAAoC;IAClC,KAAK,IAAIr4B,IAAI,CAAb,EAAgBA,IAAI+8B,SAASp/B,MAA7B,EAAqC,EAAEqC,CAAvC,EAA0C;MACxC,IAAI+8B,SAAS/8B,CAAT,MAAgBq4B,IAApB,EAA0B;QACxB,OAAO,IAAP;MAFsC;IADR;;IAMlC,OAAO,KAAP;EA5GgB;;EAmHlB,SAAS2E,kBAAT,CAA4Bf,EAA5B,EAAgC;IAC9B,IAAI,CAACA,EAAD,IAAO,CAACA,GAAGgB,YAAHhB,CAAgB,QAAhBA,CAAZ,EAAuC;MACrC,OAAO,KAAP;IAF4B;;IAI9B,OAAOA,GAAGiB,YAAHjB,CAAgB,QAAhBA,EAA0Bn/B,WAA1Bm/B,OAA4C,QAAnD;EAvHgB;;EA8HlB,SAASkB,0BAAT,CAAoCC,WAApC,EAAiD;IAG/C,IAAIC,OAAO,CAAC,QAAD,EAAW,OAAX,EAAoB,QAApB,EAA8B,QAA9B,EAAwC,UAAxC,CAAX;IACA,IAAI9gC,QAAQ8gC,KAAKC,GAALD,CAAS,UAASpB,EAAT,EAAa;MAChC,OAAOA,KAAK,kBAAZ;IADU,EAAZ;IAIA1/B,MAAMuF,IAANvF,CAAW,+CAAXA;IACA,IAAI0P,SAASmxB,YAAYj3B,aAAZi3B,CAA0B7gC,MAAM4lB,IAAN5lB,CAAW,IAAXA,CAA1B6gC,CAAb;;IAEA,IAAI,CAACnxB,MAAD,IAAW,kBAAkBsxB,QAAQ5B,SAAzC,EAAoD;MAIlD,IAAI6B,QAAQJ,YAAYK,gBAAZL,CAA6B,GAA7BA,CAAZ;;MACA,KAAK,IAAIp9B,IAAI,CAAb,EAAgBA,IAAIw9B,MAAM7/B,MAA1B,EAAkCqC,GAAlC,EAAuC;QACrC,IAAIw9B,MAAMx9B,CAAN,EAAS40B,OAAT4I,IAAoBA,MAAMx9B,CAAN,EAASoG,UAAjC,EAA6C;UAC3C6F,SAASkxB,2BAA2BK,MAAMx9B,CAAN,EAASoG,UAApC,CAAT6F;;UACA,IAAIA,MAAJ,EAAY;YACV;UAHyC;QADR;MALW;IAXL;;IAyB/C,OAAOA,MAAP;EAvJgB;;EA+JlB,SAASyxB,WAAT,CAAqB/jC,OAArB,EAA8B;IAC5B,OAAOA,QAAQ+jC,WAAR/jC,IAAuB6K,SAAS60B,IAAT70B,CAAc3J,QAAd2J,CAAuB7K,OAAvB6K,CAA9B;EAhKgB;;EAuKlB,SAASm5B,iBAAT,CAA2B7P,KAA3B,EAAkC;IAChC,IAAIA,MAAM8P,SAAV,EAAqB;MACnB,OAAO9P,MAAM8P,SAAb;IAF8B;;IAKhC,IAAIC,OAAO/P,MAAM7hB,MAAjB;;IACA,IAAI,EAAE4xB,gBAAgBC,eAAlB,CAAJ,EAAwC;MACtC,OAAO,IAAP;IAP8B;;IAUhC,IAAIF,YAAYnD,eAAesD,aAA/B;;IACA,IAAI,CAACH,SAAL,EAAgB;MACd,IAAI3xB,SAAS6hB,MAAM7hB,MAAnB;MACA,IAAI+xB,OAAQ,iBAAiB/xB,MAAjB,IAA2BA,OAAOgyB,WAAPhyB,EAA3B,IAAmDzH,QAA/D;MACAo5B,YAAYI,KAAK93B,aAAjB03B;IAd8B;;IAiBhC,IAAI,CAACA,SAAD,IAAcA,UAAUC,IAAVD,KAAmBC,IAArC,EAA2C;MACzC,OAAO,IAAP;IAlB8B;;IAoBhC,OAAOD,SAAP;EA3LgB;;EAiMlB,SAASM,iBAAT,CAA2BpQ,KAA3B,EAAkC;IAChC,IAAIA,MAAMqQ,gBAAV,EAA4B;MAC1B;IAF8B;;IAIhC,IAAIN,OAAwC/P,MAAM7hB,MAAlD;IAGA,IAAItP,QAAQ89B,eAAe2D,gBAA3B;IACA,IAAIR,YAAYD,kBAAkB7P,KAAlB,CAAhB;;IACA,IAAInxB,UAAU,IAAVA,IAAkBihC,SAAtB,EAAiC;MAC/BjhC,QAAQihC,UAAUjhC,KAAlBA;IAV8B;;IAehC,IAAI29B,SAASoC,kBAAkBmB,IAAlB,CAAb;;IACA,IAAI,CAACvD,MAAL,EAAa;MACX;IAjB8B;;IAqBhC,IAAI+D,aAAaT,aAAaA,UAAUV,YAAVU,CAAuB,YAAvBA,CAAbA,IAAqDC,KAAKX,YAALW,CAAkB,QAAlBA,CAAtE;;IACA,IAAIQ,eAAe,QAAnB,EAA6B;MAC3B;IAvB8B;;IAyBhCvQ,MAAMprB,cAANorB;;IAEA,IAAInxB,SAAS,IAAb,EAAmB;MAEjB29B,OAAOrc,KAAPqc,CAAa39B,KAAb29B;IAFF,OAGO;MACLA,OAAOrc,KAAPqc;IA/B8B;EAjMhB;;EAwOlB,SAASgE,kBAAT,CAA4BhE,MAA5B,EAAoC;IAClC,KAAKiE,OAAL,GAAejE,MAAf;IACA,KAAKkE,iBAAL,GAAyB,KAAzB;IACA,KAAKC,YAAL,GAAoB,KAApB;;IAGA,IAAI,CAACnE,OAAO2C,YAAP3C,CAAoB,MAApBA,CAAL,EAAkC;MAChCA,OAAOoE,YAAPpE,CAAoB,MAApBA,EAA4B,QAA5BA;IAPgC;;IAUlCA,OAAOx0B,IAAPw0B,GAAc,KAAKx0B,IAAL,CAAUmT,IAAV,CAAe,IAAf,CAAdqhB;IACAA,OAAOE,SAAPF,GAAmB,KAAKE,SAAL,CAAevhB,IAAf,CAAoB,IAApB,CAAnBqhB;IACAA,OAAOrc,KAAPqc,GAAe,KAAKrc,KAAL,CAAWhF,IAAX,CAAgB,IAAhB,CAAfqhB;IAEAA,OAAOj+B,gBAAPi+B,CAAwB,QAAxBA,EAAkC4D,iBAAlC5D,EAAqD,KAArDA;;IAEA,IAAI,EAAE,iBAAiBA,MAAnB,CAAJ,EAAgC;MAC9BA,OAAO9E,WAAP8E,GAAqB,EAArBA;IAjBgC;;IAoBlC,IAAI,sBAAsBjhC,MAA1B,EAAkC;MAChC,IAAIslC,KAAK,IAAIC,gBAAJ,CAAqB,KAAKC,cAAL,CAAoB5lB,IAApB,CAAyB,IAAzB,CAArB,CAAT;MACA0lB,GAAGG,OAAHH,CAAWrE,MAAXqE,EAAmB;QAACI,YAAY,IAAb;QAAmBC,iBAAiB,CAAC,MAAD;MAApC,CAAnBL;IAFF,OAGO;MAIL,IAAIM,UAAU,KAAd;;MACA,IAAIC,KAAK,YAAW;QAClBD,UAAU,KAAKE,cAAL,EAAV,GAAkC,KAAKN,cAAL,EAAlCI;QACAA,UAAU,KAAVA;MAFO,EAGPhmB,IAHO,CAGF,IAHE,CAAT;;MAIA,IAAIsM,OAAJ;;MACA,IAAI6Z,aAAa,UAAS9D,EAAT,EAAa;QAC5B,IAAIA,GAAGrvB,MAAHqvB,KAAchB,MAAlB,EAA0B;UAAE;QADA;;QAE5B,IAAI+E,OAAO,gBAAX;QACAJ,WAAY3D,GAAG1a,IAAH0a,CAAQgE,MAARhE,CAAe,CAAfA,EAAkB+D,KAAK1hC,MAAvB29B,MAAmC+D,IAA/CJ;QACA5lC,OAAOkpB,YAAPlpB,CAAoBksB,OAApBlsB;QACAksB,UAAUlsB,OAAOmpB,UAAPnpB,CAAkB6lC,EAAlB7lC,EAAsB,CAAtBA,CAAVksB;MALF;;MAOA,CAAC,iBAAD,EAAoB,gBAApB,EAAsC,4BAAtC,EAAoEga,OAApE,CAA4E,UAASx0B,IAAT,EAAe;QACzFuvB,OAAOj+B,gBAAPi+B,CAAwBvvB,IAAxBuvB,EAA8B8E,UAA9B9E;MADF;IAxCgC;;IA+ClCx2B,OAAO07B,cAAP17B,CAAsBw2B,MAAtBx2B,EAA8B,MAA9BA,EAAsC;MACpCjH,KAAK,KAAK4iC,OAAL,CAAaxmB,IAAb,CAAkB,IAAlB,CAD+B;MAEpCnO,KAAKwvB,OAAO2C,YAAP3C,CAAoBrhB,IAApBqhB,CAAyBA,MAAzBA,EAAiC,MAAjCA;IAF+B,CAAtCx2B;IAKA,KAAK47B,SAAL,GAAiBl7B,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAjB;IACA,KAAKk7B,SAAL,CAAetH,SAAf,GAA2B,UAA3B;IACA,KAAKsH,SAAL,CAAerjC,gBAAf,CAAgC,SAAhC,EAA6C,KAAKsjC,mBAAL,CAAyB1mB,IAAzB,CAA8B,IAA9B,CAA7C;IACA,KAAKymB,SAAL,CAAerjC,gBAAf,CAAgC,WAAhC,EAA6C,KAAKsjC,mBAAL,CAAyB1mB,IAAzB,CAA8B,IAA9B,CAA7C;IACA,KAAKymB,SAAL,CAAerjC,gBAAf,CAAgC,OAAhC,EAA6C,KAAKsjC,mBAAL,CAAyB1mB,IAAzB,CAA8B,IAA9B,CAA7C;EAhSgB;;EAmSlBqlB,mBAAmB3C,SAAnB2C,GAA2E;IAEzE,IAAIhE,MAAJ,GAAa;MACX,OAAO,KAAKiE,OAAZ;IAHuE;;IAWzEM,gBAAgB,YAAW;MACzB,IAAI,KAAKN,OAAL,CAAatB,YAAb,CAA0B,MAA1B,KAAqCS,YAAY,KAAKa,OAAjB,CAAzC,EAAoE;QAAE;MAD7C;;MAEzB,KAAKY,cAAL;IAbuE;IAmBzEA,gBAAgB,YAAW;MACzB,IAAI,CAAC,KAAKV,YAAV,EAAwB;QAAE;MADD;;MAEzB,KAAKA,YAAL,GAAoB,KAApB;MACA,KAAKF,OAAL,CAAa75B,KAAb,CAAmBk7B,MAAnB,GAA4B,EAA5B;;MAKA,IAAI,KAAKpB,iBAAT,EAA4B;QAC1B,KAAKD,OAAL,CAAa75B,KAAb,CAAmB1J,GAAnB,GAAyB,EAAzB;QACA,KAAKwjC,iBAAL,GAAyB,KAAzB;MAVuB;;MAczB,KAAKkB,SAAL,CAAeh6B,UAAf,IAA6B,KAAKg6B,SAAL,CAAeh6B,UAAf,CAA0Bm6B,WAA1B,CAAsC,KAAKH,SAA3C,CAA7B;MACAjF,eAAeqF,EAAfrF,CAAkBsF,YAAlBtF,CAA+B,IAA/BA;IAlCuE;IAwCzEgF,SAAS,UAAS9iC,KAAT,EAAgB;MACvB,IAAIA,KAAJ,EAAW;QACT,KAAK4hC,OAAL,CAAatB,YAAb,CAA0B,MAA1B,KAAqC,KAAKsB,OAAL,CAAaG,YAAb,CAA0B,MAA1B,EAAkC,EAAlC,CAArC;MADF,OAEO;QACL,KAAKH,OAAL,CAAayB,eAAb,CAA6B,MAA7B;QACA,KAAKnB,cAAL;MALqB;IAxCgD;IAuDzEc,qBAAqB,UAASnH,CAAT,EAAY;MAC/B,IAAI,CAAC,KAAK+F,OAAL,CAAatB,YAAb,CAA0B,UAA1B,CAAL,EAA4C;QAI1C,IAAIgD,OAAOz7B,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAX;QACA,KAAK+5B,OAAL,CAAa2B,YAAb,CAA0BD,IAA1B,EAAgC,KAAK1B,OAAL,CAAa4B,UAA7C;QACAF,KAAKG,QAALH,GAAgB,CAAC,CAAjBA;QACAA,KAAK1b,KAAL0b;QACA,KAAK1B,OAAL,CAAasB,WAAb,CAAyBI,IAAzB;MARF,OASO;QACL,KAAK1B,OAAL,CAAaha,KAAb;MAX6B;;MAc/B,IAAI8b,kBAAkB77B,SAAS+2B,WAAT/2B,CAAqB,aAArBA,CAAtB;MACA67B,gBAAgBC,cAAhBD,CAA+B7H,EAAE5X,IAAjCyf,EAAuC7H,EAAEiD,OAAzC4E,EAAkD7H,EAAEkD,UAApD2E,EAAgEhnC,MAAhEgnC,EACI7H,EAAEzK,MADNsS,EACc7H,EAAE+H,OADhBF,EACyB7H,EAAEgI,OAD3BH,EACoC7H,EAAE/E,OADtC4M,EAC+C7H,EAAE7E,OADjD0M,EAC0D7H,EAAEplB,OAD5DitB,EAEI7H,EAAEnE,MAFNgM,EAEc7H,EAAElE,QAFhB+L,EAE0B7H,EAAEnlB,OAF5BgtB,EAEqC7H,EAAEF,MAFvC+H,EAE+C7H,EAAEiI,aAFjDJ;MAGA,KAAK9B,OAAL,CAAaxC,aAAb,CAA2BsE,eAA3B;MACA7H,EAAEK,eAAFL;IA1EuE;IAiFzEkI,QAAQ,YAAW;MAEjB,IAAIz0B,SAAS,KAAKsyB,OAAL,CAAap4B,aAAb,CAA2B,6BAA3B,CAAb;;MACA,IAAI,CAAC8F,MAAD,IAAW,KAAKsyB,OAAL,CAAa6B,QAAb,IAAyB,CAAxC,EAA2C;QACzCn0B,SAAS,KAAKsyB,OAAdtyB;MAJe;;MAMjB,IAAI,CAACA,MAAL,EAAa;QACXA,SAASkxB,2BAA2B,KAAKoB,OAAhC,CAATtyB;MAPe;;MASjB4wB,SAASr4B,SAAS0B,aAAlB;MACA+F,UAAUA,OAAOsY,KAAPtY,EAAVA;IA3FuE;IAoGzE00B,cAAc,UAASC,OAAT,EAAkBC,SAAlB,EAA6B;MACzC,IAAID,UAAUC,SAAd,EAAyB;QACvB,MAAM,IAAI77B,KAAJ,CAAU,qCAAV,CAAN;MAFuC;;MAIzC,KAAKu5B,OAAL,CAAa75B,KAAb,CAAmBk7B,MAAnB,GAA4BgB,OAA5B;MACA,KAAKlB,SAAL,CAAeh7B,KAAf,CAAqBk7B,MAArB,GAA8BiB,SAA9B;IAzGuE;IA+GzE/6B,MAAM,YAAW;MACf,IAAI,CAAC,KAAKy4B,OAAL,CAAa1f,IAAlB,EAAwB;QACtB,KAAK4gB,OAAL,CAAa,IAAb;QACA,KAAKiB,MAAL;MAHa;IA/GwD;IAyHzElG,WAAW,YAAW;MACpB,IAAI,KAAK+D,OAAL,CAAatB,YAAb,CAA0B,MAA1B,CAAJ,EAAuC;QACrC,MAAM,IAAIj4B,KAAJ,CAAU,iHAAV,CAAN;MAFkB;;MAIpB,IAAI,CAAC04B,YAAY,KAAKa,OAAjB,CAAL,EAAgC;QAC9B,MAAM,IAAIv5B,KAAJ,CAAU,8EAAV,CAAN;MALkB;;MAOpB,IAAI,CAACy1B,eAAeqF,EAAfrF,CAAkBqG,UAAlBrG,CAA6B,IAA7BA,CAAL,EAAyC;QACvC,MAAM,IAAIz1B,KAAJ,CAAU,mFAAV,CAAN;MARkB;;MAWpB,IAAIg3B,uBAAuB,KAAKuC,OAAL,CAAa9B,aAApC,CAAJ,EAAwD;QACtDziC,QAAQid,IAARjd,CAAa,wDACT,yEADS,GAET,mEAFJA;MAZkB;;MAiBpB,KAAKylC,OAAL,CAAa,IAAb;MACA,KAAKhB,YAAL,GAAoB,IAApB;;MAGA,IAAIhE,eAAesG,cAAftG,CAA8B,KAAK8D,OAAnC9D,CAAJ,EAAiD;QAC/CA,eAAeuG,UAAfvG,CAA0B,KAAK8D,OAA/B9D;QACA,KAAK+D,iBAAL,GAAyB,IAAzB;MAFF,OAGO;QACL,KAAKA,iBAAL,GAAyB,KAAzB;MAzBkB;;MA6BpB,KAAKD,OAAL,CAAa74B,UAAb,CAAwBw6B,YAAxB,CAAqC,KAAKR,SAA1C,EAAqD,KAAKnB,OAAL,CAAa0C,WAAlE;MAGA,KAAKP,MAAL;IAzJuE;IAkKzEziB,OAAO,UAASijB,eAAT,EAA0B;MAC/B,IAAI,CAAC,KAAK3C,OAAL,CAAatB,YAAb,CAA0B,MAA1B,CAAL,EAAwC;QACtC,MAAM,IAAIj4B,KAAJ,CAAU,yHAAV,CAAN;MAF6B;;MAI/B,KAAKy6B,OAAL,CAAa,KAAb;;MAGA,IAAIyB,oBAAoBjmC,SAAxB,EAAmC;QACjC,KAAKsjC,OAAL,CAAa/I,WAAb,GAA2B0L,eAA3B;MAR6B;;MAY/B,IAAIC,aAAa,IAAI/F,kBAAJ,CAAuB,OAAvB,EAAgC;QAC/CK,SAAS,KADsC;QAE/CC,YAAY;MAFmC,CAAhC,CAAjB;MAIAG,kBAAkB,KAAK0C,OAAvB,EAAgC4C,UAAhC;IAlLuE;EAAA,CAA3E7C;EAuLA,IAAI7D,iBAAiB,EAArB;;EAEAA,eAAeuG,UAAfvG,GAA4B,UAAS9gC,OAAT,EAAkB;IAC5C,IAAIyB,YAAYoJ,SAAS60B,IAAT70B,CAAcpJ,SAAdoJ,IAA2BA,SAASC,eAATD,CAAyBpJ,SAApE;IACA,IAAIgmC,WAAWhmC,YAAa,QAAOimC,WAAPhoC,GAAqBM,QAAQ2nC,YAA7B,IAA6C,CAAzE;IACA3nC,QAAQ+K,KAAR/K,CAAcqB,GAAdrB,GAAoBqE,KAAKyD,GAALzD,CAAS5C,SAAT4C,EAAoBojC,QAApBpjC,IAAgC,IAApDrE;EAHF;;EAMA8gC,eAAe8G,+BAAf9G,GAAiD,UAAS9gC,OAAT,EAAkB;IACjE,KAAK,IAAIqG,IAAI,CAAb,EAAgBA,IAAIwE,SAASwT,WAATxT,CAAqB7G,MAAzC,EAAiD,EAAEqC,CAAnD,EAAsD;MACpD,IAAI+X,aAAavT,SAASwT,WAATxT,CAAqBxE,CAArBwE,CAAjB;MACA,IAAIyT,WAAW,IAAf;;MAEA,IAAI;QACFA,WAAWF,WAAWE,QAAtBA;MADF,EAEE,OAAOugB,CAAP,EAAU,CANwC;;MAOpD,IAAI,CAACvgB,QAAL,EAAe;QAAE;MAPmC;;MAQpD,KAAK,IAAIupB,IAAI,CAAb,EAAgBA,IAAIvpB,SAASta,MAA7B,EAAqC,EAAE6jC,CAAvC,EAA0C;QACxC,IAAIrpB,OAAOF,SAASupB,CAAT,CAAX;QACA,IAAIC,gBAAgB,IAApB;;QAEA,IAAI;UACFA,gBAAgBj9B,SAASi5B,gBAATj5B,CAA0B2T,KAAKupB,YAA/Bl9B,CAAhBi9B;QADF,EAEE,OAAMjJ,CAAN,EAAS,CAN6B;;QAOxC,IAAI,CAACiJ,aAAD,IAAkB,CAAC3E,WAAW2E,aAAX,EAA0B9nC,OAA1B,CAAvB,EAA2D;UACzD;QARsC;;QAUxC,IAAIgoC,SAASxpB,KAAKzT,KAALyT,CAAWypB,gBAAXzpB,CAA4B,KAA5BA,CAAb;QACA,IAAI0pB,YAAY1pB,KAAKzT,KAALyT,CAAWypB,gBAAXzpB,CAA4B,QAA5BA,CAAhB;;QACA,IAAKwpB,UAAUA,WAAW,MAArBA,IAAiCE,aAAaA,cAAc,MAAjE,EAA0E;UACxE,OAAO,IAAP;QAbsC;MARU;IADW;;IA0BjE,OAAO,KAAP;EA1BF;;EA6BApH,eAAesG,cAAftG,GAAgC,UAASH,MAAT,EAAiB;IAC/C,IAAIwH,gBAAgBzoC,OAAOyB,gBAAPzB,CAAwBihC,MAAxBjhC,CAApB;;IACA,IAAIyoC,cAAcvF,QAAduF,KAA2B,UAA/B,EAA2C;MACzC,OAAO,KAAP;IAH6C;;IAU/C,IAAKxH,OAAO51B,KAAP41B,CAAat/B,GAAbs/B,KAAqB,MAArBA,IAA+BA,OAAO51B,KAAP41B,CAAat/B,GAAbs/B,KAAqB,EAApDA,IACAA,OAAO51B,KAAP41B,CAAah6B,MAAbg6B,KAAwB,MAAxBA,IAAkCA,OAAO51B,KAAP41B,CAAah6B,MAAbg6B,KAAwB,EAD/D,EACoE;MAClE,OAAO,KAAP;IAZ6C;;IAc/C,OAAO,CAACG,eAAe8G,+BAAf9G,CAA+CH,MAA/CG,CAAR;EAdF;;EAoBAA,eAAesH,mBAAftH,GAAqC,UAAS9gC,OAAT,EAAkB;IACrD,IAAIN,OAAO2oC,iBAAP3oC,IAA4BM,QAAQ6gC,SAAxC,EAAmD;MACjDxgC,QAAQid,IAARjd,CAAa,0DACT,wBADJA,EAC8BL,OAD9BK;IAFmD;;IAKrD,IAAIL,QAAQgjC,SAARhjC,KAAsB,QAA1B,EAAoC;MAClC,MAAM,IAAIqL,KAAJ,CAAU,yDAAV,CAAN;IANmD;;IAQrD,IAAIs5B,kBAAJ,CAA0D3kC,OAA1D;EARF;;EAcA8gC,eAAeE,cAAfF,GAAgC,UAAS9gC,OAAT,EAAkB;IAChD,IAAI,CAACA,QAAQ6gC,SAAb,EAAwB;MACtBC,eAAesH,mBAAftH,CAAmC9gC,OAAnC8gC;IAF8C;EAAlD;;EASAA,eAAewH,aAAfxH,GAA+B,YAAW;IAExC,KAAKyH,kBAAL,GAA0B,EAA1B;IAEA,IAAIC,WAAW,KAAKC,SAAL,CAAenpB,IAAf,CAAoB,IAApB,CAAf;IAOA,KAAKif,OAAL,GAAe1zB,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAf;IACA,KAAK0zB,OAAL,CAAaE,SAAb,GAAyB,iBAAzB;IACA,KAAKF,OAAL,CAAa77B,gBAAb,CAA8B,OAA9B,EAAuC,UAASm8B,CAAT,EAAY;MACjD,KAAK6J,WAAL,GAAmBpnC,SAAnB;MACAu9B,EAAEK,eAAFL;MACA2J,SAAS,EAAT;IAHqC,EAIrClpB,IAJqC,CAIhC,IAJgC,CAAvC;IAMA,KAAKqpB,UAAL,GAAkB,KAAKA,UAAL,CAAgBrpB,IAAhB,CAAqB,IAArB,CAAlB;IACA,KAAKspB,YAAL,GAAoB,KAAKA,YAAL,CAAkBtpB,IAAlB,CAAuB,IAAvB,CAApB;IAEA,KAAKupB,UAAL,GAAkB,MAAlB;IACA,KAAKC,WAAL,GAAmB,SAAS,GAA5B;IAEA,KAAKJ,WAAL,GAAmBpnC,SAAnB;;IAEA,IAAI,sBAAsB5B,MAA1B,EAAkC;MAChC,KAAKqpC,GAAL,GAAW,IAAI9D,gBAAJ,CAAqB,UAAS+D,OAAT,EAAkB;QAChD,IAAI1D,UAAU,EAAd;QACA0D,QAAQpD,OAARoD,CAAgB,UAASC,GAAT,EAAc;UAC5B,KAAK,IAAI5iC,IAAI,CAAR,EAAWzB,CAAhB,EAAmBA,IAAIqkC,IAAIC,YAAJD,CAAiB5iC,CAAjB4iC,CAAvB,EAA4C,EAAE5iC,CAA9C,EAAiD;YAC/C,IAAI,EAAEzB,aAAag/B,OAAf,CAAJ,EAA6B;cAC3B;YADF,OAEO,IAAIh/B,EAAEo+B,SAAFp+B,KAAgB,QAApB,EAA8B;cACnC0gC,QAAQn9B,IAARm9B,CAAa1gC,CAAb0gC;YAJ6C;;YAM/CA,UAAUA,QAAQ6D,MAAR7D,CAAe1gC,EAAEk/B,gBAAFl/B,CAAmB,QAAnBA,CAAf0gC,CAAVA;UAP0B;QAA9B;QAUAA,QAAQthC,MAARshC,IAAkBkD,SAASlD,OAAT,CAAlBA;MAZS,EAAX;IA5BsC;EAA1C;;EAiDAxE,eAAewH,aAAfxH,CAA6BkB,SAA7BlB,CAAuCsI,aAAvCtI,GAAuD,YAAW;IAChEj2B,SAASC,eAATD,CAAyBnI,gBAAzBmI,CAA0C,OAA1CA,EAAmD,KAAK+9B,YAAxD/9B,EAAsE,IAAtEA;IACAA,SAASnI,gBAATmI,CAA0B,SAA1BA,EAAqC,KAAK89B,UAA1C99B;IACA,KAAKk+B,GAAL,IAAY,KAAKA,GAAL,CAAS5D,OAAT,CAAiBt6B,QAAjB,EAA2B;MAACw+B,WAAW,IAAZ;MAAkBC,SAAS;IAA3B,CAA3B,CAAZ;EAHF;;EAUAxI,eAAewH,aAAfxH,CAA6BkB,SAA7BlB,CAAuCyI,eAAvCzI,GAAyD,YAAW;IAClEj2B,SAASC,eAATD,CAAyB2kB,mBAAzB3kB,CAA6C,OAA7CA,EAAsD,KAAK+9B,YAA3D/9B,EAAyE,IAAzEA;IACAA,SAAS2kB,mBAAT3kB,CAA6B,SAA7BA,EAAwC,KAAK89B,UAA7C99B;IACA,KAAKk+B,GAAL,IAAY,KAAKA,GAAL,CAASS,UAAT,EAAZ;EAHF;;EASA1I,eAAewH,aAAfxH,CAA6BkB,SAA7BlB,CAAuC2I,cAAvC3I,GAAwD,YAAW;IACjE,IAAImF,SAAS,KAAK6C,WAAlB;;IAEA,KAAK,IAAIziC,IAAI,CAAR,EAAWqjC,GAAhB,EAAqBA,MAAM,KAAKnB,kBAAL,CAAwBliC,CAAxB,CAA3B,EAAuD,EAAEA,CAAzD,EAA4D;MAC1DqjC,IAAI1C,YAAJ0C,CAAiB,EAAEzD,MAAnByD,EAA2B,EAAEzD,MAA7ByD;;MACA,IAAIrjC,MAAM,CAAV,EAAa;QACX,KAAKk4B,OAAL,CAAaxzB,KAAb,CAAmBk7B,MAAnB,GAA4B,EAAEA,MAA9B;MAHwD;IAHK;;IAWjE,IAAIx9B,OAAO,KAAK8/B,kBAAL,CAAwB,CAAxB,CAAX;;IACA,IAAI9/B,IAAJ,EAAU;MACR,IAAI3D,IAAI2D,KAAKk4B,MAALl4B,CAAYsD,UAAZtD,IAA0BoC,SAAS60B,IAA3C;MACA56B,EAAE6kC,WAAF7kC,CAAc,KAAKy5B,OAAnBz5B;IAFF,OAGO,IAAI,KAAKy5B,OAAL,CAAaxyB,UAAjB,EAA6B;MAClC,KAAKwyB,OAAL,CAAaxyB,UAAb,CAAwBm6B,WAAxB,CAAoC,KAAK3H,OAAzC;IAhB+D;EAAnE;;EAwBAuC,eAAewH,aAAfxH,CAA6BkB,SAA7BlB,CAAuC8I,qBAAvC9I,GAA+D,UAAS+I,SAAT,EAAoB;IACjF,OAAOA,YAAY9G,kBAAkB8G,SAAlB,CAAnB,EAAiD;MAC/C,KAAK,IAAIxjC,IAAI,CAAR,EAAWqjC,GAAhB,EAAqBA,MAAM,KAAKnB,kBAAL,CAAwBliC,CAAxB,CAA3B,EAAuD,EAAEA,CAAzD,EAA4D;QAC1D,IAAIqjC,IAAI/I,MAAJ+I,KAAeG,SAAnB,EAA8B;UAC5B,OAAOxjC,MAAM,CAAb;QAFwD;MADb;;MAM/CwjC,YAAYA,UAAU/G,aAAtB+G;IAP+E;;IASjF,OAAO,KAAP;EATF;;EAYA/I,eAAewH,aAAfxH,CAA6BkB,SAA7BlB,CAAuC8H,YAAvC9H,GAAsD,UAAS3M,KAAT,EAAgB;IACpE,IAAI7hB,SAAS6hB,MAAM2V,YAAN3V,GAAqBA,MAAM2V,YAAN3V,GAAqB,CAArBA,CAArBA,GAA+CA,MAAM7hB,MAAlE;;IAEA,IAAI,KAAKs3B,qBAAL,CAA2Bt3B,MAA3B,CAAJ,EAAwC;MAAE;IAH0B;;IAKpE,IAAIzH,SAAS0B,aAAT1B,KAA2BA,SAASC,eAAxC,EAAyD;MAAE;IALS;;IAOpEqpB,MAAMprB,cAANorB;IACAA,MAAM+K,eAAN/K;IACA+O,SAAiC5wB,MAAjC;;IAEA,IAAI,KAAKo2B,WAAL,KAAqBpnC,SAAzB,EAAoC;MAAE;IAX8B;;IAapE,IAAIooC,MAAM,KAAKnB,kBAAL,CAAwB,CAAxB,CAAV;IACA,IAAI5H,SAAS+I,IAAI/I,MAAjB;IACA,IAAIiC,WAAWjC,OAAOoJ,uBAAPpJ,CAA+BruB,MAA/BquB,CAAf;;IACA,IAAIiC,WAAWoH,KAAKC,2BAApB,EAAiD;MAC/C,IAAI,KAAKvB,WAAT,EAAsB;QAEpBgB,IAAI3C,MAAJ2C;MAFF,OAGO,IAAIp3B,WAAWzH,SAASC,eAAxB,EAAyC;QAE9CD,SAASC,eAATD,CAAyB+f,KAAzB/f;MAN6C;IAhBmB;;IA0BpE,OAAO,KAAP;EA1BF;;EA6BAi2B,eAAewH,aAAfxH,CAA6BkB,SAA7BlB,CAAuC6H,UAAvC7H,GAAoD,UAAS3M,KAAT,EAAgB;IAClE,KAAKuU,WAAL,GAAmBpnC,SAAnB;;IACA,IAAI6yB,MAAMyG,OAANzG,KAAkB,EAAtB,EAA0B;MACxBA,MAAMprB,cAANorB;MACAA,MAAM+K,eAAN/K;MACA,IAAI+V,cAAc,IAAIzI,kBAAJ,CAAuB,QAAvB,EAAiC;QACjDK,SAAS,KADwC;QAEjDC,YAAY;MAFqC,CAAjC,CAAlB;MAIA,IAAI2H,MAAM,KAAKnB,kBAAL,CAAwB,CAAxB,CAAV;;MACA,IAAImB,OAAOxH,kBAAkBwH,IAAI/I,MAAtB,EAA8BuJ,WAA9B,CAAX,EAAuD;QACrDR,IAAI/I,MAAJ+I,CAAWplB,KAAXolB;MATsB;IAA1B,OAWO,IAAIvV,MAAMyG,OAANzG,KAAkB,CAAtB,EAAyB;MAC9B,KAAKuU,WAAL,GAAmB,CAACvU,MAAMwG,QAA1B;IAdgE;EAApE;;EAwBAmG,eAAewH,aAAfxH,CAA6BkB,SAA7BlB,CAAuC2H,SAAvC3H,GAAmD,UAASwE,OAAT,EAAkB;IAInE,IAAI6E,QAAQ,KAAK5B,kBAAL,CAAwBnL,KAAxB,EAAZ;IACA+M,MAAMvE,OAANuE,CAAc,UAAST,GAAT,EAAc;MAC1B,IAAIpE,QAAQ8E,OAAR9E,CAAgBoE,IAAI/I,MAApB2E,MAAgC,CAAC,CAArC,EAAwC;QACtCoE,IAAIlE,cAAJkE;MADF,OAEO;QACLA,IAAIxE,cAAJwE;MAJwB;IAA5B;EALF;;EAkBA5I,eAAewH,aAAfxH,CAA6BkB,SAA7BlB,CAAuCqG,UAAvCrG,GAAoD,UAAS4I,GAAT,EAAc;IAChE,IAAIW,UAAW,MAAKvB,WAAL,GAAmB,KAAKD,UAAxB,IAAsC,CAAtC,GAA0C,CAAzD;;IACA,IAAI,KAAKN,kBAAL,CAAwBvkC,MAAxB,IAAkCqmC,OAAtC,EAA+C;MAC7C,OAAO,KAAP;IAH8D;;IAKhE,IAAI,KAAK9B,kBAAL,CAAwB+B,OAAxB,CAAgCZ,GAAhC,MAAyC,CAA7C,EAAgD;MAC9C,KAAKN,aAAL;IAN8D;;IAQhE,KAAKK,cAAL;IACA,OAAO,IAAP;EATF;;EAeA3I,eAAewH,aAAfxH,CAA6BkB,SAA7BlB,CAAuCsF,YAAvCtF,GAAsD,UAAS4I,GAAT,EAAc;IAClE,IAAIzjC,QAAQ,KAAKsiC,kBAAL,CAAwB6B,OAAxB,CAAgCV,GAAhC,CAAZ;;IACA,IAAIzjC,UAAU,CAAC,CAAf,EAAkB;MAAE;IAF8C;;IAIlE,KAAKsiC,kBAAL,CAAwBlL,MAAxB,CAA+Bp3B,KAA/B,EAAsC,CAAtC;;IACA,IAAI,KAAKsiC,kBAAL,CAAwBvkC,MAAxB,KAAmC,CAAvC,EAA0C;MACxC,KAAKulC,eAAL;IANgE;;IAQlE,KAAKE,cAAL;EARF;;EAWA3I,eAAeqF,EAAfrF,GAAoB,IAAIA,eAAewH,aAAnB,EAApBxH;EACAA,eAAesD,aAAftD,GAA+B,IAA/BA;EACAA,eAAe2D,gBAAf3D,GAAkC,IAAlCA;;EAMA,IAAIphC,OAAO2oC,iBAAP3oC,KAA6B4B,SAAjC,EAA4C;IAM1C,IAAIipC,WAAW1/B,SAAS2zB,aAAT3zB,CAAuB,MAAvBA,CAAf;IACA0/B,SAASxF,YAATwF,CAAsB,QAAtBA,EAAgC,QAAhCA;;IACA,IAAIA,SAASC,MAATD,KAAoB,QAAxB,EAAkC;MAChC,IAAIE,mBAAmBtgC,OAAOugC,wBAAPvgC,CAAgCg6B,gBAAgBnC,SAAhD73B,EAA2D,QAA3DA,CAAvB;;MACA,IAAIsgC,gBAAJ,EAAsB;QAGpB,IAAIE,UAAUF,iBAAiBt5B,GAA/B;;QACAs5B,iBAAiBt5B,GAAjBs5B,GAAuB,YAAW;UAChC,IAAIpH,mBAAmB,IAAnB,CAAJ,EAA8B;YAC5B,OAAO,QAAP;UAF8B;;UAIhC,OAAOsH,QAAQC,IAARD,CAAa,IAAbA,CAAP;QAJF;;QAMA,IAAIE,UAAUJ,iBAAiBvnC,GAA/B;;QAEAunC,iBAAiBvnC,GAAjBunC,GAAuB,UAASx/B,CAAT,EAAY;UACjC,IAAI,OAAOA,CAAP,KAAa,QAAb,IAAyBA,EAAE9H,WAAF8H,OAAoB,QAAjD,EAA2D;YACzD,OAAO,KAAK85B,YAAL,CAAkB,QAAlB,EAA4B95B,CAA5B,CAAP;UAF+B;;UAIjC,OAAO4/B,QAAQD,IAARC,CAAa,IAAbA,EAAmB5/B,CAAnB4/B,CAAP;QAJF;;QAMA1gC,OAAO07B,cAAP17B,CAAsBg6B,gBAAgBnC,SAAtC73B,EAAiD,QAAjDA,EAA2DsgC,gBAA3DtgC;MApB8B;IARQ;;IAqC1CU,SAASnI,gBAATmI,CAA0B,OAA1BA,EAAmC,UAAS82B,EAAT,EAAa;MAC9Cb,eAAesD,aAAftD,GAA+B,IAA/BA;MACAA,eAAe2D,gBAAf3D,GAAkC,IAAlCA;;MACA,IAAIa,GAAG6C,gBAAP,EAAyB;QAAE;MAHmB;;MAK9C,IAAIlyB,SAAiCqvB,GAAGrvB,MAAxC;;MACA,IAAI,kBAAkBqvB,EAAtB,EAA0B;QACxB,IAAImJ,OAAOnJ,GAAGmI,YAAHnI,EAAX;QACArvB,SAASw4B,KAAKC,KAALD,MAAgBx4B,MAAzBA;MAR4C;;MAU9C,IAAI,CAACA,MAAD,IAAW,CAAC+wB,mBAAmB/wB,OAAO4xB,IAA1B,CAAhB,EAAiD;QAAE;MAVL;;MAY9C,IAAI8G,QAAS14B,OAAO2U,IAAP3U,KAAgB,QAAhBA,IAA4B,CAAC,QAAD,EAAW,OAAX,EAAoB83B,OAApB,CAA4B93B,OAAO0wB,SAAnC,IAAgD,CAAC,CAA1F;;MACA,IAAI,CAACgI,KAAL,EAAY;QACV,IAAI,EAAE14B,OAAO0wB,SAAP1wB,KAAqB,OAArBA,IAAgCA,OAAO2U,IAAP3U,KAAgB,OAAlD,CAAJ,EAAgE;UAAE;QADxD;;QAGVwuB,eAAe2D,gBAAf3D,GAAkCa,GAAGjhC,OAAHihC,GAAa,GAAbA,GAAmBA,GAAGphC,OAAxDugC;MAhB4C;;MAmB9C,IAAIH,SAASoC,kBAAkBzwB,MAAlB,CAAb;;MACA,IAAI,CAACquB,MAAL,EAAa;QAAE;MApB+B;;MAsB9CG,eAAesD,aAAftD,GAA+BxuB,MAA/BwuB;IAtBF,GAwBG,KAxBHj2B;IA8BAA,SAASnI,gBAATmI,CAA0B,QAA1BA,EAAoC,UAAS82B,EAAT,EAAa;MAC/C,IAAIuC,OAAOvC,GAAGrvB,MAAd;MACA,IAAIquB,SAASoC,kBAAkBmB,IAAlB,CAAb;;MACA,IAAIvD,MAAJ,EAAY;QACV;MAJ6C;;MAO/C,IAAIsD,YAAYD,kBAAkBrC,EAAlB,CAAhB;MACA,IAAI+C,aAAaT,aAAaA,UAAUV,YAAVU,CAAuB,YAAvBA,CAAbA,IAAqDC,KAAKX,YAALW,CAAkB,QAAlBA,CAAtE;;MACA,IAAIQ,eAAe,QAAnB,EAA6B;QAC3B/C,GAAG54B,cAAH44B;MAV6C;IAAjD;IAkBA,IAAIsJ,mBAAmB9G,gBAAgBnC,SAAhBmC,CAA0B+G,MAAjD;;IACA,IAAIC,wBAAwB,YAAY;MACtC,IAAI,CAAC9H,mBAAmB,IAAnB,CAAL,EAA+B;QAC7B,OAAO4H,iBAAiBL,IAAjBK,CAAsB,IAAtBA,CAAP;MAFoC;;MAItC,IAAItK,SAASoC,kBAAkB,IAAlB,CAAb;MACApC,UAAUA,OAAOrc,KAAPqc,EAAVA;IALF;;IAOAwD,gBAAgBnC,SAAhBmC,CAA0B+G,MAA1B/G,GAAmCgH,qBAAnChH;EAx1BgB;;EA21BlB,OAAOrD,cAAP;AA/1BD,EAAD;;;;;;;;;;;;;ACeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAcA,MAAMtf,cAAN,CAAqB;EAcnBhiB,YAAYgS,OAAZ,EAAqB4J,cAArB,EAAqCI,IAArC,EAAqE;IAAA,IAA1BI,gBAA0B,uEAAP,KAAO;;IAAA;;IAAA;;IAAA;;IAAA;MAAA;MAAA,OAbjD;IAaiD;;IAAA;MAAA;MAAA,OAXnD;IAWmD;;IAAA;MAAA;MAAA,OAT3D;IAS2D;;IACnE,KAAK+kB,MAAL,GAAcnvB,QAAQmvB,MAAtB;IACA,KAAK7R,KAAL,GAAatd,QAAQsd,KAArB;IACA,KAAKsc,KAAL,GAAa55B,QAAQ45B,KAArB;IACA,KAAKC,YAAL,GAAoB75B,QAAQ65B,YAA5B;IACA,KAAKC,YAAL,GAAoB95B,QAAQ85B,YAA5B;IACA,KAAKlwB,cAAL,GAAsBA,cAAtB;IACA,KAAKI,IAAL,GAAYA,IAAZ;IACA,KAAK+vB,iBAAL,GAAyB3vB,gBAAzB;IAGA,KAAKyvB,YAAL,CAAkB3oC,gBAAlB,CAAmC,OAAnC,EAA4C,gDAAa4c,IAAb,CAAkB,IAAlB,CAA5C;IACA,KAAKgsB,YAAL,CAAkB5oC,gBAAlB,CAAmC,OAAnC,EAA4C,KAAK4hB,KAAL,CAAWhF,IAAX,CAAgB,IAAhB,CAA5C;IACA,KAAK8rB,KAAL,CAAW1oC,gBAAX,CAA4B,SAA5B,EAAuCm8B,KAAK;MAC1C,IAAIA,EAAEjE,OAAFiE,KAA4B,EAAhC,EAAoC;QAClC;MAFwC;IAA5C;IAMA,KAAKzjB,cAAL,CAAoBslB,QAApB,CAA6B,KAAKC,MAAlC,EAAgE,IAAhE;IAEA,KAAKA,MAAL,CAAYj+B,gBAAZ,CAA6B,OAA7B,EAAsC,gDAAa4c,IAAb,CAAkB,IAAlB,CAAtC;EAnCiB;;EAsCnB,MAAM4F,IAAN,GAAa;IACX,0BAAI,IAAJ,sBAA4B;MAC1B,MAAM,+CAAuBtC,OAA7B;IAFS;;IAIX,+CAAyB1I,wCAAzB;;IAEA,IAAI;MACF,MAAM,KAAKkB,cAAL,CAAoB8J,IAApB,CAAyB,KAAKyb,MAA9B,CAAN;IADF,EAEE,OAAOvqB,EAAP,EAAW;MACX,+CAAyB,IAAzB;;MACA,MAAMA,EAAN;IAVS;;IAaX,MAAMo1B,oBACJ,yCAAiBC,4BAAkBC,kBADrC;;IAGA,IAAI,CAAC,KAAKH,iBAAN,IAA2BC,iBAA/B,EAAkD;MAChD,KAAKJ,KAAL,CAAWxgB,KAAX;IAjBS;;IAmBX,KAAKkE,KAAL,CAAW7G,WAAX,GAAyB,MAAM,KAAKzM,IAAL,CAAUrK,GAAV,CAC5B,YAAWq6B,oBAAoB,SAApB,GAAgC,OAA5C,EAD6B,CAA/B;EAzDiB;;EA8DnB,MAAMlnB,KAAN,GAAc;IACZ,IAAI,KAAKlJ,cAAL,CAAoBif,MAApB,KAA+B,KAAKsG,MAAxC,EAAgD;MAC9C,KAAKvlB,cAAL,CAAoBkJ,KAApB,CAA0B,KAAKqc,MAA/B;IAFU;EA9DK;;EA2FnB,MAAM7a,iBAAN,CAAwBD,cAAxB,EAAwCtI,MAAxC,EAAgD;IAC9C,0BAAI,IAAJ,sBAA4B;MAC1B,MAAM,+CAAuBqF,OAA7B;IAF4C;;IAI9C,6CAAuBiD,cAAvB;;IACA,qCAAetI,MAAf;EAhGiB;;AAAA;;;;oBAoET;EACR,MAAMouB,WAAW,KAAKP,KAAL,CAAWpoC,KAA5B;;EACA,IAAI2oC,8DAAU3nC,MAAV2nC,IAAmB,CAAvB,EAA0B;IACxB,2EAAqBA,QAArB;EAHM;AApES;;oBA2ET;EACR,2EAAqB,IAAItgC,KAAJ,CAAU,2BAAV,CAArB;;EACA,+CAAuBV,OAAvB;AA7EiB;;0BAgFHghC,UAAU;EACxB,IAAI,uBAAC,IAAD,kBAAJ,EAA2B;IACzB;EAFsB;;EAIxB,KAAKrnB,KAAL;EACA,KAAK8mB,KAAL,CAAWpoC,KAAX,GAAmB,EAAnB;;EAEA,wDAAqB2oC,QAArB;;EACA,6CAAuB,IAAvB;AAxFiB;;;;;;;;;;;;;ACdrB;;AACA;;AACA;;;;;;;;;;AAcA,MAAM/pB,mBAAN,SAAkCgqB,gCAAlC,CAAiD;EAI/CpsC,YAAYgS,OAAZ,EAAqB;IACnB,MAAMA,OAAN;;IADmB;;IAEnB,KAAK2J,eAAL,GAAuB3J,QAAQ2J,eAA/B;;IAEA,KAAKpI,QAAL,CAAcgZ,GAAd,CACE,0BADF,EAEE,oEAAuBzM,IAAvB,CAA4B,IAA5B,CAFF;EAR6C;;EAc/CyF,QAAsC;IAAA,IAAhC8mB,sBAAgC,uEAAP,KAAO;IACpC,MAAM9mB,KAAN;IACA,KAAK+mB,YAAL,GAAoB,IAApB;;IAEA,IAAI,CAACD,sBAAL,EAA6B;MAG3B,KAAKE,mBAAL,GAA2B7xB,wCAA3B;IAPkC;;IASpC,KAAK8xB,qBAAL,GAA6B,KAA7B;EAvB6C;;EA6B/C,MAAMC,cAAN,CAAqBC,gBAArB,EAAuC;IACrC,KAAKH,mBAAL,CAAyBphC,OAAzB;;IAEA,IAAIuhC,qBAAqB,CAArBA,IAA0B,CAAC,KAAKF,qBAApC,EAA2D;MAKzD,KAAKA,qBAAL,GAA6B,IAA7B;MAEA,MAAM1P,uCAAqB;QACzBhqB,QAAQ,KAAKS,QADY;QAEzB3B,MAAM,yBAFmB;QAGzBmrB,OAAO;MAHkB,CAArBD,CAAN;;MAMA,IAAI,CAAC,KAAK0P,qBAAV,EAAiC;QAC/B;MAduD;IAHtB;;IAoBrC,KAAKA,qBAAL,GAA6B,KAA7B;IAEA,KAAKj5B,QAAL,CAAcwC,QAAd,CAAuB,mBAAvB,EAA4C;MAC1CC,QAAQ,IADkC;MAE1C02B;IAF0C,CAA5C;EAnD6C;;EA4D/CC,UAAUnsC,OAAV,QAA0C;IAAA,IAAvB;MAAEosC,OAAF;MAAWvlB;IAAX,CAAuB;;IACxC7mB,QAAQ4S,OAAR5S,GAAkB,MAAM;MACtB,KAAKmb,eAAL,CAAqBkxB,kBAArB,CAAwCrsC,OAAxC,EAAiDosC,OAAjD,EAA0DvlB,QAA1D;MACA,OAAO,KAAP;IAFF;EA7D6C;;EAsE/CuE,cAAwD;IAAA,IAAjD;MAAEE,WAAF;MAAeugB,yBAAyB;IAAxC,CAAiD;;IACtD,IAAI,KAAKC,YAAT,EAAuB;MACrB,KAAK/mB,KAAL,CAAW8mB,sBAAX;IAFoD;;IAItD,KAAKC,YAAL,GAAoBxgB,eAAe,IAAnC;;IAEA,IAAI,CAACA,WAAL,EAAkB;MAChB,KAAK2gB,cAAL,CAA6C,CAA7C;;MACA;IARoD;;IAUtD,MAAMK,QAAQniC,OAAOyH,IAAPzH,CAAYmhB,WAAZnhB,EAAyBxB,IAAzBwB,CAA8B,UAAUzF,CAAV,EAAaC,CAAb,EAAgB;MAC1D,OAAOD,EAAEvB,WAAFuB,GAAgB6nC,aAAhB7nC,CAA8BC,EAAExB,WAAFwB,EAA9BD,CAAP;IADY,EAAd;IAIA,MAAM8nC,WAAW3hC,SAAS4hC,sBAAT5hC,EAAjB;IACA,IAAIqhC,mBAAmB,CAAvB;;IACA,WAAW96B,IAAX,IAAmBk7B,KAAnB,EAA0B;MACxB,MAAMI,OAAOphB,YAAYla,IAAZ,CAAb;MACA,MAAMg7B,UAAUM,KAAKN,OAArB;MAAA,MACEvlB,WAAW/C,kCAAmB4oB,KAAK7lB,QAAxB/C,CADb;MAGA,MAAM5e,MAAM2F,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAZ;MACA3F,IAAIu5B,SAAJv5B,GAAgB,UAAhBA;MAEA,MAAMlF,UAAU6K,SAAS2zB,aAAT3zB,CAAuB,GAAvBA,CAAhB;;MACA,KAAKshC,SAAL,CAAensC,OAAf,EAAwB;QAAEosC,OAAF;QAAWvlB;MAAX,CAAxB;;MACA7mB,QAAQioB,WAARjoB,GAAsB,KAAK2sC,qBAAL,CAA2B9lB,QAA3B,CAAtB7mB;MAEAkF,IAAIy6B,MAAJz6B,CAAWlF,OAAXkF;MAEAsnC,SAAS7M,MAAT6M,CAAgBtnC,GAAhBsnC;MACAN;IA/BoD;;IAkCtD,KAAKU,gBAAL,CAAsBJ,QAAtB,EAAgCN,gBAAhC;EAxG6C;;AAAA;;;;mCA8GN;EAAA,IAAvB;IAAErlB,QAAF;IAAYulB;EAAZ,CAAuB;EACvC,MAAMS,kBAAkB,KAAKd,mBAAL,CAAyBnpB,OAAjD;EAEAiqB,gBAAgBt1B,IAAhBs1B,CAAqB,MAAM;IACzB,IAAIA,oBAAoB,KAAKd,mBAAL,CAAyBnpB,OAAjD,EAA0D;MACxD;IAFuB;;IAIzB,MAAM0I,cAAc,KAAKwgB,YAAL,IAAqB3hC,OAAO6C,MAAP7C,CAAc,IAAdA,CAAzC;;IAEA,WAAWiH,IAAX,IAAmBka,WAAnB,EAAgC;MAC9B,IAAIzE,aAAazV,IAAjB,EAAuB;QACrB;MAF4B;IANP;;IAWzBka,YAAYzE,QAAZ,IAAwB;MACtBA,QADsB;MAEtBulB;IAFsB,CAAxB9gB;IAIA,KAAKF,MAAL,CAAY;MACVE,WADU;MAEVugB,wBAAwB;IAFd,CAAZ;EAfF;AAjH6C;;;;;;;;;;;;;AChBjD;;AAEA,MAAMiB,sBAAsB,CAAC,GAA7B;AACA,MAAMC,0BAA0B,UAAhC;;AAEA,MAAMnB,cAAN,CAAqB;EACnBpsC,YAAYgS,OAAZ,EAAqB;IACnB,IAAI,KAAKhS,WAAL,KAAqBosC,cAAzB,EAAyC;MACvC,MAAM,IAAIvgC,KAAJ,CAAU,mCAAV,CAAN;IAFiB;;IAInB,KAAKS,SAAL,GAAiB0F,QAAQ1F,SAAzB;IACA,KAAKiH,QAAL,GAAgBvB,QAAQuB,QAAxB;IAEA,KAAKgS,KAAL;EARiB;;EAWnBA,QAAQ;IACN,KAAKioB,YAAL,GAAoB,IAApB;IACA,KAAKC,iBAAL,GAAyB,IAAzB;IACA,KAAKC,gBAAL,GAAwB,IAAxB;IAGA,KAAKphC,SAAL,CAAemc,WAAf,GAA6B,EAA7B;IAGA,KAAKnc,SAAL,CAAe7K,SAAf,CAAyByK,MAAzB,CAAgC,qBAAhC;EApBiB;;EA0BnBugC,eAAekB,KAAf,EAAsB;IACpB,MAAM,IAAI9hC,KAAJ,CAAU,iCAAV,CAAN;EA3BiB;;EAiCnB8gC,UAAUnsC,OAAV,EAAmB6C,MAAnB,EAA2B;IACzB,MAAM,IAAIwI,KAAJ,CAAU,4BAAV,CAAN;EAlCiB;;EAwCnBshC,sBAAsBppC,GAAtB,EAA2B;IAGzB,OACED,oCAAqBC,GAArBD,EAAiD,IAAjDA,KACgB,QAFlB;EA3CiB;;EAsDnB8pC,iBAAiBloC,GAAjB,EAAsC;IAAA,IAAhBgf,MAAgB,uEAAP,KAAO;IACpC,MAAMmpB,UAAUxiC,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAhB;IACAwiC,QAAQ5O,SAAR4O,GAAoB,iBAApBA;;IACA,IAAInpB,MAAJ,EAAY;MACVmpB,QAAQpsC,SAARosC,CAAkB9kC,GAAlB8kC,CAAsB,iBAAtBA;IAJkC;;IAMpCA,QAAQz6B,OAARy6B,GAAkBvrC,OAAO;MACvBA,IAAIo9B,eAAJp9B;MACAurC,QAAQpsC,SAARosC,CAAkB/V,MAAlB+V,CAAyB,iBAAzBA;;MAEA,IAAIvrC,IAAI64B,QAAR,EAAkB;QAChB,MAAM2S,gBAAgB,CAACD,QAAQpsC,SAARosC,CAAkBnsC,QAAlBmsC,CAA2B,iBAA3BA,CAAvB;;QACA,KAAKE,eAAL,CAAqBroC,GAArB,EAA0BooC,aAA1B;MANqB;IAAzB;;IASApoC,IAAIi8B,OAAJj8B,CAAYmoC,OAAZnoC;EArEiB;;EAgFnBqoC,gBAAgBlJ,IAAhB,EAAoC;IAAA,IAAdl4B,IAAc,uEAAP,KAAO;IAClC,KAAK8gC,iBAAL,GAAyB9gC,IAAzB;;IACA,WAAWkhC,OAAX,IAAsBhJ,KAAKP,gBAALO,CAAsB,kBAAtBA,CAAtB,EAAiE;MAC/DgJ,QAAQpsC,SAARosC,CAAkB/V,MAAlB+V,CAAyB,iBAAzBA,EAA4C,CAAClhC,IAA7CkhC;IAHgC;EAhFjB;;EA2FnBG,sBAAsB;IACpB,KAAKD,eAAL,CAAqB,KAAKzhC,SAA1B,EAAqC,CAAC,KAAKmhC,iBAA3C;EA5FiB;;EAkGnBL,iBAAiBJ,QAAjB,EAA2BW,KAA3B,EAAyD;IAAA,IAAvBM,aAAuB,uEAAP,KAAO;;IACvD,IAAIA,aAAJ,EAAmB;MACjB,KAAK3hC,SAAL,CAAe7K,SAAf,CAAyBsH,GAAzB,CAA6B,qBAA7B;MAEA,KAAK0kC,iBAAL,GAAyB,CAACT,SAAShgC,aAATggC,CAAuB,kBAAvBA,CAA1B;IAJqD;;IAMvD,KAAK1gC,SAAL,CAAe6zB,MAAf,CAAsB6M,QAAtB;;IAEA,KAAKP,cAAL,CAAoBkB,KAApB;EA1GiB;;EA6GnB/hB,OAAOvoB,MAAP,EAAe;IACb,MAAM,IAAIwI,KAAJ,CAAU,yBAAV,CAAN;EA9GiB;;EAoHnBqiC,yBAAwC;IAAA,IAAjBC,QAAiB,uEAAN,IAAM;;IACtC,IAAI,KAAKT,gBAAT,EAA2B;MAEzB,KAAKA,gBAAL,CAAsBjsC,SAAtB,CAAgCyK,MAAhC,CAAuCqhC,uBAAvC;;MACA,KAAKG,gBAAL,GAAwB,IAAxB;IAJoC;;IAMtC,IAAIS,QAAJ,EAAc;MACZA,SAAS1sC,SAAT0sC,CAAmBplC,GAAnBolC,CAAuBZ,uBAAvBY;MACA,KAAKT,gBAAL,GAAwBS,QAAxB;IARoC;EApHrB;;EAmInBC,yBAAyBD,QAAzB,EAAmC;IACjC,IAAI,CAACA,QAAL,EAAe;MACb;IAF+B;;IAMjC,IAAIE,cAAcF,SAAS5hC,UAA3B;;IACA,OAAO8hC,eAAeA,gBAAgB,KAAK/hC,SAA3C,EAAsD;MACpD,IAAI+hC,YAAY5sC,SAAZ4sC,CAAsB3sC,QAAtB2sC,CAA+B,UAA/BA,CAAJ,EAAgD;QAC9C,MAAMR,UAAUQ,YAAYC,iBAA5B;QACAT,0DAASpsC,SAATosC,CAAmB3hC,MAAnB2hC,CAA0B,iBAA1BA;MAHkD;;MAKpDQ,cAAcA,YAAY9hC,UAA1B8hC;IAZ+B;;IAcjC,KAAKH,sBAAL,CAA4BC,QAA5B;;IAEA,KAAK7hC,SAAL,CAAe0zB,QAAf,CACEmO,SAAShtC,UADX,EAEEgtC,SAASntC,SAATmtC,GAAqBb,mBAFvB;EAnJiB;;AAAA;;;;;;;;;;;;;;;ACLrB;;AACA;;;;;;;;;;;;;;;;;;;;AAEA,MAAMiB,wBAAwB,GAA9B;AAGA,MAAMC,qBAAqB,CAAC,OAAD,EAAU,OAAV,EAAmB,IAAnB,CAA3B;AAIA,MAAMC,gBAAgB;EACpB,UAAU,QADU;EAEpB,UAAU;AAFU,CAAtB;AAIA,MAAMC,oBAAoB;EACxB,WAAW,IADa;EAExB,WAAW;AAFa,CAA1B;;AAKA,SAASC,WAAT,CAAqB3jC,IAArB,EAA2B4jC,UAA3B,EAAuCC,SAAvC,EAAkD;EAChD,MAAMvoC,QAAQsoC,aAAa5jC,KAAK1E,KAAlB,GAA0B0E,KAAKzE,MAA7C;EACA,MAAMA,SAASqoC,aAAa5jC,KAAKzE,MAAlB,GAA2ByE,KAAK1E,KAA/C;EAEA,OAAOuoC,UAAU,GAAGvoC,KAAM,IAAGC,MAAZ,EAAV,CAAP;AAtCF;;;;;;;;;;;;;;;;AAgDA,MAAMgb,qBAAN,CAA4B;EAW1BvhB,kBAEE4b,cAFF,EAGErI,QAHF,EAIEyI,IAJF,EAKE8yB,cALF,EAME;IAAA,IALA;MAAE3N,MAAF;MAAU4N,MAAV;MAAkBrmB;IAAlB,CAKA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;MAAA;MAAA,OAhBW;IAgBX;;IACA,KAAKyY,MAAL,GAAcA,MAAd;IACA,KAAK4N,MAAL,GAAcA,MAAd;IACA,KAAKnzB,cAAL,GAAsBA,cAAtB;IACA,KAAKI,IAAL,GAAYA,IAAZ;IACA,KAAKgzB,eAAL,GAAuBF,cAAvB;;IAEA;;IAEApmB,YAAYxlB,gBAAZwlB,CAA6B,OAA7BA,EAAsC,KAAK5D,KAAL,CAAWhF,IAAX,CAAgB,IAAhB,CAAtC4I;IAEA,KAAK9M,cAAL,CAAoBslB,QAApB,CAA6B,KAAKC,MAAlC;;IAEA5tB,SAASgZ,GAAThZ,CAAa,cAAbA,EAA6BjR,OAAO;MAClC,KAAK2sC,kBAAL,GAA0B3sC,IAAI0S,UAA9B;IADF;;IAGAzB,SAASgZ,GAAThZ,CAAa,kBAAbA,EAAiCjR,OAAO;MACtC,KAAK4sC,cAAL,GAAsB5sC,IAAIiS,aAA1B;IADF;;IAIA,KAAK46B,kBAAL,GAA0B,IAA1B;IACAnzB,KAAKozB,WAALpzB,GAAmBjE,IAAnBiE,CAAwB3K,UAAU;MAChC,KAAK89B,kBAAL,GAA0BX,mBAAmB3jC,QAAnB2jC,CAA4Bn9B,MAA5Bm9B,CAA1B;IADF;EAtCwB;;EA8C1B,MAAM9oB,IAAN,GAAa;IACX,MAAMxa,QAAQua,GAARva,CAAY,CAChB,KAAK0Q,cAAL,CAAoB8J,IAApB,CAAyB,KAAKyb,MAA9B,CADgB,EAEhB,KAAKkO,wBAAL,CAA8BjsB,OAFd,CAAZlY,CAAN;IAIA,MAAMmJ,oBAAoB,KAAK46B,kBAA/B;IACA,MAAM16B,gBAAgB,KAAK26B,cAA3B;;IAIA,IACE,2CACA76B,sBAAsB,wCAAgB46B,kBADtC,IAEA16B,kBAAkB,wCAAgB26B,cAHpC,EAIE;MACA;;MACA;IAhBS;;IAoBX,MAAM;MACJzhB,IADI;MAIJE;IAJI,IAKF,MAAM,KAAKha,WAAL,CAAiBia,WAAjB,EALV;IAOA,MAAM,CACJ0hB,QADI,EAEJC,QAFI,EAGJC,YAHI,EAIJC,gBAJI,EAKJC,QALI,EAMJC,YANI,IAOF,MAAMzkC,QAAQua,GAARva,CAAY,CACpB,KAAK8jC,eAAL,EADoB,yBAEpB,IAFoB,wCAEpB,IAFoB,EAEArhB,aAFA,0BAGpB,IAHoB,gCAGpB,IAHoB,EAGJF,KAAKmiB,YAHD,0BAIpB,IAJoB,gCAIpB,IAJoB,EAIJniB,KAAKoiB,OAJD,GAKpB,KAAKl8B,WAAL,CAAiBm8B,OAAjB,CAAyBz7B,iBAAzB,EAA4C0D,IAA5C,CAAiDwS,WAAW;MAC1D,8BAAO,IAAP,wCAAO,IAAP,EAA2B1kB,iCAAkB0kB,OAAlB1kB,CAA3B,EAAuD0O,aAAvD;IADF,EALoB,yBAQpB,IARoB,kDAQpB,IARoB,EAQKkZ,KAAKsiB,YARV,EAAZ7kC,CAPV;;IAkBA,wCAAkBP,OAAOqlC,MAAPrlC,CAAc;MAC9B2kC,QAD8B;MAE9BC,QAF8B;MAG9Bp8B,OAAOsa,KAAKU,KAHkB;MAI9B8hB,QAAQxiB,KAAKyiB,MAJiB;MAK9BC,SAAS1iB,KAAK2iB,OALgB;MAM9BC,UAAU5iB,KAAK6iB,QANe;MAO9Bd,YAP8B;MAQ9BC,gBAR8B;MAS9Bc,SAAS9iB,KAAKQ,OATgB;MAU9Ba,UAAUrB,KAAKM,QAVe;MAW9B7F,SAASuF,KAAKK,gBAXgB;MAY9B0iB,WAAW,KAAK78B,WAAL,CAAiBQ,QAZE;MAa9Bu7B,QAb8B;MAc9Be,YAAYd,YAdkB;MAe9BV,oBAAoB56B,iBAfU;MAgB9B66B,gBAAgB36B;IAhBc,CAAd5J,CAAlB;;IAkBA;;IAIA,MAAM;MAAEnG;IAAF,IAAa,MAAM,KAAKmP,WAAL,CAAiB2V,eAAjB,EAAzB;;IACA,IAAIqE,kBAAkBnpB,MAAtB,EAA8B;MAC5B;IArES;;IAuEX,MAAM4U,OAAOzO,OAAO2wB,MAAP3wB,CAAcA,OAAO6C,MAAP7C,CAAc,IAAdA,CAAdA,wBAAmC,IAAnCA,cAAb;IACAyO,KAAKm2B,QAALn2B,GAAgB,6BAAM,IAAN,wCAAM,IAAN,EAA0B5U,MAA1B,CAAhB4U;;IAEA,wCAAkBzO,OAAOqlC,MAAPrlC,CAAcyO,IAAdzO,CAAlB;;IACA;EAzHwB;;EA+H1B,MAAMma,KAAN,GAAc;IACZ,KAAKlJ,cAAL,CAAoBkJ,KAApB,CAA0B,KAAKqc,MAA/B;EAhIwB;;EA0I1BrtB,YAAYH,WAAZ,EAAyB;IACvB,IAAI,KAAKA,WAAT,EAAsB;MACpB;;MACA,+DAAe,IAAf;IAHqB;;IAKvB,IAAI,CAACA,WAAL,EAAkB;MAChB;IANqB;;IAQvB,KAAKA,WAAL,GAAmBA,WAAnB;;IAEA,KAAK07B,wBAAL,CAA8BlkC,OAA9B;EApJwB;;AAAA;;;;mBAuJjB;EACP,KAAKwI,WAAL,GAAmB,IAAnB;;EAEA,wCAAkB,IAAlB;;EACA,KAAK07B,wBAAL,GAAgC30B,wCAAhC;EACA,KAAKu0B,kBAAL,GAA0B,CAA1B;EACA,KAAKC,cAAL,GAAsB,CAAtB;AA7JwB;;sBAqKD;EAAA,IAAf3pB,KAAe,uEAAP,KAAO;;EACvB,IAAIA,SAAS,uBAAC,IAAD,aAAb,EAA+B;IAC7B,WAAW3c,EAAX,IAAiB,KAAKmmC,MAAtB,EAA8B;MAC5B,KAAKA,MAAL,CAAYnmC,EAAZ,EAAgB6f,WAAhB,GAA8B8lB,qBAA9B;IAF2B;;IAI7B;EALqB;;EAOvB,IAAI,KAAK3yB,cAAL,CAAoBif,MAApB,KAA+B,KAAKsG,MAAxC,EAAgD;IAG9C;EAVqB;;EAYvB,WAAWv4B,EAAX,IAAiB,KAAKmmC,MAAtB,EAA8B;IAC5B,MAAMnC,UAAU,wCAAgBhkC,EAAhB,CAAhB;;IACA,KAAKmmC,MAAL,CAAYnmC,EAAZ,EAAgB6f,WAAhB,GACEmkB,WAAWA,YAAY,CAAvBA,GAA2BA,OAA3BA,GAAqC2B,qBADvC;EAdqB;AArKC;;iCAwLS;EAAA,IAAdgB,QAAc,uEAAH,CAAG;EACjC,MAAMmB,KAAKnB,WAAW,IAAtB;EAAA,MACEoB,KAAKD,KAAK,IADZ;;EAEA,IAAI,CAACA,EAAL,EAAS;IACP,OAAO5uC,SAAP;EAJ+B;;EAMjC,OAAO,KAAKka,IAAL,CAAUrK,GAAV,CAAe,uBAAsBg/B,MAAM,CAANA,GAAU,IAAVA,GAAiB,IAAxC,EAAd,EAA8D;IACnEC,SAASD,MAAM,CAANA,IAAY,EAACA,GAAGE,WAAHF,CAAe,CAAfA,CAAD,EAAoBG,cAApB,EAD8C;IAEnEC,SAASJ,KAAK,CAALA,IAAW,EAACD,GAAGG,WAAHH,CAAe,CAAfA,CAAD,EAAoBI,cAApB,EAF+C;IAGnEE,QAAQzB,SAASuB,cAATvB;EAH2D,CAA9D,CAAP;AA9LwB;;+BAqML0B,gBAAgB18B,eAAe;EAClD,IAAI,CAAC08B,cAAL,EAAqB;IACnB,OAAOnvC,SAAP;EAFgD;;EAKlD,IAAIyS,gBAAgB,GAAhBA,KAAwB,CAA5B,EAA+B;IAC7B08B,iBAAiB;MACf3qC,OAAO2qC,eAAe1qC,MADP;MAEfA,QAAQ0qC,eAAe3qC;IAFR,CAAjB2qC;EANgD;;EAWlD,MAAMrC,aAAa7jC,qCAAsBkmC,cAAtBlmC,CAAnB;EAEA,IAAImmC,aAAa;IACf5qC,OAAOzB,KAAKe,KAALf,CAAWosC,eAAe3qC,KAAf2qC,GAAuB,GAAlCpsC,IAAyC,GADjC;IAEf0B,QAAQ1B,KAAKe,KAALf,CAAWosC,eAAe1qC,MAAf0qC,GAAwB,GAAnCpsC,IAA0C;EAFnC,CAAjB;EAKA,IAAIssC,kBAAkB;IACpB7qC,OAAOzB,KAAKe,KAALf,CAAWosC,eAAe3qC,KAAf2qC,GAAuB,IAAvBA,GAA8B,EAAzCpsC,IAA+C,EADlC;IAEpB0B,QAAQ1B,KAAKe,KAALf,CAAWosC,eAAe1qC,MAAf0qC,GAAwB,IAAxBA,GAA+B,EAA1CpsC,IAAgD;EAFpC,CAAtB;EAKA,IAAIusC,UACFzC,YAAYuC,UAAZ,EAAwBtC,UAAxB,EAAoCH,aAApC,KACAE,YAAYwC,eAAZ,EAA6BvC,UAA7B,EAAyCF,iBAAzC,CAFF;;EAIA,IACE,CAAC0C,OAAD,IACA,EACE7mC,OAAOC,SAAPD,CAAiB4mC,gBAAgB7qC,KAAjCiE,KACAA,OAAOC,SAAPD,CAAiB4mC,gBAAgB5qC,MAAjCgE,CAFF,CAFF,EAME;IAIA,MAAM8mC,mBAAmB;MACvB/qC,OAAO2qC,eAAe3qC,KAAf2qC,GAAuB,IADP;MAEvB1qC,QAAQ0qC,eAAe1qC,MAAf0qC,GAAwB;IAFT,CAAzB;IAIA,MAAMK,iBAAiB;MACrBhrC,OAAOzB,KAAKe,KAALf,CAAWssC,gBAAgB7qC,KAA3BzB,CADc;MAErB0B,QAAQ1B,KAAKe,KAALf,CAAWssC,gBAAgB5qC,MAA3B1B;IAFa,CAAvB;;IAMA,IACEA,KAAKwE,GAALxE,CAASwsC,iBAAiB/qC,KAAjB+qC,GAAyBC,eAAehrC,KAAjDzB,IAA0D,GAA1DA,IACAA,KAAKwE,GAALxE,CAASwsC,iBAAiB9qC,MAAjB8qC,GAA0BC,eAAe/qC,MAAlD1B,IAA4D,GAF9D,EAGE;MACAusC,UAAUzC,YAAY2C,cAAZ,EAA4B1C,UAA5B,EAAwCF,iBAAxC,CAAV0C;;MACA,IAAIA,OAAJ,EAAa;QAGXF,aAAa;UACX5qC,OAAOzB,KAAKe,KAALf,CAAYysC,eAAehrC,KAAfgrC,GAAuB,IAAvBA,GAA+B,GAA3CzsC,IAAkD,GAD9C;UAEX0B,QAAQ1B,KAAKe,KAALf,CAAYysC,eAAe/qC,MAAf+qC,GAAwB,IAAxBA,GAAgC,GAA5CzsC,IAAmD;QAFhD,CAAbqsC;QAIAC,kBAAkBG,cAAlBH;MATF;IAjBF;EAjCgD;;EAgElD,MAAM,CAAC;IAAE7qC,KAAF;IAASC;EAAT,CAAD,EAAoBgrC,IAApB,EAA0B3/B,IAA1B,EAAgC4/B,WAAhC,IAA+C,MAAMtmC,QAAQua,GAARva,CAAY,CACrE,KAAKikC,kBAAL,GAA0B+B,UAA1B,GAAuCC,eAD8B,EAErE,KAAKn1B,IAAL,CAAUrK,GAAV,CACG,sCACC,KAAKw9B,kBAAL,GAA0B,QAA1B,GAAqC,aADvC,EADF,CAFqE,EAOrEiC,WACE,KAAKp1B,IAAL,CAAUrK,GAAV,CACG,sCAAqCy/B,QAAQztC,WAARytC,EAAtC,EADF,CARmE,EAWrE,KAAKp1B,IAAL,CAAUrK,GAAV,CACG,6CACCi9B,aAAa,UAAb,GAA0B,WAD5B,EADF,CAXqE,CAAZ1jC,CAA3D;EAkBA,OAAO,KAAK8Q,IAAL,CAAUrK,GAAV,CACJ,2CAA0CC,OAAO,OAAP,GAAiB,EAAG,QAD1D,EAEL;IACEtL,OAAOA,MAAMwqC,cAANxqC,EADT;IAEEC,QAAQA,OAAOuqC,cAAPvqC,EAFV;IAGEgrC,IAHF;IAIE3/B,IAJF;IAKE4/B;EALF,CAFK,CAAP;AAvRwB;;2BAmSTC,WAAW;EAC1B,MAAMC,aAAaC,wBAAcC,YAAdD,CAA2BF,SAA3BE,CAAnB;;EACA,IAAI,CAACD,UAAL,EAAiB;IACf,OAAO5vC,SAAP;EAHwB;;EAK1B,OAAO,KAAKka,IAAL,CAAUrK,GAAV,CAAc,iCAAd,EAAiD;IACtDkgC,MAAMH,WAAWI,kBAAXJ,EADgD;IAEtDK,MAAML,WAAWM,kBAAXN;EAFgD,CAAjD,CAAP;AAxSwB;;8BA8SN/B,cAAc;EAChC,OAAO,KAAK3zB,IAAL,CAAUrK,GAAV,CACJ,kCAAiCg+B,eAAe,KAAf,GAAuB,IAAzD,EADK,CAAP;AA/SwB;;;;;;;;;;;;;ACjC5B;;;;;;;;AAEA,MAAMsC,sBAAsB,IAA5B;;;;AAQA,MAAM7wB,UAAN,CAAiB;EACfphB,YAAYgS,OAAZ,EAAqBuB,QAArB,EAA+ByI,IAA/B,EAAqC;IAAA;;IACnC,KAAKggB,MAAL,GAAc,KAAd;IAEA,KAAKlwB,GAAL,GAAWkG,QAAQlG,GAAnB;IACA,KAAK8uB,YAAL,GAAoB5oB,QAAQ4oB,YAA5B;IACA,KAAKsX,SAAL,GAAiBlgC,QAAQkgC,SAAzB;IACA,KAAKtZ,YAAL,GAAoB5mB,QAAQmgC,oBAA5B;IACA,KAAKzZ,aAAL,GAAqB1mB,QAAQogC,qBAA7B;IACA,KAAKtZ,eAAL,GAAuB9mB,QAAQqgC,uBAA/B;IACA,KAAK1Z,UAAL,GAAkB3mB,QAAQsgC,kBAA1B;IACA,KAAKC,OAAL,GAAevgC,QAAQugC,OAAvB;IACA,KAAKC,gBAAL,GAAwBxgC,QAAQwgC,gBAAhC;IACA,KAAKC,kBAAL,GAA0BzgC,QAAQygC,kBAAlC;IACA,KAAKC,cAAL,GAAsB1gC,QAAQ0gC,cAA9B;IACA,KAAKn/B,QAAL,GAAgBA,QAAhB;IACA,KAAKyI,IAAL,GAAYA,IAAZ;IAGA,KAAK4e,YAAL,CAAkB13B,gBAAlB,CAAmC,OAAnC,EAA4C,MAAM;MAChD,KAAK40B,MAAL;IADF;IAIA,KAAKoa,SAAL,CAAehvC,gBAAf,CAAgC,OAAhC,EAAyC,MAAM;MAC7C,KAAK0/B,aAAL,CAAmB,EAAnB;IADF;IAIA,KAAK92B,GAAL,CAAS5I,gBAAT,CAA0B,SAA1B,EAAqCm8B,KAAK;MACxC,QAAQA,EAAEjE,OAAV;QACE,KAAK,EAAL;UACE,IAAIiE,EAAEvsB,MAAFusB,KAAa,KAAK6S,SAAtB,EAAiC;YAC/B,KAAKtP,aAAL,CAAmB,OAAnB,EAA4BvD,EAAElE,QAA9B;UAFJ;;UAIE;;QACF,KAAK,EAAL;UACE,KAAKrW,KAAL;UACA;MARJ;IADF;IAaA,KAAK2tB,kBAAL,CAAwBvvC,gBAAxB,CAAyC,OAAzC,EAAkD,MAAM;MACtD,KAAK0/B,aAAL,CAAmB,OAAnB,EAA4B,IAA5B;IADF;IAIA,KAAK8P,cAAL,CAAoBxvC,gBAApB,CAAqC,OAArC,EAA8C,MAAM;MAClD,KAAK0/B,aAAL,CAAmB,OAAnB,EAA4B,KAA5B;IADF;IAIA,KAAKhK,YAAL,CAAkB11B,gBAAlB,CAAmC,OAAnC,EAA4C,MAAM;MAChD,KAAK0/B,aAAL,CAAmB,oBAAnB;IADF;IAIA,KAAKlK,aAAL,CAAmBx1B,gBAAnB,CAAoC,OAApC,EAA6C,MAAM;MACjD,KAAK0/B,aAAL,CAAmB,uBAAnB;IADF;IAIA,KAAKjK,UAAL,CAAgBz1B,gBAAhB,CAAiC,OAAjC,EAA0C,MAAM;MAC9C,KAAK0/B,aAAL,CAAmB,kBAAnB;IADF;IAIA,KAAK9J,eAAL,CAAqB51B,gBAArB,CAAsC,OAAtC,EAA+C,MAAM;MACnD,KAAK0/B,aAAL,CAAmB,yBAAnB;IADF;;IAIA,KAAKrvB,QAAL,CAAcgZ,GAAd,CAAkB,QAAlB,EAA4B,0DAAkBzM,IAAlB,CAAuB,IAAvB,CAA5B;EAhEa;;EAmEfyF,QAAQ;IACN,KAAK4T,aAAL;EApEa;;EAuEfyJ,cAAcnb,IAAd,EAAsC;IAAA,IAAlBkrB,QAAkB,uEAAP,KAAO;IACpC,KAAKp/B,QAAL,CAAcwC,QAAd,CAAuB,MAAvB,EAA+B;MAC7BC,QAAQ,IADqB;MAE7ByR,IAF6B;MAG7BrkB,OAAO,KAAK8uC,SAAL,CAAe1uC,KAHO;MAI7ByS,cAAc,IAJe;MAK7ByiB,eAAe,KAAKA,aAAL,CAAmBka,OALL;MAM7Bja,YAAY,KAAKA,UAAL,CAAgBia,OANC;MAO7Bha,cAAc,KAAKA,YAAL,CAAkBga,OAPH;MAQ7B/Z,cAAc8Z,QARe;MAS7B7Z,iBAAiB,KAAKA,eAAL,CAAqB8Z;IATT,CAA/B;EAxEa;;EAqFfzZ,cAAcv2B,KAAd,EAAqBq2B,QAArB,EAA+BF,YAA/B,EAA6C;IAC3C,IAAIwZ,UAAUrnC,QAAQC,OAARD,CAAgB,EAAhBA,CAAd;IACA,IAAI2nC,SAAS,EAAb;;IAEA,QAAQjwC,KAAR;MACE,KAAKkwC,+BAAUC,KAAf;QACE;;MACF,KAAKD,+BAAUE,OAAf;QACEH,SAAS,SAATA;QACA;;MACF,KAAKC,+BAAUG,SAAf;QACEV,UAAU,KAAKv2B,IAAL,CAAUrK,GAAV,CAAc,gBAAd,CAAV4gC;QACAM,SAAS,UAATA;QACA;;MACF,KAAKC,+BAAUrzC,OAAf;QACE8yC,UAAU,KAAKv2B,IAAL,CAAUrK,GAAV,CAAe,gBAAesnB,WAAW,KAAX,GAAmB,QAAnC,EAAd,CAAVsZ;QACA;IAZJ;;IAcA,KAAKL,SAAL,CAAe3M,YAAf,CAA4B,aAA5B,EAA2CsN,MAA3C;IACA,KAAKX,SAAL,CAAe3M,YAAf,CAA4B,cAA5B,EAA4C3iC,UAAUkwC,+BAAUG,SAAhE;IAEAV,QAAQx6B,IAARw6B,CAAatrB,OAAO;MAClB,KAAKsrB,OAAL,CAAa9pB,WAAb,GAA2BxB,GAA3B;;MACA;IAFF;IAKA,KAAK+R,kBAAL,CAAwBD,YAAxB;EA/Ga;;EAkHfC,qBAAoD;IAAA,IAAjC;MAAEka,UAAU,CAAZ;MAAezsB,QAAQ;IAAvB,CAAiC,uEAAJ,EAAI;IAClD,MAAMzhB,QAAQitC,mBAAd;IACA,IAAIkB,gBAAgBjoC,QAAQC,OAARD,CAAgB,EAAhBA,CAApB;;IAEA,IAAIub,QAAQ,CAAZ,EAAe;MACb,IAAIA,QAAQzhB,KAAZ,EAAmB;QACjB,IAAIzB,MAAM,wBAAV;QAOA4vC,gBAAgB,KAAKn3B,IAAL,CAAUrK,GAAV,CAAcpO,GAAd,EAAmB;UAAEyB;QAAF,CAAnB,CAAhBmuC;MARF,OASO;QACL,IAAI5vC,MAAM,kBAAV;QAOA4vC,gBAAgB,KAAKn3B,IAAL,CAAUrK,GAAV,CAAcpO,GAAd,EAAmB;UAAE2vC,OAAF;UAAWzsB;QAAX,CAAnB,CAAhB0sB;MAlBW;IAJmC;;IAyBlDA,cAAcp7B,IAAdo7B,CAAmBlsB,OAAO;MACxB,KAAKurB,gBAAL,CAAsB/pB,WAAtB,GAAoCxB,GAApC;;MAGA;IAJF;EA3Ia;;EAmJfvB,OAAO;IACL,IAAI,CAAC,KAAKsW,MAAV,EAAkB;MAChB,KAAKA,MAAL,GAAc,IAAd;MACA,KAAKpB,YAAL,CAAkBn5B,SAAlB,CAA4BsH,GAA5B,CAAgC,SAAhC;MACA,KAAK6xB,YAAL,CAAkB2K,YAAlB,CAA+B,eAA/B,EAAgD,MAAhD;MACA,KAAKz5B,GAAL,CAASrK,SAAT,CAAmByK,MAAnB,CAA0B,QAA1B;IALG;;IAOL,KAAKgmC,SAAL,CAAera,MAAf;IACA,KAAKqa,SAAL,CAAe9mB,KAAf;;IAEA;EA7Ja;;EAgKftG,QAAQ;IACN,IAAI,CAAC,KAAKkX,MAAV,EAAkB;MAChB;IAFI;;IAIN,KAAKA,MAAL,GAAc,KAAd;IACA,KAAKpB,YAAL,CAAkBn5B,SAAlB,CAA4ByK,MAA5B,CAAmC,SAAnC;IACA,KAAK0uB,YAAL,CAAkB2K,YAAlB,CAA+B,eAA/B,EAAgD,OAAhD;IACA,KAAKz5B,GAAL,CAASrK,SAAT,CAAmBsH,GAAnB,CAAuB,QAAvB;IAEA,KAAKwK,QAAL,CAAcwC,QAAd,CAAuB,cAAvB,EAAuC;MAAEC,QAAQ;IAAV,CAAvC;EAzKa;;EA4Kf8hB,SAAS;IACP,IAAI,KAAKkE,MAAT,EAAiB;MACf,KAAKlX,KAAL;IADF,OAEO;MACL,KAAKY,IAAL;IAJK;EA5KM;;AAAA;;;;yBAoLA;EACb,IAAI,CAAC,KAAKsW,MAAV,EAAkB;IAChB;EAFW;;EASb,KAAKlwB,GAAL,CAASrK,SAAT,CAAmByK,MAAnB,CAA0B,gBAA1B;EAEA,MAAMknC,gBAAgB,KAAKtnC,GAAL,CAASzK,YAA/B;EACA,MAAMgyC,uBAAuB,KAAKvnC,GAAL,CAASwiC,iBAAT,CAA2BjtC,YAAxD;;EAEA,IAAI+xC,gBAAgBC,oBAApB,EAA0C;IAIxC,KAAKvnC,GAAL,CAASrK,SAAT,CAAmBsH,GAAnB,CAAuB,gBAAvB;EAlBW;AApLA;;;;;;;;;;;;;ACNjB;;AACA;;AACA;;;;;;;;;;;;;;;;AAEA,MAAM+pC,YAAY;EAChBC,OAAO,CADS;EAEhBE,WAAW,CAFK;EAGhBxzC,SAAS,CAHO;EAIhBuzC,SAAS;AAJO,CAAlB;;AAOA,MAAMM,eAAe,GAArB;AACA,MAAMC,0BAA0B,CAAC,EAAjC;AACA,MAAMC,2BAA2B,CAAC,GAAlC;AAEA,MAAMC,0BAA0B;EAC9B,UAAU,GADoB;EAE9B,UAAU,GAFoB;EAG9B,UAAU,GAHoB;EAI9B,UAAU,GAJoB;EAK9B,UAAU,GALoB;EAM9B,UAAU,GANoB;EAO9B,UAAU,GAPoB;EAQ9B,UAAU,GARoB;EAS9B,UAAU,GAToB;EAU9B,UAAU,KAVoB;EAW9B,UAAU,KAXoB;EAY9B,UAAU;AAZoB,CAAhC;AAqBA,MAAMC,uBAAuB,IAAI/rC,GAAJ,CAAQ,CAGnC,MAHmC,EAG3B,MAH2B,EAMnC,MANmC,EAM3B,MAN2B,EAMnB,MANmB,EAMX,MANW,EAMH,MANG,EAMK,MANL,EAMa,MANb,EAMqB,MANrB,EAM6B,MAN7B,EAOnC,MAPmC,EAO3B,MAP2B,EAOnB,MAPmB,EAOX,MAPW,EAOH,MAPG,EAOK,MAPL,EAOa,MAPb,EAOqB,MAPrB,EAO6B,MAP7B,EAQnC,MARmC,EAQ3B,MAR2B,EAQnB,MARmB,EAQX,MARW,EAQH,MARG,EAQK,MARL,EAQa,MARb,EAQqB,MARrB,EAQ6B,MAR7B,EASnC,MATmC,EAS3B,MAT2B,EASnB,MATmB,EASX,MATW,EASH,MATG,EASK,MATL,EASa,MATb,EAYnC,MAZmC,EAenC,MAfmC,EAkBnC,MAlBmC,EAkB3B,MAlB2B,EAkBnB,MAlBmB,EAkBX,MAlBW,EAkBH,MAlBG,EAkBK,MAlBL,EAqBnC,MArBmC,CAAR,CAA7B;AAuBA,MAAMgsC,2BAA2B,CAAC,GAAGD,qBAAqB9oC,MAArB8oC,EAAJ,EAC9BvP,GAD8B,CAC1Bv/B,KAAKgvC,OAAOC,YAAPD,CAAoBhvC,CAApBgvC,CADqB,EAE9B5qB,IAF8B,CAEzB,EAFyB,CAAjC;AAIA,MAAM8qB,qBAAqB,UAA3B;AACA,MAAMC,wBACJ,sDADF;AAEA,MAAMC,iCAAiC,oBAAvC;AACA,MAAMC,mCAAmC,oBAAzC;AAIA,MAAMC,oBAAoB,mDAA1B;AACA,MAAMC,oBAAoB,IAAI7wC,GAAJ,EAA1B;AAGA,MAAM8wC,+BACJ,4EADF;AAGA,IAAIC,oBAAoB,IAAxB;AACA,IAAIC,sBAAsB,IAA1B;;AAEA,SAASC,SAAT,CAAmBC,IAAnB,EAAyB;EAMvB,MAAMC,oBAAoB,EAA1B;EACA,IAAIC,CAAJ;;EACA,OAAQ,KAAIR,kBAAkB70B,IAAlB60B,CAAuBM,IAAvBN,CAAJ,MAAsC,IAA9C,EAAoD;IAClD,IAAI;MAAEztC;IAAF,IAAYiuC,CAAhB;;IACA,WAAWC,IAAX,IAAmBD,EAAE,CAAF,CAAnB,EAAyB;MACvB,IAAIE,MAAMT,kBAAkBxiC,GAAlBwiC,CAAsBQ,IAAtBR,CAAV;;MACA,IAAI,CAACS,GAAL,EAAU;QACRA,MAAMD,KAAKJ,SAALI,CAAe,KAAfA,EAAsBnwC,MAA5BowC;QACAT,kBAAkBzwC,GAAlBywC,CAAsBQ,IAAtBR,EAA4BS,GAA5BT;MAJqB;;MAMvBM,kBAAkB9rC,IAAlB8rC,CAAuB,CAACG,GAAD,EAAMnuC,OAAN,CAAvBguC;IARgD;EAR7B;;EAoBvB,IAAII,kBAAJ;;EACA,IAAIJ,kBAAkBjwC,MAAlBiwC,KAA6B,CAA7BA,IAAkCJ,iBAAtC,EAAyD;IACvDQ,qBAAqBR,iBAArBQ;EADF,OAEO,IAAIJ,kBAAkBjwC,MAAlBiwC,GAA2B,CAA3BA,IAAgCH,mBAApC,EAAyD;IAC9DO,qBAAqBP,mBAArBO;EADK,OAEA;IAEL,MAAM5wC,UAAU0G,OAAOyH,IAAPzH,CAAY8oC,uBAAZ9oC,EAAqCqe,IAArCre,CAA0C,EAA1CA,CAAhB;IACA,MAAMmqC,SAAU,KAAI7wC,OAAQ,uCAA5B;;IAEA,IAAIwwC,kBAAkBjwC,MAAlBiwC,KAA6B,CAAjC,EAAoC;MAIlCI,qBAAqBR,oBAAoB,IAAIU,MAAJ,CACvCD,SAAS,YAD8B,EAEvC,KAFuC,CAAzCD;IAJF,OAQO;MACLA,qBAAqBP,sBAAsB,IAAIS,MAAJ,CACzCD,SAAU,KAAIV,4BAA6B,GADF,EAEzC,KAFyC,CAA3CS;IAdG;EAzBgB;;EA0EvB,MAAMG,yBAAyB,EAA/B;;EACA,OAAQ,KAAIlB,mBAAmBz0B,IAAnBy0B,CAAwBU,IAAxBV,CAAJ,MAAuC,IAA/C,EAAqD;IACnDkB,uBAAuBrsC,IAAvBqsC,CAA4B,CAACN,EAAE,CAAF,EAAKlwC,MAAN,EAAckwC,EAAEjuC,KAAhB,CAA5BuuC;EA5EqB;;EA+EvB,IAAIC,aAAaT,KAAKD,SAALC,CAAe,KAAfA,CAAjB;EACA,MAAMU,YAAY,CAAC,CAAC,CAAD,EAAI,CAAJ,CAAD,CAAlB;EACA,IAAIC,qBAAqB,CAAzB;EACA,IAAIC,gBAAgB,CAApB;EACA,IAAI7J,QAAQ,CAAZ;EACA,IAAI8J,cAAc,CAAlB;EACA,IAAIC,MAAM,CAAV;EACA,IAAIC,gBAAgB,KAApB;EAEAN,aAAaA,WAAWhxC,OAAXgxC,CACXJ,kBADWI,EAEX,CAACO,KAAD,EAAQC,EAAR,EAAYC,EAAZ,EAAgBC,EAAhB,EAAoBC,EAApB,EAAwBC,EAAxB,EAA4BhvC,CAA5B,KAAkC;IAAA;;IAChCA,KAAKwuC,WAALxuC;;IACA,IAAI4uC,EAAJ,EAAQ;MAEN,MAAMK,cAAcrC,wBAAwB+B,KAAxB,CAApB;MACA,MAAMO,KAAKD,YAAYtxC,MAAvB;;MACA,KAAK,IAAI6jC,IAAI,CAAb,EAAgBA,IAAI0N,EAApB,EAAwB1N,GAAxB,EAA6B;QAC3B6M,UAAUvsC,IAAVusC,CAAe,CAACruC,IAAI0kC,KAAJ1kC,GAAYwhC,CAAb,EAAgBkD,QAAQlD,CAAxB,CAAf6M;MALI;;MAON3J,SAASwK,KAAK,CAAdxK;MACA,OAAOuK,WAAP;IAV8B;;IAahC,IAAIJ,EAAJ,EAAQ;MAAA;;MACN,MAAMM,qBAAqBN,GAAGO,QAAHP,CAAY,IAAZA,CAA3B;MACA,MAAMd,MAAMoB,qBAAqBN,GAAGlxC,MAAHkxC,GAAY,CAAjC,GAAqCA,GAAGlxC,MAApD;MAGA+wC,gBAAgB,IAAhBA;MACA,IAAIQ,KAAKnB,GAAT;;MACA,IAAI/tC,IAAIyuC,GAAJzuC,+BAAYmuC,uBAAuBG,kBAAvB,CAAZtuC,0DAAYmuC,sBAA6C,CAA7CA,CAAZnuC,CAAJ,EAAiE;QAC/DkvC,MAAMf,uBAAuBG,kBAAvB,EAA2C,CAA3CH,CAANe;QACA,EAAEZ,kBAAF;MATI;;MAYN,KAAK,IAAI9M,IAAI,CAAb,EAAgBA,KAAK0N,EAArB,EAAyB1N,GAAzB,EAA8B;QAG5B6M,UAAUvsC,IAAVusC,CAAe,CAACruC,IAAI,CAAJA,GAAQ0kC,KAAR1kC,GAAgBwhC,CAAjB,EAAoBkD,QAAQlD,CAA5B,CAAf6M;MAfI;;MAiBN3J,SAASwK,EAATxK;MACA8J,eAAeU,EAAfV;;MAEA,IAAIW,kBAAJ,EAAwB;QAGtBnvC,KAAK+tC,MAAM,CAAX/tC;QACAquC,UAAUvsC,IAAVusC,CAAe,CAACruC,IAAI0kC,KAAJ1kC,GAAY,CAAb,EAAgB,IAAI0kC,KAApB,CAAf2J;QACA3J,SAAS,CAATA;QACA8J,eAAe,CAAfA;QACAC,OAAO,CAAPA;QACA,OAAOI,GAAG9X,KAAH8X,CAAS,CAATA,EAAYd,GAAZc,CAAP;MA5BI;;MA+BN,OAAOA,EAAP;IA5C8B;;IA+ChC,IAAIC,EAAJ,EAAQ;MAKNT,UAAUvsC,IAAVusC,CAAe,CAACruC,IAAI0kC,KAAJ1kC,GAAY,CAAb,EAAgB,IAAI0kC,KAApB,CAAf2J;MACA3J,SAAS,CAATA;MACA8J,eAAe,CAAfA;MACAC,OAAO,CAAPA;MACA,OAAOK,GAAGO,MAAHP,CAAU,CAAVA,CAAP;IAxD8B;;IA2DhC,IAAIC,EAAJ,EAAQ;MAGNV,UAAUvsC,IAAVusC,CAAe,CAACruC,IAAI0kC,KAAJ1kC,GAAY,CAAb,EAAgB0kC,QAAQ,CAAxB,CAAf2J;MACA3J,SAAS,CAATA;MACA8J,eAAe,CAAfA;MACAC,OAAO,CAAPA;MACA,OAAO,GAAP;IAlE8B;;IAsEhC,IAAIzuC,IAAIyuC,GAAJzuC,+BAAY4tC,kBAAkBW,aAAlB,CAAZvuC,0DAAY4tC,sBAAmC,CAAnCA,CAAZ5tC,CAAJ,EAAuD;MAGrD,MAAMsvC,aAAa1B,kBAAkBW,aAAlB,EAAiC,CAAjCX,IAAsC,CAAzD;MACA,EAAEW,aAAF;;MACA,KAAK,IAAI/M,IAAI,CAAb,EAAgBA,KAAK8N,UAArB,EAAiC9N,GAAjC,EAAsC;QACpC6M,UAAUvsC,IAAVusC,CAAe,CAACruC,KAAK0kC,QAAQlD,CAAb,CAAD,EAAkBkD,QAAQlD,CAA1B,CAAf6M;MANmD;;MAQrD3J,SAAS4K,UAAT5K;MACA8J,eAAec,UAAfd;IA/E8B;;IAiFhC,OAAOQ,EAAP;EAnFS,EAAbZ;EAuFAC,UAAUvsC,IAAVusC,CAAe,CAACD,WAAWzwC,MAAZ,EAAoB+mC,KAApB,CAAf2J;EAEA,OAAO,CAACD,UAAD,EAAaC,SAAb,EAAwBK,aAAxB,CAAP;AArRF;;AA2RA,SAASa,gBAAT,CAA0BC,KAA1B,EAAiCC,GAAjC,EAAsC1B,GAAtC,EAA2C;EACzC,IAAI,CAACyB,KAAL,EAAY;IACV,OAAO,CAACC,GAAD,EAAM1B,GAAN,CAAP;EAFuC;;EAKzC,MAAMvwC,QAAQiyC,GAAd;EACA,MAAMC,MAAMD,MAAM1B,GAAlB;EACA,IAAI/tC,IAAI3C,qCAAsBmyC,KAAtBnyC,EAA6BU,KAAKA,EAAE,CAAF,KAAQP,KAA1CH,CAAR;;EACA,IAAImyC,MAAMxvC,CAAN,EAAS,CAATwvC,IAAchyC,KAAlB,EAAyB;IACvB,EAAEwC,CAAF;EATuC;;EAYzC,IAAIwhC,IAAInkC,qCAAsBmyC,KAAtBnyC,EAA6BU,KAAKA,EAAE,CAAF,KAAQ2xC,GAA1CryC,EAA+C2C,CAA/C3C,CAAR;;EACA,IAAImyC,MAAMhO,CAAN,EAAS,CAATgO,IAAcE,GAAlB,EAAuB;IACrB,EAAElO,CAAF;EAduC;;EAiBzC,OAAO,CAAChkC,QAAQgyC,MAAMxvC,CAAN,EAAS,CAATwvC,CAAT,EAAsBzB,MAAMyB,MAAMhO,CAAN,EAAS,CAATgO,CAANzB,GAAoByB,MAAMxvC,CAAN,EAAS,CAATwvC,CAA1C,CAAP;AA5SF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwTA,MAAMr2B,iBAAN,CAAwB;EAItBhgB,kBAAuC;IAAA,IAA3B;MAAEigB,WAAF,EAAEA,YAAF;MAAe1M;IAAf,CAA2B;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;MAAA;MAAA;IAAA;;IAAA;;IAAA;;IACrC,KAAKijC,YAAL,GAAoBv2B,YAApB;IACA,KAAKw2B,SAAL,GAAiBljC,QAAjB;;IAEA;;IACAA,SAASgZ,GAAThZ,CAAa,MAAbA,EAAqB,gDAAauM,IAAb,CAAkB,IAAlB,CAArBvM;;IACAA,SAASgZ,GAAThZ,CAAa,cAAbA,EAA6B,gEAAqBuM,IAArB,CAA0B,IAA1B,CAA7BvM;EAVoB;;EAatB,IAAImjC,gBAAJ,GAAuB;IACrB,OAAO,KAAKC,iBAAZ;EAdoB;;EAiBtB,IAAIC,WAAJ,GAAkB;IAChB,OAAO,KAAKC,YAAZ;EAlBoB;;EAqBtB,IAAIC,iBAAJ,GAAwB;IACtB,OAAO,KAAKC,kBAAZ;EAtBoB;;EAyBtB,IAAIC,QAAJ,GAAe;IACb,OAAO,KAAKC,SAAZ;EA1BoB;;EA6BtB,IAAIr0C,KAAJ,GAAY;IACV,OAAO,KAAKs0C,MAAZ;EA9BoB;;EAuCtBpjC,YAAYH,WAAZ,EAAyB;IACvB,IAAI,KAAK65B,YAAT,EAAuB;MACrB;IAFqB;;IAIvB,IAAI,CAAC75B,WAAL,EAAkB;MAChB;IALqB;;IAOvB,KAAK65B,YAAL,GAAoB75B,WAApB;;IACA,KAAKwjC,oBAAL,CAA0BhsC,OAA1B;EA/CoB;;EAqHtBisC,2BAKG;IAAA,IALiB;MAClB52C,UAAU,IADQ;MAElB62C,eAAe,CAFG;MAGlBr/B,YAAY,CAAC,CAHK;MAIlBs/B,aAAa,CAAC;IAJI,CAKjB;;IACD,IAAI,CAAC,KAAKC,cAAN,IAAwB,CAAC/2C,OAA7B,EAAsC;MACpC;IADF,OAEO,IAAI82C,eAAe,CAAC,CAAhBA,IAAqBA,eAAe,KAAKL,SAAL,CAAeO,QAAvD,EAAiE;MACtE;IADK,OAEA,IAAIx/B,cAAc,CAAC,CAAfA,IAAoBA,cAAc,KAAKi/B,SAAL,CAAeQ,OAArD,EAA8D;MACnE;IAND;;IAQD,KAAKF,cAAL,GAAsB,KAAtB;IAEA,MAAM92C,OAAO;MACXoB,KAAK0xC,uBADM;MAEXxxC,MAAMs1C,eAAe7D;IAFV,CAAb;IAIAjzC,8BAAeC,OAAfD,EAAwBE,IAAxBF,EAAoD,IAApDA;EAxIoB;;AAAA;;;;kBAkDdqC,OAAO;EACb,IAAI,CAACA,KAAL,EAAY;IACV;EAFW;;EAIb,MAAM+Q,cAAc,KAAK65B,YAAzB;EACA,MAAM;IAAE/lB;EAAF,IAAW7kB,KAAjB;;EAEA,IAAI,KAAKs0C,MAAL,KAAgB,IAAhB,2BAAwB,IAAxB,8CAAwB,IAAxB,EAA+Ct0C,KAA/C,CAAJ,EAA2D;IACzD,KAAK80C,WAAL,GAAmB,IAAnB;EARW;;EAUb,KAAKR,MAAL,GAAct0C,KAAd;;EACA,IAAI6kB,SAAS,oBAAb,EAAmC;IACjC,yEAAoBqrB,UAAUE,OAA9B;EAZW;;EAeb,KAAKmE,oBAAL,CAA0B/zB,OAA1B,CAAkCrL,IAAlC,CAAuC,MAAM;IAG3C,IACE,CAAC,KAAKy1B,YAAN,IACC75B,eAAe,KAAK65B,YAAL,KAAsB75B,WAFxC,EAGE;MACA;IAPyC;;IAS3C;;IAEA,MAAMgkC,gBAAgB,CAAC,KAAKhB,iBAA5B;IACA,MAAMiB,iBAAiB,CAAC,CAAC,KAAKC,YAA9B;;IAEA,IAAI,KAAKA,YAAT,EAAuB;MACrBzuB,aAAa,KAAKyuB,YAAlB;MACA,KAAKA,YAAL,GAAoB,IAApB;IAhByC;;IAkB3C,IAAI,CAACpwB,IAAL,EAAW;MAGT,KAAKowB,YAAL,GAAoBxuB,WAAW,MAAM;QACnC;;QACA,KAAKwuB,YAAL,GAAoB,IAApB;MAFkB,GAGjBvE,YAHiB,CAApB;IAHF,OAOO,IAAI,KAAKoE,WAAT,EAAsB;MAG3B;IAHK,OAIA,IAAIjwB,SAAS,OAAb,EAAsB;MAC3B;;MAIA,IAAIkwB,iBAAiB,KAAKT,MAAL,CAAYte,YAAjC,EAA+C;QAC7C;MANyB;IAAtB,OAQA,IAAInR,SAAS,oBAAb,EAAmC;MAGxC,IAAImwB,cAAJ,EAAoB;QAClB;MADF,OAEO;QACL,KAAKjB,iBAAL,GAAyB,IAAzB;MANsC;;MAQxC;IARK,OASA;MACL;IA/CyC;EAA7C;AAjEoB;;mBA2Ib;EACP,KAAKA,iBAAL,GAAyB,KAAzB;EACA,KAAKY,cAAL,GAAsB,KAAtB;EACA,KAAK/J,YAAL,GAAoB,IAApB;EACA,KAAKqJ,YAAL,GAAoB,EAApB;EACA,KAAKE,kBAAL,GAA0B,EAA1B;EACA,KAAKG,MAAL,GAAc,IAAd;EAEA,KAAKD,SAAL,GAAiB;IACfQ,SAAS,CAAC,CADK;IAEfD,UAAU,CAAC;EAFI,CAAjB;EAKA,KAAKM,OAAL,GAAe;IACbL,SAAS,IADI;IAEbD,UAAU,IAFG;IAGbO,SAAS;EAHI,CAAf;EAKA,KAAKC,oBAAL,GAA4B,EAA5B;EACA,KAAKC,aAAL,GAAqB,EAArB;EACA,KAAKC,UAAL,GAAkB,EAAlB;EACA,KAAKC,cAAL,GAAsB,EAAtB;EACA,KAAKC,kBAAL,GAA0B,CAA1B;EACA,KAAKC,cAAL,GAAsB,IAAtB;EACA,KAAKC,mBAAL,GAA2B,IAAI3wC,GAAJ,EAA3B;EACA,KAAK4wC,cAAL,GAAsB,IAAtB;EACA,KAAKb,WAAL,GAAmB,KAAnB;EACAtuB,aAAa,KAAKyuB,YAAlB;EACA,KAAKA,YAAL,GAAoB,IAApB;EAEA,KAAKV,oBAAL,GAA4Bz8B,wCAA5B;AAzKoB;;sBA+KT;EACX,IAAI,KAAKw8B,MAAL,CAAY9zC,KAAZ,KAAsB,KAAKo1C,SAA/B,EAA0C;IACxC,KAAKA,SAAL,GAAiB,KAAKtB,MAAL,CAAY9zC,KAA7B;IACA,CAAC,KAAKq1C,gBAAN,IAA0BlE,UAAU,KAAK2C,MAAL,CAAY9zC,KAAtB,CAA1B;EAHS;;EAKX,OAAO,KAAKq1C,gBAAZ;AApLoB;;4BAuLJ71C,OAAO;EAGvB,IAAIA,MAAMQ,KAANR,KAAgB,KAAKs0C,MAAL,CAAY9zC,KAAhC,EAAuC;IACrC,OAAO,IAAP;EAJqB;;EAMvB,QAAQR,MAAM6kB,IAAd;IACE,KAAK,OAAL;MACE,MAAMzS,aAAa,KAAKiiC,SAAL,CAAeQ,OAAf,GAAyB,CAA5C;MACA,MAAMx3B,cAAc,KAAKu2B,YAAzB;;MASA,IACExhC,cAAc,CAAdA,IACAA,cAAciL,YAAY/L,UAD1Bc,IAEAA,eAAeiL,YAAY7L,IAF3BY,IAGA,CAACiL,YAAYvI,aAAZuI,CAA0BjL,UAA1BiL,CAJH,EAKE;QACA,OAAO,IAAP;MAjBJ;;MAmBE,OAAO,KAAP;;IACF,KAAK,oBAAL;MACE,OAAO,KAAP;EAtBJ;;EAwBA,OAAO,IAAP;AArNoB;;wBA4NR2sB,SAAS8L,UAAUl0C,QAAQ;EACvC,IAAIgxC,QAAQ5I,QACThP,KADSgP,CACH,CADGA,EACA8L,QADA9L,EAET4I,KAFS5I,CAEHoH,8BAFGpH,CAAZ;;EAGA,IAAI4I,KAAJ,EAAW;IACT,MAAMxsC,QAAQ4jC,QAAQ+L,UAAR/L,CAAmB8L,QAAnB9L,CAAd;IACA,MAAM5nC,QAAQwwC,MAAM,CAAN,EAASmD,UAATnD,CAAoB,CAApBA,CAAd;;IACA,IAAIoD,sCAAiB5vC,KAAjB4vC,MAA4BA,sCAAiB5zC,KAAjB4zC,CAAhC,EAAyD;MACvD,OAAO,KAAP;IAJO;EAJ4B;;EAYvCpD,QAAQ5I,QACLhP,KADKgP,CACC8L,WAAWl0C,MADZooC,EAEL4I,KAFK5I,CAECqH,gCAFDrH,CAAR4I;;EAGA,IAAIA,KAAJ,EAAW;IACT,MAAMvsC,OAAO2jC,QAAQ+L,UAAR/L,CAAmB8L,WAAWl0C,MAAXk0C,GAAoB,CAAvC9L,CAAb;IACA,MAAM5nC,QAAQwwC,MAAM,CAAN,EAASmD,UAATnD,CAAoB,CAApBA,CAAd;;IACA,IAAIoD,sCAAiB3vC,IAAjB2vC,MAA2BA,sCAAiB5zC,KAAjB4zC,CAA/B,EAAwD;MACtD,OAAO,KAAP;IAJO;EAf4B;;EAuBvC,OAAO,IAAP;AAnPoB;;gCAsPAx1C,OAAOu1B,YAAY3gB,WAAW6gC,aAAa;EAC/D,MAAMr4B,UAAU,EAAhB;EAAA,MACEs4B,gBAAgB,EADlB;EAGA,MAAMzC,QAAQ,KAAK6B,UAAL,CAAgBlgC,SAAhB,CAAd;EACA,IAAIw9B,KAAJ;;EACA,OAAQ,SAAQpyC,MAAMic,IAANjc,CAAWy1C,WAAXz1C,CAAR,MAAqC,IAA7C,EAAmD;IACjD,IACEu1B,cACA,wBAAC,IAAD,sCAAC,IAAD,EAAoBkgB,WAApB,EAAiCrD,MAAM/uC,KAAvC,EAA8C+uC,MAAM,CAAN,EAAShxC,MAAvD,CAFF,EAGE;MACA;IAL+C;;IAQjD,MAAM,CAACu0C,QAAD,EAAWC,QAAX,IAAuB5C,iBAC3BC,KAD2B,EAE3Bb,MAAM/uC,KAFqB,EAG3B+uC,MAAM,CAAN,EAAShxC,MAHkB,CAA7B;;IAMA,IAAIw0C,QAAJ,EAAc;MACZx4B,QAAQ7X,IAAR6X,CAAau4B,QAAbv4B;MACAs4B,cAAcnwC,IAAdmwC,CAAmBE,QAAnBF;IAhB+C;EANY;;EAyB/D,KAAKjC,YAAL,CAAkB7+B,SAAlB,IAA+BwI,OAA/B;EACA,KAAKu2B,kBAAL,CAAwB/+B,SAAxB,IAAqC8gC,aAArC;AAhRoB;;iCAmRC11C,OAAOmyC,eAAe;EAC3C,MAAM;IAAEzc;EAAF,IAAsB,KAAKoe,MAAjC;EACA,IAAI+B,YAAY,KAAhB;EACA71C,QAAQA,MAAMa,OAANb,CACN2wC,qBADM3wC,EAEN,CACEoyC,KADF,EAEEC,EAFF,EAGEC,EAHF,EAIEC,EAJF,EAKEC,EALF,EAMEC,EANF,KAOK;IAIH,IAAIJ,EAAJ,EAAQ;MAEN,OAAQ,SAAQA,EAAG,MAAnB;IANC;;IAQH,IAAIC,EAAJ,EAAQ;MAEN,OAAQ,OAAMA,EAAG,MAAjB;IAVC;;IAYH,IAAIC,EAAJ,EAAQ;MAEN,OAAO,MAAP;IAdC;;IAgBH,IAAI7c,eAAJ,EAAqB;MACnB,OAAO8c,MAAMC,EAAb;IAjBC;;IAoBH,IAAID,EAAJ,EAAQ;MAEN,OAAOlC,qBAAqB59B,GAArB49B,CAAyBkC,GAAG+C,UAAH/C,CAAc,CAAdA,CAAzBlC,IAA6CkC,EAA7ClC,GAAkD,EAAzD;IAtBC;;IA2BH,IAAI6B,aAAJ,EAAmB;MACjB0D,YAAY,IAAZA;MACA,OAAO,GAAGpD,EAAG,SAAb;IA7BC;;IA+BH,OAAOA,EAAP;EAxCI,EAARzyC;EA4CA,MAAM81C,iBAAiB,MAAvB;;EACA,IAAI91C,MAAM6yC,QAAN7yC,CAAe81C,cAAf91C,CAAJ,EAAoC;IAIlCA,QAAQA,MAAMw6B,KAANx6B,CAAY,CAAZA,EAAeA,MAAMoB,MAANpB,GAAe81C,eAAe10C,MAA7CpB,CAARA;EApDyC;;EAuD3C,IAAI01B,eAAJ,EAAqB;IAEnB,IAAIyc,aAAJ,EAAmB;MACjB0D,YAAY,IAAZA;MACA71C,QAAQ,GAAGA,KAAM,OAAMuwC,wBAAyB,gBAAhDvwC;IAJiB;EAvDsB;;EA+D3C,OAAO,CAAC61C,SAAD,EAAY71C,KAAZ,CAAP;AAlVoB;;0BAqVN4U,WAAW;EACzB,IAAI5U,8BAAQ,IAAR,SAAJ;;EACA,IAAIA,MAAMoB,MAANpB,KAAiB,CAArB,EAAwB;IAEtB;EAJuB;;EAOzB,MAAM;IAAEs1B,aAAF;IAAiBC,UAAjB;IAA6B1iB;EAA7B,IAA8C,KAAKihC,MAAzD;EACA,MAAM2B,cAAc,KAAKZ,aAAL,CAAmBjgC,SAAnB,CAApB;EACA,MAAMu9B,gBAAgB,KAAK4C,cAAL,CAAoBngC,SAApB,CAAtB;EAEA,IAAIihC,YAAY,KAAhB;;EACA,IAAIhjC,YAAJ,EAAkB;IAChB,CAACgjC,SAAD,EAAY71C,KAAZ,2BAAqB,IAArB,wDAAqB,IAArB,EAAiDA,KAAjD,EAAwDmyC,aAAxD;EADF,OAEO;IAGL,MAAMC,QAAQpyC,MAAMoyC,KAANpyC,CAAY,MAAZA,CAAd;;IACA,IAAIoyC,KAAJ,EAAW;MACTpyC,QAAQoyC,MACLrsC,IADKqsC,GAEL2D,OAFK3D,GAGLrR,GAHKqR,CAGDjwC,KAAK;QACR,MAAM,CAAC6zC,aAAD,EAAgBC,SAAhB,2BAA6B,IAA7B,wDAA6B,IAA7B,EACJ9zC,CADI,EAEJgwC,aAFI,CAAN;;QAIA0D,0BAAcG,aAAd;QACA,OAAQ,IAAGC,SAAU,GAArB;MATI,GAWLrwB,IAXKwsB,CAWA,GAXAA,CAARpyC;IALG;EAdkB;;EAkCzB,MAAMk2C,QAAS,IAAGL,YAAY,GAAZ,GAAkB,EAAtB,GAA2BvgB,gBAAgB,EAAhB,GAAqB,GAAhD,EAAd;EACAt1B,QAAQ,IAAI2xC,MAAJ,CAAW3xC,KAAX,EAAkBk2C,KAAlB,CAARl2C;;EAEA,uFAA2BA,KAA3B,EAAkCu1B,UAAlC,EAA8C3gB,SAA9C,EAAyD6gC,WAAzD;;EAIA,IAAI,KAAK3B,MAAL,CAAYte,YAAhB,EAA8B;IAC5B,mEAAiB5gB,SAAjB;EA1CuB;;EA4CzB,IAAI,KAAKugC,cAAL,KAAwBvgC,SAA5B,EAAuC;IACrC,KAAKugC,cAAL,GAAsB,IAAtB;;IACA;EA9CuB;;EAkDzB,MAAMgB,mBAAmB,KAAK1C,YAAL,CAAkB7+B,SAAlB,EAA6BxT,MAAtD;;EACA,IAAI+0C,mBAAmB,CAAvB,EAA0B;IACxB,KAAKnB,kBAAL,IAA2BmB,gBAA3B;;IACA;EArDuB;AArVL;;yBA8YP;EAEb,IAAI,KAAKvB,oBAAL,CAA0BxzC,MAA1B,GAAmC,CAAvC,EAA0C;IACxC;EAHW;;EAMb,IAAI4e,UAAUlY,QAAQC,OAARD,EAAd;;EACA,KAAK,IAAIrE,IAAI,CAAR,EAAWkY,KAAK,KAAKy3B,YAAL,CAAkBtiC,UAAvC,EAAmDrN,IAAIkY,EAAvD,EAA2DlY,GAA3D,EAAgE;IAC9D,MAAM2yC,wBAAwB9+B,wCAA9B;IACA,KAAKs9B,oBAAL,CAA0BnxC,CAA1B,IAA+B2yC,sBAAsBp2B,OAArD;IAEAA,UAAUA,QAAQrL,IAARqL,CAAa,MAAM;MAC3B,OAAO,KAAKoqB,YAAL,CACJsC,OADI,CACIjpC,IAAI,CADR,EAEJkR,IAFI,CAECwS,WAAW;QACf,OAAOA,QAAQkvB,cAARlvB,EAAP;MAHG,GAKJxS,IALI,CAMH0Q,eAAe;QACb,MAAMixB,SAAS,EAAf;;QAEA,WAAWC,QAAX,IAAuBlxB,YAAYtkB,KAAnC,EAA0C;UACxCu1C,OAAO/wC,IAAP+wC,CAAYC,SAAS51C,GAArB21C;;UACA,IAAIC,SAASC,MAAb,EAAqB;YACnBF,OAAO/wC,IAAP+wC,CAAY,IAAZA;UAHsC;QAH7B;;QAWb,CACE,KAAKzB,aAAL,CAAmBpxC,CAAnB,CADF,EAEE,KAAKqxC,UAAL,CAAgBrxC,CAAhB,CAFF,EAGE,KAAKsxC,cAAL,CAAoBtxC,CAApB,CAHF,IAII0tC,UAAUmF,OAAO1wB,IAAP0wB,CAAY,EAAZA,CAAV,CAJJ;QAKAF,sBAAsBruC,OAAtBquC;MAtBC,GAwBHz7B,UAAU;QACRld,QAAQC,KAARD,CACG,uCAAsCgG,IAAI,CAA3C,EADFhG,EAEEkd,MAFFld;QAKA,KAAKo3C,aAAL,CAAmBpxC,CAAnB,IAAwB,EAAxB;QACA,KAAKqxC,UAAL,CAAgBrxC,CAAhB,IAAqB,IAArB;QACA,KAAKsxC,cAAL,CAAoBtxC,CAApB,IAAyB,KAAzB;QACA2yC,sBAAsBruC,OAAtBquC;MAjCC,EAAP;IADQ,EAAVp2B;EAXW;AA9YO;;sBAkcV3c,OAAO;EACjB,IAAI,KAAK8wC,cAAL,IAAuB,KAAKN,SAAL,CAAeQ,OAAf,KAA2BhxC,KAAtD,EAA6D;IAI3D,KAAK+vC,YAAL,CAAkBpiC,IAAlB,GAAyB3N,QAAQ,CAAjC;EALe;;EAQjB,KAAKgwC,SAAL,CAAe1gC,QAAf,CAAwB,wBAAxB,EAAkD;IAChDC,QAAQ,IADwC;IAEhDgC,WAAWvR;EAFqC,CAAlD;AA1coB;;4BAgdJ;EAChB,KAAKgwC,SAAL,CAAe1gC,QAAf,CAAwB,wBAAxB,EAAkD;IAChDC,QAAQ,IADwC;IAEhDgC,WAAW,CAAC;EAFoC,CAAlD;AAjdoB;;uBAudT;EACX,MAAMihB,WAAW,KAAKie,MAAL,CAAYre,YAA7B;EACA,MAAMghB,mBAAmB,KAAKrD,YAAL,CAAkBpiC,IAAlB,GAAyB,CAAlD;EACA,MAAMD,WAAW,KAAKqiC,YAAL,CAAkBtiC,UAAnC;EAEA,KAAKyiC,iBAAL,GAAyB,IAAzB;;EAEA,IAAI,KAAKe,WAAT,EAAsB;IAEpB,KAAKA,WAAL,GAAmB,KAAnB;IACA,KAAKT,SAAL,CAAeQ,OAAf,GAAyB,KAAKR,SAAL,CAAeO,QAAf,GAA0B,CAAC,CAApD;IACA,KAAKM,OAAL,CAAaL,OAAb,GAAuBoC,gBAAvB;IACA,KAAK/B,OAAL,CAAaN,QAAb,GAAwB,IAAxB;IACA,KAAKM,OAAL,CAAaC,OAAb,GAAuB,KAAvB;IACA,KAAKQ,cAAL,GAAsB,IAAtB;IACA,KAAK1B,YAAL,CAAkBryC,MAAlB,GAA2B,CAA3B;IACA,KAAKuyC,kBAAL,CAAwBvyC,MAAxB,GAAiC,CAAjC;IACA,KAAK4zC,kBAAL,GAA0B,CAA1B;;IAEA;;IAEA,KAAK,IAAIvxC,IAAI,CAAb,EAAgBA,IAAIsN,QAApB,EAA8BtN,GAA9B,EAAmC;MAEjC,IAAI,KAAKyxC,mBAAL,CAAyBxiC,GAAzB,CAA6BjP,CAA7B,CAAJ,EAAqC;QACnC;MAH+B;;MAKjC,KAAKyxC,mBAAL,CAAyBvvC,GAAzB,CAA6BlC,CAA7B;;MACA,KAAKmxC,oBAAL,CAA0BnxC,CAA1B,EAA6BkR,IAA7B,CAAkC,MAAM;QACtC,KAAKugC,mBAAL,CAAyBnsB,MAAzB,CAAgCtlB,CAAhC;;QACA,2EAAqBA,CAArB;MAFF;IApBkB;EAPX;;EAmCX,IAAI,wCAAgB,EAApB,EAAwB;IACtB,yEAAoBisC,UAAUC,KAA9B;;IACA;EArCS;;EAwCX,IAAI,KAAKwF,cAAT,EAAyB;IACvB;EAzCS;;EA4CX,MAAMuB,SAAS,KAAKhC,OAApB;EAEA,KAAKO,cAAL,GAAsBlkC,QAAtB;;EAGA,IAAI2lC,OAAOtC,QAAPsC,KAAoB,IAAxB,EAA8B;IAC5B,MAAMC,iBAAiB,KAAKlD,YAAL,CAAkBiD,OAAOrC,OAAzB,EAAkCjzC,MAAzD;;IACA,IACG,CAACy0B,QAAD,IAAa6gB,OAAOtC,QAAPsC,GAAkB,CAAlBA,GAAsBC,cAAnC,IACA9gB,YAAY6gB,OAAOtC,QAAPsC,GAAkB,CAFjC,EAGE;MAGAA,OAAOtC,QAAPsC,GAAkB7gB,WAAW6gB,OAAOtC,QAAPsC,GAAkB,CAA7B,GAAiCA,OAAOtC,QAAPsC,GAAkB,CAArEA;;MACA,qEAAgC,IAAhC;;MACA;IAV0B;;IAc5B,iFAAwB7gB,QAAxB;EA/DS;;EAkEX;AAzhBoB;;wBA4hBRzY,SAAS;EACrB,MAAMs5B,SAAS,KAAKhC,OAApB;EACA,MAAMkC,aAAax5B,QAAQhc,MAA3B;EACA,MAAMy0B,WAAW,KAAKie,MAAL,CAAYre,YAA7B;;EAEA,IAAImhB,UAAJ,EAAgB;IAEdF,OAAOtC,QAAPsC,GAAkB7gB,WAAW+gB,aAAa,CAAxB,GAA4B,CAA9CF;;IACA,qEAAgC,IAAhC;;IACA,OAAO,IAAP;EATmB;;EAYrB,iFAAwB7gB,QAAxB;;EACA,IAAI6gB,OAAO/B,OAAX,EAAoB;IAClB+B,OAAOtC,QAAPsC,GAAkB,IAAlBA;;IACA,IAAI,KAAKzB,cAAL,GAAsB,CAA1B,EAA6B;MAE3B,qEAAgC,KAAhC;;MAGA,OAAO,IAAP;IAPgB;EAbC;;EAwBrB,OAAO,KAAP;AApjBoB;;2BAujBL;EACf,IAAI,KAAKE,cAAL,KAAwB,IAA5B,EAAkC;IAChC13C,QAAQC,KAARD,CAAc,qCAAdA;EAFa;;EAKf,IAAI2f,UAAU,IAAd;;EACA,GAAG;IACD,MAAMi3B,UAAU,KAAKK,OAAL,CAAaL,OAA7B;IACAj3B,UAAU,KAAKq2B,YAAL,CAAkBY,OAAlB,CAAVj3B;;IACA,IAAI,CAACA,OAAL,EAAc;MAGZ,KAAK+3B,cAAL,GAAsBd,OAAtB;MACA;IAPD;EAAH,SASS,wBAAC,IAAD,sCAAC,IAAD,EAAoBj3B,OAApB,CATT;AA7jBoB;;6BAykBHyY,UAAU;EAC3B,MAAM6gB,SAAS,KAAKhC,OAApB;EACA,MAAM3jC,WAAW,KAAKqiC,YAAL,CAAkBtiC,UAAnC;EACA4lC,OAAOrC,OAAPqC,GAAiB7gB,WAAW6gB,OAAOrC,OAAPqC,GAAiB,CAA5B,GAAgCA,OAAOrC,OAAPqC,GAAiB,CAAlEA;EACAA,OAAOtC,QAAPsC,GAAkB,IAAlBA;EAEA,KAAKzB,cAAL;;EAEA,IAAIyB,OAAOrC,OAAPqC,IAAkB3lC,QAAlB2lC,IAA8BA,OAAOrC,OAAPqC,GAAiB,CAAnD,EAAsD;IACpDA,OAAOrC,OAAPqC,GAAiB7gB,WAAW9kB,WAAW,CAAtB,GAA0B,CAA3C2lC;IACAA,OAAO/B,OAAP+B,GAAiB,IAAjBA;EAVyB;AAzkBP;;yBAulBM;EAAA,IAAfG,KAAe,uEAAP,KAAO;EAC1B,IAAIr3C,QAAQkwC,UAAUG,SAAtB;EACA,MAAM8E,UAAU,KAAKD,OAAL,CAAaC,OAA7B;EACA,KAAKD,OAAL,CAAaC,OAAb,GAAuB,KAAvB;;EAEA,IAAIkC,KAAJ,EAAW;IACT,MAAM/iC,eAAe,KAAK+/B,SAAL,CAAeQ,OAApC;IACA,KAAKR,SAAL,CAAeQ,OAAf,GAAyB,KAAKK,OAAL,CAAaL,OAAtC;IACA,KAAKR,SAAL,CAAeO,QAAf,GAA0B,KAAKM,OAAL,CAAaN,QAAvC;IACA50C,QAAQm1C,UAAUjF,UAAUrzC,OAApB,GAA8BqzC,UAAUC,KAAhDnwC;;IAGA,IAAIsU,iBAAiB,CAAC,CAAlBA,IAAuBA,iBAAiB,KAAK+/B,SAAL,CAAeQ,OAA3D,EAAoE;MAClE,mEAAiBvgC,YAAjB;IARO;EALe;;EAiB1B,yEAAoBtU,KAApB,EAA2B,KAAKs0C,MAAL,CAAYre,YAAvC;;EACA,IAAI,KAAKoe,SAAL,CAAeQ,OAAf,KAA2B,CAAC,CAAhC,EAAmC;IAEjC,KAAKF,cAAL,GAAsB,IAAtB;;IAEA,mEAAiB,KAAKN,SAAL,CAAeQ,OAAhC;EAtBwB;AAvlBN;;0BAinBNn1C,KAAK;EACnB,MAAMqR,cAAc,KAAK65B,YAAzB;;EAIA,KAAK2J,oBAAL,CAA0B/zB,OAA1B,CAAkCrL,IAAlC,CAAuC,MAAM;IAE3C,IACE,CAAC,KAAKy1B,YAAN,IACC75B,eAAe,KAAK65B,YAAL,KAAsB75B,WAFxC,EAGE;MACA;IANyC;;IAS3C,IAAI,KAAKkkC,YAAT,EAAuB;MACrBzuB,aAAa,KAAKyuB,YAAlB;MACA,KAAKA,YAAL,GAAoB,IAApB;IAXyC;;IAiB3C,IAAI,KAAKU,cAAT,EAAyB;MACvB,KAAKA,cAAL,GAAsB,IAAtB;MACA,KAAKb,WAAL,GAAmB,IAAnB;IAnByC;;IAsB3C,yEAAoB5E,UAAUC,KAA9B;;IAEA,KAAK4D,iBAAL,GAAyB,KAAzB;;IACA;EAzBF;AAtnBoB;;iCAmpBC;EACrB,MAAM;IAAEc,OAAF;IAAWD;EAAX,IAAwB,KAAKP,SAAnC;EACA,IAAI/D,UAAU,CAAd;EAAA,IACEzsB,QAAQ,KAAK2xB,kBADf;;EAEA,IAAIZ,aAAa,CAAC,CAAlB,EAAqB;IACnB,KAAK,IAAI3wC,IAAI,CAAb,EAAgBA,IAAI4wC,OAApB,EAA6B5wC,GAA7B,EAAkC;MAAA;;MAChCqsC,WAAW,8BAAK2D,YAAL,CAAkBhwC,CAAlB,+EAAsBrC,MAAtB,KAAgC,CAA3C0uC;IAFiB;;IAInBA,WAAWsE,WAAW,CAAtBtE;EARmB;;EAarB,IAAIA,UAAU,CAAVA,IAAeA,UAAUzsB,KAA7B,EAAoC;IAClCysB,UAAUzsB,QAAQ,CAAlBysB;EAdmB;;EAgBrB,OAAO;IAAEA,OAAF;IAAWzsB;EAAX,CAAP;AAnqBoB;;kCAsqBE;EACtB,KAAKgwB,SAAL,CAAe1gC,QAAf,CAAwB,wBAAxB,EAAkD;IAChDC,QAAQ,IADwC;IAEhD+iB,qCAAc,IAAd,oDAAc,IAAd;EAFgD,CAAlD;AAvqBoB;;yBA6qBPn2B,OAAyB;EAAA;;EAAA,IAAlBq2B,QAAkB,uEAAP,KAAO;;EACtC,KAAKwd,SAAL,CAAe1gC,QAAf,CAAwB,wBAAxB,EAAkD;IAChDC,QAAQ,IADwC;IAEhDpT,KAFgD;IAGhDq2B,QAHgD;IAIhDF,qCAAc,IAAd,oDAAc,IAAd,CAJgD;IAKhDG,gDAAU,KAAKge,MAAf,iDAAU,aAAa9zC,KAAvB,mEAAgC;EALgB,CAAlD;AA9qBoB;;;;;;;;;;;;;ACzSxB,MAAM82C,gBAAgB;EACpBC,OAAO,CADa;EAEpBC,cAAc,CAFM;EAGpBC,OAAO,CAHa;EAIpBC,YAAY,CAJQ;EAKpBC,iBAAiB,CALG;EAMpBC,iBAAiB,CANG;EAOpBC,2BAA2B,CAPP;EAQpBC,aAAa;AARO,CAAtB;;;AAWA,SAASC,oBAAT,CAA8BC,QAA9B,EAAwC;EACtC,OAAOA,WAAW,MAAlB;AA3BF;;AA8BA,SAASC,OAAT,CAAiBD,QAAjB,EAA2B;EACzB,OAAQ,YAAW,MAAX,MAAuB,CAA/B;AA/BF;;AAkCA,SAASE,YAAT,CAAsBF,QAAtB,EAAgC;EAC9B,OACGA,YAAsB,IAAtBA,IAA8BA,YAAsB,IAApDA,IACAA,YAAsB,IAAtBA,IAA8BA,YAAsB,IAFvD;AAnCF;;AAyCA,SAASG,YAAT,CAAsBH,QAAtB,EAAgC;EAC9B,OAAOA,YAAsB,IAAtBA,IAA8BA,YAAsB,IAA3D;AA1CF;;AA6CA,SAASI,YAAT,CAAsBJ,QAAtB,EAAgC;EAC9B,OACEA,aAA2B,IAA3BA,IACAA,aAAyB,IADzBA,IAEAA,aAAwB,IAFxBA,IAGAA,aAAwB,IAJ1B;AA9CF;;AAsDA,SAASK,KAAT,CAAeL,QAAf,EAAyB;EACvB,OACGA,YAAY,MAAZA,IAAsBA,YAAY,MAAlCA,IACAA,YAAY,MAAZA,IAAsBA,YAAY,MAFrC;AAvDF;;AA6DA,SAASM,UAAT,CAAoBN,QAApB,EAA8B;EAC5B,OAAOA,YAAY,MAAZA,IAAsBA,YAAY,MAAzC;AA9DF;;AAiEA,SAASO,UAAT,CAAoBP,QAApB,EAA8B;EAC5B,OAAOA,YAAY,MAAZA,IAAsBA,YAAY,MAAzC;AAlEF;;AAqEA,SAASQ,mBAAT,CAA6BR,QAA7B,EAAuC;EACrC,OAAOA,YAAY,MAAZA,IAAsBA,YAAY,MAAzC;AAtEF;;AAyEA,SAASS,MAAT,CAAgBT,QAAhB,EAA0B;EACxB,OAAQ,YAAW,MAAX,MAAuB,MAA/B;AA1EF;;AAiFA,SAAShC,gBAAT,CAA0BgC,QAA1B,EAAoC;EAClC,IAAID,qBAAqBC,QAArB,CAAJ,EAAoC;IAClC,IAAIC,QAAQD,QAAR,CAAJ,EAAuB;MACrB,IAAII,aAAaJ,QAAb,CAAJ,EAA4B;QAC1B,OAAOV,cAAcC,KAArB;MADF,OAEO,IACLW,aAAaF,QAAb,KACAG,aAAaH,QAAb,CADAE,IAEAF,aAAgC,IAH3B,EAIL;QACA,OAAOV,cAAcE,YAArB;MARmB;;MAUrB,OAAOF,cAAcG,KAArB;IAVF,OAWO,IAAIgB,OAAOT,QAAP,CAAJ,EAAsB;MAC3B,OAAOV,cAAcQ,WAArB;IADK,OAEA,IAAIE,aAA0B,IAA9B,EAAoC;MACzC,OAAOV,cAAcC,KAArB;IAfgC;;IAiBlC,OAAOD,cAAcE,YAArB;EAlBgC;;EAqBlC,IAAIa,MAAML,QAAN,CAAJ,EAAqB;IACnB,OAAOV,cAAcI,UAArB;EADF,OAEO,IAAIY,WAAWN,QAAX,CAAJ,EAA0B;IAC/B,OAAOV,cAAcK,eAArB;EADK,OAEA,IAAIY,WAAWP,QAAX,CAAJ,EAA0B;IAC/B,OAAOV,cAAcM,eAArB;EADK,OAEA,IAAIY,oBAAoBR,QAApB,CAAJ,EAAmC;IACxC,OAAOV,cAAcO,yBAArB;EA5BgC;;EA8BlC,OAAOP,cAAcE,YAArB;AA/GF;;;;;;;;;;;;;;;ACkBA;;AACA;;AAGA,MAAMkB,sBAAsB,IAA5B;AAEA,MAAMC,6BAA6B,EAAnC;AAEA,MAAMC,0BAA0B,IAAhC;;AAwBA,SAASC,cAAT,GAA0B;EACxB,OAAOpwC,SAASkP,QAATlP,CAAkBwK,IAAzB;AAnDF;;AAsDA,MAAMqL,UAAN,CAAiB;EAIflhB,kBAAuC;IAAA,IAA3B;MAAEigB,WAAF;MAAe1M;IAAf,CAA2B;IACrC,KAAK0M,WAAL,GAAmBA,WAAnB;IACA,KAAK1M,QAAL,GAAgBA,QAAhB;IAEA,KAAKmoC,YAAL,GAAoB,KAApB;IACA,KAAKC,YAAL,GAAoB,EAApB;IACA,KAAKp2B,KAAL;IAEA,KAAKhJ,YAAL,GAAoB,IAApB;;IAGA,KAAKhJ,QAAL,CAAcgZ,GAAd,CAAkB,WAAlB,EAA+B,MAAM;MACnC,KAAKqvB,cAAL,GAAsB,KAAtB;;MAEA,KAAKroC,QAAL,CAAcgZ,GAAd,CACE,aADF,EAEEjqB,OAAO;QACL,KAAKs5C,cAAL,GAAsB,CAAC,CAACt5C,IAAI4R,UAA5B;MAHJ,GAKE;QAAEsY,MAAM;MAAR,CALF;IAHF;EAfa;;EAiCfpP,kBAAqE;IAAA,IAA1D;MAAE2N,WAAF;MAAe2E,eAAe,KAA9B;MAAqCC,YAAY;IAAjD,CAA0D;;IACnE,IAAI,CAAC5E,WAAD,IAAgB,OAAOA,WAAP,KAAuB,QAA3C,EAAqD;MACnDlqB,QAAQC,KAARD,CACE,sEADFA;MAGA;IALiE;;IAQnE,IAAI,KAAK66C,YAAT,EAAuB;MACrB,KAAKn2B,KAAL;IATiE;;IAWnE,MAAMs2B,gBACJ,KAAKF,YAAL,KAAsB,EAAtB,IAA4B,KAAKA,YAAL,KAAsB5wB,WADpD;IAEA,KAAK4wB,YAAL,GAAoB5wB,WAApB;IACA,KAAK+wB,UAAL,GAAkBnsB,cAAc,IAAhC;IAEA,KAAK+rB,YAAL,GAAoB,IAApB;;IACA,KAAKK,WAAL;;IACA,MAAMn5C,QAAQ1C,OAAO87C,OAAP97C,CAAe0C,KAA7B;IAEA,KAAKq5C,mBAAL,GAA2B,KAA3B;IACA,KAAKC,gBAAL,GAAwB,CAAxB;IACA,KAAKC,YAAL,GAAoBV,gBAApB;IACA,KAAKW,mBAAL,GAA2B,CAA3B;IAEA,KAAKC,IAAL,GAAY,KAAKC,OAAL,GAAe,CAA3B;IACA,KAAKC,YAAL,GAAoB,IAApB;IACA,KAAKC,SAAL,GAAiB,IAAjB;;IAEA,IAAI,CAAC,KAAKC,aAAL,CAAmB75C,KAAnB,EAA8C,IAA9C,CAAD,IAAwD8sB,YAA5D,EAA0E;MACxE,MAAM;QAAE7Z,IAAF;QAAQzB,IAAR;QAAcE;MAAd,IAA2B,KAAKooC,iBAAL,CACR,IADQ,CAAjC;;MAIA,IAAI,CAAC7mC,IAAD,IAASgmC,aAAT,IAA0BnsB,YAA9B,EAA4C;QAE1C,KAAKitB,mBAAL,CAAyB,IAAzB,EAAoD,IAApD;;QACA;MARsE;;MAYxE,KAAKA,mBAAL,CACE;QAAE9mC,IAAF;QAAQzB,IAAR;QAAcE;MAAd,CADF,EAEuB,IAFvB;;MAIA;IA7CiE;;IAkDnE,MAAMsoC,cAAch6C,MAAMg6C,WAA1B;;IACA,KAAKC,oBAAL,CACED,WADF,EAEEh6C,MAAMk6C,GAFR,EAG0B,IAH1B;;IAMA,IAAIF,YAAYtoC,QAAZsoC,KAAyB96C,SAA7B,EAAwC;MACtC,KAAKi7C,gBAAL,GAAwBH,YAAYtoC,QAApC;IA1DiE;;IA4DnE,IAAIsoC,YAAYnoC,IAAhB,EAAsB;MACpB,KAAKuoC,gBAAL,GAAwBvnC,KAAKC,SAALD,CAAemnC,YAAYnoC,IAA3BgB,CAAxB;MAKA,KAAK8mC,YAAL,CAAkBnoC,IAAlB,GAAyB,IAAzB;IANF,OAOO,IAAIwoC,YAAY/mC,IAAhB,EAAsB;MAC3B,KAAKmnC,gBAAL,GAAwBJ,YAAY/mC,IAApC;IADK,OAEA,IAAI+mC,YAAYxoC,IAAhB,EAAsB;MAE3B,KAAK4oC,gBAAL,GAAyB,QAAOJ,YAAYxoC,IAApB,EAAxB;IAvEiE;EAjCtD;;EAgHfmR,QAAQ;IACN,IAAI,KAAKm2B,YAAT,EAAuB;MACrB,KAAKuB,SAAL;;MAEA,KAAKvB,YAAL,GAAoB,KAApB;;MACA,KAAKwB,aAAL;IALI;;IAON,IAAI,KAAKC,sBAAT,EAAiC;MAC/B/zB,aAAa,KAAK+zB,sBAAlB;MACA,KAAKA,sBAAL,GAA8B,IAA9B;IATI;;IAWN,KAAKH,gBAAL,GAAwB,IAAxB;IACA,KAAKD,gBAAL,GAAwB,IAAxB;EA5Ha;;EAmIfp0C,YAAqD;IAAA,IAAhD;MAAE+L,YAAY,IAAd;MAAoBC,YAApB;MAAkCK;IAAlC,CAAgD;;IACnD,IAAI,CAAC,KAAK0mC,YAAV,EAAwB;MACtB;IAFiD;;IAInD,IAAIhnC,aAAa,OAAOA,SAAP,KAAqB,QAAtC,EAAgD;MAC9C7T,QAAQC,KAARD,CACE,sBACG,IAAG6T,SAAU,uCAFlB7T;MAIA;IALF,OAMO,IAAI,CAACgU,MAAMC,OAAND,CAAcF,YAAdE,CAAL,EAAkC;MACvChU,QAAQC,KAARD,CACE,sBACG,IAAG8T,YAAa,0CAFrB9T;MAIA;IALK,OAMA,IAAI,CAAC,KAAKu8C,YAAL,CAAkBpoC,UAAlB,CAAL,EAAoC;MAGzC,IAAIA,eAAe,IAAfA,IAAuB,KAAKunC,YAAhC,EAA8C;QAC5C17C,QAAQC,KAARD,CACE,sBACG,IAAGmU,UAAW,wCAFnBnU;QAIA;MARuC;IAhBQ;;IA4BnD,MAAMgV,OAAOnB,aAAae,KAAKC,SAALD,CAAed,YAAfc,CAA1B;;IACA,IAAI,CAACI,IAAL,EAAW;MAGT;IAhCiD;;IAmCnD,IAAIwnC,eAAe,KAAnB;;IACA,IACE,KAAKd,YAAL,KACCe,kBAAkB,KAAKf,YAAL,CAAkB1mC,IAApC,EAA0CA,IAA1C,KACC0nC,kBAAkB,KAAKhB,YAAL,CAAkB9nC,IAApC,EAA0CE,YAA1C,CAFF,CADF,EAIE;MAMA,IAAI,KAAK4nC,YAAL,CAAkBnoC,IAAtB,EAA4B;QAC1B;MAPF;;MASAipC,eAAe,IAAfA;IAjDiD;;IAmDnD,IAAI,KAAKpB,mBAAL,IAA4B,CAACoB,YAAjC,EAA+C;MAC7C;IApDiD;;IAuDnD,KAAKV,mBAAL,CACE;MACEloC,MAAME,YADR;MAEEkB,IAFF;MAGEzB,MAAMY,UAHR;MAIEV,UAAU,KAAK2L,WAAL,CAAiB3L;IAJ7B,CADF,EAOE+oC,YAPF;;IAUA,IAAI,CAAC,KAAKpB,mBAAV,EAA+B;MAG7B,KAAKA,mBAAL,GAA2B,IAA3B;MAGA/wC,QAAQC,OAARD,GAAkB6M,IAAlB7M,CAAuB,MAAM;QAC3B,KAAK+wC,mBAAL,GAA2B,KAA3B;MADF;IAvEiD;EAnItC;;EAqNf9mC,SAASH,UAAT,EAAqB;IAAA;;IACnB,IAAI,CAAC,KAAK0mC,YAAV,EAAwB;MACtB;IAFiB;;IAInB,IAAI,CAAC,KAAK0B,YAAL,CAAkBpoC,UAAlB,CAAL,EAAoC;MAClCnU,QAAQC,KAARD,CACG,yBAAwBmU,UAAW,+BADtCnU;MAGA;IARiB;;IAWnB,IAAI,4BAAK07C,YAAL,0EAAmBnoC,IAAnB,MAA4BY,UAAhC,EAA4C;MAG1C;IAdiB;;IAgBnB,IAAI,KAAKinC,mBAAT,EAA8B;MAC5B;IAjBiB;;IAoBnB,KAAKU,mBAAL,CAAyB;MAEvBloC,MAAM,IAFiB;MAGvBoB,MAAO,QAAOb,UAAR,EAHiB;MAIvBZ,MAAMY,UAJiB;MAKvBV,UAAU,KAAK2L,WAAL,CAAiB3L;IALJ,CAAzB;;IAQA,IAAI,CAAC,KAAK2nC,mBAAV,EAA+B;MAG7B,KAAKA,mBAAL,GAA2B,IAA3B;MAGA/wC,QAAQC,OAARD,GAAkB6M,IAAlB7M,CAAuB,MAAM;QAC3B,KAAK+wC,mBAAL,GAA2B,KAA3B;MADF;IAlCiB;EArNN;;EAgQf/mC,sBAAsB;IACpB,IAAI,CAAC,KAAKwmC,YAAN,IAAsB,KAAKO,mBAA/B,EAAoD;MAClD;IAFkB;;IAIpB,KAAKuB,uBAAL;EApQa;;EA2QfzmC,OAAO;IACL,IAAI,CAAC,KAAK2kC,YAAN,IAAsB,KAAKO,mBAA/B,EAAoD;MAClD;IAFG;;IAIL,MAAMr5C,QAAQ1C,OAAO87C,OAAP97C,CAAe0C,KAA7B;;IACA,IAAI,KAAK65C,aAAL,CAAmB75C,KAAnB,KAA6BA,MAAMk6C,GAANl6C,GAAY,CAA7C,EAAgD;MAC9C1C,OAAO87C,OAAP97C,CAAe6W,IAAf7W;IANG;EA3QQ;;EAyRf8W,UAAU;IACR,IAAI,CAAC,KAAK0kC,YAAN,IAAsB,KAAKO,mBAA/B,EAAoD;MAClD;IAFM;;IAIR,MAAMr5C,QAAQ1C,OAAO87C,OAAP97C,CAAe0C,KAA7B;;IACA,IAAI,KAAK65C,aAAL,CAAmB75C,KAAnB,KAA6BA,MAAMk6C,GAANl6C,GAAY,KAAK05C,OAAlD,EAA2D;MACzDp8C,OAAO87C,OAAP97C,CAAe8W,OAAf9W;IANM;EAzRK;;EAuSf,IAAIq4B,kBAAJ,GAAyB;IACvB,OACE,KAAKmjB,YAAL,KACC,KAAKO,mBAAL,IAA4B,KAAKC,gBAAL,GAAwB,CADrD,CADF;EAxSa;;EA8Sf,IAAI5hC,eAAJ,GAAsB;IACpB,OAAO,KAAKohC,YAAL,GAAoB,KAAKsB,gBAAzB,GAA4C,IAAnD;EA/Sa;;EAkTf,IAAIptB,eAAJ,GAAsB;IACpB,OAAO,KAAK8rB,YAAL,GAAoB,KAAKqB,gBAAzB,GAA4C,IAAnD;EAnTa;;EAyTfJ,oBAAoBC,WAApB,EAAuD;IAAA,IAAtBS,YAAsB,uEAAP,KAAO;IACrD,MAAMI,gBAAgBJ,gBAAgB,CAAC,KAAKd,YAA5C;IACA,MAAMmB,WAAW;MACf3yB,aAAa,KAAK4wB,YADH;MAEfmB,KAAKW,gBAAgB,KAAKpB,IAArB,GAA4B,KAAKA,IAAL,GAAY,CAF9B;MAGfO;IAHe,CAAjB;;IAcA,KAAKC,oBAAL,CAA0BD,WAA1B,EAAuCc,SAASZ,GAAhD;;IAEA,IAAIa,MAAJ;;IACA,IAAI,KAAK7B,UAAL,IAAmBc,WAAnB,aAAmBA,WAAnB,eAAmBA,YAAa/mC,IAApC,EAA0C;MACxC,MAAMnC,UAAUrI,SAASkP,QAATlP,CAAkB6H,IAAlB7H,CAAuB8K,KAAvB9K,CAA6B,GAA7BA,EAAkC,CAAlCA,CAAhB;;MAEA,IAAI,CAACqI,QAAQkqC,UAARlqC,CAAmB,SAAnBA,CAAL,EAAoC;QAClCiqC,SAAS,GAAGjqC,OAAQ,IAAGkpC,YAAY/mC,IAA1B,EAAT8nC;MAJsC;IAnBW;;IA0BrD,IAAIF,aAAJ,EAAmB;MACjBv9C,OAAO87C,OAAP97C,CAAe29C,YAAf39C,CAA4Bw9C,QAA5Bx9C,EAAsC,EAAtCA,EAA0Cy9C,MAA1Cz9C;IADF,OAEO;MACLA,OAAO87C,OAAP97C,CAAe49C,SAAf59C,CAAyBw9C,QAAzBx9C,EAAmC,EAAnCA,EAAuCy9C,MAAvCz9C;IA7BmD;EAzTxC;;EAsWfs9C,0BAA2C;IAAA,IAAnBO,SAAmB,uEAAP,KAAO;;IACzC,IAAI,CAAC,KAAKvB,SAAV,EAAqB;MACnB;IAFuC;;IAIzC,IAAIpZ,WAAW,KAAKoZ,SAApB;;IACA,IAAIuB,SAAJ,EAAe;MACb3a,WAAWz4B,OAAO2wB,MAAP3wB,CAAcA,OAAO6C,MAAP7C,CAAc,IAAdA,CAAdA,EAAmC,KAAK6xC,SAAxC7xC,CAAXy4B;MACAA,SAAS2a,SAAT3a,GAAqB,IAArBA;IAPuC;;IAUzC,IAAI,CAAC,KAAKmZ,YAAV,EAAwB;MACtB,KAAKI,mBAAL,CAAyBvZ,QAAzB;;MACA;IAZuC;;IAczC,IAAI,KAAKmZ,YAAL,CAAkBwB,SAAtB,EAAiC;MAE/B,KAAKpB,mBAAL,CAAyBvZ,QAAzB,EAAwD,IAAxD;;MACA;IAjBuC;;IAmBzC,IAAI,KAAKmZ,YAAL,CAAkB1mC,IAAlB,KAA2ButB,SAASvtB,IAAxC,EAA8C;MAC5C;IApBuC;;IAsBzC,IACE,CAAC,KAAK0mC,YAAL,CAAkBnoC,IAAnB,KACCmnC,8BAA8B,CAA9BA,IACC,KAAKa,mBAAL,IAA4Bb,0BAF9B,CADF,EAIE;MAKA;IA/BuC;;IAkCzC,IAAI8B,eAAe,KAAnB;;IACA,IACE,KAAKd,YAAL,CAAkBnoC,IAAlB,IAA0BgvB,SAASp6B,KAAnC,IACA,KAAKuzC,YAAL,CAAkBnoC,IAAlB,IAA0BgvB,SAAShvB,IAFrC,EAGE;MAMA,IAAI,KAAKmoC,YAAL,CAAkB9nC,IAAlB,KAA2B3S,SAA3B,IAAwC,CAAC,KAAKy6C,YAAL,CAAkBvzC,KAA/D,EAAsE;QACpE;MAPF;;MAUAq0C,eAAe,IAAfA;IAhDuC;;IAkDzC,KAAKV,mBAAL,CAAyBvZ,QAAzB,EAAmCia,YAAnC;EAxZa;;EA8ZfD,aAAapxC,GAAb,EAAkB;IAChB,OACEzB,OAAOC,SAAPD,CAAiByB,GAAjBzB,KAAyByB,MAAM,CAA/BzB,IAAoCyB,OAAO,KAAKiU,WAAL,CAAiB/L,UAD9D;EA/Za;;EAuafuoC,cAAc75C,KAAd,EAA0C;IAAA,IAArBo7C,WAAqB,uEAAP,KAAO;;IACxC,IAAI,CAACp7C,KAAL,EAAY;MACV,OAAO,KAAP;IAFsC;;IAIxC,IAAIA,MAAMmoB,WAANnoB,KAAsB,KAAK+4C,YAA/B,EAA6C;MAC3C,IAAIqC,WAAJ,EAAiB;QAGf,IACE,OAAOp7C,MAAMmoB,WAAb,KAA6B,QAA7B,IACAnoB,MAAMmoB,WAANnoB,CAAkB4B,MAAlB5B,KAA6B,KAAK+4C,YAAL,CAAkBn3C,MAFjD,EAGE;UACA,OAAO,KAAP;QAPa;;QASf,MAAM,CAACy5C,SAAD,IAAcC,YAAYC,gBAAZD,CAA6B,YAA7BA,CAApB;;QACA,IAAID,iEAAWx2B,IAAXw2B,MAAoB,QAAxB,EAAkC;UAChC,OAAO,KAAP;QAXa;MAAjB,OAaO;QAGL,OAAO,KAAP;MAjByC;IAJL;;IAwBxC,IAAI,CAAC1zC,OAAOC,SAAPD,CAAiB3H,MAAMk6C,GAAvBvyC,CAAD,IAAgC3H,MAAMk6C,GAANl6C,GAAY,CAAhD,EAAmD;MACjD,OAAO,KAAP;IAzBsC;;IA2BxC,IAAIA,MAAMg6C,WAANh6C,KAAsB,IAAtBA,IAA8B,OAAOA,MAAMg6C,WAAb,KAA6B,QAA/D,EAAyE;MACvE,OAAO,KAAP;IA5BsC;;IA8BxC,OAAO,IAAP;EArca;;EA2cfC,qBAAqBD,WAArB,EAAkCE,GAAlC,EAAgE;IAAA,IAAzBsB,eAAyB,uEAAP,KAAO;;IAC9D,IAAI,KAAKjB,sBAAT,EAAiC;MAI/B/zB,aAAa,KAAK+zB,sBAAlB;MACA,KAAKA,sBAAL,GAA8B,IAA9B;IAN4D;;IAQ9D,IAAIiB,mBAAmBxB,WAAnB,aAAmBA,WAAnB,eAAmBA,YAAamB,SAApC,EAA+C;MAG7C,OAAOnB,YAAYmB,SAAnB;IAX4D;;IAa9D,KAAKxB,YAAL,GAAoBK,WAApB;IACA,KAAKP,IAAL,GAAYS,GAAZ;IACA,KAAKR,OAAL,GAAez3C,KAAKyD,GAALzD,CAAS,KAAKy3C,OAAdz3C,EAAuBi4C,GAAvBj4C,CAAf;IAEA,KAAKu3C,mBAAL,GAA2B,CAA3B;EA5da;;EAkefM,oBAA0C;IAAA,IAAxB2B,cAAwB,uEAAP,KAAO;IACxC,MAAMxoC,OAAOY,SAASglC,gBAAT,EAA2BjhC,SAA3B/D,CAAqC,CAArCA,CAAb;IACA,MAAMpT,SAASF,gCAAiB0S,IAAjB1S,CAAf;IAEA,MAAMm7C,YAAYj7C,OAAOsO,GAAPtO,CAAW,WAAXA,KAA2B,EAA7C;IACA,IAAI+Q,OAAO/Q,OAAOsO,GAAPtO,CAAW,MAAXA,IAAqB,CAAhC;;IAEA,IAAI,CAAC,KAAK+5C,YAAL,CAAkBhpC,IAAlB,CAAD,IAA6BiqC,kBAAkBC,UAAU95C,MAAV85C,GAAmB,CAAtE,EAA0E;MACxElqC,OAAO,IAAPA;IARsC;;IAUxC,OAAO;MAAEyB,IAAF;MAAQzB,IAAR;MAAcE,UAAU,KAAK2L,WAAL,CAAiB3L;IAAzC,CAAP;EA5ea;;EAkffiqC,uBAA8B;IAAA,IAAd;MAAEhkC;IAAF,CAAc;;IAC5B,IAAI,KAAK4iC,sBAAT,EAAiC;MAC/B/zB,aAAa,KAAK+zB,sBAAlB;MACA,KAAKA,sBAAL,GAA8B,IAA9B;IAH0B;;IAM5B,KAAKX,SAAL,GAAiB;MACf3mC,MAAM0E,SAAS2d,aAAT3d,CAAuBC,SAAvBD,CAAiC,CAAjCA,CADS;MAEfnG,MAAM,KAAK6L,WAAL,CAAiB7L,IAFR;MAGfpL,OAAOuR,SAASvF,UAHD;MAIfV,UAAUiG,SAASjG;IAJJ,CAAjB;;IAOA,IAAI,KAAK2nC,mBAAT,EAA8B;MAC5B;IAd0B;;IAiB5B,IACEV,6BAA6B,CAA7BA,IACA,KAAKK,cADLL,IAEA,KAAKgB,YAFLhB,IAGA,CAAC,KAAKgB,YAAL,CAAkBnoC,IAJrB,EAKE;MASA,KAAKgoC,mBAAL;IA/B0B;;IAkC5B,IAAIZ,0BAA0B,CAA9B,EAAiC;MAgB/B,KAAK2B,sBAAL,GAA8B9zB,WAAW,MAAM;QAC7C,IAAI,CAAC,KAAK4yB,mBAAV,EAA+B;UAC7B,KAAKuB,uBAAL,CAA+C,IAA/C;QAF2C;;QAI7C,KAAKL,sBAAL,GAA8B,IAA9B;MAJ4B,GAK3B3B,uBAL2B,CAA9B;IAlD0B;EAlff;;EAgjBfgD,iBAAqB;IAAA,IAAX;MAAE57C;IAAF,CAAW;IACnB,MAAM67C,UAAUhD,gBAAhB;IAAA,MACEiD,cAAc,KAAKvC,YAAL,KAAsBsC,OADtC;IAEA,KAAKtC,YAAL,GAAoBsC,OAApB;;IAEA,IAKE,CAAC77C,KALH,EAME;MAEA,KAAKy5C,IAAL;;MAEA,MAAM;QAAExmC,IAAF;QAAQzB,IAAR;QAAcE;MAAd,IAA2B,KAAKooC,iBAAL,EAAjC;;MACA,KAAKC,mBAAL,CACE;QAAE9mC,IAAF;QAAQzB,IAAR;QAAcE;MAAd,CADF,EAEuB,IAFvB;;MAIA;IApBiB;;IAsBnB,IAAI,CAAC,KAAKmoC,aAAL,CAAmB75C,KAAnB,CAAL,EAAgC;MAG9B;IAzBiB;;IA8BnB,KAAKq5C,mBAAL,GAA2B,IAA3B;;IAEA,IAAIyC,WAAJ,EAAiB;MAUf,KAAKxC,gBAAL;MACApf,uCAAqB;QACnBhqB,QAAQ5S,MADW;QAEnB0R,MAAM,YAFa;QAGnBmrB,OAAOue;MAHY,CAArBxe,EAIG/kB,IAJH+kB,CAIQ,MAAM;QACZ,KAAKof,gBAAL;MALF;IA3CiB;;IAqDnB,MAAMU,cAAch6C,MAAMg6C,WAA1B;;IACA,KAAKC,oBAAL,CACED,WADF,EAEEh6C,MAAMk6C,GAFR,EAG0B,IAH1B;;IAMA,IAAIxyC,+BAAgBsyC,YAAYtoC,QAA5BhK,CAAJ,EAA2C;MACzC,KAAK2V,WAAL,CAAiB3L,QAAjB,GAA4BsoC,YAAYtoC,QAAxC;IA7DiB;;IA+DnB,IAAIsoC,YAAYnoC,IAAhB,EAAsB;MACpB,KAAKwL,WAAL,CAAiBzL,eAAjB,CAAiCooC,YAAYnoC,IAA7C;IADF,OAEO,IAAImoC,YAAY/mC,IAAhB,EAAsB;MAC3B,KAAKoK,WAAL,CAAiBrK,OAAjB,CAAyBgnC,YAAY/mC,IAArC;IADK,OAEA,IAAI+mC,YAAYxoC,IAAhB,EAAsB;MAE3B,KAAK6L,WAAL,CAAiB7L,IAAjB,GAAwBwoC,YAAYxoC,IAApC;IArEiB;;IA0EnBlJ,QAAQC,OAARD,GAAkB6M,IAAlB7M,CAAuB,MAAM;MAC3B,KAAK+wC,mBAAL,GAA2B,KAA3B;IADF;EA1nBa;;EAkoBfgB,YAAY;IAMV,IAAI,CAAC,KAAKV,YAAN,IAAsB,KAAKA,YAAL,CAAkBwB,SAA5C,EAAuD;MACrD,KAAKP,uBAAL;IAPQ;EAloBG;;EAgpBfzB,cAAc;IACZ,IAAI,KAAKx/B,YAAT,EAAuB;MACrB;IAFU;;IAIZ,KAAKA,YAAL,GAAoB;MAClBoiC,gBAAgB,KAAKJ,eAAL,CAAqBz+B,IAArB,CAA0B,IAA1B,CADE;MAElB8+B,UAAU,KAAKJ,SAAL,CAAe1+B,IAAf,CAAoB,IAApB,CAFQ;MAGlB++B,UAAU,KAAK5B,SAAL,CAAen9B,IAAf,CAAoB,IAApB;IAHQ,CAApB;;IAMA,KAAKvM,QAAL,CAAcgZ,GAAd,CAAkB,gBAAlB,EAAoC,KAAKhQ,YAAL,CAAkBoiC,cAAtD;;IACAz+C,OAAOgD,gBAAPhD,CAAwB,UAAxBA,EAAoC,KAAKqc,YAAL,CAAkBqiC,QAAtD1+C;IACAA,OAAOgD,gBAAPhD,CAAwB,UAAxBA,EAAoC,KAAKqc,YAAL,CAAkBsiC,QAAtD3+C;EA5pBa;;EAkqBfg9C,gBAAgB;IACd,IAAI,CAAC,KAAK3gC,YAAV,EAAwB;MACtB;IAFY;;IAId,KAAKhJ,QAAL,CAAc6hB,IAAd,CAAmB,gBAAnB,EAAqC,KAAK7Y,YAAL,CAAkBoiC,cAAvD;;IACAz+C,OAAO8vB,mBAAP9vB,CAA2B,UAA3BA,EAAuC,KAAKqc,YAAL,CAAkBqiC,QAAzD1+C;IACAA,OAAO8vB,mBAAP9vB,CAA2B,UAA3BA,EAAuC,KAAKqc,YAAL,CAAkBsiC,QAAzD3+C;IAEA,KAAKqc,YAAL,GAAoB,IAApB;EA1qBa;;AAAA;;;;AA8qBjB,SAAS+gC,iBAAT,CAA2BwB,QAA3B,EAAqCC,QAArC,EAA+C;EAC7C,IAAI,OAAOD,QAAP,KAAoB,QAApB,IAAgC,OAAOC,QAAP,KAAoB,QAAxD,EAAkE;IAChE,OAAO,KAAP;EAF2C;;EAI7C,IAAID,aAAaC,QAAjB,EAA2B;IACzB,OAAO,IAAP;EAL2C;;EAO7C,MAAMT,YAAYn7C,gCAAiB27C,QAAjB37C,EAA2BwO,GAA3BxO,CAA+B,WAA/BA,CAAlB;;EACA,IAAIm7C,cAAcS,QAAlB,EAA4B;IAC1B,OAAO,IAAP;EAT2C;;EAW7C,OAAO,KAAP;AA/uBF;;AAkvBA,SAASxB,iBAAT,CAA2ByB,SAA3B,EAAsCC,UAAtC,EAAkD;EAChD,SAASC,YAAT,CAAsBl2C,KAAtB,EAA6Bm2C,MAA7B,EAAqC;IACnC,IAAI,OAAOn2C,KAAP,KAAiB,OAAOm2C,MAA5B,EAAoC;MAClC,OAAO,KAAP;IAFiC;;IAInC,IAAItqC,MAAMC,OAAND,CAAc7L,KAAd6L,KAAwBA,MAAMC,OAAND,CAAcsqC,MAAdtqC,CAA5B,EAAmD;MACjD,OAAO,KAAP;IALiC;;IAOnC,IAAI7L,UAAU,IAAVA,IAAkB,OAAOA,KAAP,KAAiB,QAAnCA,IAA+Cm2C,WAAW,IAA9D,EAAoE;MAClE,IAAIx0C,OAAOyH,IAAPzH,CAAY3B,KAAZ2B,EAAmBnG,MAAnBmG,KAA8BA,OAAOyH,IAAPzH,CAAYw0C,MAAZx0C,EAAoBnG,MAAtD,EAA8D;QAC5D,OAAO,KAAP;MAFgE;;MAIlE,WAAWjB,GAAX,IAAkByF,KAAlB,EAAyB;QACvB,IAAI,CAACk2C,aAAal2C,MAAMzF,GAAN,CAAb,EAAyB47C,OAAO57C,GAAP,CAAzB,CAAL,EAA4C;UAC1C,OAAO,KAAP;QAFqB;MAJyC;;MASlE,OAAO,IAAP;IAhBiC;;IAkBnC,OAAOyF,UAAUm2C,MAAVn2C,IAAqBuB,OAAO0B,KAAP1B,CAAavB,KAAbuB,KAAuBA,OAAO0B,KAAP1B,CAAa40C,MAAb50C,CAAnD;EAnB8C;;EAsBhD,IAAI,EAAEsK,MAAMC,OAAND,CAAcmqC,SAAdnqC,KAA4BA,MAAMC,OAAND,CAAcoqC,UAAdpqC,CAA9B,CAAJ,EAA8D;IAC5D,OAAO,KAAP;EAvB8C;;EAyBhD,IAAImqC,UAAUx6C,MAAVw6C,KAAqBC,WAAWz6C,MAApC,EAA4C;IAC1C,OAAO,KAAP;EA1B8C;;EA4BhD,KAAK,IAAIqC,IAAI,CAAR,EAAWkY,KAAKigC,UAAUx6C,MAA/B,EAAuCqC,IAAIkY,EAA3C,EAA+ClY,GAA/C,EAAoD;IAClD,IAAI,CAACq4C,aAAaF,UAAUn4C,CAAV,CAAb,EAA2Bo4C,WAAWp4C,CAAX,CAA3B,CAAL,EAAgD;MAC9C,OAAO,KAAP;IAFgD;EA5BJ;;EAiChD,OAAO,IAAP;AAnxBF;;;;;;;;;;;;;ACeA;;AAgBA,MAAMyb,cAAN,SAA6B8pB,gCAA7B,CAA4C;EAC1CpsC,YAAYgS,OAAZ,EAAqB;IACnB,MAAMA,OAAN;IACA,KAAKgK,IAAL,GAAYhK,QAAQgK,IAApB;;IAEA,KAAKzI,QAAL,CAAcgZ,GAAd,CAAkB,aAAlB,EAAiC,KAAK6yB,YAAL,CAAkBt/B,IAAlB,CAAuB,IAAvB,CAAjC;;IACA,KAAKvM,QAAL,CAAcgZ,GAAd,CAAkB,kBAAlB,EAAsC,KAAKyhB,mBAAL,CAAyBluB,IAAzB,CAA8B,IAA9B,CAAtC;EANwC;;EAS1CyF,QAAQ;IACN,MAAMA,KAAN;IACA,KAAK85B,sBAAL,GAA8B,IAA9B;EAXwC;;EAiB1C5S,eAAe6S,WAAf,EAA4B;IAC1B,KAAK/rC,QAAL,CAAcwC,QAAd,CAAuB,cAAvB,EAAuC;MACrCC,QAAQ,IAD6B;MAErCspC;IAFqC,CAAvC;EAlBwC;;EA2B1C3S,UAAUnsC,OAAV,QAAuC;IAAA,IAApB;MAAE++C,OAAF;MAAW3T;IAAX,CAAoB;;IACrC,MAAM4T,gBAAgB,MAAM;MAC1B,KAAKH,sBAAL,CAA4BG,aAA5B,CAA0CD,OAA1C,EAAmD3T,MAAMgH,OAAzD;;MAEA,KAAKr/B,QAAL,CAAcwC,QAAd,CAAuB,uBAAvB,EAAgD;QAC9CC,QAAQ,IADsC;QAE9CoN,SAASlY,QAAQC,OAARD,CAAgB,KAAKm0C,sBAArBn0C;MAFqC,CAAhD;IAHF;;IASA1K,QAAQ4S,OAAR5S,GAAkB8B,OAAO;MACvB,IAAIA,IAAIwQ,MAAJxQ,KAAespC,KAAnB,EAA0B;QACxB4T;QACA,OAAO,IAAP;MAFF,OAGO,IAAIl9C,IAAIwQ,MAAJxQ,KAAe9B,OAAnB,EAA4B;QACjC,OAAO,IAAP;MALqB;;MAOvBorC,MAAMgH,OAANhH,GAAgB,CAACA,MAAMgH,OAAvBhH;MACA4T;MACA,OAAO,KAAP;IATF;EArCwC;;EAqD1C,MAAMC,cAAN,CAAqBj/C,OAArB,SAA+C;IAAA,IAAjB;MAAEoR,OAAO;IAAT,CAAiB;;IAC7C,IAAI,OAAOA,IAAP,KAAgB,QAApB,EAA8B;MAC5BpR,QAAQioB,WAARjoB,GAAsB,KAAK2sC,qBAAL,CAA2Bv7B,IAA3B,CAAtBpR;MACA;IAH2C;;IAK7CA,QAAQioB,WAARjoB,GAAsB,MAAM,KAAKwb,IAAL,CAAUrK,GAAV,CAAc,mBAAd,CAA5BnR;IACAA,QAAQ+K,KAAR/K,CAAck/C,SAAdl/C,GAA0B,QAA1BA;EA3DwC;;EAiE1CotC,iBAAiBloC,GAAjB,SAAuC;IAAA,IAAjB;MAAEkM,OAAO;IAAT,CAAiB;;IACrC,MAAMg8B,gBAAN,CAAuBloC,GAAvB,EAA2CkM,SAAS,IAApD;EAlEwC;;EAwE1Co8B,sBAAsB;IACpB,IAAI,CAAC,KAAKqR,sBAAV,EAAkC;MAChC;IAFkB;;IAIpB,MAAMrR,mBAAN;EA5EwC;;EAkF1CpiB,cAA+C;IAAA,IAAxC;MAAEI,qBAAF;MAAyBrY;IAAzB,CAAwC;;IAC7C,IAAI,KAAK0rC,sBAAT,EAAiC;MAC/B,KAAK95B,KAAL;IAF2C;;IAI7C,KAAK85B,sBAAL,GAA8BrzB,yBAAyB,IAAvD;IACA,KAAKwhB,YAAL,GAAoB75B,eAAe,IAAnC;IAEA,MAAMgsC,SAAS3zB,qBAAT,aAASA,qBAAT,uBAASA,sBAAuB4zB,QAAvB5zB,EAAf;;IACA,IAAI,CAAC2zB,MAAL,EAAa;MACX,KAAKlT,cAAL,CAAwC,CAAxC;;MACA;IAV2C;;IAa7C,MAAMO,WAAW3hC,SAAS4hC,sBAAT5hC,EAAjB;IAAA,MACEw0C,QAAQ,CAAC;MAAEl/C,QAAQqsC,QAAV;MAAoB2S;IAApB,CAAD,CADV;IAEA,IAAIL,cAAc,CAAlB;IAAA,IACErR,gBAAgB,KADlB;;IAEA,OAAO4R,MAAMr7C,MAANq7C,GAAe,CAAtB,EAAyB;MACvB,MAAMC,YAAYD,MAAMtU,KAANsU,EAAlB;;MACA,WAAWN,OAAX,IAAsBO,UAAUH,MAAhC,EAAwC;QACtC,MAAMj6C,MAAM2F,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAZ;QACA3F,IAAIu5B,SAAJv5B,GAAgB,UAAhBA;QAEA,MAAMlF,UAAU6K,SAAS2zB,aAAT3zB,CAAuB,GAAvBA,CAAhB;QACA3F,IAAIy6B,MAAJz6B,CAAWlF,OAAXkF;;QAEA,IAAI,OAAO65C,OAAP,KAAmB,QAAvB,EAAiC;UAC/BtR,gBAAgB,IAAhBA;;UACA,KAAKL,gBAAL,CAAsBloC,GAAtB,EAA2B65C,OAA3B;;UACA,KAAKE,cAAL,CAAoBj/C,OAApB,EAA6B++C,OAA7B;;UAEA,MAAMQ,WAAW10C,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAjB;UACA00C,SAAS9gB,SAAT8gB,GAAqB,WAArBA;UACAr6C,IAAIy6B,MAAJz6B,CAAWq6C,QAAXr6C;UAEAm6C,MAAMl3C,IAANk3C,CAAW;YAAEl/C,QAAQo/C,QAAV;YAAoBJ,QAAQJ,QAAQS;UAApC,CAAXH;QATF,OAUO;UACL,MAAMI,QAAQj0B,sBAAsBk0B,QAAtBl0B,CAA+BuzB,OAA/BvzB,CAAd;UAEA,MAAM4f,QAAQvgC,SAAS2zB,aAAT3zB,CAAuB,OAAvBA,CAAd;;UACA,KAAKshC,SAAL,CAAensC,OAAf,EAAwB;YAAE++C,OAAF;YAAW3T;UAAX,CAAxB;;UACAA,MAAMnkB,IAANmkB,GAAa,UAAbA;UACAA,MAAMgH,OAANhH,GAAgBqU,MAAMx4C,OAAtBmkC;UAEA,MAAMtc,QAAQjkB,SAAS2zB,aAAT3zB,CAAuB,OAAvBA,CAAd;UACAikB,MAAM7G,WAAN6G,GAAoB,KAAK6d,qBAAL,CAA2B8S,MAAMruC,IAAjC,CAApB0d;UAEAA,MAAM6Q,MAAN7Q,CAAasc,KAAbtc;UACA9uB,QAAQ2/B,MAAR3/B,CAAe8uB,KAAf9uB;UACA8+C;QA9BoC;;QAiCtCQ,UAAUn/C,MAAVm/C,CAAiB3f,MAAjB2f,CAAwBp6C,GAAxBo6C;MAnCqB;IAjBoB;;IAwD7C,KAAK1S,gBAAL,CAAsBJ,QAAtB,EAAgCsS,WAAhC,EAA6CrR,aAA7C;EA1IwC;;EAgJ1C,MAAMmR,YAAN,GAAqB;IACnB,IAAI,CAAC,KAAKC,sBAAV,EAAkC;MAChC;IAFiB;;IAKnB,MAAMrzB,wBACJ,MAAM,KAAKwhB,YAAL,CAAkB2S,wBAAlB,EADR;IAGA,KAAK5sC,QAAL,CAAcwC,QAAd,CAAuB,uBAAvB,EAAgD;MAC9CC,QAAQ,IADsC;MAE9CoN,SAASlY,QAAQC,OAARD,CAAgB8gB,qBAAhB9gB;IAFqC,CAAhD;IAMA,KAAK0gB,MAAL,CAAY;MACVI,qBADU;MAEVrY,aAAa,KAAK65B;IAFR,CAAZ;EA9JwC;;AAAA;;;;;;;;;;;;;;;AChB5C;;AACA;;AACA;;AAeA,MAAMtrB,gBAAN,SAA+BkqB,gCAA/B,CAA8C;EAI5CpsC,YAAYgS,OAAZ,EAAqB;IACnB,MAAMA,OAAN;IACA,KAAKiO,WAAL,GAAmBjO,QAAQiO,WAA3B;;IAEA,KAAK1M,QAAL,CAAcgZ,GAAd,CAAkB,mBAAlB,EAAuC,KAAKyhB,mBAAL,CAAyBluB,IAAzB,CAA8B,IAA9B,CAAvC;;IACA,KAAKvM,QAAL,CAAcgZ,GAAd,CACE,oBADF,EAEE,KAAK6zB,mBAAL,CAAyBtgC,IAAzB,CAA8B,IAA9B,CAFF;;IAKA,KAAKvM,QAAL,CAAcgZ,GAAd,CAAkB,cAAlB,EAAkCjqB,OAAO;MACvC,KAAK2sC,kBAAL,GAA0B3sC,IAAI0S,UAA9B;IADF;;IAGA,KAAKzB,QAAL,CAAcgZ,GAAd,CAAkB,aAAlB,EAAiCjqB,OAAO;MACtC,KAAKs5C,cAAL,GAAsB,CAAC,CAACt5C,IAAI4R,UAA5B;;MAIA,IACE,KAAKmsC,6BAAL,IACA,CAAC,KAAKA,6BAAL,CAAmCn9B,OAFtC,EAGE;QACA,KAAKm9B,6BAAL,CAAmCl1C,OAAnC,CACkB,KAAKywC,cADvB;MAToC;IAAxC;;IAcA,KAAKroC,QAAL,CAAcgZ,GAAd,CAAkB,oBAAlB,EAAwCjqB,OAAO;MAC7C,KAAKg+C,YAAL,GAAoBh+C,IAAIwD,IAAxB;IADF;EA/B0C;;EAoC5Cyf,QAAQ;IACN,MAAMA,KAAN;IACA,KAAKg7B,QAAL,GAAgB,IAAhB;IAEA,KAAKC,+BAAL,GAAuC,IAAvC;IACA,KAAKvR,kBAAL,GAA0B,CAA1B;IACA,KAAK2M,cAAL,GAAsB,IAAtB;;IAEA,IACE,KAAKyE,6BAAL,IACA,CAAC,KAAKA,6BAAL,CAAmCn9B,OAFtC,EAGE;MACA,KAAKm9B,6BAAL,CAAmCl1C,OAAnC,CAA2D,KAA3D;IAZI;;IAcN,KAAKk1C,6BAAL,GAAqC,IAArC;EAlD0C;;EAwD5C5T,eAAegU,YAAf,EAA6B;IAAA;;IAC3B,KAAKJ,6BAAL,GAAqC3lC,wCAArC;;IACA,IACE+lC,iBAAiB,CAAjBA,0BACA,KAAKjT,YADLiT,+CACA,mBAAmBv3B,aAAnB,CAAiC7Y,gBAFnC,EAGE;MACA,KAAKgwC,6BAAL,CAAmCl1C,OAAnC,CAA2D,KAA3D;IAJF,OAKO,IAAI,KAAKywC,cAAL,KAAwB,IAA5B,EAAkC;MACvC,KAAKyE,6BAAL,CAAmCl1C,OAAnC,CACkB,KAAKywC,cADvB;IARyB;;IAa3B,KAAKroC,QAAL,CAAcwC,QAAd,CAAuB,eAAvB,EAAwC;MACtCC,QAAQ,IAD8B;MAEtCyqC,YAFsC;MAGtCC,2BAA2B,KAAKL,6BAAL,CAAmCj9B;IAHxB,CAAxC;EArE0C;;EA+E5CupB,UAAUnsC,OAAV,QAA6C;IAAA,IAA1B;MAAEqS,GAAF;MAAOwC,SAAP;MAAkBZ;IAAlB,CAA0B;IAC3C,MAAM;MAAEwL;IAAF,IAAkB,IAAxB;;IAEA,IAAIpN,GAAJ,EAAS;MACPoN,YAAYtN,iBAAZsN,CAA8Bzf,OAA9Byf,EAAuCpN,GAAvCoN,EAA4C5K,SAA5C4K;MACA;IALyC;;IAQ3Czf,QAAQ0S,IAAR1S,GAAeyf,YAAY3K,kBAAZ2K,CAA+BxL,IAA/BwL,CAAfzf;;IACAA,QAAQ4S,OAAR5S,GAAkB8B,OAAO;MACvB,KAAK4rC,sBAAL,CAA4B5rC,IAAIwQ,MAAJxQ,CAAWiK,UAAvC;;MAEA,IAAIkI,IAAJ,EAAU;QACRwL,YAAYzL,eAAZyL,CAA4BxL,IAA5BwL;MAJqB;;MAMvB,OAAO,KAAP;IANF;EAxF0C;;EAqG5C0gC,WAAWngD,OAAX,SAAsC;IAAA,IAAlB;MAAEogD,IAAF;MAAQC;IAAR,CAAkB;;IACpC,IAAID,IAAJ,EAAU;MACRpgD,QAAQ+K,KAAR/K,CAAcsgD,UAAdtgD,GAA2B,MAA3BA;IAFkC;;IAIpC,IAAIqgD,MAAJ,EAAY;MACVrgD,QAAQ+K,KAAR/K,CAAck/C,SAAdl/C,GAA0B,QAA1BA;IALkC;EArGM;;EAiH5CotC,iBAAiBloC,GAAjB,SAAwC;IAAA,IAAlB;MAAEioC,KAAF;MAASxpC;IAAT,CAAkB;IACtC,IAAIugB,SAAS,KAAb;;IACA,IAAIipB,QAAQ,CAAZ,EAAe;MACb,IAAIoT,aAAa58C,MAAMK,MAAvB;;MACA,IAAIu8C,aAAa,CAAjB,EAAoB;QAClB,MAAMlB,QAAQ,CAAC,GAAG17C,KAAJ,CAAd;;QACA,OAAO07C,MAAMr7C,MAANq7C,GAAe,CAAtB,EAAyB;UACvB,MAAM;YAAElS,OAAOqT,WAAT;YAAsB78C,OAAO88C;UAA7B,IAA6CpB,MAAMtU,KAANsU,EAAnD;;UACA,IAAImB,cAAc,CAAdA,IAAmBC,YAAYz8C,MAAZy8C,GAAqB,CAA5C,EAA+C;YAC7CF,cAAcE,YAAYz8C,MAA1Bu8C;YACAlB,MAAMl3C,IAANk3C,CAAW,GAAGoB,WAAdpB;UAJqB;QAFP;MAFP;;MAYb,IAAIh7C,KAAKwE,GAALxE,CAAS8oC,KAAT9oC,MAAoBk8C,UAAxB,EAAoC;QAClCr8B,SAAS,IAATA;MAbW;IAFuB;;IAkBtC,MAAMkpB,gBAAN,CAAuBloC,GAAvB,EAA4Bgf,MAA5B;EAnI0C;;EAyI5CspB,sBAAsB;IACpB,IAAI,CAAC,KAAKuS,QAAV,EAAoB;MAClB;IAFkB;;IAIpB,MAAMvS,mBAAN;EA7I0C;;EAmJ5CpiB,cAAiC;IAAA,IAA1B;MAAED,OAAF;MAAWhY;IAAX,CAA0B;;IAC/B,IAAI,KAAK4sC,QAAT,EAAmB;MACjB,KAAKh7B,KAAL;IAF6B;;IAI/B,KAAKg7B,QAAL,GAAgB50B,WAAW,IAA3B;IACA,KAAK6hB,YAAL,GAAoB75B,eAAe,IAAnC;;IAEA,IAAI,CAACgY,OAAL,EAAc;MACZ,KAAK8gB,cAAL,CAAyC,CAAzC;;MACA;IAT6B;;IAY/B,MAAMO,WAAW3hC,SAAS4hC,sBAAT5hC,EAAjB;IACA,MAAMw0C,QAAQ,CAAC;MAAEl/C,QAAQqsC,QAAV;MAAoB7oC,OAAOwnB;IAA3B,CAAD,CAAd;IACA,IAAI80B,eAAe,CAAnB;IAAA,IACExS,gBAAgB,KADlB;;IAEA,OAAO4R,MAAMr7C,MAANq7C,GAAe,CAAtB,EAAyB;MACvB,MAAMC,YAAYD,MAAMtU,KAANsU,EAAlB;;MACA,WAAW3S,IAAX,IAAmB4S,UAAU37C,KAA7B,EAAoC;QAClC,MAAMuB,MAAM2F,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAZ;QACA3F,IAAIu5B,SAAJv5B,GAAgB,UAAhBA;QAEA,MAAMlF,UAAU6K,SAAS2zB,aAAT3zB,CAAuB,GAAvBA,CAAhB;;QACA,KAAKshC,SAAL,CAAensC,OAAf,EAAwB0sC,IAAxB;;QACA,KAAKyT,UAAL,CAAgBngD,OAAhB,EAAyB0sC,IAAzB;;QACA1sC,QAAQioB,WAARjoB,GAAsB,KAAK2sC,qBAAL,CAA2BD,KAAK/5B,KAAhC,CAAtB3S;QAEAkF,IAAIy6B,MAAJz6B,CAAWlF,OAAXkF;;QAEA,IAAIwnC,KAAK/oC,KAAL+oC,CAAW1oC,MAAX0oC,GAAoB,CAAxB,EAA2B;UACzBe,gBAAgB,IAAhBA;;UACA,KAAKL,gBAAL,CAAsBloC,GAAtB,EAA2BwnC,IAA3B;;UAEA,MAAM6S,WAAW10C,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAjB;UACA00C,SAAS9gB,SAAT8gB,GAAqB,WAArBA;UACAr6C,IAAIy6B,MAAJz6B,CAAWq6C,QAAXr6C;UAEAm6C,MAAMl3C,IAANk3C,CAAW;YAAEl/C,QAAQo/C,QAAV;YAAoB57C,OAAO+oC,KAAK/oC;UAAhC,CAAX07C;QAnBgC;;QAsBlCC,UAAUn/C,MAAVm/C,CAAiB3f,MAAjB2f,CAAwBp6C,GAAxBo6C;QACAW;MAzBqB;IAhBM;;IA6C/B,KAAKrT,gBAAL,CAAsBJ,QAAtB,EAAgCyT,YAAhC,EAA8CxS,aAA9C;EAhM0C;;EAuM5C,MAAMmS,mBAAN,GAA4B;IAC1B,IAAI,CAAC,KAAKxE,cAAV,EAA0B;MACxB,MAAM,IAAI/vC,KAAJ,CAAU,sDAAV,CAAN;IAFwB;;IAI1B,IAAI,CAAC,KAAK00C,QAAN,IAAkB,CAAC,KAAK/S,YAA5B,EAA0C;MACxC;IALwB;;IAQ1B,MAAM0T,uBAAuB,MAAM,KAAKC,wBAAL,CACjC,KAAK3T,YAD4B,CAAnC;;IAGA,IAAI,CAAC0T,oBAAL,EAA2B;MACzB;IAZwB;;IAc1B,KAAKhT,sBAAL,CAA6C,IAA7C;;IAEA,IAAI,KAAKoS,YAAL,KAAsB7hD,sBAAYG,OAAtC,EAA+C;MAC7C;IAjBwB;;IAqB1B,KAAK,IAAIiI,IAAI,KAAKooC,kBAAlB,EAAsCpoC,IAAI,CAA1C,EAA6CA,GAA7C,EAAkD;MAChD,MAAMi4C,WAAWoC,qBAAqBvvC,GAArBuvC,CAAyBr6C,CAAzBq6C,CAAjB;;MACA,IAAI,CAACpC,QAAL,EAAe;QACb;MAH8C;;MAKhD,MAAMsC,cAAc,KAAK90C,SAAL,CAAeU,aAAf,CAA8B,WAAU8xC,QAAS,IAAjD,CAApB;;MACA,IAAI,CAACsC,WAAL,EAAkB;QAChB;MAP8C;;MAShD,KAAKhT,wBAAL,CAA8BgT,YAAY70C,UAA1C;;MACA;IA/BwB;EAvMgB;;EAiP5C,MAAM40C,wBAAN,CAA+BxtC,WAA/B,EAA4C;IAC1C,IAAI,KAAK6sC,+BAAT,EAA0C;MACxC,OAAO,KAAKA,+BAAL,CAAqCp9B,OAA5C;IAFwC;;IAI1C,KAAKo9B,+BAAL,GAAuC9lC,wCAAvC;IAEA,MAAMwmC,uBAAuB,IAAI59C,GAAJ,EAA7B;IAAA,MACE+9C,oBAAoB,IAAI/9C,GAAJ,EADtB;IAEA,MAAMu8C,QAAQ,CAAC;MAAEyB,SAAS,CAAX;MAAcn9C,OAAO,KAAKo8C;IAA1B,CAAD,CAAd;;IACA,OAAOV,MAAMr7C,MAANq7C,GAAe,CAAtB,EAAyB;MACvB,MAAMC,YAAYD,MAAMtU,KAANsU,EAAlB;MAAA,MACE0B,iBAAiBzB,UAAUwB,OAD7B;;MAEA,WAAW;QAAE7sC,IAAF;QAAQtQ;MAAR,CAAX,IAA8B27C,UAAU37C,KAAxC,EAA+C;QAC7C,IAAIwQ,YAAJ,EAAkBK,UAAlB;;QACA,IAAI,OAAOP,IAAP,KAAgB,QAApB,EAA8B;UAC5BE,eAAe,MAAMhB,YAAYiB,cAAZjB,CAA2Bc,IAA3Bd,CAArBgB;;UAEA,IAAIhB,gBAAgB,KAAK65B,YAAzB,EAAuC;YACrC,OAAO,IAAP;UAJ0B;QAA9B,OAMO;UACL74B,eAAeF,IAAfE;QAT2C;;QAW7C,IAAIE,MAAMC,OAAND,CAAcF,YAAdE,CAAJ,EAAiC;UAC/B,MAAM,CAACgD,OAAD,IAAYlD,YAAlB;;UAEA,IAAI,OAAOkD,OAAP,KAAmB,QAAnB,IAA+BA,YAAY,IAA/C,EAAqD;YACnD7C,aAAa,KAAKiL,WAAL,CAAiBxI,iBAAjB,CAAmCI,OAAnC,CAAb7C;;YAEA,IAAI,CAACA,UAAL,EAAiB;cACf,IAAI;gBACFA,aAAc,OAAMrB,YAAYmE,YAAZnE,CAAyBkE,OAAzBlE,CAAN,IAA2C,CAAzDqB;;gBAEA,IAAIrB,gBAAgB,KAAK65B,YAAzB,EAAuC;kBACrC,OAAO,IAAP;gBAJA;;gBAMF,KAAKvtB,WAAL,CAAiB9I,YAAjB,CAA8BnC,UAA9B,EAA0C6C,OAA1C;cANF,EAOE,OAAOjB,EAAP,EAAW,CARE;YAHkC;UAArD,OAeO,IAAIrM,OAAOC,SAAPD,CAAiBsN,OAAjBtN,CAAJ,EAA+B;YACpCyK,aAAa6C,UAAU,CAAvB7C;UAnB6B;;UAsB/B,IACEzK,OAAOC,SAAPD,CAAiByK,UAAjBzK,MACC,CAAC22C,qBAAqBprC,GAArBorC,CAAyBlsC,UAAzBksC,CAAD,IACCK,iBAAiBF,kBAAkB1vC,GAAlB0vC,CAAsBrsC,UAAtBqsC,CAFnB92C,CADF,EAIE;YACA,MAAMu0C,WAAW,KAAK7+B,WAAL,CAAiB3K,kBAAjB,CAAoCb,IAApC,CAAjB;YACAysC,qBAAqBx9C,GAArBw9C,CAAyBlsC,UAAzBksC,EAAqCpC,QAArCoC;YACAG,kBAAkB39C,GAAlB29C,CAAsBrsC,UAAtBqsC,EAAkCE,cAAlCF;UA7B6B;QAXY;;QA4C7C,IAAIl9C,MAAMK,MAANL,GAAe,CAAnB,EAAsB;UACpB07C,MAAMl3C,IAANk3C,CAAW;YAAEyB,SAASC,iBAAiB,CAA5B;YAA+Bp9C;UAA/B,CAAX07C;QA7C2C;MAHxB;IATiB;;IA8D1C,KAAKW,+BAAL,CAAqCr1C,OAArC,CACE+1C,qBAAqBl2C,IAArBk2C,GAA4B,CAA5BA,GAAgCA,oBAAhCA,GAAuD,IADzD;;IAGA,OAAO,KAAKV,+BAAL,CAAqCp9B,OAA5C;EAlT0C;;AAAA;;;;;;;;;;;;;;;ACjB9C;;AAMA;;;;;;;;;;;;;;;;;;;;AAEA,MAAMo+B,+BAA+B,IAArC;AACA,MAAMC,kBAAkB,qBAAxB;AACA,MAAMC,oBAAoB,6BAA1B;AACA,MAAMC,6BAA6B,EAAnC;AACA,MAAMC,wBAAwB,GAA9B;AAGA,MAAMC,+BAA+B,EAArC;AAIA,MAAMC,wBAAwBj9C,KAAKkF,EAALlF,GAAU,CAAxC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AASA,MAAMid,mBAAN,CAA0B;EAQxB9hB,kBAAgD;IAAA,IAApC;MAAEsM,SAAF;MAAasH,SAAb;MAAwBL;IAAxB,CAAoC;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;MAAA;MAAA,OAPvCnV,gCAAsBC;IAOiB;;IAAA;MAAA;MAAA,OALxC;IAKwC;;IAC9C,KAAKiO,SAAL,GAAiBA,SAAjB;IACA,KAAKsH,SAAL,GAAiBA,SAAjB;IACA,KAAKL,QAAL,GAAgBA,QAAhB;IAEA,KAAKwuC,eAAL,GAAuB,KAAvB;IACA,KAAKC,oBAAL,GAA4B,CAA5B;IACA,KAAKC,gBAAL,GAAwB,CAAxB;IACA,KAAKC,eAAL,GAAuB,IAAvB;EAhBsB;;EAuBxB,MAAMxwB,OAAN,GAAgB;IACd,MAAM;MAAEplB,SAAF;MAAasH;IAAb,IAA2B,IAAjC;;IAEA,IAAI,KAAKinB,MAAL,IAAe,CAACjnB,UAAUM,UAA1B,IAAwC,CAAC5H,UAAU61C,iBAAvD,EAA0E;MACxE,OAAO,KAAP;IAJY;;IAMd;;IACA,iFAAwB/jD,gCAAsBG,QAA9C;;IAEA,MAAM6kB,UAAU9W,UAAU61C,iBAAV71C,EAAhB;;IAEA,mCAAa;MACX0I,YAAYpB,UAAUS,iBADX;MAEX+tC,YAAYxuC,UAAUgQ,iBAFX;MAGXxW,YAAYwG,UAAUxG,UAHX;MAIXC,YAAY,IAJD;MAKXmB,sBAAsB;IALX,CAAb;;IAQA,IACEoF,UAAUvG,UAAVuG,KAAyBjU,qBAAWjB,IAApCkV,IACA,EAAEA,UAAUmd,cAAVnd,IAA4BA,UAAU0X,iBAAxC,CAFF,EAGE;MACAzqB,QAAQid,IAARjd,CACE,2DACE,oDAFJA;MAIA,mCAAWwM,UAAX,GAAwBuG,UAAUvG,UAAlC;IA3BY;;IA6Bd,IAAIuG,UAAUpF,oBAAVoF,KAAmCyN,+BAAqBliB,OAA5D,EAAqE;MACnE,mCAAWqP,oBAAX,GAAkCoF,UAAUpF,oBAA5C;IA9BY;;IAiCd,IAAI;MACF,MAAM4U,OAAN;MACAxP,UAAUwX,KAAVxX;MACA,OAAO,IAAP;IAHF,EAIE,OAAOmK,MAAP,EAAe;MACf;;MACA,iFAAwB3f,gCAAsBE,MAA9C;IAvCY;;IAyCd,OAAO,KAAP;EAhEsB;;EAmExB,IAAIu8B,MAAJ,GAAa;IACX,OACE,wCAAgBz8B,gCAAsBG,QAAtC,IACA,wCAAgBH,gCAAsBI,UAFxC;EApEsB;;AAAA;;;;sBA0EZ8D,KAAK;EACf,IAAI,CAAC,KAAKu4B,MAAV,EAAkB;IAChB;EAFa;;EAIfv4B,IAAIiH,cAAJjH;EAEA,MAAMmH,QAAQO,wCAAyB1H,GAAzB0H,CAAd;EACA,MAAMq4C,cAAcC,KAAKC,GAALD,EAApB;EACA,MAAME,aAAa,KAAKR,oBAAxB;;EAGA,IACEK,cAAcG,UAAdH,IACAA,cAAcG,UAAdH,GAA2BV,0BAF7B,EAGE;IACA;EAfa;;EAkBf,IACG,KAAKM,gBAAL,GAAwB,CAAxB,IAA6Bx4C,QAAQ,CAArC,IACA,KAAKw4C,gBAAL,GAAwB,CAAxB,IAA6Bx4C,QAAQ,CAFxC,EAGE;IACA;EAtBa;;EAwBf,KAAKw4C,gBAAL,IAAyBx4C,KAAzB;;EAEA,IAAI5E,KAAKwE,GAALxE,CAAS,KAAKo9C,gBAAdp9C,KAAmC+8C,qBAAvC,EAA8D;IAC5D,MAAMa,aAAa,KAAKR,gBAAxB;;IACA;;IACA,MAAMS,UACJD,aAAa,CAAbA,GACI,KAAK7uC,SAAL,CAAesD,YAAf,EADJurC,GAEI,KAAK7uC,SAAL,CAAeqD,QAAf,EAHN;;IAIA,IAAIyrC,OAAJ,EAAa;MACX,KAAKV,oBAAL,GAA4BK,WAA5B;IAR0D;EA1B/C;AA1EO;;6BAiHLz/C,OAAO;EACxB,oCAAcA,KAAd;;EAEA,KAAK2Q,QAAL,CAAcwC,QAAd,CAAuB,yBAAvB,EAAkD;IAAEC,QAAQ,IAAV;IAAgBpT;EAAhB,CAAlD;AApHsB;;mBAuHf;EACP,iFAAwBxE,gCAAsBI,UAA9C;;EACA,KAAK8N,SAAL,CAAe7K,SAAf,CAAyBsH,GAAzB,CAA6B04C,eAA7B;EAIAp4B,WAAW,MAAM;IACf,KAAKzV,SAAL,CAAexG,UAAf,GAA4B9N,qBAAWI,IAAvC;;IACA,IAAI,mCAAW2N,UAAX,KAA0B,IAA9B,EAAoC;MAClC,KAAKuG,SAAL,CAAevG,UAAf,GAA4B1N,qBAAWjB,IAAvC;IAHa;;IAKf,KAAKkV,SAAL,CAAeS,iBAAf,GAAmC,mCAAWW,UAA9C;IACA,KAAKpB,SAAL,CAAegQ,iBAAf,GAAmC,UAAnC;;IAEA,IAAI,mCAAWpV,oBAAX,KAAoC,IAAxC,EAA8C;MAC5C,KAAKoF,SAAL,CAAepF,oBAAf,GAAsC6S,+BAAqB3iB,IAA3D;IATa;EAAjB,GAWG,CAXH;;EAaA;;EACA;;EACA,KAAKqjD,eAAL,GAAuB,KAAvB;EAKA7hD,OAAOyiD,YAAPziD,GAAsB0iD,eAAtB1iD;AAjJsB;;kBAoJhB;EACN,MAAM8U,aAAa,KAAKpB,SAAL,CAAeS,iBAAlC;EACA,KAAK/H,SAAL,CAAe7K,SAAf,CAAyByK,MAAzB,CAAgCu1C,eAAhC;EAIAp4B,WAAW,MAAM;IACf;;IACA,iFAAwBjrB,gCAAsBE,MAA9C;;IAEA,KAAKsV,SAAL,CAAexG,UAAf,GAA4B,mCAAWA,UAAvC;;IACA,IAAI,mCAAWC,UAAX,KAA0B,IAA9B,EAAoC;MAClC,KAAKuG,SAAL,CAAevG,UAAf,GAA4B,mCAAWA,UAAvC;IANa;;IAQf,KAAKuG,SAAL,CAAegQ,iBAAf,GAAmC,mCAAWw+B,UAA9C;IACA,KAAKxuC,SAAL,CAAeS,iBAAf,GAAmCW,UAAnC;;IAEA,IAAI,mCAAWxG,oBAAX,KAAoC,IAAxC,EAA8C;MAC5C,KAAKoF,SAAL,CAAepF,oBAAf,GAAsC,mCAAWA,oBAAjD;IAZa;;IAcf,mCAAa,IAAb;EAdF,GAeG,CAfH;;EAiBA;;EACA;;EACA;;EACA,KAAKuzC,eAAL,GAAuB,KAAvB;AA9KsB;;qBAiLbz/C,KAAK;EACd,IAAI,KAAKy/C,eAAT,EAA0B;IACxB,KAAKA,eAAL,GAAuB,KAAvB;IACAz/C,IAAIiH,cAAJjH;IACA;EAJY;;EAMd,IAAIA,IAAI68B,MAAJ78B,KAAe,CAAnB,EAAsB;IAGpB,MAAMugD,iBACJvgD,IAAIwQ,MAAJxQ,CAAW4Q,IAAX5Q,IAAmBA,IAAIwQ,MAAJxQ,CAAWb,SAAXa,CAAqBZ,QAArBY,CAA8B,cAA9BA,CADrB;;IAEA,IAAI,CAACugD,cAAL,EAAqB;MAEnBvgD,IAAIiH,cAAJjH;;MAEA,IAAIA,IAAI64B,QAAR,EAAkB;QAChB,KAAKvnB,SAAL,CAAesD,YAAf;MADF,OAEO;QACL,KAAKtD,SAAL,CAAeqD,QAAf;MAPiB;IALD;EANR;AAjLQ;;yBAyMT;EACb,KAAK8qC,eAAL,GAAuB,IAAvB;AA1MsB;;0BA6MR;EACd,IAAI,KAAKe,eAAT,EAA0B;IACxB15B,aAAa,KAAK05B,eAAlB;EADF,OAEO;IACL,KAAKx2C,SAAL,CAAe7K,SAAf,CAAyBsH,GAAzB,CAA6B24C,iBAA7B;EAJY;;EAMd,KAAKoB,eAAL,GAAuBz5B,WAAW,MAAM;IACtC,KAAK/c,SAAL,CAAe7K,SAAf,CAAyByK,MAAzB,CAAgCw1C,iBAAhC;IACA,OAAO,KAAKoB,eAAZ;EAFqB,GAGpBtB,4BAHoB,CAAvB;AAnNsB;;0BAyNR;EACd,IAAI,CAAC,KAAKsB,eAAV,EAA2B;IACzB;EAFY;;EAId15B,aAAa,KAAK05B,eAAlB;EACA,KAAKx2C,SAAL,CAAe7K,SAAf,CAAyByK,MAAzB,CAAgCw1C,iBAAhC;EACA,OAAO,KAAKoB,eAAZ;AA/NsB;;mCAqOC;EACvB,KAAKd,oBAAL,GAA4B,CAA5B;EACA,KAAKC,gBAAL,GAAwB,CAAxB;AAvOsB;;sBA0OZ3/C,KAAK;EACf,IAAI,CAAC,KAAKu4B,MAAV,EAAkB;IAChB;EAFa;;EAIf,IAAIv4B,IAAIm4B,OAAJn4B,CAAYkC,MAAZlC,GAAqB,CAAzB,EAA4B;IAE1B,KAAK4/C,eAAL,GAAuB,IAAvB;IACA;EAPa;;EAUf,QAAQ5/C,IAAImlB,IAAZ;IACE,KAAK,YAAL;MACE,KAAKy6B,eAAL,GAAuB;QACrBa,QAAQzgD,IAAIm4B,OAAJn4B,CAAY,CAAZA,EAAe0gD,KADF;QAErBC,QAAQ3gD,IAAIm4B,OAAJn4B,CAAY,CAAZA,EAAe4gD,KAFF;QAGrBC,MAAM7gD,IAAIm4B,OAAJn4B,CAAY,CAAZA,EAAe0gD,KAHA;QAIrBI,MAAM9gD,IAAIm4B,OAAJn4B,CAAY,CAAZA,EAAe4gD;MAJA,CAAvB;MAMA;;IACF,KAAK,WAAL;MACE,IAAI,KAAKhB,eAAL,KAAyB,IAA7B,EAAmC;QACjC;MAFJ;;MAIE,KAAKA,eAAL,CAAqBiB,IAArB,GAA4B7gD,IAAIm4B,OAAJn4B,CAAY,CAAZA,EAAe0gD,KAA3C;MACA,KAAKd,eAAL,CAAqBkB,IAArB,GAA4B9gD,IAAIm4B,OAAJn4B,CAAY,CAAZA,EAAe4gD,KAA3C;MAGA5gD,IAAIiH,cAAJjH;MACA;;IACF,KAAK,UAAL;MACE,IAAI,KAAK4/C,eAAL,KAAyB,IAA7B,EAAmC;QACjC;MAFJ;;MAIE,IAAIz4C,QAAQ,CAAZ;MACA,MAAM4wB,KAAK,KAAK6nB,eAAL,CAAqBiB,IAArB,GAA4B,KAAKjB,eAAL,CAAqBa,MAA5D;MACA,MAAMxoB,KAAK,KAAK2nB,eAAL,CAAqBkB,IAArB,GAA4B,KAAKlB,eAAL,CAAqBe,MAA5D;MACA,MAAMI,WAAWx+C,KAAKwE,GAALxE,CAASA,KAAKiF,KAALjF,CAAW01B,EAAX11B,EAAew1B,EAAfx1B,CAATA,CAAjB;;MACA,IACEA,KAAKwE,GAALxE,CAASw1B,EAATx1B,IAAeg9C,4BAAfh9C,KACCw+C,YAAYvB,qBAAZuB,IACCA,YAAYx+C,KAAKkF,EAALlF,GAAUi9C,qBAFxBj9C,CADF,EAIE;QAEA4E,QAAQ4wB,EAAR5wB;MANF,OAOO,IACL5E,KAAKwE,GAALxE,CAAS01B,EAAT11B,IAAeg9C,4BAAfh9C,IACAA,KAAKwE,GAALxE,CAASw+C,WAAWx+C,KAAKkF,EAALlF,GAAU,CAA9BA,KAAoCi9C,qBAF/B,EAGL;QAEAr4C,QAAQ8wB,EAAR9wB;MApBJ;;MAsBE,IAAIA,QAAQ,CAAZ,EAAe;QACb,KAAKmK,SAAL,CAAesD,YAAf;MADF,OAEO,IAAIzN,QAAQ,CAAZ,EAAe;QACpB,KAAKmK,SAAL,CAAeqD,QAAf;MAzBJ;;MA2BE;EA9CJ;AApPsB;;gCAsSF;EACpB,KAAKqsC,gBAAL,GAAwB,4DAAmBxjC,IAAnB,CAAwB,IAAxB,CAAxB;EACA,KAAKyjC,aAAL,GAAqB,sDAAgBzjC,IAAhB,CAAqB,IAArB,CAArB;EACA,KAAK0jC,cAAL,GAAsB,wDAAiB1jC,IAAjB,CAAsB,IAAtB,CAAtB;EACA,KAAK2jC,yBAAL,GAAiC,8EAA4B3jC,IAA5B,CAAiC,IAAjC,CAAjC;EACA,KAAK4jC,eAAL,GAAuB,0DAAkB5jC,IAAlB,CAAuB,IAAvB,CAAvB;EACA,KAAK6jC,cAAL,GAAsB,wDAAiB7jC,IAAjB,CAAsB,IAAtB,CAAtB;EAEA5f,OAAOgD,gBAAPhD,CAAwB,WAAxBA,EAAqC,KAAKojD,gBAA1CpjD;EACAA,OAAOgD,gBAAPhD,CAAwB,WAAxBA,EAAqC,KAAKqjD,aAA1CrjD;EACAA,OAAOgD,gBAAPhD,CAAwB,OAAxBA,EAAiC,KAAKsjD,cAAtCtjD,EAAsD;IAAE60B,SAAS;EAAX,CAAtD70B;EACAA,OAAOgD,gBAAPhD,CAAwB,SAAxBA,EAAmC,KAAKujD,yBAAxCvjD;EACAA,OAAOgD,gBAAPhD,CAAwB,aAAxBA,EAAuC,KAAKwjD,eAA5CxjD;EACAA,OAAOgD,gBAAPhD,CAAwB,YAAxBA,EAAsC,KAAKyjD,cAA3CzjD;EACAA,OAAOgD,gBAAPhD,CAAwB,WAAxBA,EAAqC,KAAKyjD,cAA1CzjD;EACAA,OAAOgD,gBAAPhD,CAAwB,UAAxBA,EAAoC,KAAKyjD,cAAzCzjD;AArTsB;;mCAwTC;EACvBA,OAAO8vB,mBAAP9vB,CAA2B,WAA3BA,EAAwC,KAAKojD,gBAA7CpjD;EACAA,OAAO8vB,mBAAP9vB,CAA2B,WAA3BA,EAAwC,KAAKqjD,aAA7CrjD;EACAA,OAAO8vB,mBAAP9vB,CAA2B,OAA3BA,EAAoC,KAAKsjD,cAAzCtjD,EAAyD;IACvD60B,SAAS;EAD8C,CAAzD70B;EAGAA,OAAO8vB,mBAAP9vB,CAA2B,SAA3BA,EAAsC,KAAKujD,yBAA3CvjD;EACAA,OAAO8vB,mBAAP9vB,CAA2B,aAA3BA,EAA0C,KAAKwjD,eAA/CxjD;EACAA,OAAO8vB,mBAAP9vB,CAA2B,YAA3BA,EAAyC,KAAKyjD,cAA9CzjD;EACAA,OAAO8vB,mBAAP9vB,CAA2B,WAA3BA,EAAwC,KAAKyjD,cAA7CzjD;EACAA,OAAO8vB,mBAAP9vB,CAA2B,UAA3BA,EAAuC,KAAKyjD,cAA5CzjD;EAEA,OAAO,KAAKojD,gBAAZ;EACA,OAAO,KAAKC,aAAZ;EACA,OAAO,KAAKC,cAAZ;EACA,OAAO,KAAKC,yBAAZ;EACA,OAAO,KAAKC,eAAZ;EACA,OAAO,KAAKC,cAAZ;AAzUsB;;8BA4UJ;EAClB,IAAyBt4C,SAASu4C,iBAAlC,EAAqD;IACnD;EADF,OAEO;IACL;EAJgB;AA5UI;;0CAoVQ;EAC9B,KAAKC,oBAAL,GAA4B,oEAAuB/jC,IAAvB,CAA4B,IAA5B,CAA5B;EACA5f,OAAOgD,gBAAPhD,CAAwB,kBAAxBA,EAA4C,KAAK2jD,oBAAjD3jD;AAtVsB;;6CAyVW;EACjCA,OAAO8vB,mBAAP9vB,CAA2B,kBAA3BA,EAA+C,KAAK2jD,oBAApD3jD;EACA,OAAO,KAAK2jD,oBAAZ;AA3VsB;;;;;;;;;;;;;ACvB1B;;AACA;;AAEA,MAAMC,kBAAkB,KAAxB;;AAKA,MAAMnkC,iBAAN,CAAwB;EACtB3f,cAAc;IACZ,KAAK4T,SAAL,GAAiB,IAAjB;IACA,KAAKkH,kBAAL,GAA0B,IAA1B;IACA,KAAK8E,MAAL,GAAc,IAAd;IACA,KAAKmkC,mBAAL,GAA2B,IAA3B;IAEA,KAAKC,WAAL,GAAmB,IAAnB;IACA,KAAKxzB,QAAL,GAAgB,KAAhB;IACA,KAAKC,sBAAL,GAA8B,KAA9B;EAToB;;EAetBzc,UAAUJ,SAAV,EAAqB;IACnB,KAAKA,SAAL,GAAiBA,SAAjB;EAhBoB;;EAsBtBqN,mBAAmBnG,kBAAnB,EAAuC;IACrC,KAAKA,kBAAL,GAA0BA,kBAA1B;EAvBoB;;EA8BtBmpC,kBAAkBn+C,IAAlB,EAAwB;IACtB,OAAO,KAAKi+C,mBAAL,KAA6Bj+C,KAAKo+C,WAAzC;EA/BoB;;EAqCtBC,YAAY;IACV,OAAO,CAAC,CAAC,KAAKvwC,SAAd;EAtCoB;;EA4CtB+c,sBAAsByzB,qBAAtB,EAA6C;IAAA;;IAC3C,IAAI,KAAKJ,WAAT,EAAsB;MACpB56B,aAAa,KAAK46B,WAAlB;MACA,KAAKA,WAAL,GAAmB,IAAnB;IAHyC;;IAO3C,IAAI,KAAKpwC,SAAL,CAAe+O,cAAf,CAA8ByhC,qBAA9B,CAAJ,EAA0D;MACxD;IARyC;;IAW3C,IACE,KAAK3zB,sBAAL,6BACA,KAAK3V,kBADL,kDACA,sBAAyB6H,cAAzB,EAFF,EAGE;MACA;IAfyC;;IAkB3C,IAAI,KAAK6N,QAAT,EAAmB;MAEjB;IApByC;;IAuB3C,IAAI,KAAK5Q,MAAT,EAAiB;MACf,KAAKokC,WAAL,GAAmB36B,WAAW,KAAKzJ,MAAL,CAAYE,IAAZ,CAAiB,IAAjB,CAAX,EAAmCgkC,eAAnC,CAAnB;IAxByC;EA5CvB;;EA8EtBO,mBAAmB58C,OAAnB,EAA4Bf,KAA5B,EAAmC49C,YAAnC,EAAyE;IAAA,IAAxBC,cAAwB,uEAAP,KAAO;IAUvE,MAAMC,eAAe/8C,QAAQf,KAA7B;IAAA,MACE+9C,aAAaD,aAAahgD,MAD5B;;IAGA,IAAIigD,eAAe,CAAnB,EAAsB;MACpB,OAAO,IAAP;IAdqE;;IAgBvE,KAAK,IAAI59C,IAAI,CAAb,EAAgBA,IAAI49C,UAApB,EAAgC59C,GAAhC,EAAqC;MACnC,MAAMf,OAAO0+C,aAAa39C,CAAb,EAAgBf,IAA7B;;MACA,IAAI,CAAC,KAAK4+C,cAAL,CAAoB5+C,IAApB,CAAL,EAAgC;QAC9B,OAAOA,IAAP;MAHiC;IAhBkC;;IAsBvE,MAAM6+C,UAAUl9C,QAAQuB,KAARvB,CAAcmB,EAA9B;IAAA,MACEg8C,SAASn9C,QAAQwB,IAARxB,CAAamB,EADxB;;IAKA,IAAIg8C,SAASD,OAATC,GAAmB,CAAnBA,GAAuBH,UAA3B,EAAuC;MACrC,MAAMI,aAAap9C,QAAQC,GAA3B;;MACA,KAAK,IAAIb,IAAI,CAAR,EAAWkY,KAAK6lC,SAASD,OAA9B,EAAuC99C,IAAIkY,EAA3C,EAA+ClY,GAA/C,EAAoD;QAClD,MAAMi+C,SAASR,eAAeK,UAAU99C,CAAzB,GAA6B+9C,SAAS/9C,CAArD;;QACA,IAAIg+C,WAAW/uC,GAAX+uC,CAAeC,MAAfD,CAAJ,EAA4B;UAC1B;QAHgD;;QAKlD,MAAME,WAAWr+C,MAAMo+C,SAAS,CAAf,CAAjB;;QACA,IAAI,CAAC,KAAKJ,cAAL,CAAoBK,QAApB,CAAL,EAAoC;UAClC,OAAOA,QAAP;QAPgD;MAFf;IA3BgC;;IA2CvE,IAAIC,iBAAiBV,eAAeM,MAAf,GAAwBD,UAAU,CAAvD;IACA,IAAIM,gBAAgBv+C,MAAMs+C,cAAN,CAApB;;IAEA,IAAIC,iBAAiB,CAAC,KAAKP,cAAL,CAAoBO,aAApB,CAAtB,EAA0D;MACxD,OAAOA,aAAP;IA/CqE;;IAiDvE,IAAIV,cAAJ,EAAoB;MAClBS,kBAAkBV,eAAe,CAAf,GAAmB,CAAC,CAAtCU;MACAC,gBAAgBv+C,MAAMs+C,cAAN,CAAhBC;;MAEA,IAAIA,iBAAiB,CAAC,KAAKP,cAAL,CAAoBO,aAApB,CAAtB,EAA0D;QACxD,OAAOA,aAAP;MALgB;IAjDmD;;IA0DvE,OAAO,IAAP;EAxIoB;;EA+ItBP,eAAe5+C,IAAf,EAAqB;IACnB,OAAOA,KAAKuyB,cAALvyB,KAAwB/H,0BAAgBI,QAA/C;EAhJoB;;EA0JtB+mD,WAAWp/C,IAAX,EAAiB;IACf,QAAQA,KAAKuyB,cAAb;MACE,KAAKt6B,0BAAgBI,QAArB;QACE,OAAO,KAAP;;MACF,KAAKJ,0BAAgBG,MAArB;QACE,KAAK6lD,mBAAL,GAA2Bj+C,KAAKo+C,WAAhC;QACAp+C,KAAKq/C,MAALr/C;QACA;;MACF,KAAK/H,0BAAgBE,OAArB;QACE,KAAK8lD,mBAAL,GAA2Bj+C,KAAKo+C,WAAhC;QACA;;MACF,KAAKnmD,0BAAgBC,OAArB;QACE,KAAK+lD,mBAAL,GAA2Bj+C,KAAKo+C,WAAhC;QACAp+C,KACGs/C,IADHt/C,GAEGu/C,OAFHv/C,CAEW,MAAM;UACb,KAAK6qB,qBAAL;QAHJ,GAKG1Y,KALHnS,CAKSiY,UAAU;UACf,IAAIA,kBAAkBunC,qCAAtB,EAAmD;YACjD;UAFa;;UAIfzkD,QAAQC,KAARD,CAAe,gBAAekd,MAAO,GAArCld;QATJ;QAWA;IAvBJ;;IAyBA,OAAO,IAAP;EApLoB;;AAAA;;;;;;;;;;;;;;;ACXxB;;AACA;;AAcA,MAAMqf,mBAAN,CAA0B;EAIxBlgB,kBAKG;IAAA,IALS;MACVuT,QADU;MAEV/B,mBAAmB,IAFT;MAGV2O,mBAAmB,IAHT;MAIVC,sBAAsB;IAJZ,CAKT;IACD,KAAKotB,YAAL,GAAoB,IAApB;IACA,KAAK+X,UAAL,GAAkB,IAAlB;IACA,KAAKC,gBAAL,GAAwB,IAAxB;IACA,KAAKC,kBAAL,GAA0B,IAA1B;IAEA,KAAKC,UAAL,GAAkB,IAAlB;IACA,KAAKC,WAAL,GAAmBh7C,OAAO6C,MAAP7C,CAAc,IAAdA,CAAnB;IACA,KAAKi7C,MAAL,GAAc,KAAd;IAEA,KAAKnP,SAAL,GAAiBljC,QAAjB;IACA,KAAKsyC,iBAAL,GAAyBr0C,gBAAzB;IACA,KAAKs0C,iBAAL,GAAyB3lC,gBAAzB;IACA,KAAK4lC,oBAAL,GAA4B3lC,mBAA5B;EAtBsB;;EAwCxBpM,UAAUJ,SAAV,EAAqB;IACnB,KAAK2xC,UAAL,GAAkB3xC,SAAlB;EAzCsB;;EA4CxB,MAAME,WAAN,CAAkBH,WAAlB,EAA+B;IAAA;;IAC7B,IAAI,KAAK65B,YAAT,EAAuB;MACrB,MAAM,KAAKwY,iBAAL,EAAN;IAF2B;;IAI7B,KAAKxY,YAAL,GAAoB75B,WAApB;;IAEA,IAAI,CAACA,WAAL,EAAkB;MAChB;IAP2B;;IAS7B,MAAM,CAACsyC,OAAD,EAAUC,gBAAV,EAA4BC,UAA5B,IAA0C,MAAMj7C,QAAQua,GAARva,CAAY,CAChEyI,YAAYyyC,eAAZzyC,EADgE,EAEhEA,YAAY0yC,sBAAZ1yC,EAFgE,EAGhEA,YAAY2yC,YAAZ3yC,EAHgE,CAAZzI,CAAtD;;IAMA,IAAI,CAAC+6C,OAAD,IAAY,CAACE,UAAjB,EAA6B;MAE3B,MAAM,KAAKH,iBAAL,EAAN;MACA;IAlB2B;;IAoB7B,IAAIryC,gBAAgB,KAAK65B,YAAzB,EAAuC;MACrC;IArB2B;;IAuB7B,IAAI;MACF,KAAKkY,UAAL,GAAkB,KAAKa,gBAAL,EAAlB;IADF,EAEE,OAAOzlD,KAAP,EAAc;MACdD,QAAQC,KAARD,CAAe,qCAAoCC,KAArC,aAAqCA,KAArC,uBAAqCA,MAAOkd,OAAQ,IAAlEnd;MAEA,MAAM,KAAKmlD,iBAAL,EAAN;MACA;IA7B2B;;IAgC7B,KAAKQ,eAAL,CAAqB9iD,GAArB,CAAyB,mBAAzB,EAA8CixB,SAAS;MACrD,IAAIA,qDAAO3e,MAAP2e,MAAkBz0B,MAAtB,EAA8B;QAC5B;MAFmD;;MAIrD,KAAKumD,kBAAL,CAAwB9xB,MAAMC,MAA9B;IAJF;;IAMA,KAAK4xB,eAAL,CAAqB9iD,GAArB,CAAyB,wBAAzB,EAAmDixB,SAAS;MAAA;;MAC1D,yBAAK+wB,UAAL,sEAAiBgB,sBAAjB,CAAwC/xB,MAAMC,MAA9C;IADF;;IAIA,KAAK4xB,eAAL,CAAqB9iD,GAArB,CAAyB,cAAzB,EAAyC,SAA8B;MAAA,IAA7B;QAAEsR,UAAF;QAAcikB;MAAd,CAA6B;;MACrE,IAAIjkB,eAAeikB,QAAnB,EAA6B;QAC3B;MAFmE;;MAIrE,KAAK0tB,kBAAL,CAAwB1tB,QAAxB;;MACA,KAAK2tB,iBAAL,CAAuB5xC,UAAvB;IALF;;IAOA,KAAKwxC,eAAL,CAAqB9iD,GAArB,CAAyB,cAAzB,EAAyC,SAAoB;MAAA,IAAnB;QAAEsR;MAAF,CAAmB;;MAC3D,IAAI,CAAC,KAAK6xC,gBAAL,CAAsB/wC,GAAtB,CAA0Bd,UAA1B,CAAL,EAA4C;QAC1C;MAFyD;;MAI3D,IAAIA,eAAe,KAAKuwC,UAAL,CAAgBlxC,iBAAnC,EAAsD;QACpD;MALyD;;MAO3D,KAAKuyC,iBAAL,CAAuB5xC,UAAvB;IAPF;;IASA,KAAKwxC,eAAL,CAAqB9iD,GAArB,CAAyB,cAAzB,EAAyC,MAAMixB,KAAN,IAAe;MAAA;;MACtD,MAAM,KAAKgyB,kBAAL,CAAwB,KAAKpB,UAAL,CAAgBlxC,iBAAxC,CAAN;MAEA,4BAAM,KAAKqxC,UAAX,sDAAM,kBAAiBgB,sBAAjB,CAAwC;QAC5C99C,IAAI,KADwC;QAE5CgJ,MAAM;MAFsC,CAAxC,CAAN;MAKA,8BAAK4zC,gBAAL,gFAAuBr6C,OAAvB;IARF;;IAWA,KAAK27C,UAAL,CAAgBpjD,GAAhB,CAAoB,WAApB,EAAiCixB,SAAS;MACxC,KAAKgxB,WAAL,CAAiBoB,MAAjB,GAA0B,IAA1B;IADF;;IAGA,KAAKD,UAAL,CAAgBpjD,GAAhB,CAAoB,SAApB,EAA+BixB,SAAS;MACtC,KAAKgxB,WAAL,CAAiBoB,MAAjB,GAA0B,KAA1B;IADF;;IAIA,WAAW,CAACn1C,IAAD,EAAO2rB,QAAP,CAAX,IAA+B,KAAKipB,eAApC,EAAqD;MACnD,KAAK/P,SAAL,CAAelqB,GAAf,CAAmB3a,IAAnB,EAAyB2rB,QAAzB;IA7E2B;;IA+E7B,WAAW,CAAC3rB,IAAD,EAAO2rB,QAAP,CAAX,IAA+B,KAAKupB,UAApC,EAAgD;MAC9C5mD,OAAOgD,gBAAPhD,CAAwB0R,IAAxB1R,EAA8Bq9B,QAA9Br9B,EAAwC,IAAxCA;IAhF2B;;IAmF7B,IAAI;MACF,MAAM8mD,gBAAgB,MAAM,KAAKC,iBAAL,EAA5B;;MACA,IAAItzC,gBAAgB,KAAK65B,YAAzB,EAAuC;QACrC;MAHA;;MAMF,MAAM,KAAKkY,UAAL,CAAgBwB,aAAhB,CAA8B;QAClCjB,OADkC;QAElCC,gBAFkC;QAGlCiB,SAAS;UACPx5C,UAAUD,UAAUC,QADb;UAEP2D,UAAU5D,UAAU4D;QAFb,CAHyB;QAOlC81C,SAAS,EACP,GAAGJ,aADI;UAEPK,SAASlB;QAFF;MAPyB,CAA9B,CAAN;;MAaA,KAAK1P,SAAL,CAAe1gC,QAAf,CAAwB,gBAAxB,EAA0C;QAAEC,QAAQ;MAAV,CAA1C;IAnBF,EAoBE,OAAOlV,KAAP,EAAc;MACdD,QAAQC,KAARD,CAAe,qCAAoCC,KAArC,aAAqCA,KAArC,uBAAqCA,MAAOkd,OAAQ,IAAlEnd;MAEA,MAAM,KAAKmlD,iBAAL,EAAN;MACA;IA3G2B;;IA8G7B,4BAAM,KAAKN,UAAX,sDAAM,kBAAiBgB,sBAAjB,CAAwC;MAC5C99C,IAAI,KADwC;MAE5CgJ,MAAM;IAFsC,CAAxC,CAAN;IAIA,MAAM,KAAKg1C,iBAAL,CACJ,KAAKrB,UAAL,CAAgBlxC,iBADZ,EAEe,IAFf,CAAN;IAMAnJ,QAAQC,OAARD,GAAkB6M,IAAlB7M,CAAuB,MAAM;MAC3B,IAAIyI,gBAAgB,KAAK65B,YAAzB,EAAuC;QACrC,KAAKoY,MAAL,GAAc,IAAd;MAFyB;IAA7B;EApKsB;;EA2KxB,MAAMl+B,gBAAN,CAAuBkN,MAAvB,EAA+B;IAAA;;IAC7B,4BAAO,KAAK8wB,UAAZ,sDAAO,kBAAiBgB,sBAAjB,CAAwC;MAC7C99C,IAAI,KADyC;MAE7CgJ,MAAM;IAFuC,CAAxC,CAAP;EA5KsB;;EAkLxB,MAAMgW,eAAN,CAAsBgN,MAAtB,EAA8B;IAAA;;IAC5B,4BAAO,KAAK8wB,UAAZ,sDAAO,kBAAiBgB,sBAAjB,CAAwC;MAC7C99C,IAAI,KADyC;MAE7CgJ,MAAM;IAFuC,CAAxC,CAAP;EAnLsB;;EAyLxB,MAAMif,iBAAN,CAAwB+D,MAAxB,EAAgC;IAAA;;IAC9B,4BAAO,KAAK8wB,UAAZ,sDAAO,kBAAiBgB,sBAAjB,CAAwC;MAC7C99C,IAAI,KADyC;MAE7CgJ,MAAM;IAFuC,CAAxC,CAAP;EA1LsB;;EAgMxB,MAAM0f,gBAAN,CAAuBsD,MAAvB,EAA+B;IAAA;;IAC7B,4BAAO,KAAK8wB,UAAZ,sDAAO,kBAAiBgB,sBAAjB,CAAwC;MAC7C99C,IAAI,KADyC;MAE7CgJ,MAAM;IAFuC,CAAxC,CAAP;EAjMsB;;EAuMxB,IAAI01C,UAAJ,GAAiB;IACf,OAAO,KAAK3B,WAAZ;EAxMsB;;EA2MxB,IAAIrgC,cAAJ,GAAqB;IAAA;;IACnB,OAAO,+BAAKmgC,kBAAL,gFAAyBriC,OAAzB,KAAoC,IAA3C;EA5MsB;;EA+MxB,IAAI0S,KAAJ,GAAY;IACV,OAAO,KAAK8vB,MAAZ;EAhNsB;;EAsNxB,IAAIY,eAAJ,GAAsB;IACpB,OAAO1sC,sBAAO,IAAPA,EAAa,iBAAbA,EAAgC,IAAIxW,GAAJ,EAAhCwW,CAAP;EAvNsB;;EA6NxB,IAAIgtC,UAAJ,GAAiB;IACf,OAAOhtC,sBAAO,IAAPA,EAAa,YAAbA,EAA2B,IAAIxW,GAAJ,EAA3BwW,CAAP;EA9NsB;;EAoOxB,IAAI+sC,gBAAJ,GAAuB;IACrB,OAAO/sC,sBAAO,IAAPA,EAAa,kBAAbA,EAAiC,IAAInS,GAAJ,EAAjCmS,CAAP;EArOsB;;EA2OxB,IAAIytC,aAAJ,GAAoB;IAClB,OAAOztC,sBAAO,IAAPA,EAAa,eAAbA,EAA8B,IAAIxW,GAAJ,EAA9BwW,CAAP;EA5OsB;;EAkPxB,MAAM2sC,kBAAN,CAAyB7xB,MAAzB,EAAiC;IAE/B,MAAMrR,uBACJ,KAAKgiC,UAAL,CAAgBhiC,oBAAhB,IACA,KAAKgiC,UAAL,CAAgBiC,0BAFlB;IAIA,MAAM;MAAE5+C,EAAF;MAAM6+C,QAAN;MAAgBC,OAAhB;MAAyBlkD;IAAzB,IAAmCoxB,MAAzC;;IACA,IAAI,CAAChsB,EAAL,EAAS;MACP,QAAQ8+C,OAAR;QACE,KAAK,OAAL;UACE7mD,QAAQkT,KAARlT;UACA;;QACF,KAAK,OAAL;UACEA,QAAQC,KAARD,CAAc2C,KAAd3C;UACA;;QACF,KAAK,QAAL;UACE,IAAI0iB,oBAAJ,EAA0B;YACxB;UAFJ;;UAIE,MAAM2H,QAAQhe,0CAA2B1J,KAA3B0J,CAAd;UACA,KAAKq4C,UAAL,CAAgBl4C,UAAhB,GAA6B6d,MAAM7d,UAAnC;UACA;;QACF,KAAK,UAAL;UACE,KAAKk4C,UAAL,CAAgBlxC,iBAAhB,GAAoC7Q,QAAQ,CAA5C;UACA;;QACF,KAAK,OAAL;UACE,MAAM,KAAK+hD,UAAL,CAAgBt7B,YAAtB;;UACA,KAAKwsB,SAAL,CAAe1gC,QAAf,CAAwB,OAAxB,EAAiC;YAAEC,QAAQ;UAAV,CAAjC;;UACA;;QACF,KAAK,SAAL;UACEnV,QAAQgtB,GAARhtB,CAAY2C,KAAZ3C;UACA;;QACF,KAAK,MAAL;UACE,IAAI0iB,oBAAJ,EAA0B;YACxB;UAFJ;;UAIE,KAAKgiC,UAAL,CAAgB3hC,iBAAhB,GAAoCpgB,KAApC;UACA;;QACF,KAAK,QAAL;UACE,KAAKizC,SAAL,CAAe1gC,QAAf,CAAwB,UAAxB,EAAoC;YAAEC,QAAQ;UAAV,CAApC;;UACA;;QACF,KAAK,WAAL;UACE,KAAKuvC,UAAL,CAAgBlxC,iBAAhB,GAAoC,CAApC;UACA;;QACF,KAAK,UAAL;UACE,KAAKkxC,UAAL,CAAgBlxC,iBAAhB,GAAoC,KAAKkxC,UAAL,CAAgBrxC,UAApD;UACA;;QACF,KAAK,UAAL;UACE,KAAKqxC,UAAL,CAAgBtuC,QAAhB;;UACA;;QACF,KAAK,UAAL;UACE,KAAKsuC,UAAL,CAAgBruC,YAAhB;;UACA;;QACF,KAAK,YAAL;UACE,IAAIqM,oBAAJ,EAA0B;YACxB;UAFJ;;UAIE,KAAKgiC,UAAL,CAAgB/hC,aAAhB;;UACA;;QACF,KAAK,aAAL;UACE,IAAID,oBAAJ,EAA0B;YACxB;UAFJ;;UAIE,KAAKgiC,UAAL,CAAgB7hC,aAAhB;;UACA;MAxDJ;;MA0DA;IAlE6B;;IAqE/B,IAAIH,oBAAJ,EAA0B;MACxB,IAAIqR,OAAOxJ,KAAX,EAAkB;QAChB;MAFsB;IArEK;;IA0E/B,OAAOwJ,OAAOhsB,EAAd;IACA,OAAOgsB,OAAO6yB,QAAd;IAEA,MAAM//C,MAAM+/C,WAAW,CAAC7+C,EAAD,EAAK,GAAG6+C,QAAR,CAAX,GAA+B,CAAC7+C,EAAD,CAA3C;;IACA,WAAW++C,SAAX,IAAwBjgD,GAAxB,EAA6B;MAC3B,MAAMlH,UAAU6K,SAAS2B,aAAT3B,CACb,qBAAoBs8C,SAAU,IADjBt8C,CAAhB;;MAGA,IAAI7K,OAAJ,EAAa;QACXA,QAAQoiC,aAARpiC,CAAsB,IAAI0hC,WAAJ,CAAgB,mBAAhB,EAAqC;UAAEtN;QAAF,CAArC,CAAtBp0B;MADF,OAEO;QAAA;;QAEL,2BAAKgtC,YAAL,0EAAmBvoB,iBAAnB,CAAqC2iC,QAArC,CAA8CD,SAA9C,EAAyD/yB,MAAzD;MARyB;IA9EE;EAlPT;;EAgVxB,MAAMgyB,iBAAN,CAAwB5xC,UAAxB,EAAwD;IAAA,IAApBoI,UAAoB,uEAAP,KAAO;IACtD,MAAMzJ,cAAc,KAAK65B,YAAzB;IAAA,MACEqa,eAAe,KAAKN,aADtB;;IAGA,IAAInqC,UAAJ,EAAgB;MACd,KAAKooC,gBAAL,GAAwB9qC,wCAAxB;IALoD;;IAOtD,IAAI,CAAC,KAAK8qC,gBAAV,EAA4B;MAC1B;IARoD;;IAUtD,MAAM5uB,WAAW,KAAK2uB,UAAL,CAAgB1uB,WAAhB,CAA0C7hB,aAAa,CAAvD,CAAjB;;IAEA,IAAI4hB,8DAAUyB,cAAVzB,MAA6B74B,0BAAgBI,QAAjD,EAA2D;MACzD,KAAK0oD,gBAAL,CAAsB99C,GAAtB,CAA0BiM,UAA1B;;MACA;IAdoD;;IAgBtD,KAAK6xC,gBAAL,CAAsB16B,MAAtB,CAA6BnX,UAA7B;;IAEA,MAAM8yC,iBAAkB,aAAY;MAAA;;MAElC,MAAMT,UAAU,OAAO,CAACQ,aAAa/xC,GAAb+xC,CAAiB7yC,UAAjB6yC,CAAD,wBACnBjxB,SAASrM,OADU,sDACnBqM,kBAAkB0vB,YAAlB1vB,EADmB,GAEnB,IAFY,CAAhB;;MAGA,IAAIjjB,gBAAgB,KAAK65B,YAAzB,EAAuC;QACrC;MANgC;;MASlC,4BAAM,KAAKkY,UAAX,sDAAM,kBAAiBgB,sBAAjB,CAAwC;QAC5C99C,IAAI,MADwC;QAE5CgJ,MAAM,UAFsC;QAG5CoD,UAH4C;QAI5CqyC;MAJ4C,CAAxC,CAAN;IATsB,IAAxB;;IAgBAQ,aAAankD,GAAbmkD,CAAiB7yC,UAAjB6yC,EAA6BC,cAA7BD;EAlXsB;;EAwXxB,MAAMlB,kBAAN,CAAyB3xC,UAAzB,EAAqC;IAAA;;IACnC,MAAMrB,cAAc,KAAK65B,YAAzB;IAAA,MACEqa,eAAe,KAAKN,aADtB;;IAGA,IAAI,CAAC,KAAK/B,gBAAV,EAA4B;MAC1B;IALiC;;IAOnC,IAAI,KAAKqB,gBAAL,CAAsB/wC,GAAtB,CAA0Bd,UAA1B,CAAJ,EAA2C;MACzC;IARiC;;IAUnC,MAAM8yC,iBAAiBD,aAAal2C,GAAbk2C,CAAiB7yC,UAAjB6yC,CAAvB;;IACA,IAAI,CAACC,cAAL,EAAqB;MACnB;IAZiC;;IAcnCD,aAAankD,GAAbmkD,CAAiB7yC,UAAjB6yC,EAA6B,IAA7BA;IAGA,MAAMC,cAAN;;IACA,IAAIn0C,gBAAgB,KAAK65B,YAAzB,EAAuC;MACrC;IAnBiC;;IAsBnC,4BAAM,KAAKkY,UAAX,sDAAM,kBAAiBgB,sBAAjB,CAAwC;MAC5C99C,IAAI,MADwC;MAE5CgJ,MAAM,WAFsC;MAG5CoD;IAH4C,CAAxC,CAAN;EA9YsB;;EA2ZxB,MAAMiyC,iBAAN,GAA0B;IACxB,IAAI,KAAKlB,oBAAT,EAA+B;MAC7B,OAAO,KAAKA,oBAAL,CAA0B,KAAKvY,YAA/B,CAAP;IAFsB;;IASxB,MAAM,IAAI3hC,KAAJ,CAAU,iDAAV,CAAN;EApasB;;EA0axB06C,mBAAmB;IACjB,KAAKd,kBAAL,GAA0B/qC,wCAA1B;;IAEA,IAAI,KAAKgrC,UAAT,EAAqB;MACnB,MAAM,IAAI75C,KAAJ,CAAU,6CAAV,CAAN;IAJe;;IAMjB,IAAI,KAAKi6C,iBAAT,EAA4B;MAC1B,OAAO,KAAKA,iBAAL,CAAuBlsC,eAAvB,CAAuC;QAC5CpI,kBAAkB,KAAKq0C;MADqB,CAAvC,CAAP;IAPe;;IAgBjB,MAAM,IAAIh6C,KAAJ,CAAU,4CAAV,CAAN;EA1bsB;;EAgcxB,MAAMm6C,iBAAN,GAA0B;IAAA;;IACxB,IAAI,CAAC,KAAKN,UAAV,EAAsB;MAAA;;MACpB,KAAKlY,YAAL,GAAoB,IAApB;MAEA,+BAAKiY,kBAAL,kFAAyBt6C,OAAzB;MACA;IALsB;;IAOxB,IAAI,KAAKq6C,gBAAT,EAA2B;MACzB,MAAMt6C,QAAQmgB,IAARngB,CAAa,CACjB,KAAKs6C,gBAAL,CAAsBpiC,OADL,EAEjB,IAAIlY,OAAJ,CAAYC,WAAW;QAErBke,WAAWle,OAAX,EAAoB,IAApB;MAFF,EAFiB,CAAbD,EAMH+M,KANG/M,CAMG6S,UAAU,CANb,EAAN;MASA,KAAKynC,gBAAL,GAAwB,IAAxB;IAjBsB;;IAmBxB,KAAKhY,YAAL,GAAoB,IAApB;;IAEA,IAAI;MACF,MAAM,KAAKkY,UAAL,CAAgBqC,cAAhB,EAAN;IADF,EAEE,OAAOnxC,EAAP,EAAW,CAvBW;;IAyBxB,WAAW,CAAChF,IAAD,EAAO2rB,QAAP,CAAX,IAA+B,KAAKipB,eAApC,EAAqD;MACnD,KAAK/P,SAAL,CAAerhB,IAAf,CAAoBxjB,IAApB,EAA0B2rB,QAA1B;IA1BsB;;IA4BxB,KAAKipB,eAAL,CAAqBzyC,KAArB;;IAEA,WAAW,CAACnC,IAAD,EAAO2rB,QAAP,CAAX,IAA+B,KAAKupB,UAApC,EAAgD;MAC9C5mD,OAAO8vB,mBAAP9vB,CAA2B0R,IAA3B1R,EAAiCq9B,QAAjCr9B,EAA2C,IAA3CA;IA/BsB;;IAiCxB,KAAK4mD,UAAL,CAAgB/yC,KAAhB;;IAEA,KAAK8yC,gBAAL,CAAsB9yC,KAAtB;;IACA,KAAKwzC,aAAL,CAAmBxzC,KAAnB;;IAEA,KAAK2xC,UAAL,GAAkB,IAAlB;IACA,OAAO,KAAKC,WAAL,CAAiBoB,MAAxB;IACA,KAAKnB,MAAL,GAAc,KAAd;IAEA,+BAAKH,kBAAL,kFAAyBt6C,OAAzB;EA1esB;;AAAA;;;;;;;;;;;;;;;ACjB1B;;;;;;;;AAMA,MAAM68C,wBAAwB,wBAA9B;;;;;;;;;;;;;;AAyCA,MAAMxlC,UAAN,CAAiB;EAIfxiB,kBAAyE;IAAA,IAA7D;MAAEyiB,QAAF;MAAY7O,SAAZ,EAAYA,UAAZ;MAAuBkH,kBAAvB,EAAuBA,mBAAvB;MAA2CvH,QAA3C;MAAqDyI;IAArD,CAA6D;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IACvE,KAAK0e,MAAL,GAAc,KAAd;IACA,KAAKG,MAAL,GAAcp8B,sBAAYE,MAA1B;IACA,KAAKud,gBAAL,GAAwB,KAAxB;IACA,KAAK+rC,wBAAL,GAAgC,KAAhC;IAMA,KAAKvlC,SAAL,GAAiB,IAAjB;IAEA,KAAK9O,SAAL,GAAiBA,UAAjB;IACA,KAAKkH,kBAAL,GAA0BA,mBAA1B;IAEA,KAAKotC,cAAL,GAAsBzlC,SAASylC,cAA/B;IACA,KAAKC,gBAAL,GAAwB1lC,SAAS0lC,gBAAjC;IACA,KAAKvtB,YAAL,GAAoBnY,SAASmY,YAA7B;IAEA,KAAKwtB,eAAL,GAAuB3lC,SAAS2lC,eAAhC;IACA,KAAKC,aAAL,GAAqB5lC,SAAS4lC,aAA9B;IACA,KAAKC,iBAAL,GAAyB7lC,SAAS6lC,iBAAlC;IACA,KAAKC,YAAL,GAAoB9lC,SAAS8lC,YAA7B;IAEA,KAAKvnC,aAAL,GAAqByB,SAASzB,aAA9B;IACA,KAAKmB,WAAL,GAAmBM,SAASN,WAA5B;IACA,KAAKE,eAAL,GAAuBI,SAASJ,eAAhC;IACA,KAAKE,UAAL,GAAkBE,SAASF,UAA3B;IAEA,KAAKimC,wBAAL,GAAgC/lC,SAASgmC,uBAAzC;IACA,KAAKC,yBAAL,GAAiCjmC,SAASkmC,wBAA1C;IAEA,KAAKp1C,QAAL,GAAgBA,QAAhB;IACA,KAAKyI,IAAL,GAAYA,IAAZ;;IAEA;EAvCa;;EA0CfuJ,QAAQ;IACN,KAAKrJ,gBAAL,GAAwB,KAAxB;IACA,KAAK+rC,wBAAL,GAAgC,KAAhC;;IAEA,mFAAuC,IAAvC;;IACA,KAAKrwB,UAAL,CAAgBn5B,sBAAYE,MAA5B;IAEA,KAAK0pD,aAAL,CAAmBO,QAAnB,GAA8B,KAA9B;IACA,KAAKN,iBAAL,CAAuBM,QAAvB,GAAkC,KAAlC;IACA,KAAKL,YAAL,CAAkBK,QAAlB,GAA6B,KAA7B;IACA,KAAKF,yBAAL,CAA+BE,QAA/B,GAA0C,IAA1C;EApDa;;EA0Df,IAAIl4B,WAAJ,GAAkB;IAChB,OAAO,KAAKgK,MAAL,GAAc,KAAKG,MAAnB,GAA4Bp8B,sBAAYC,IAA/C;EA3Da;;EAkEfysB,iBAAwC;IAAA,IAAzBrlB,IAAyB,uEAAlBrH,sBAAYC,IAAM;;IACtC,IAAI,KAAKwd,gBAAT,EAA2B;MACzB;IAFoC;;IAItC,KAAKA,gBAAL,GAAwB,IAAxB;;IAIA,IAAIpW,SAASrH,sBAAYC,IAArBoH,IAA6BA,SAASrH,sBAAYJ,OAAtD,EAA+D;MAC7D;;MACA;IAVoC;;IAYtC,KAAKu5B,UAAL,CAAgB9xB,IAAhB,EAAwC,IAAxC;;IAIA,IAAI,CAAC,KAAKmiD,wBAAV,EAAoC;MAClC;IAjBoC;EAlEzB;;EA6FfrwB,WAAW9xB,IAAX,EAAoC;IAAA,IAAnB+iD,SAAmB,uEAAP,KAAO;IAClC,MAAMC,gBAAgBhjD,SAAS,KAAK+0B,MAApC;IACA,IAAIkuB,uBAAuB,KAA3B;;IAEA,QAAQjjD,IAAR;MACE,KAAKrH,sBAAYC,IAAjB;QACE,IAAI,KAAKg8B,MAAT,EAAiB;UACf,KAAK5V,KAAL;QAFJ;;QAIE;;MACF,KAAKrmB,sBAAYE,MAAjB;QACE,IAAI,KAAK+7B,MAAL,IAAeouB,aAAnB,EAAkC;UAChCC,uBAAuB,IAAvBA;QAFJ;;QAIE;;MACF,KAAKtqD,sBAAYG,OAAjB;QACE,IAAI,KAAKypD,aAAL,CAAmBO,QAAvB,EAAiC;UAC/B;QAFJ;;QAIE;;MACF,KAAKnqD,sBAAYI,WAAjB;QACE,IAAI,KAAKypD,iBAAL,CAAuBM,QAA3B,EAAqC;UACnC;QAFJ;;QAIE;;MACF,KAAKnqD,sBAAYK,MAAjB;QACE,IAAI,KAAKypD,YAAL,CAAkBK,QAAtB,EAAgC;UAC9B;QAFJ;;QAIE;;MACF;QACE/nD,QAAQC,KAARD,CAAe,2BAA0BiF,IAAK,wBAA9CjF;QACA;IA5BJ;;IAgCA,KAAKg6B,MAAL,GAAc/0B,IAAd;IAEA,MAAMkjD,WAAWljD,SAASrH,sBAAYE,MAAtC;IAAA,MACEsqD,YAAYnjD,SAASrH,sBAAYG,OADnC;IAAA,MAEEsqD,gBAAgBpjD,SAASrH,sBAAYI,WAFvC;IAAA,MAGEsqD,WAAWrjD,SAASrH,sBAAYK,MAHlC;IAMA,KAAKspD,eAAL,CAAqB3mD,SAArB,CAA+Bq2B,MAA/B,CAAsC,SAAtC,EAAiDkxB,QAAjD;IACA,KAAKX,aAAL,CAAmB5mD,SAAnB,CAA6Bq2B,MAA7B,CAAoC,SAApC,EAA+CmxB,SAA/C;IACA,KAAKX,iBAAL,CAAuB7mD,SAAvB,CAAiCq2B,MAAjC,CAAwC,SAAxC,EAAmDoxB,aAAnD;IACA,KAAKX,YAAL,CAAkB9mD,SAAlB,CAA4Bq2B,MAA5B,CAAmC,SAAnC,EAA8CqxB,QAA9C;IAEA,KAAKf,eAAL,CAAqB7iB,YAArB,CAAkC,cAAlC,EAAkDyjB,QAAlD;IACA,KAAKX,aAAL,CAAmB9iB,YAAnB,CAAgC,cAAhC,EAAgD0jB,SAAhD;IACA,KAAKX,iBAAL,CAAuB/iB,YAAvB,CAAoC,cAApC,EAAoD2jB,aAApD;IACA,KAAKX,YAAL,CAAkBhjB,YAAlB,CAA+B,cAA/B,EAA+C4jB,QAA/C;IAEA,KAAKnoC,aAAL,CAAmBvf,SAAnB,CAA6Bq2B,MAA7B,CAAoC,QAApC,EAA8C,CAACkxB,QAA/C;IACA,KAAK7mC,WAAL,CAAiB1gB,SAAjB,CAA2Bq2B,MAA3B,CAAkC,QAAlC,EAA4C,CAACmxB,SAA7C;IACA,KAAK5mC,eAAL,CAAqB5gB,SAArB,CAA+Bq2B,MAA/B,CAAsC,QAAtC,EAAgD,CAACoxB,aAAjD;IACA,KAAK3mC,UAAL,CAAgB9gB,SAAhB,CAA0Bq2B,MAA1B,CAAiC,QAAjC,EAA2C,CAACqxB,QAA5C;;IAGA,KAAKX,wBAAL,CAA8B/mD,SAA9B,CAAwCq2B,MAAxC,CAA+C,QAA/C,EAAyD,CAACmxB,SAA1D;;IAEA,IAAIJ,aAAa,CAAC,KAAKnuB,MAAvB,EAA+B;MAC7B,KAAKhV,IAAL;MACA;IAhEgC;;IAkElC,IAAIqjC,oBAAJ,EAA0B;MACxB;;MACA;IApEgC;;IAsElC,IAAID,aAAJ,EAAmB;MACjB;IAvEgC;EA7FrB;;EAwKfpjC,OAAO;IACL,IAAI,KAAKgV,MAAT,EAAiB;MACf;IAFG;;IAIL,KAAKA,MAAL,GAAc,IAAd;IACA,KAAKE,YAAL,CAAkBn5B,SAAlB,CAA4BsH,GAA5B,CAAgC,SAAhC;IACA,KAAK6xB,YAAL,CAAkB2K,YAAlB,CAA+B,eAA/B,EAAgD,MAAhD;IAEA,KAAK2iB,cAAL,CAAoBzmD,SAApB,CAA8BsH,GAA9B,CAAkC,eAAlC,EAAmD,aAAnD;;IAEA,IAAI,KAAK8xB,MAAL,KAAgBp8B,sBAAYE,MAAhC,EAAwC;MACtC;IAXG;;IAaL;;IACA;;IAEA;EAxLa;;EA2LfmmB,QAAQ;IACN,IAAI,CAAC,KAAK4V,MAAV,EAAkB;MAChB;IAFI;;IAIN,KAAKA,MAAL,GAAc,KAAd;IACA,KAAKE,YAAL,CAAkBn5B,SAAlB,CAA4ByK,MAA5B,CAAmC,SAAnC;IACA,KAAK0uB,YAAL,CAAkB2K,YAAlB,CAA+B,eAA/B,EAAgD,OAAhD;IAEA,KAAK2iB,cAAL,CAAoBzmD,SAApB,CAA8BsH,GAA9B,CAAkC,eAAlC;IACA,KAAKm/C,cAAL,CAAoBzmD,SAApB,CAA8ByK,MAA9B,CAAqC,aAArC;;IAEA;;IACA;EAvMa;;EA0Mf4rB,SAAS;IACP,IAAI,KAAK4C,MAAT,EAAiB;MACf,KAAK5V,KAAL;IADF,OAEO;MACL,KAAKY,IAAL;IAJK;EA1MM;;AAAA;;;;2BAkNE;EACf,IAAI,KAAKxJ,gBAAL,IAAyB,CAAC,KAAK+rC,wBAAnC,EAA6D;IAC3D,KAAKA,wBAAL,GAAgC,IAAhC;EAFa;;EAKf,KAAK10C,QAAL,CAAcwC,QAAd,CAAuB,oBAAvB,EAA6C;IAC3CC,QAAQ,IADmC;IAE3ClQ,MAAM,KAAK4qB;EAFgC,CAA7C;AAvNa;;4BA6NG;EAChB,IAAI,KAAKhO,SAAT,EAAoB;IAClB,KAAKA,SAAL;EADF,OAEO;IAEL,KAAK9O,SAAL,CAAe+O,cAAf;IACA,KAAK7H,kBAAL,CAAwB6H,cAAxB;EANc;AA7NH;;mCAuOU;EACvB,MAAM;IAAE/O,SAAF;IAAakH;EAAb,IAAoC,IAA1C;EAGA,MAAM5G,aAAaN,UAAUM,UAA7B;;EACA,KAAK,IAAI8D,YAAY,CAArB,EAAwBA,YAAY9D,UAApC,EAAgD8D,WAAhD,EAA6D;IAC3D,MAAM4e,WAAWhjB,UAAUijB,WAAVjjB,CAAsBoE,SAAtBpE,CAAjB;;IACA,IAAIgjB,8DAAUyB,cAAVzB,MAA6B74B,0BAAgBI,QAAjD,EAA2D;MACzD,MAAM6iB,gBAAgBlG,mBAAmB4c,YAAnB5c,CAAgC9C,SAAhC8C,CAAtB;MACAkG,cAAc2W,QAAd3W,CAAuB4V,QAAvB5V;IAJyD;EALtC;;EAYvBlG,mBAAmBye,uBAAnBze,CAA2ClH,UAAUS,iBAArDyG;AAnPa;;gCAsPO;EACpB,KAAKkB,IAAL,CAAUrK,GAAV,CAAc,oCAAd,EAAoDoG,IAApD,CAAyDkP,OAAO;IAC9D,KAAK2T,YAAL,CAAkBznB,KAAlB,GAA0B8T,GAA1B;EADF;;EAIA,IAAI,CAAC,KAAKyT,MAAV,EAAkB;IAGhB,KAAKE,YAAL,CAAkBn5B,SAAlB,CAA4BsH,GAA5B,CAAgCi/C,qBAAhC;EARkB;AAtPP;;gCAkQoB;EAAA,IAAfziC,KAAe,uEAAP,KAAO;;EACjC,IAAI,KAAKmV,MAAL,IAAenV,KAAnB,EAA0B;IAGxB,KAAKqV,YAAL,CAAkBn5B,SAAlB,CAA4ByK,MAA5B,CAAmC87C,qBAAnC;EAJ+B;;EAOjC,IAAIziC,KAAJ,EAAW;IACT,KAAKvJ,IAAL,CAAUrK,GAAV,CAAc,sBAAd,EAAsCoG,IAAtC,CAA2CkP,OAAO;MAChD,KAAK2T,YAAL,CAAkBznB,KAAlB,GAA0B8T,GAA1B;IADF;EAR+B;AAlQpB;;+BAgRM;EACnB,KAAKkhC,gBAAL,CAAsBjlD,gBAAtB,CAAuC,eAAvC,EAAwDZ,OAAO;IAC7D,IAAIA,IAAIwQ,MAAJxQ,KAAe,KAAK6lD,gBAAxB,EAA0C;MACxC,KAAKD,cAAL,CAAoBzmD,SAApB,CAA8ByK,MAA9B,CAAqC,eAArC;IAF2D;EAA/D;EAMA,KAAK0uB,YAAL,CAAkB13B,gBAAlB,CAAmC,OAAnC,EAA4C,MAAM;IAChD,KAAK40B,MAAL;EADF;EAKA,KAAKswB,eAAL,CAAqBllD,gBAArB,CAAsC,OAAtC,EAA+C,MAAM;IACnD,KAAK00B,UAAL,CAAgBn5B,sBAAYE,MAA5B;EADF;EAIA,KAAK0pD,aAAL,CAAmBnlD,gBAAnB,CAAoC,OAApC,EAA6C,MAAM;IACjD,KAAK00B,UAAL,CAAgBn5B,sBAAYG,OAA5B;EADF;EAGA,KAAKypD,aAAL,CAAmBnlD,gBAAnB,CAAoC,UAApC,EAAgD,MAAM;IACpD,KAAKqQ,QAAL,CAAcwC,QAAd,CAAuB,mBAAvB,EAA4C;MAAEC,QAAQ;IAAV,CAA5C;EADF;EAIA,KAAKsyC,iBAAL,CAAuBplD,gBAAvB,CAAwC,OAAxC,EAAiD,MAAM;IACrD,KAAK00B,UAAL,CAAgBn5B,sBAAYI,WAA5B;EADF;EAIA,KAAK0pD,YAAL,CAAkBrlD,gBAAlB,CAAmC,OAAnC,EAA4C,MAAM;IAChD,KAAK00B,UAAL,CAAgBn5B,sBAAYK,MAA5B;EADF;EAGA,KAAKypD,YAAL,CAAkBrlD,gBAAlB,CAAmC,UAAnC,EAA+C,MAAM;IACnD,KAAKqQ,QAAL,CAAcwC,QAAd,CAAuB,aAAvB,EAAsC;MAAEC,QAAQ;IAAV,CAAtC;EADF;;EAKA,KAAK0yC,yBAAL,CAA+BxlD,gBAA/B,CAAgD,OAAhD,EAAyD,MAAM;IAC7D,KAAKqQ,QAAL,CAAcwC,QAAd,CAAuB,oBAAvB,EAA6C;MAAEC,QAAQ;IAAV,CAA7C;EADF;;EAKA,MAAMozC,eAAe,CAACzb,KAAD,EAAQxO,MAAR,EAAgBr5B,IAAhB,KAAyB;IAC5Cq5B,OAAOypB,QAAPzpB,GAAkB,CAACwO,KAAnBxO;;IAEA,IAAIwO,KAAJ,EAAW;MACT;IADF,OAEO,IAAI,KAAK9S,MAAL,KAAgB/0B,IAApB,EAA0B;MAG/B,KAAK8xB,UAAL,CAAgBn5B,sBAAYE,MAA5B;IAR0C;EAA9C;;EAYA,KAAK4U,QAAL,CAAcgZ,GAAd,CAAkB,eAAlB,EAAmCjqB,OAAO;IACxC8mD,aAAa9mD,IAAIm+C,YAAjB,EAA+B,KAAK4H,aAApC,EAAmD5pD,sBAAYG,OAA/D;IAEA0D,IAAIo+C,yBAAJp+C,CAA8ByV,IAA9BzV,CAAmC0Q,WAAW;MAC5C,IAAI,CAAC,KAAKkJ,gBAAV,EAA4B;QAC1B;MAF0C;;MAI5C,KAAKwsC,yBAAL,CAA+BE,QAA/B,GAA0C,CAAC51C,OAA3C;IAJF;EAHF;;EAWA,KAAKO,QAAL,CAAcgZ,GAAd,CAAkB,mBAAlB,EAAuCjqB,OAAO;IAC5C8mD,aACE9mD,IAAIoqC,gBADN,EAEE,KAAK4b,iBAFP,EAGE7pD,sBAAYI,WAHd;EADF;;EAQA,KAAK0U,QAAL,CAAcgZ,GAAd,CAAkB,cAAlB,EAAkCjqB,OAAO;IACvC8mD,aAAa9mD,IAAIg9C,WAAjB,EAA8B,KAAKiJ,YAAnC,EAAiD9pD,sBAAYK,MAA7D;EADF;;EAKA,KAAKyU,QAAL,CAAcgZ,GAAd,CAAkB,yBAAlB,EAA6CjqB,OAAO;IAClD,IACEA,IAAIM,KAAJN,KAAclE,gCAAsBE,MAApCgE,IACA,KAAKouB,WAAL,KAAqBjyB,sBAAYE,MAFnC,EAGE;MACA;IALgD;EAApD;AA5Va;;;;;;;;;;;;;AC/CjB;;AAEA,MAAM0qD,oBAAoB,iBAA1B;AACA,MAAMC,oBAAoB,GAA1B;AACA,MAAMC,yBAAyB,iBAA/B;;AAUA,MAAM3mC,iBAAN,CAAwB;EAMtB5iB,YAAYgS,OAAZ,EAAqBuB,QAArB,EAA+ByI,IAA/B,EAAqC;IACnC,KAAKwtC,KAAL,GAAa,KAAb;IACA,KAAKC,WAAL,GAAmB,KAAnB;IACA,KAAKC,MAAL,GAAc,IAAd;IACA,KAAKC,oBAAL,GAA4B,IAA5B;IACA,KAAKptC,YAAL,GAAoB5R,OAAO6C,MAAP7C,CAAc,IAAdA,CAApB;IAEA,KAAKu9C,cAAL,GAAsBl2C,QAAQk2C,cAA9B;IACA,KAAK0B,OAAL,GAAe53C,QAAQ43C,OAAvB;IACA,KAAKr2C,QAAL,GAAgBA,QAAhB;IAEAyI,KAAKyC,YAALzC,GAAoBjE,IAApBiE,CAAyBwC,OAAO;MAC9B,KAAKgrC,KAAL,GAAahrC,QAAQ,KAArB;IADF;;IAGA,KAAKqrC,kBAAL;EApBoB;;EA0BtB,IAAIC,mBAAJ,GAA0B;IACxB,OAAQ,KAAKH,oBAAb,KAAQ,KAAKA,oBAAb,GAAsC,KAAKzB,cAAL,CAAoB3mD,WAA1D;EA3BoB;;EAkCtBwoD,eAAwB;IAAA,IAAXzjD,KAAW,uEAAH,CAAG;IAGtB,MAAM0jD,WAAWnlD,KAAKC,KAALD,CAAW,KAAKilD,mBAAL,GAA2B,CAAtCjlD,CAAjB;;IACA,IAAIyB,QAAQ0jD,QAAZ,EAAsB;MACpB1jD,QAAQ0jD,QAAR1jD;IALoB;;IAOtB,IAAIA,QAAQgjD,iBAAZ,EAA+B;MAC7BhjD,QAAQgjD,iBAARhjD;IARoB;;IAWtB,IAAIA,UAAU,KAAKojD,MAAnB,EAA2B;MACzB,OAAO,KAAP;IAZoB;;IActB,KAAKA,MAAL,GAAcpjD,KAAd;;IAEA8E,mBAASe,WAATf,CAAqBi+C,iBAArBj+C,EAAwC,GAAG9E,KAAM,IAAjD8E;;IACA,OAAO,IAAP;EAnDoB;;EAyDtB6+C,WAAW3nD,GAAX,EAAgB;IACd,IAAIgE,QAAQhE,IAAIg4B,OAAhB;;IAEA,IAAI,KAAKkvB,KAAT,EAAgB;MACdljD,QAAQ,KAAKwjD,mBAAL,GAA2BxjD,KAAnCA;IAJY;;IAMd,KAAKyjD,YAAL,CAAkBzjD,KAAlB;EA/DoB;;EAqEtB4jD,SAAS5nD,GAAT,EAAc;IAEZ,KAAK4lD,cAAL,CAAoBzmD,SAApB,CAA8ByK,MAA9B,CAAqCq9C,sBAArC;IAEA,KAAKh2C,QAAL,CAAcwC,QAAd,CAAuB,QAAvB,EAAiC;MAAEC,QAAQ;IAAV,CAAjC;IAEA,MAAMuG,eAAe,KAAKA,YAA1B;IACArc,OAAO8vB,mBAAP9vB,CAA2B,WAA3BA,EAAwCqc,aAAa4tC,SAArDjqD;IACAA,OAAO8vB,mBAAP9vB,CAA2B,SAA3BA,EAAsCqc,aAAa6tC,OAAnDlqD;EA7EoB;;EAmFtB2pD,qBAAqB;IACnB,MAAMttC,eAAe,KAAKA,YAA1B;IACAA,aAAa4tC,SAAb5tC,GAAyB,KAAK0tC,UAAL,CAAgBnqC,IAAhB,CAAqB,IAArB,CAAzBvD;IACAA,aAAa6tC,OAAb7tC,GAAuB,KAAK2tC,QAAL,CAAcpqC,IAAd,CAAmB,IAAnB,CAAvBvD;IAEA,KAAKqtC,OAAL,CAAa1mD,gBAAb,CAA8B,WAA9B,EAA2CZ,OAAO;MAChD,IAAIA,IAAI68B,MAAJ78B,KAAe,CAAnB,EAAsB;QACpB;MAF8C;;MAMhD,KAAK4lD,cAAL,CAAoBzmD,SAApB,CAA8BsH,GAA9B,CAAkCwgD,sBAAlC;MAEArpD,OAAOgD,gBAAPhD,CAAwB,WAAxBA,EAAqCqc,aAAa4tC,SAAlDjqD;MACAA,OAAOgD,gBAAPhD,CAAwB,SAAxBA,EAAmCqc,aAAa6tC,OAAhDlqD;IATF;;IAYA,KAAKqT,QAAL,CAAcgZ,GAAd,CAAkB,oBAAlB,EAAwCjqB,OAAO;MAC7C,KAAKmnD,WAAL,GAAmB,CAAC,EAACnnD,GAAD,aAACA,GAAD,eAACA,IAAKwD,IAAN,CAApB;IADF;;IAIA,KAAKyN,QAAL,CAAcgZ,GAAd,CAAkB,QAAlB,EAA4BjqB,OAAO;MAGjC,IAAIA,+CAAK0T,MAAL1T,MAAgBpC,MAApB,EAA4B;QAC1B;MAJ+B;;MAOjC,KAAKypD,oBAAL,GAA4B,IAA5B;;MAEA,IAAI,CAAC,KAAKD,MAAV,EAAkB;QAEhB;MAX+B;;MAejC,IAAI,CAAC,KAAKD,WAAV,EAAuB;QACrB,KAAKM,YAAL,CAAkB,KAAKL,MAAvB;;QACA;MAjB+B;;MAmBjC,KAAKxB,cAAL,CAAoBzmD,SAApB,CAA8BsH,GAA9B,CAAkCwgD,sBAAlC;;MACA,MAAMc,UAAU,KAAKN,YAAL,CAAkB,KAAKL,MAAvB,CAAhB;;MAEAx+C,QAAQC,OAARD,GAAkB6M,IAAlB7M,CAAuB,MAAM;QAC3B,KAAKg9C,cAAL,CAAoBzmD,SAApB,CAA8ByK,MAA9B,CAAqCq9C,sBAArC;;QAGA,IAAIc,OAAJ,EAAa;UACX,KAAK92C,QAAL,CAAcwC,QAAd,CAAuB,QAAvB,EAAiC;YAAEC,QAAQ;UAAV,CAAjC;QALyB;MAA7B;IAtBF;EAxGoB;;AAAA;;;;;;;;;;;;;;;ACPxB;;AAOA;;;;;;;;AAEA,MAAMs0C,0BAA0B,CAAC,EAAjC;AACA,MAAMC,2BAA2B,UAAjC;;;;;;AAkBA,MAAMzpC,kBAAN,CAAyB;EAIvB9gB,kBAOG;IAAA,IAPS;MACVsM,SADU;MAEViH,QAFU;MAGV0M,WAHU;MAIVW,cAJU;MAKV5E,IALU;MAMVsE;IANU,CAOT;;IAAA;;IAAA;;IACD,KAAKhU,SAAL,GAAiBA,SAAjB;IACA,KAAK2T,WAAL,GAAmBA,WAAnB;IACA,KAAKW,cAAL,GAAsBA,cAAtB;IACA,KAAK5E,IAAL,GAAYA,IAAZ;IACA,KAAKsE,UAAL,GAAkBA,cAAc,IAAhC;;IAGE,IACE,KAAKA,UAAL,IACA,EACEkqC,IAAIC,QAAJD,CAAa,OAAbA,EAAsB,KAAKlqC,UAAL,CAAgBG,UAAtC+pC,KACAA,IAAIC,QAAJD,CAAa,OAAbA,EAAsB,KAAKlqC,UAAL,CAAgBI,UAAtC8pC,CAFF,CAFF,EAME;MACA,IAAI,KAAKlqC,UAAL,CAAgBG,UAAhB,IAA8B,KAAKH,UAAL,CAAgBI,UAAlD,EAA8D;QAC5D7f,QAAQid,IAARjd,CACE,sGADFA;MAFF;;MAMA,KAAKyf,UAAL,GAAkB,IAAlB;IApBH;;IAwBD,KAAKgQ,MAAL,GAAcpuB,2BAAY,KAAKoK,SAAjBpK,EAA4B,KAAKwoD,cAAL,CAAoB5qC,IAApB,CAAyB,IAAzB,CAA5B5d,CAAd;;IACA,KAAKyoD,UAAL;EApCqB;;EA0CvBD,iBAAiB;IACf,KAAK9pC,cAAL,CAAoB+P,qBAApB;EA3CqB;;EA8CvB+G,aAAajxB,KAAb,EAAoB;IAClB,OAAO,KAAKmkD,WAAL,CAAiBnkD,KAAjB,CAAP;EA/CqB;;EAqDvBokD,oBAAoB;IAClB,OAAO/jD,kCAAmB;MACxBC,UAAU,KAAKuF,SADS;MAExB5F,OAAO,KAAKkkD;IAFY,CAAnB9jD,CAAP;EAtDqB;;EA4DvByyB,wBAAwBvkB,UAAxB,EAAoC;IAClC,IAAI,CAAC,KAAKrB,WAAV,EAAuB;MACrB;IAFgC;;IAIlC,MAAMqN,gBAAgB,KAAK4pC,WAAL,CAAiB51C,aAAa,CAA9B,CAAtB;;IAEA,IAAI,CAACgM,aAAL,EAAoB;MAClBngB,QAAQC,KAARD,CAAc,0DAAdA;MACA;IARgC;;IAWlC,IAAImU,eAAe,KAAKi6B,kBAAxB,EAA4C;MAC1C,MAAM6b,oBAAoB,KAAKF,WAAL,CAAiB,KAAK3b,kBAAL,GAA0B,CAA3C,CAA1B;MAEA6b,kBAAkBplD,GAAlBolD,CAAsBrpD,SAAtBqpD,CAAgC5+C,MAAhC4+C,CAAuCP,wBAAvCO;MAEA9pC,cAActb,GAAdsb,CAAkBvf,SAAlBuf,CAA4BjY,GAA5BiY,CAAgCupC,wBAAhCvpC;IAhBgC;;IAkBlC,MAAM;MAAEhY,KAAF;MAASC,IAAT;MAAevC;IAAf,IAAyB,KAAKmkD,iBAAL,EAA/B;;IAGA,IAAInkD,MAAMlC,MAANkC,GAAe,CAAnB,EAAsB;MACpB,IAAIqkD,eAAe,KAAnB;;MACA,IAAI/1C,cAAchM,MAAMJ,EAApBoM,IAA0BA,cAAc/L,KAAKL,EAAjD,EAAqD;QACnDmiD,eAAe,IAAfA;MADF,OAEO;QACL,WAAW;UAAEniD,EAAF;UAAMF;QAAN,CAAX,IAA8BhC,KAA9B,EAAqC;UACnC,IAAIkC,OAAOoM,UAAX,EAAuB;YACrB;UAFiC;;UAInC+1C,eAAeriD,UAAU,GAAzBqiD;UACA;QANG;MAJa;;MAapB,IAAIA,YAAJ,EAAkB;QAChBxqD,8BAAeygB,cAActb,GAA7BnF,EAAkC;UAAEsB,KAAKyoD;QAAP,CAAlC/pD;MAdkB;IArBY;;IAuClC,KAAK0uC,kBAAL,GAA0Bj6B,UAA1B;EAnGqB;;EAsGvB,IAAIT,aAAJ,GAAoB;IAClB,OAAO,KAAK26B,cAAZ;EAvGqB;;EA0GvB,IAAI36B,aAAJ,CAAkBD,QAAlB,EAA4B;IAC1B,IAAI,CAAChK,+BAAgBgK,QAAhBhK,CAAL,EAAgC;MAC9B,MAAM,IAAIuB,KAAJ,CAAU,oCAAV,CAAN;IAFwB;;IAI1B,IAAI,CAAC,KAAK8H,WAAV,EAAuB;MACrB;IALwB;;IAO1B,IAAI,KAAKu7B,cAAL,KAAwB56B,QAA5B,EAAsC;MACpC;IARwB;;IAU1B,KAAK46B,cAAL,GAAsB56B,QAAtB;IAEA,MAAM02C,aAAa;MAAE12C;IAAF,CAAnB;;IACA,WAAW22C,SAAX,IAAwB,KAAKL,WAA7B,EAA0C;MACxCK,UAAU1/B,MAAV0/B,CAAiBD,UAAjBC;IAdwB;EA1GL;;EA4HvBzlC,UAAU;IACR,WAAWylC,SAAX,IAAwB,KAAKL,WAA7B,EAA0C;MACxC,IAAIK,UAAU5yB,cAAV4yB,KAA6BltD,0BAAgBI,QAAjD,EAA2D;QACzD8sD,UAAU1lC,KAAV0lC;MAFsC;IADlC;;IAMRC,qCAAiBC,aAAjBD;EAlIqB;;EAwIvBP,aAAa;IACX,KAAKC,WAAL,GAAmB,EAAnB;IACA,KAAK3b,kBAAL,GAA0B,CAA1B;IACA,KAAKmc,WAAL,GAAmB,IAAnB;IACA,KAAKlc,cAAL,GAAsB,CAAtB;IAGA,KAAK5iC,SAAL,CAAemc,WAAf,GAA6B,EAA7B;EA/IqB;;EAqJvB3U,YAAYH,WAAZ,EAAyB;IACvB,IAAI,KAAKA,WAAT,EAAsB;MACpB,KAAK03C,gBAAL;;MACA,KAAKV,UAAL;IAHqB;;IAMvB,KAAKh3C,WAAL,GAAmBA,WAAnB;;IACA,IAAI,CAACA,WAAL,EAAkB;MAChB;IARqB;;IAUvB,MAAM4V,mBAAmB5V,YAAYm8B,OAAZn8B,CAAoB,CAApBA,CAAzB;IACA,MAAMoY,+BAA+BpY,YAAYwsC,wBAAZxsC,EAArC;IAEA4V,iBACGxR,IADHwR,CACQ+hC,gBAAgB;MACpB,MAAMp3C,aAAaP,YAAYQ,QAA/B;MACA,MAAMo3C,WAAWD,aAAaE,WAAbF,CAAyB;QAAErzB,OAAO;MAAT,CAAzBqzB,CAAjB;;MAEA,KAAK,IAAIl0C,UAAU,CAAnB,EAAsBA,WAAWlD,UAAjC,EAA6C,EAAEkD,OAA/C,EAAwD;QACtD,MAAM6zC,YAAY,IAAIQ,oCAAJ,CAAqB;UACrCn/C,WAAW,KAAKA,SADqB;UAErC1D,IAAIwO,OAFiC;UAGrCs0C,iBAAiBH,SAAS5gB,KAAT4gB,EAHoB;UAIrCx/B,4BAJqC;UAKrC9L,aAAa,KAAKA,WALmB;UAMrCW,gBAAgB,KAAKA,cANgB;UAOrC5E,MAAM,KAAKA,IAP0B;UAQrCsE,YAAY,KAAKA;QARoB,CAArB,CAAlB;;QAUA,KAAKsqC,WAAL,CAAiBjiD,IAAjB,CAAsBsiD,SAAtB;MAfkB;;MAoBpB,MAAMU,qBAAqB,KAAKf,WAAL,CAAiB,CAAjB,CAA3B;;MACA,IAAIe,kBAAJ,EAAwB;QACtBA,mBAAmBC,UAAnBD,CAA8BL,YAA9BK;MAtBkB;;MA0BpB,MAAM3qC,gBAAgB,KAAK4pC,WAAL,CAAiB,KAAK3b,kBAAL,GAA0B,CAA3C,CAAtB;MACAjuB,cAActb,GAAdsb,CAAkBvf,SAAlBuf,CAA4BjY,GAA5BiY,CAAgCupC,wBAAhCvpC;IA5BJ,GA8BG/I,KA9BHsR,CA8BSxL,UAAU;MACfld,QAAQC,KAARD,CAAc,uCAAdA,EAAuDkd,MAAvDld;IA/BJ;EAlKqB;;EAwMvBwqD,mBAAmB;IACjB,WAAWJ,SAAX,IAAwB,KAAKL,WAA7B,EAA0C;MACxCK,UAAUY,eAAVZ;IAFe;EAxMI;;EAiNvB17B,cAAcN,MAAd,EAAsB;IACpB,IAAI,CAAC,KAAKtb,WAAV,EAAuB;MACrB;IAFkB;;IAIpB,IAAI,CAACsb,MAAL,EAAa;MACX,KAAKm8B,WAAL,GAAmB,IAAnB;IADF,OAEO,IACL,EAAEv2C,MAAMC,OAAND,CAAcoa,MAAdpa,KAAyB,KAAKlB,WAAL,CAAiBQ,QAAjB,KAA8B8a,OAAOzqB,MAAhE,CADK,EAEL;MACA,KAAK4mD,WAAL,GAAmB,IAAnB;MACAvqD,QAAQC,KAARD,CAAc,wDAAdA;IAJK,OAKA;MACL,KAAKuqD,WAAL,GAAmBn8B,MAAnB;IAZkB;;IAepB,KAAK,IAAIpoB,IAAI,CAAR,EAAWkY,KAAK,KAAK6rC,WAAL,CAAiBpmD,MAAtC,EAA8CqC,IAAIkY,EAAlD,EAAsDlY,GAAtD,EAA2D;MAAA;;MACzD,KAAK+jD,WAAL,CAAiB/jD,CAAjB,EAAoBilD,YAApB,6CAAiC,KAAKV,WAAtC,sDAAiC,kBAAmBvkD,CAAnB,CAAjC,qEAA0D,IAA1D;IAhBkB;EAjNC;;EAkQvB8b,iBAAiB;IACf,MAAMopC,gBAAgB,KAAKlB,iBAAL,EAAtB;;IACA,MAAMmB,qCAAc,IAAd,0CAAc,IAAd,EAAmCD,aAAnC,CAAN;;IACA,MAAME,YAAY,KAAKrrC,cAAL,CAAoByjC,kBAApB,CAChB0H,aADgB,EAEhB,KAAKnB,WAFW,EAGhBoB,WAHgB,CAAlB;;IAKA,IAAIC,SAAJ,EAAe;MACb,qFAA0BA,SAA1B,EAAqCl0C,IAArC,CAA0C,MAAM;QAC9C,KAAK6I,cAAL,CAAoBskC,UAApB,CAA+B+G,SAA/B;MADF;;MAGA,OAAO,IAAP;IAZa;;IAcf,OAAO,KAAP;EAhRqB;;AAAA;;;;qCAyOIA,WAAW;EACpC,IAAIA,UAAU1hC,OAAd,EAAuB;IACrB,OAAO0hC,UAAU1hC,OAAjB;EAFkC;;EAIpC,IAAI;IACF,MAAMA,UAAU,MAAM,KAAK5W,WAAL,CAAiBm8B,OAAjB,CAAyBmc,UAAUrjD,EAAnC,CAAtB;;IACA,IAAI,CAACqjD,UAAU1hC,OAAf,EAAwB;MACtB0hC,UAAUL,UAAVK,CAAqB1hC,OAArB0hC;IAHA;;IAKF,OAAO1hC,OAAP;EALF,EAME,OAAOxM,MAAP,EAAe;IACfld,QAAQC,KAARD,CAAc,mCAAdA,EAAmDkd,MAAnDld;IACA,OAAO,IAAP;EAZkC;AAzOf;;0BAyPP4G,SAAS;EAAA;;EACvB,IAAIA,2BAAQuB,KAARvB,kEAAemB,EAAfnB,MAAsB,CAA1B,EAA6B;IAC3B,OAAO,IAAP;EADF,OAEO,IAAIA,0BAAQwB,IAARxB,gEAAcmB,EAAdnB,MAAqB,KAAKmjD,WAAL,CAAiBpmD,MAA1C,EAAkD;IACvD,OAAO,KAAP;EAJqB;;EAMvB,OAAO,KAAK8rB,MAAL,CAAYttB,IAAnB;AA/PqB;;;;;;;;;;;;;AC7BzB;;AACA;;;;;;;;;;;;;;AAEA,MAAMkpD,sBAAsB,CAA5B;AACA,MAAMC,wBAAwB,CAA9B;AACA,MAAMC,gCAAgC,CAAtC;AACA,MAAMC,kBAAkB,EAAxB;;AAkBA,MAAMnB,gBAAN,CAAuB;EAGrB,OAAOoB,SAAP,CAAiBhmD,KAAjB,EAAwBC,MAAxB,EAAgC;IAC9B,MAAMgmD,6CAAc,IAAd,EAJJrB,gBAII,kDAAc,IAAd,EAJJA,gBAII,eAAmC7/C,SAAS2zB,aAAT3zB,CAAuB,QAAvBA,CAAnC,CAAN;;IACAkhD,WAAWjmD,KAAXimD,GAAmBjmD,KAAnBimD;IACAA,WAAWhmD,MAAXgmD,GAAoBhmD,MAApBgmD;IAIA,MAAMC,MAAMD,WAAWE,UAAXF,CAAsB,IAAtBA,EAA4B;MAAEG,OAAO;IAAT,CAA5BH,CAAZ;IACAC,IAAIrnC,IAAJqnC;IACAA,IAAIG,SAAJH,GAAgB,oBAAhBA;IACAA,IAAII,QAAJJ,CAAa,CAAbA,EAAgB,CAAhBA,EAAmBlmD,KAAnBkmD,EAA0BjmD,MAA1BimD;IACAA,IAAIK,OAAJL;IACA,OAAO,CAACD,UAAD,EAAaA,WAAWE,UAAXF,CAAsB,IAAtBA,CAAb,CAAP;EAfmB;;EAkBrB,OAAOpB,aAAP,GAAuB;IACrB,MAAMoB,6CAAa,IAAb,EAnBJrB,gBAmBI,cAAN;;IACA,IAAIqB,UAAJ,EAAgB;MAGdA,WAAWjmD,KAAXimD,GAAmB,CAAnBA;MACAA,WAAWhmD,MAAXgmD,GAAoB,CAApBA;IANmB;;IAQrB,sCA1BErB,gBA0BF,eAAmB,IAAnB;EA1BmB;;AAAA;;;;;SACA;;;AAgCvB,MAAMO,gBAAN,CAAuB;EAIrBzrD,kBASG;IAAA,IATS;MACVsM,SADU;MAEV1D,EAFU;MAGV8iD,eAHU;MAIV3/B,4BAJU;MAKV9L,WALU;MAMVW,cANU;MAOV5E,IAPU;MAQVsE;IARU,CAST;IACD,KAAK1X,EAAL,GAAUA,EAAV;IACA,KAAKs7C,WAAL,GAAmB,cAAct7C,EAAjC;IACA,KAAK0wB,SAAL,GAAiB,IAAjB;IAEA,KAAK/O,OAAL,GAAe,IAAf;IACA,KAAKjW,QAAL,GAAgB,CAAhB;IACA,KAAKi3C,QAAL,GAAgBG,eAAhB;IACA,KAAKoB,aAAL,GAAqBpB,gBAAgBp3C,QAArC;IACA,KAAKy4C,6BAAL,GAAqChhC,gCAAgC,IAArE;IACA,KAAKzL,UAAL,GAAkBA,cAAc,IAAhC;IAEA,KAAKL,WAAL,GAAmBA,WAAnB;IACA,KAAKW,cAAL,GAAsBA,cAAtB;IAEA,KAAKosC,UAAL,GAAkB,IAAlB;IACA,KAAK30B,cAAL,GAAsBt6B,0BAAgBC,OAAtC;IACA,KAAKmnD,MAAL,GAAc,IAAd;IAEA,MAAM8H,YAAY,KAAK1B,QAAL,CAAcjlD,KAAhC;IAAA,MACE4mD,aAAa,KAAK3B,QAAL,CAAchlD,MAD7B;IAAA,MAEE4mD,YAAYF,YAAYC,UAF1B;IAIA,KAAKE,WAAL,GAAmBf,eAAnB;IACA,KAAKgB,YAAL,GAAqB,KAAKD,WAAL,GAAmBD,SAAnB,GAAgC,CAArD;IACA,KAAKl1B,KAAL,GAAa,KAAKm1B,WAAL,GAAmBH,SAAhC;IAEA,KAAKjxC,IAAL,GAAYA,IAAZ;IAEA,MAAMrG,SAAStK,SAAS2zB,aAAT3zB,CAAuB,GAAvBA,CAAf;IACAsK,OAAOzC,IAAPyC,GAAcsK,YAAY1K,YAAZ0K,CAAyB,WAAWrX,EAApCqX,CAAdtK;;IACA,KAAK23C,eAAL,CAAqBv1C,IAArB,CAA0BkP,OAAO;MAC/BtR,OAAOxC,KAAPwC,GAAesR,GAAftR;IADF;;IAGAA,OAAOvC,OAAPuC,GAAiB,YAAY;MAC3BsK,YAAYlL,QAAZkL,CAAqBrX,EAArBqX;MACA,OAAO,KAAP;IAFF;;IAIA,KAAKtK,MAAL,GAAcA,MAAd;IAEA,MAAMjQ,MAAM2F,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAZ;IACA3F,IAAIu5B,SAAJv5B,GAAgB,WAAhBA;IACAA,IAAI6/B,YAAJ7/B,CAAiB,kBAAjBA,EAAqC,KAAKkD,EAA1ClD;IACA,KAAKA,GAAL,GAAWA,GAAX;IAEA,MAAM6nD,OAAOliD,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAb;IACAkiD,KAAKtuB,SAALsuB,GAAiB,wBAAjBA;IACA,MAAMC,mBAAmB,IAAIpB,6BAA7B;IACAmB,KAAKhiD,KAALgiD,CAAWjnD,KAAXinD,GAAmB,KAAKH,WAAL,GAAmBI,gBAAnB,GAAsC,IAAzDD;IACAA,KAAKhiD,KAALgiD,CAAWhnD,MAAXgnD,GAAoB,KAAKF,YAAL,GAAoBG,gBAApB,GAAuC,IAA3DD;IACA,KAAKA,IAAL,GAAYA,IAAZ;IAEA7nD,IAAIy6B,MAAJz6B,CAAW6nD,IAAX7nD;IACAiQ,OAAOwqB,MAAPxqB,CAAcjQ,GAAdiQ;IACArJ,UAAU6zB,MAAV7zB,CAAiBqJ,MAAjBrJ;EAnEmB;;EAsErBs/C,WAAWrhC,OAAX,EAAoB;IAClB,KAAKA,OAAL,GAAeA,OAAf;IACA,KAAKuiC,aAAL,GAAqBviC,QAAQvkB,MAA7B;IACA,MAAMynD,gBAAiB,MAAKn5C,QAAL,GAAgB,KAAKw4C,aAArB,IAAsC,GAA7D;IACA,KAAKvB,QAAL,GAAgBhhC,QAAQihC,WAARjhC,CAAoB;MAAE0N,OAAO,CAAT;MAAY3jB,UAAUm5C;IAAtB,CAApBljC,CAAhB;IACA,KAAKhF,KAAL;EA3EmB;;EA8ErBA,QAAQ;IACN,KAAKsmC,eAAL;IACA,KAAKxzB,cAAL,GAAsBt6B,0BAAgBC,OAAtC;IAEA,MAAMivD,YAAY,KAAK1B,QAAL,CAAcjlD,KAAhC;IAAA,MACE4mD,aAAa,KAAK3B,QAAL,CAAchlD,MAD7B;IAAA,MAEE4mD,YAAYF,YAAYC,UAF1B;IAIA,KAAKG,YAAL,GAAqB,KAAKD,WAAL,GAAmBD,SAAnB,GAAgC,CAArD;IACA,KAAKl1B,KAAL,GAAa,KAAKm1B,WAAL,GAAmBH,SAAhC;IAEA,KAAKvnD,GAAL,CAASmhC,eAAT,CAAyB,aAAzB;IACA,MAAM0mB,OAAO,KAAKA,IAAlB;IACAA,KAAK9kC,WAAL8kC,GAAmB,EAAnBA;IACA,MAAMC,mBAAmB,IAAIpB,6BAA7B;IACAmB,KAAKhiD,KAALgiD,CAAWjnD,KAAXinD,GAAmB,KAAKH,WAAL,GAAmBI,gBAAnB,GAAsC,IAAzDD;IACAA,KAAKhiD,KAALgiD,CAAWhnD,MAAXgnD,GAAoB,KAAKF,YAAL,GAAoBG,gBAApB,GAAuC,IAA3DD;;IAEA,IAAI,KAAKG,MAAT,EAAiB;MAGf,KAAKA,MAAL,CAAYpnD,KAAZ,GAAoB,CAApB;MACA,KAAKonD,MAAL,CAAYnnD,MAAZ,GAAqB,CAArB;MACA,OAAO,KAAKmnD,MAAZ;IAvBI;;IAyBN,IAAI,KAAKC,KAAT,EAAgB;MACd,KAAKA,KAAL,CAAW9mB,eAAX,CAA2B,KAA3B;MACA,OAAO,KAAK8mB,KAAZ;IA3BI;EA9Ea;;EA6GrBpiC,cAA4B;IAAA,IAArB;MAAEjX,WAAW;IAAb,CAAqB;;IAC1B,IAAI,OAAOA,QAAP,KAAoB,QAAxB,EAAkC;MAChC,KAAKA,QAAL,GAAgBA,QAAhB;IAFwB;;IAI1B,MAAMm5C,gBAAiB,MAAKn5C,QAAL,GAAgB,KAAKw4C,aAArB,IAAsC,GAA7D;IACA,KAAKvB,QAAL,GAAgB,KAAKA,QAAL,CAAc5gB,KAAd,CAAoB;MAClC1S,OAAO,CAD2B;MAElC3jB,UAAUm5C;IAFwB,CAApB,CAAhB;IAIA,KAAKloC,KAAL;EAtHmB;;EA6HrBsmC,kBAAkB;IAChB,IAAI,KAAKmB,UAAT,EAAqB;MACnB,KAAKA,UAAL,CAAgBY,MAAhB;MACA,KAAKZ,UAAL,GAAkB,IAAlB;IAHc;;IAKhB,KAAK7H,MAAL,GAAc,IAAd;EAlImB;;EAwIrB0I,sBAAuC;IAAA,IAAnBC,aAAmB,uEAAH,CAAG;IAGrC,MAAMJ,SAASriD,SAAS2zB,aAAT3zB,CAAuB,QAAvBA,CAAf;IACA,MAAMmhD,MAAMkB,OAAOjB,UAAPiB,CAAkB,IAAlBA,EAAwB;MAAEhB,OAAO;IAAT,CAAxBgB,CAAZ;IACA,MAAMK,cAAc,IAAIhuD,qBAAJ,EAApB;IAEA2tD,OAAOpnD,KAAPonD,GAAgBI,gBAAgB,KAAKV,WAArBU,GAAmCC,YAAY3tD,EAA/C0tD,GAAqD,CAArEJ;IACAA,OAAOnnD,MAAPmnD,GAAiBI,gBAAgB,KAAKT,YAArBS,GAAoCC,YAAY1tD,EAAhDytD,GAAsD,CAAvEJ;IAEA,MAAMM,YAAYD,YAAYztD,MAAZytD,GACd,CAACA,YAAY3tD,EAAb,EAAiB,CAAjB,EAAoB,CAApB,EAAuB2tD,YAAY1tD,EAAnC,EAAuC,CAAvC,EAA0C,CAA1C,CADc0tD,GAEd,IAFJ;IAIA,OAAO;MAAEvB,GAAF;MAAOkB,MAAP;MAAeM;IAAf,CAAP;EAtJmB;;EA4JrBC,sBAAsBP,MAAtB,EAA8B;IAC5B,IAAI,KAAKr1B,cAAL,KAAwBt6B,0BAAgBI,QAA5C,EAAsD;MACpD,MAAM,IAAI0N,KAAJ,CAAU,oDAAV,CAAN;IAF0B;;IAI5B,MAAMqiD,gBAAgB,KAAKC,YAAL,CAAkBT,MAAlB,CAAtB;;IAEA,MAAMC,QAAQtiD,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAd;IACAsiD,MAAM1uB,SAAN0uB,GAAkB,gBAAlBA;;IACA,KAAKS,gBAAL,CAAsBr2C,IAAtB,CAA2BkP,OAAO;MAChC0mC,MAAMpoB,YAANooB,CAAmB,YAAnBA,EAAiC1mC,GAAjC0mC;IADF;;IAGAA,MAAMpiD,KAANoiD,CAAYrnD,KAAZqnD,GAAoB,KAAKP,WAAL,GAAmB,IAAvCO;IACAA,MAAMpiD,KAANoiD,CAAYpnD,MAAZonD,GAAqB,KAAKN,YAAL,GAAoB,IAAzCM;IAEAA,MAAMU,GAANV,GAAYO,cAAcI,SAAdJ,EAAZP;IACA,KAAKA,KAAL,GAAaA,KAAb;IAEA,KAAKjoD,GAAL,CAAS6/B,YAAT,CAAsB,aAAtB,EAAqC,IAArC;IACA,KAAKgoB,IAAL,CAAUptB,MAAV,CAAiBwtB,KAAjB;IAIAO,cAAc5nD,KAAd4nD,GAAsB,CAAtBA;IACAA,cAAc3nD,MAAd2nD,GAAuB,CAAvBA;EAnLmB;;EAsLrB9I,OAAO;IAAA;;IACL,IAAI,KAAK/sB,cAAL,KAAwBt6B,0BAAgBC,OAA5C,EAAqD;MACnD6C,QAAQC,KAARD,CAAc,qCAAdA;MACA,OAAOqK,QAAQC,OAARD,EAAP;IAHG;;IAKL,MAAM;MAAEqf;IAAF,IAAc,IAApB;;IAEA,IAAI,CAACA,OAAL,EAAc;MACZ,KAAK8N,cAAL,GAAsBt6B,0BAAgBI,QAAtC;MACA,OAAO+M,QAAQ8xB,MAAR9xB,CAAe,IAAIW,KAAJ,CAAU,uBAAV,CAAfX,CAAP;IATG;;IAYL,KAAKmtB,cAAL,GAAsBt6B,0BAAgBE,OAAtC;;IAEA,MAAMswD,mBAAmB,kBAAwB;MAAA,IAAjBztD,KAAiB,uEAAT,IAAS;;MAI/C,IAAIksD,eAAe,MAAKA,UAAxB,EAAoC;QAClC,MAAKA,UAAL,GAAkB,IAAlB;MAL6C;;MAQ/C,IAAIlsD,iBAAiBwkD,qCAArB,EAAkD;QAChD;MAT6C;;MAW/C,MAAKjtB,cAAL,GAAsBt6B,0BAAgBI,QAAtC;;MACA,MAAK8vD,qBAAL,CAA2BP,MAA3B;;MAEA,IAAI5sD,KAAJ,EAAW;QACT,MAAMA,KAAN;MAf6C;IAAjD;;IAwBA,MAAM;MAAE0rD,GAAF;MAAOkB,MAAP;MAAeM;IAAf,IACJ,KAAKH,mBAAL,CAAyB3B,mBAAzB,CADF;;IAEA,MAAMsC,eAAe,KAAKjD,QAAL,CAAc5gB,KAAd,CAAoB;MACvC1S,OAAOi0B,sBAAsB,KAAKj0B;IADK,CAApB,CAArB;;IAGA,MAAMw2B,yBAAyBC,QAAQ;MACrC,IAAI,CAAC,KAAK9tC,cAAL,CAAoBqjC,iBAApB,CAAsC,IAAtC,CAAL,EAAkD;QAChD,KAAK5rB,cAAL,GAAsBt6B,0BAAgBG,MAAtC;;QACA,KAAKinD,MAAL,GAAc,MAAM;UAClB,KAAK9sB,cAAL,GAAsBt6B,0BAAgBE,OAAtC;UACAywD;QAFF;;QAIA;MAPmC;;MASrCA;IATF;;IAYA,MAAMC,gBAAgB;MACpBC,eAAepC,GADK;MAEpBwB,SAFoB;MAGpBzC,UAAUiD,YAHU;MAIpBziC,8BAA8B,KAAKghC,6BAJf;MAKpBzsC,YAAY,KAAKA;IALG,CAAtB;IAOA,MAAM0sC,aAAc,KAAKA,UAAL,GAAkBziC,QAAQqB,MAARrB,CAAeokC,aAAfpkC,CAAtC;IACAyiC,WAAW6B,UAAX7B,GAAwByB,sBAAxBzB;IAEA,MAAM8B,gBAAgB9B,WAAW5pC,OAAX4pC,CAAmBj1C,IAAnBi1C,CACpB,YAAY;MACV,OAAOuB,iBAAiB,IAAjB,CAAP;IAFkB,GAIpB,UAAUztD,KAAV,EAAiB;MACf,OAAOytD,iBAAiBztD,KAAjB,CAAP;IALkB,EAAtB;IAQAguD,cAAczJ,OAAdyJ,CAAsB,MAAM;MAG1BpB,OAAOpnD,KAAPonD,GAAe,CAAfA;MACAA,OAAOnnD,MAAPmnD,GAAgB,CAAhBA;MAIA,MAAMqB,aAAa,KAAK9uC,WAAL,CAAiBtI,YAAjB,CAA8B,KAAK/O,EAAnC,CAAnB;;MACA,IAAI,CAACmmD,UAAL,EAAiB;QAAA;;QACf,sBAAKxkC,OAAL,gEAAc/E,OAAd;MAVwB;IAA5B;IAcA,OAAOspC,aAAP;EA7QmB;;EAgRrBn3B,SAASf,QAAT,EAAmB;IACjB,IAAI,KAAKyB,cAAL,KAAwBt6B,0BAAgBC,OAA5C,EAAqD;MACnD;IAFe;;IAIjB,MAAM;MAAEgxD,iBAAiBtB,MAAnB;MAA2BnjC,OAA3B;MAAoC0N;IAApC,IAA8CrB,QAApD;;IACA,IAAI,CAAC82B,MAAL,EAAa;MACX;IANe;;IAQjB,IAAI,CAAC,KAAKnjC,OAAV,EAAmB;MACjB,KAAKqhC,UAAL,CAAgBrhC,OAAhB;IATe;;IAWjB,IAAI0N,QAAQ,KAAKA,KAAjB,EAAwB;MAEtB;IAbe;;IAejB,KAAKI,cAAL,GAAsBt6B,0BAAgBI,QAAtC;;IACA,KAAK8vD,qBAAL,CAA2BP,MAA3B;EAhSmB;;EAsSrBS,aAAac,GAAb,EAAkB;IAChB,MAAM;MAAEzC,GAAF;MAAOkB;IAAP,IAAkB,KAAKG,mBAAL,EAAxB;;IAEA,IAAIoB,IAAI3oD,KAAJ2oD,IAAa,IAAIvB,OAAOpnD,KAA5B,EAAmC;MACjCkmD,IAAI0C,SAAJ1C,CACEyC,GADFzC,EAEE,CAFFA,EAGE,CAHFA,EAIEyC,IAAI3oD,KAJNkmD,EAKEyC,IAAI1oD,MALNimD,EAME,CANFA,EAOE,CAPFA,EAQEkB,OAAOpnD,KARTkmD,EASEkB,OAAOnnD,MATTimD;MAWA,OAAOkB,MAAP;IAfc;;IAkBhB,IAAIyB,eAAezB,OAAOpnD,KAAPonD,IAAgBvB,qBAAnC;IACA,IAAIiD,gBAAgB1B,OAAOnnD,MAAPmnD,IAAiBvB,qBAArC;IACA,MAAM,CAACkD,YAAD,EAAeC,eAAf,IAAkCpE,iBAAiBoB,SAAjBpB,CACtCiE,YADsCjE,EAEtCkE,aAFsClE,CAAxC;;IAKA,OAAOiE,eAAeF,IAAI3oD,KAAnB6oD,IAA4BC,gBAAgBH,IAAI1oD,MAAvD,EAA+D;MAC7D4oD,iBAAiB,CAAjBA;MACAC,kBAAkB,CAAlBA;IA3Bc;;IA6BhBE,gBAAgBJ,SAAhBI,CACEL,GADFK,EAEE,CAFFA,EAGE,CAHFA,EAIEL,IAAI3oD,KAJNgpD,EAKEL,IAAI1oD,MALN+oD,EAME,CANFA,EAOE,CAPFA,EAQEH,YARFG,EASEF,aATFE;;IAWA,OAAOH,eAAe,IAAIzB,OAAOpnD,KAAjC,EAAwC;MACtCgpD,gBAAgBJ,SAAhBI,CACED,YADFC,EAEE,CAFFA,EAGE,CAHFA,EAIEH,YAJFG,EAKEF,aALFE,EAME,CANFA,EAOE,CAPFA,EAQEH,gBAAgB,CARlBG,EASEF,iBAAiB,CATnBE;MAWAH,iBAAiB,CAAjBA;MACAC,kBAAkB,CAAlBA;IArDc;;IAuDhB5C,IAAI0C,SAAJ1C,CACE6C,YADF7C,EAEE,CAFFA,EAGE,CAHFA,EAIE2C,YAJF3C,EAKE4C,aALF5C,EAME,CANFA,EAOE,CAPFA,EAQEkB,OAAOpnD,KARTkmD,EASEkB,OAAOnnD,MATTimD;IAWA,OAAOkB,MAAP;EAxWmB;;EA2WrB,IAAIJ,eAAJ,GAAsB;IAAA;;IACpB,OAAO,KAAKtxC,IAAL,CAAUrK,GAAV,CAAc,kBAAd,EAAkC;MACvCyC,yBAAM,KAAKklB,SAAX,6DAAwB,KAAK1wB;IADU,CAAlC,CAAP;EA5WmB;;EAiXrB,IAAIwlD,gBAAJ,GAAuB;IAAA;;IACrB,OAAO,KAAKpyC,IAAL,CAAUrK,GAAV,CAAc,mBAAd,EAAmC;MACxCyC,0BAAM,KAAKklB,SAAX,+DAAwB,KAAK1wB;IADW,CAAnC,CAAP;EAlXmB;;EA0XrBkjD,aAAax8B,KAAb,EAAoB;IAClB,KAAKgK,SAAL,GAAiB,OAAOhK,KAAP,KAAiB,QAAjB,GAA4BA,KAA5B,GAAoC,IAArD;;IAEA,KAAKg+B,eAAL,CAAqBv1C,IAArB,CAA0BkP,OAAO;MAC/B,KAAKtR,MAAL,CAAYxC,KAAZ,GAAoB8T,GAApB;IADF;;IAIA,IAAI,KAAKoR,cAAL,KAAwBt6B,0BAAgBI,QAA5C,EAAsD;MACpD;IARgB;;IAWlB,KAAKiwD,gBAAL,CAAsBr2C,IAAtB,CAA2BkP,OAAO;MAAA;;MAChC,oBAAK0mC,KAAL,4DAAYpoB,YAAZ,CAAyB,YAAzB,EAAuCte,GAAvC;IADF;EArYmB;;AAAA;;;;;;;;;;;;;;;AC/DvB;;AACA;;AAEA,MAAMtG,SAAN,SAAwB4uC,uBAAxB,CAAmC;;;;AAEnC,MAAMC,mBAAN,SAAkCD,uBAAlC,CAA6C;EAC3C5E,aAAa;IACX,MAAMA,UAAN;;IACA,KAAK8E,WAAL,GAAmBnwD,qBAAWI,IAA9B;IACA,KAAKgwD,WAAL,GAAmB/vD,qBAAWjB,IAA9B;EAJyC;;EAQ3C,IAAI0O,UAAJ,CAAe1C,IAAf,EAAqB,CARsB;;EAU3CilD,oBAAoB,CAVuB;;EAa3C,IAAItiD,UAAJ,CAAe3C,IAAf,EAAqB,CAbsB;;EAe3CklD,oBAAoB,CAfuB;;AAAA;;;;;;;;;;;;;;;ACe7C;;AASA;;AAyBA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;;;;;;;;;;;;;;;;;;;;;AAEA,MAAMC,qBAAqB,EAA3B;AACA,MAAMC,2BAA2B,mBAAjC;AAEA,MAAMC,kBAAkB;EACtBC,wBAAwB,KADF;EAEtBC,sBAAsB,IAFA;EAGtBC,uBAAuB;AAHD,CAAxB;;;AAMA,SAASC,2BAAT,CAAqCzlD,IAArC,EAA2C;EACzC,OACEC,OAAOC,MAAPD,CAAc0W,8BAAd1W,EAAoCE,QAApCF,CAA6CD,IAA7CC,KACAD,SAAS2W,+BAAqBliB,OAFhC;AA1FF;;;;;;;;mBAoMGixD,OAAOC;;AAxDV,MAAMC,iBAAN,CAAwB;EAMtBtwD,YAAYgL,IAAZ,EAAkB;IAAA;;IAAA;MAAA;MAAA,OAJX,IAAIrD,GAAJ;IAIW;;IAAA;MAAA;MAAA,OAFV;IAEU;;IAChB,mCAAaqD,IAAb;EAPoB;;EAUtBrC,KAAK7C,IAAL,EAAW;IACT,MAAMyqD,4BAAM,IAAN,OAAN;;IACA,IAAIA,IAAIz6C,GAAJy6C,CAAQzqD,IAARyqD,CAAJ,EAAmB;MACjBA,IAAIpkC,MAAJokC,CAAWzqD,IAAXyqD;IAHO;;IAKTA,IAAIxnD,GAAJwnD,CAAQzqD,IAARyqD;;IAEA,IAAIA,IAAIvlD,IAAJulD,yBAAW,IAAXA,QAAJ,EAA2B;MACzB;IARO;EAVW;;EA6BtBC,OAAOC,OAAP,EAAkC;IAAA,IAAlBC,SAAkB,uEAAN,IAAM;;IAChC,mCAAaD,OAAb;;IAEA,MAAMF,4BAAM,IAAN,OAAN;;IACA,IAAIG,SAAJ,EAAe;MACb,MAAM3xC,KAAKwxC,IAAIvlD,IAAf;MACA,IAAInE,IAAI,CAAR;;MACA,WAAWf,IAAX,IAAmByqD,GAAnB,EAAwB;QACtB,IAAIG,UAAU56C,GAAV46C,CAAc5qD,KAAK8C,EAAnB8nD,CAAJ,EAA4B;UAC1BH,IAAIpkC,MAAJokC,CAAWzqD,IAAXyqD;UACAA,IAAIxnD,GAAJwnD,CAAQzqD,IAARyqD;QAHoB;;QAKtB,IAAI,EAAE1pD,CAAF,GAAMkY,EAAV,EAAc;UACZ;QANoB;MAHX;IAJiB;;IAkBhC,OAAOwxC,IAAIvlD,IAAJulD,yBAAW,IAAXA,QAAP,EAA8B;MAC5B;IAnB8B;EA7BZ;;EAoDtBz6C,IAAIhQ,IAAJ,EAAU;IACR,OAAO,kCAAUgQ,GAAV,CAAchQ,IAAd,CAAP;EArDoB;;EAwDtB,qBAAoB;IAClB,OAAO,kCAAUsM,IAAV,EAAP;EAzDoB;;AAAA;;;;8BA4DF;EAClB,MAAMu+C,YAAY,kCAAUv+C,IAAV,GAAiBw+C,IAAjB,GAAwBptD,KAA1C;;EAEAmtD,gEAAWtrC,OAAXsrC;;EACA,kCAAUxkC,MAAV,CAAiBwkC,SAAjB;AAhEoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6ExB,MAAMpB,UAAN,CAAiB;EAoBfvvD,YAAYgS,OAAZ,EAAqB;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;MAAA;MAAA,OAnBX;IAmBW;;IAAA;MAAA;MAAA,OAjBGqP,+BAAqBliB;IAiBxB;;IAAA;MAAA;MAAA,OAfQ;IAeR;;IAAA;MAAA;MAAA,OAbH0xD,yBAAeC;IAaZ;;IAAA;MAAA;MAAA,OAXA;IAWA;;IAAA;MAAA;MAAA,OATM;IASN;;IAAA;MAAA;MAAA,OAPE;IAOF;;IAAA;MAAA;MAAA,OALC;IAKD;;IACnB,IAAI,KAAK9wD,WAAL,KAAqBuvD,UAAzB,EAAqC;MACnC,MAAM,IAAI1jD,KAAJ,CAAU,+BAAV,CAAN;IAFiB;;IAInB,MAAMklD,gBAC8B,UADpC;;IAEA,IAAI7oC,sBAAY6oC,aAAhB,EAA+B;MAC7B,MAAM,IAAIllD,KAAJ,CACH,oBAAmBqc,iBAAQ,wCAAuC6oC,aAAc,IAD7E,CAAN;IAPiB;;IAWnB,KAAKzkD,SAAL,GAAiB0F,QAAQ1F,SAAzB;IACA,KAAKD,MAAL,GAAc2F,QAAQ3F,MAAR2F,IAAkBA,QAAQ1F,SAAR0F,CAAkBs8B,iBAAlD;;IAME,IACE,EACE,yBAAKhiC,SAAL,oEAAgBmvB,OAAhB,CAAwBC,WAAxB,QAA0C,KAA1C,IACA,sBAAKrvB,MAAL,8DAAaovB,OAAb,CAAqBC,WAArB,QAAuC,KAFzC,CADF,EAKE;MACA,MAAM,IAAI7vB,KAAJ,CAAU,6CAAV,CAAN;IAxBe;;IA2BjB,IACE,KAAKS,SAAL,CAAe1L,YAAf,IACAe,iBAAiB,KAAK2K,SAAtB,EAAiC82B,QAAjCzhC,KAA8C,UAFhD,EAGE;MACA,MAAM,IAAIkK,KAAJ,CAAU,gDAAV,CAAN;IA/Be;;IAkCnB,KAAK0H,QAAL,GAAgBvB,QAAQuB,QAAxB;IACA,KAAK0M,WAAL,GAAmBjO,QAAQiO,WAARjO,IAAuB,IAAIsG,mCAAJ,EAA1C;IACA,KAAKqD,eAAL,GAAuB3J,QAAQ2J,eAAR3J,IAA2B,IAAlD;IACA,KAAK+N,cAAL,GAAsB/N,QAAQ+N,cAAR/N,IAA0B,IAAhD;IACA,KAAKg/C,iBAAL,GAAyBh/C,QAAQ6O,gBAAR7O,IAA4B,IAArD;IACA,KAAKi/C,iBAAL,GAAyBj/C,QAAQi/C,iBAARj/C,IAA6B,KAAtD;IACA,KAAKjC,aAAL,4BAAqBiC,QAAQjC,aAA7B,yEAA8C7Q,wBAAcE,MAA5D;;IACA,sEACE4S,QAAQtD,cADV,yEAC4BmiD,yBAAeC,YAD3C;;IAEA,4EACE9+C,QAAQxD,oBADV,yEACkC6S,+BAAqBliB,OADvD;;IAEA,KAAKmQ,kBAAL,GAA0B0C,QAAQ1C,kBAAR0C,IAA8B,EAAxD;IACA,KAAKhD,qBAAL,GAA6BgD,QAAQhD,qBAARgD,IAAiC,KAA9D;IAKE,KAAKT,QAAL,GAAgBS,QAAQT,QAARS,IAAoBjT,uBAAaC,MAAjD;IAEF,KAAKgR,cAAL,GAAsBgC,QAAQhC,cAARgC,IAA0B,KAAhD;IACA,KAAK/D,eAAL,GAAuB+D,QAAQ/D,eAA/B;IACA,KAAK+N,IAAL,GAAYhK,QAAQgK,IAARhK,IAAgBk/C,oBAA5B;;IACA,gDAA0Bl/C,QAAQjD,iBAARiD,IAA6B,KAAvD;;IACA,KAAKsO,UAAL,GAAkBtO,QAAQsO,UAARtO,IAAsB,IAAxC;;IAGE,IACE,KAAKsO,UAAL,IACA,EACEkqC,IAAIC,QAAJD,CAAa,OAAbA,EAAsB,KAAKlqC,UAAL,CAAgBG,UAAtC+pC,KACAA,IAAIC,QAAJD,CAAa,OAAbA,EAAsB,KAAKlqC,UAAL,CAAgBI,UAAtC8pC,CAFF,CAFF,EAME;MACA,IAAI,KAAKlqC,UAAL,CAAgBG,UAAhB,IAA8B,KAAKH,UAAL,CAAgBI,UAAlD,EAA8D;QAC5D7f,QAAQid,IAARjd,CACE,8FADFA;MAFF;;MAMA,KAAKyf,UAAL,GAAkB,IAAlB;IAxEe;;IA4EnB,KAAK6wC,qBAAL,GAA6B,CAACn/C,QAAQ4O,cAAtC;;IACA,IAAI,KAAKuwC,qBAAT,EAAgC;MAE9B,KAAKvwC,cAAL,GAAsB,IAAIjB,sCAAJ,EAAtB;MACA,KAAKiB,cAAL,CAAoB5M,SAApB,CAA8B,IAA9B;IAHF,OAIO;MACL,KAAK4M,cAAL,GAAsB5O,QAAQ4O,cAA9B;IAlFiB;;IAqFnB,KAAK0P,MAAL,GAAcpuB,2BAAY,KAAKoK,SAAjBpK,EAA4B,KAAKkvD,aAAL,CAAmBtxC,IAAnB,CAAwB,IAAxB,CAA5B5d,CAAd;IACA,KAAK61B,qBAAL,GAA6B35B,gCAAsBC,OAAnD;IACA,KAAKgzD,aAAL,GAAqB,KAAKC,YAAL,GAAoB,IAAzC;;IACA,KAAK3G,UAAL;;IAEA,IAAI,KAAKsG,iBAAT,EAA4B;MAC1B,KAAK5kD,MAAL,CAAY5K,SAAZ,CAAsBsH,GAAtB,CAA0B,mBAA1B;IA3FiB;;IA6FnB,KAAKuvB,wBAAL;EAjHa;;EAoHf,IAAIpkB,UAAJ,GAAiB;IACf,OAAO,KAAKq9C,MAAL,CAAY/sD,MAAnB;EArHa;;EAwHfqyB,YAAYpwB,KAAZ,EAAmB;IACjB,OAAO,KAAK8qD,MAAL,CAAY9qD,KAAZ,CAAP;EAzHa;;EA+Hf,IAAIsqB,cAAJ,GAAqB;IACnB,IAAI,CAAC,KAAKygC,gBAAL,CAAsBtuC,OAA3B,EAAoC;MAClC,OAAO,KAAP;IAFiB;;IAMnB,OAAO,KAAKquC,MAAL,CAAYE,KAAZ,CAAkB,UAAU76B,QAAV,EAAoB;MAC3C,OAAOA,QAAP,aAAOA,QAAP,uBAAOA,SAAUrM,OAAjB;IADK,EAAP;EArIa;;EA6If,IAAIkE,WAAJ,GAAkB;IAChB,OAAO,iDAAyBoiC,yBAAeC,YAA/C;EA9Ia;;EAoJf,IAAI7hD,eAAJ,GAAsB;IACpB,OAAO,CAAC,CAAC,KAAK+hD,iBAAd;EArJa;;EA2Jf,IAAI38C,iBAAJ,GAAwB;IACtB,OAAO,KAAK46B,kBAAZ;EA5Ja;;EAkKf,IAAI56B,iBAAJ,CAAsBrI,GAAtB,EAA2B;IACzB,IAAI,CAACzB,OAAOC,SAAPD,CAAiByB,GAAjBzB,CAAL,EAA4B;MAC1B,MAAM,IAAIsB,KAAJ,CAAU,sBAAV,CAAN;IAFuB;;IAIzB,IAAI,CAAC,KAAK8H,WAAV,EAAuB;MACrB;IALuB;;IAQzB,IAAI,CAAC,KAAK+9C,qBAAL,CAA2B1lD,GAA3B,EAA6D,IAA7D,CAAL,EAAyE;MACvEnL,QAAQC,KAARD,CAAe,uBAAsBmL,GAAI,wBAAzCnL;IATuB;EAlKZ;;EAmLf6wD,sBAAsB1lD,GAAtB,EAAyD;IAAA;;IAAA,IAA9B2lD,oBAA8B,uEAAP,KAAO;;IACvD,IAAI,KAAK1iB,kBAAL,KAA4BjjC,GAAhC,EAAqC;MACnC,IAAI2lD,oBAAJ,EAA0B;QACxB;MAFiC;;MAInC,OAAO,IAAP;IALqD;;IAQvD,IAAI,EAAE,IAAI3lD,GAAJ,IAAWA,OAAO,KAAKkI,UAAzB,CAAJ,EAA0C;MACxC,OAAO,KAAP;IATqD;;IAWvD,MAAM+kB,WAAW,KAAKgW,kBAAtB;IACA,KAAKA,kBAAL,GAA0BjjC,GAA1B;IAEA,KAAKuH,QAAL,CAAcwC,QAAd,CAAuB,cAAvB,EAAuC;MACrCC,QAAQ,IAD6B;MAErChB,YAAYhJ,GAFyB;MAGrCstB,sDAAW,KAAK8xB,WAAhB,uDAAW,mBAAmBp/C,MAAM,CAAzB,CAAX,iEAA0C,IAHL;MAIrCitB;IAJqC,CAAvC;;IAOA,IAAI04B,oBAAJ,EAA0B;MACxB;IAtBqD;;IAwBvD,OAAO,IAAP;EA3Ma;;EAkNf,IAAIliC,gBAAJ,GAAuB;IAAA;;IACrB,mDAAO,KAAK27B,WAAZ,uDAAO,mBAAmB,KAAKnc,kBAAL,GAA0B,CAA7C,CAAP,mEAA0D,IAA1D;EAnNa;;EAyNf,IAAIxf,gBAAJ,CAAqBzjB,GAArB,EAA0B;IACxB,IAAI,CAAC,KAAK2H,WAAV,EAAuB;MACrB;IAFsB;;IAIxB,IAAIS,OAAOpI,MAAM,CAAjB;;IACA,IAAI,KAAKo/C,WAAT,EAAsB;MACpB,MAAMvkD,IAAI,KAAKukD,WAAL,CAAiBxgB,OAAjB,CAAyB5+B,GAAzB,CAAV;;MACA,IAAInF,KAAK,CAAT,EAAY;QACVuN,OAAOvN,IAAI,CAAXuN;MAHkB;IALE;;IAYxB,IAAI,CAAC,KAAKs9C,qBAAL,CAA2Bt9C,IAA3B,EAA8D,IAA9D,CAAL,EAA0E;MACxEvT,QAAQC,KAARD,CAAe,sBAAqBmL,GAAI,wBAAxCnL;IAbsB;EAzNX;;EA6Of,IAAIg5B,YAAJ,GAAmB;IACjB,OAAO,KAAK+3B,aAAL,KAAuBj0D,uBAAvB,GACH,KAAKi0D,aADF,GAEHr0D,uBAFJ;EA9Oa;;EAsPf,IAAIs8B,YAAJ,CAAiB7tB,GAAjB,EAAsB;IACpB,IAAIC,MAAMD,GAAN,CAAJ,EAAgB;MACd,MAAM,IAAIH,KAAJ,CAAU,wBAAV,CAAN;IAFkB;;IAIpB,IAAI,CAAC,KAAK8H,WAAV,EAAuB;MACrB;IALkB;;IAOpB,KAAKk+C,SAAL,CAAe7lD,GAAf,EAAoB,KAApB;EA7Pa;;EAmQf,IAAI4X,iBAAJ,GAAwB;IACtB,OAAO,KAAKkuC,kBAAZ;EApQa;;EA0Qf,IAAIluC,iBAAJ,CAAsB5X,GAAtB,EAA2B;IACzB,IAAI,CAAC,KAAK2H,WAAV,EAAuB;MACrB;IAFuB;;IAIzB,KAAKk+C,SAAL,CAAe7lD,GAAf,EAAoB,KAApB;EA9Qa;;EAoRf,IAAIuI,aAAJ,GAAoB;IAClB,OAAO,KAAK26B,cAAZ;EArRa;;EA2Rf,IAAI36B,aAAJ,CAAkBD,QAAlB,EAA4B;IAC1B,IAAI,CAAChK,+BAAgBgK,QAAhBhK,CAAL,EAAgC;MAC9B,MAAM,IAAIuB,KAAJ,CAAU,+BAAV,CAAN;IAFwB;;IAI1B,IAAI,CAAC,KAAK8H,WAAV,EAAuB;MACrB;IALwB;;IAQ1BW,YAAY,GAAZA;;IACA,IAAIA,WAAW,CAAf,EAAkB;MAChBA,YAAY,GAAZA;IAVwB;;IAY1B,IAAI,KAAK46B,cAAL,KAAwB56B,QAA5B,EAAsC;MACpC;IAbwB;;IAe1B,KAAK46B,cAAL,GAAsB56B,QAAtB;IAEA,MAAMU,aAAa,KAAKi6B,kBAAxB;IAEA,MAAM+b,aAAa;MAAE12C;IAAF,CAAnB;;IACA,WAAWsiB,QAAX,IAAuB,KAAK26B,MAA5B,EAAoC;MAClC36B,SAASrL,MAATqL,CAAgBo0B,UAAhBp0B;IArBwB;;IAyB1B,IAAI,KAAKk7B,kBAAT,EAA6B;MAC3B,KAAKD,SAAL,CAAe,KAAKC,kBAApB,EAAwC,IAAxC;IA1BwB;;IA6B1B,KAAKv+C,QAAL,CAAcwC,QAAd,CAAuB,kBAAvB,EAA2C;MACzCC,QAAQ,IADiC;MAEzCzB,eAAeD,QAF0B;MAGzCU;IAHyC,CAA3C;;IAMA,IAAI,KAAKm8C,qBAAT,EAAgC;MAC9B,KAAK5lC,MAAL;IApCwB;EA3Rb;;EAmUf,IAAIhC,gBAAJ,GAAuB;IACrB,OAAO,KAAK5V,WAAL,GAAmB,KAAKwjC,oBAAL,CAA0B/zB,OAA7C,GAAuD,IAA9D;EApUa;;EAuUf,IAAI4G,eAAJ,GAAsB;IACpB,OAAO,KAAKrW,WAAL,GAAmB,KAAKo+C,0BAAL,CAAgC3uC,OAAnD,GAA6D,IAApE;EAxUa;;EA2Uf,IAAI6G,YAAJ,GAAmB;IACjB,OAAO,KAAKtW,WAAL,GAAmB,KAAK69C,gBAAL,CAAsBpuC,OAAzC,GAAmD,IAA1D;EA5Ua;;EA8ZftP,YAAYH,WAAZ,EAAyB;IACvB,IAAI,KAAKA,WAAT,EAAsB;MACpB,KAAKJ,QAAL,CAAcwC,QAAd,CAAuB,cAAvB,EAAuC;QAAEC,QAAQ;MAAV,CAAvC;;MAEA,KAAKq1C,gBAAL;;MACA,KAAKV,UAAL;;MAEA,IAAI,KAAK5qC,cAAT,EAAyB;QACvB,KAAKA,cAAL,CAAoBjM,WAApB,CAAgC,IAAhC;MAPkB;;MASpB,IAAI,KAAKk9C,iBAAT,EAA4B;QAC1B,KAAKA,iBAAL,CAAuBl9C,WAAvB,CAAmC,IAAnC;MAVkB;;MAYpB,0BAAI,IAAJ,+BAAqC;QACnC,wDAAgCuR,OAAhC;;QACA,wDAAkC,IAAlC;MAdkB;IADC;;IAmBvB,KAAK1R,WAAL,GAAmBA,WAAnB;;IACA,IAAI,CAACA,WAAL,EAAkB;MAChB;IArBqB;;IAuBvB,MAAM4a,YAAY5a,YAAY4a,SAA9B;IACA,MAAMra,aAAaP,YAAYQ,QAA/B;IACA,MAAMoV,mBAAmB5V,YAAYm8B,OAAZn8B,CAAoB,CAApBA,CAAzB;IAEA,MAAMoY,+BAA+BpY,YAAYwsC,wBAAZxsC,EAArC;IACA,MAAMq+C,qBAAqB,kDACvBr+C,YAAYs+C,cAAZt+C,EADuB,GAEvBzI,QAAQC,OAARD,EAFJ;;IAMA,IAAIgJ,aAAa67C,gBAAgBC,sBAAjC,EAAyD;MACvDnvD,QAAQid,IAARjd,CACE,mFADFA;MAGA,MAAM6J,OAAQ,KAAK+kD,WAAL,GAAmBnwD,qBAAWI,IAA5C;MACA,KAAK6T,QAAL,CAAcwC,QAAd,CAAuB,mBAAvB,EAA4C;QAAEC,QAAQ,IAAV;QAAgBtL;MAAhB,CAA5C;IAvCqB;;IA0CvB,KAAK8mD,gBAAL,CAAsBpuC,OAAtB,CAA8BrL,IAA9B,CACE,MAAM;MACJ,KAAKxE,QAAL,CAAcwC,QAAd,CAAuB,aAAvB,EAAsC;QAAEC,QAAQ,IAAV;QAAgB9B;MAAhB,CAAtC;IAFJ,GAIE,MAAM,CAJR;;IASA,KAAKm9C,aAAL,GAAqB/uD,OAAO;MAC1B,MAAMs0B,WAAW,KAAK26B,MAAL,CAAYjvD,IAAI0S,UAAJ1S,GAAiB,CAA7B,CAAjB;;MACA,IAAI,CAACs0B,QAAL,EAAe;QACb;MAHwB;;MAO1B,qCAAajuB,IAAb,CAAkBiuB,QAAlB;IAPF;;IASA,KAAKrjB,QAAL,CAAcgZ,GAAd,CAAkB,YAAlB,EAAgC,KAAK8kC,aAArC;;IAEA,KAAKC,YAAL,GAAoBhvD,OAAO;MACzB,IAAIA,IAAI4vD,YAAJ5vD,IAAoB,KAAKyvD,0BAAL,CAAgC7uC,OAAxD,EAAiE;QAC/D;MAFuB;;MAIzB,KAAK6uC,0BAAL,CAAgC5mD,OAAhC,CAAwC;QAAEsgB,WAAWnpB,IAAImpB;MAAjB,CAAxC;;MAEA,KAAKlY,QAAL,CAAc6hB,IAAd,CAAmB,cAAnB,EAAmC,KAAKk8B,YAAxC;;MACA,KAAKA,YAAL,GAAoB,IAApB;;MAEA,0BAAI,IAAJ,wBAA8B;QAC5BjmD,SAAS2kB,mBAAT3kB,CACE,kBADFA,wBAEE,IAFFA;;QAIA,iDAA2B,IAA3B;MAduB;IAA3B;;IAiBA,KAAKkI,QAAL,CAAcgZ,GAAd,CAAkB,cAAlB,EAAkC,KAAK+kC,YAAvC;;IAIApmD,QAAQua,GAARva,CAAY,CAACqe,gBAAD,EAAmByoC,kBAAnB,CAAZ9mD,EACG6M,IADH7M,CACQ,QAAiC;MAAA,IAAhC,CAACogD,YAAD,EAAe6G,WAAf,CAAgC;;MACrC,IAAIx+C,gBAAgB,KAAKA,WAAzB,EAAsC;QACpC;MAFmC;;MAIrC,KAAKwjC,oBAAL,CAA0BhsC,OAA1B,CAAkCmgD,YAAlC;;MACA,KAAKyB,6BAAL,GAAqChhC,4BAArC;;MAEA,MAAM;QAAEvd,oBAAF;QAAwBE,cAAxB;QAAwCqB;MAAxC,2BACJ,IADI,wDACJ,IADI,EACwBoiD,WADxB,CAAN;;MAGA,IAAI3jD,yBAAyB6S,+BAAqBliB,OAAlD,EAA2D;QACzD,MAAMuL,OAAO8D,oBAAb;;QAEA,IAAI+f,SAAJ,EAAe;UACb1tB,QAAQid,IAARjd,CAAa,0CAAbA;QADF,OAEO,IAAIsvD,4BAA4BzlD,IAA5B,CAAJ,EAAuC;UAC5C,wDAAkC,IAAI0nD,mCAAJ,CAChC,KAAK9lD,SAD2B,EAEhC,KAAKiH,QAF2B,CAAlC;;UAIA,IAAI7I,SAAS2W,+BAAqB3iB,IAAlC,EAAwC;YACtC,wDAAgC2zD,UAAhC,CAA2C3nD,IAA3C;UAN0C;QAAvC,OAQA;UACL7J,QAAQC,KAARD,CAAe,kCAAiC6J,IAAlC,EAAd7J;QAduD;MAVtB;;MA4BrC,MAAMyxD,gBACJ,KAAK7C,WAAL,KAAqBnwD,qBAAWI,IAAhC,GAAuC,IAAvC,GAA8C,KAAK2M,MADrD;MAEA,MAAM4rB,QAAQ,KAAK4B,YAAnB;MACA,MAAM0xB,WAAWD,aAAaE,WAAbF,CAAyB;QACxCrzB,OAAOA,QAAQs6B,wBAAcC;MADW,CAAzBlH,CAAjB;MAGA,MAAMmH,mBACJ1iD,kBAAkB7Q,wBAAcC,OAAhC4Q,IAA2C,CAACwe,SAA5Cxe,GAAwD,IAAxDA,GAA+D,IADjE;MAEA,MAAM2iD,yBACJhkD,mBAAmBmiD,yBAAe1xD,OAAlCuP,GAA4C,IAA5CA,GAAmD,IADrD;MAEA,MAAMikD,kBAAkBpkC,YAAY,IAAZ,GAAmB,IAA3C;MACA,MAAMqkC,+BAA+B,0DACjC,IADiC,GAEjC,IAFJ;;MAIA,KAAK,IAAIx7C,UAAU,CAAnB,EAAsBA,WAAWlD,UAAjC,EAA6C,EAAEkD,OAA/C,EAAwD;QACtD,MAAMwf,WAAW,IAAIi8B,0BAAJ,CAAgB;UAC/BvmD,WAAWgmD,aADoB;UAE/B/+C,UAAU,KAAKA,QAFgB;UAG/B3K,IAAIwO,OAH2B;UAI/B6gB,KAJ+B;UAK/ByzB,iBAAiBH,SAAS5gB,KAAT4gB,EALc;UAM/Bx/B,4BAN+B;UAO/BnL,gBAAgB,KAAKA,cAPU;UAQ/B6xC,gBAR+B;UAS/B1iD,aAT+B;UAU/B2iD,sBAV+B;UAW/BhkD,cAX+B;UAY/BikD,eAZ+B;UAa/BC,4BAb+B;UAc/BE,wBAAwB,IAdO;UAe/BC,wBAAwB,IAfO;UAgB/BzjD,oBAAoB,KAAKA,kBAhBM;UAiB/BiC,UAGM,KAAKA,QApBoB;UAsB/BvB,gBAAgB,KAAKA,cAtBU;UAuB/B/B,iBAAiB,KAAKA,eAvBS;UAwB/BqS,YAAY,KAAKA,UAxBc;UAyB/BtE,MAAM,KAAKA;QAzBoB,CAAhB,CAAjB;;QA2BA,KAAKu1C,MAAL,CAAY5oD,IAAZ,CAAiBiuB,QAAjB;MAvEmC;;MA4ErC,MAAMo8B,gBAAgB,KAAKzB,MAAL,CAAY,CAAZ,CAAtB;;MACA,IAAIyB,aAAJ,EAAmB;QACjBA,cAAcpH,UAAdoH,CAAyB1H,YAAzB0H;QACA,KAAK/yC,WAAL,CAAiB9I,YAAjB,CAA8B,CAA9B,EAAiCm0C,aAAa2H,GAA9C;MA/EmC;;MAkFrC,IAAI,KAAKxD,WAAL,KAAqBnwD,qBAAWI,IAApC,EAA0C;QAExC;MAFF,OAGO,IAAI,KAAKgwD,WAAL,KAAqB/vD,qBAAWjB,IAApC,EAA0C;QAC/C,KAAKkxD,iBAAL;MAtFmC;;MA4FrC,qGAAoC73C,IAApC,CAAyC,YAAY;QACnD,IAAI,KAAKgI,cAAT,EAAyB;UACvB,KAAKA,cAAL,CAAoBjM,WAApB,CAAgCH,WAAhC;QAFiD;;QAInD,IAAI,KAAKq9C,iBAAT,EAA4B;UAC1B,KAAKA,iBAAL,CAAuBl9C,WAAvB,CAAmCH,WAAnC;QALiD;;QAQnD,0BAAI,IAAJ,+BAAqC;UAEnC,KAAKJ,QAAL,CAAcwC,QAAd,CAAuB,6BAAvB,EAAsD;YACpDC,QAAQ,IAD4C;YAEpDtL,4BAAM,IAAN;UAFoD,CAAtD;QAViD;;QAkBnD,IACEiJ,YAAYuV,aAAZvV,CAA0BtD,gBAA1BsD,IACAO,aAAa67C,gBAAgBE,oBAF/B,EAGE;UAEA,KAAKuB,gBAAL,CAAsBrmD,OAAtB;;UACA;QAxBiD;;QA0BnD,IAAI+nD,eAAeh/C,aAAa,CAAhC;;QAEA,IAAIg/C,gBAAgB,CAApB,EAAuB;UACrB,KAAK1B,gBAAL,CAAsBrmD,OAAtB;;UACA;QA9BiD;;QAgCnD,KAAK,IAAIiM,UAAU,CAAnB,EAAsBA,WAAWlD,UAAjC,EAA6C,EAAEkD,OAA/C,EAAwD;UACtD,MAAMgM,UAAUzP,YAAYm8B,OAAZn8B,CAAoByD,OAApBzD,EAA6BoE,IAA7BpE,CACd4W,WAAW;YACT,MAAMqM,WAAW,KAAK26B,MAAL,CAAYn6C,UAAU,CAAtB,CAAjB;;YACA,IAAI,CAACwf,SAASrM,OAAd,EAAuB;cACrBqM,SAASg1B,UAATh1B,CAAoBrM,OAApBqM;YAHO;;YAKT,KAAK3W,WAAL,CAAiB9I,YAAjB,CAA8BC,OAA9B,EAAuCmT,QAAQ0oC,GAA/C;;YACA,IAAI,EAAEC,YAAF,KAAmB,CAAvB,EAA0B;cACxB,KAAK1B,gBAAL,CAAsBrmD,OAAtB;YAPO;UADG,GAWd4S,UAAU;YACRld,QAAQC,KAARD,CACG,sBAAqBuW,OAAQ,uBADhCvW,EAEEkd,MAFFld;;YAIA,IAAI,EAAEqyD,YAAF,KAAmB,CAAvB,EAA0B;cACxB,KAAK1B,gBAAL,CAAsBrmD,OAAtB;YANM;UAXI,EAAhB;;UAsBA,IAAIiM,UAAU24C,gBAAgBG,qBAA1B94C,KAAoD,CAAxD,EAA2D;YACzD,MAAMgM,OAAN;UAxBoD;QAhCL;MAArD;;MA6DA,KAAK7P,QAAL,CAAcwC,QAAd,CAAuB,WAAvB,EAAoC;QAAEC,QAAQ;MAAV,CAApC;MAEArC,YAAYia,WAAZja,GAA0BoE,IAA1BpE,CAA+B,SAAc;QAAA,IAAb;UAAE8Z;QAAF,CAAa;;QAC3C,IAAI9Z,gBAAgB,KAAKA,WAAzB,EAAsC;UACpC;QAFyC;;QAI3C,IAAI8Z,KAAK0lC,QAAT,EAAmB;UACjB,KAAK9mD,MAAL,CAAY+mD,IAAZ,GAAmB3lC,KAAK0lC,QAAxB;QALyC;MAA7C;;MASA,IAAI,KAAKhC,qBAAT,EAAgC;QAC9B,KAAK5lC,MAAL;MArKmC;IADzC,GAyKGtT,KAzKH/M,CAyKS6S,UAAU;MACfld,QAAQC,KAARD,CAAc,6BAAdA,EAA6Ckd,MAA7Cld;;MAEA,KAAK2wD,gBAAL,CAAsBx0B,MAAtB,CAA6Bjf,MAA7B;IA5KJ;EAjfa;;EAoqBfwR,cAAcN,MAAd,EAAsB;IACpB,IAAI,CAAC,KAAKtb,WAAV,EAAuB;MACrB;IAFkB;;IAIpB,IAAI,CAACsb,MAAL,EAAa;MACX,KAAKm8B,WAAL,GAAmB,IAAnB;IADF,OAEO,IACL,EAAEv2C,MAAMC,OAAND,CAAcoa,MAAdpa,KAAyB,KAAKlB,WAAL,CAAiBQ,QAAjB,KAA8B8a,OAAOzqB,MAAhE,CADK,EAEL;MACA,KAAK4mD,WAAL,GAAmB,IAAnB;MACAvqD,QAAQC,KAARD,CAAe,qCAAfA;IAJK,OAKA;MACL,KAAKuqD,WAAL,GAAmBn8B,MAAnB;IAZkB;;IAepB,KAAK,IAAIpoB,IAAI,CAAR,EAAWkY,KAAK,KAAKwyC,MAAL,CAAY/sD,MAAjC,EAAyCqC,IAAIkY,EAA7C,EAAiDlY,GAAjD,EAAsD;MAAA;;MACpD,KAAK0qD,MAAL,CAAY1qD,CAAZ,EAAeilD,YAAf,8CAA4B,KAAKV,WAAjC,uDAA4B,mBAAmBvkD,CAAnB,CAA5B,qEAAqD,IAArD;IAhBkB;EApqBP;;EAwrBf8jD,aAAa;IACX,KAAK4G,MAAL,GAAc,EAAd;IACA,KAAKtiB,kBAAL,GAA0B,CAA1B;IACA,KAAK2iB,aAAL,GAAqBj0D,uBAArB;IACA,KAAKm0D,kBAAL,GAA0B,IAA1B;IACA,KAAK1G,WAAL,GAAmB,IAAnB;;IACA,qCAAe,IAAIkF,iBAAJ,CAAsBT,kBAAtB,CAAf;;IACA,KAAKwD,SAAL,GAAiB,IAAjB;IACA,KAAKnkB,cAAL,GAAsB,CAAtB;IACA,KAAK6d,6BAAL,GAAqC,IAArC;IACA,KAAK5V,oBAAL,GAA4Bz8B,wCAA5B;IACA,KAAKq3C,0BAAL,GAAkCr3C,wCAAlC;IACA,KAAK82C,gBAAL,GAAwB92C,wCAAxB;IACA,KAAK+0C,WAAL,GAAmBnwD,qBAAWC,QAA9B;IACA,KAAK+zD,mBAAL,GAA2Bh0D,qBAAWjB,OAAtC;IACA,KAAKqxD,WAAL,GAAmB/vD,qBAAWjB,IAA9B;;IAEA,kDAA4B;MAC1B60D,oBAAoB,CADM;MAE1BC,YAAY,IAFc;MAG1BC,OAAO;IAHmB,CAA5B;;IAMA,IAAI,KAAKpC,aAAT,EAAwB;MACtB,KAAK99C,QAAL,CAAc6hB,IAAd,CAAmB,YAAnB,EAAiC,KAAKi8B,aAAtC;;MACA,KAAKA,aAAL,GAAqB,IAArB;IAzBS;;IA2BX,IAAI,KAAKC,YAAT,EAAuB;MACrB,KAAK/9C,QAAL,CAAc6hB,IAAd,CAAmB,cAAnB,EAAmC,KAAKk8B,YAAxC;;MACA,KAAKA,YAAL,GAAoB,IAApB;IA7BS;;IA+BX,0BAAI,IAAJ,wBAA8B;MAC5BjmD,SAAS2kB,mBAAT3kB,CACE,kBADFA,wBAEE,IAFFA;;MAIA,iDAA2B,IAA3B;IApCS;;IAuCX,KAAKgB,MAAL,CAAYoc,WAAZ,GAA0B,EAA1B;;IAEA,KAAKknC,iBAAL;;IAEA,KAAKtjD,MAAL,CAAYw6B,eAAZ,CAA4B,MAA5B;IAEA,KAAKx6B,MAAL,CAAY5K,SAAZ,CAAsByK,MAAtB,CAA6B4jD,wBAA7B;EAruBa;;EAuyBfsB,gBAAgB;IACd,IAAI,KAAKl9C,UAAL,KAAoB,CAAxB,EAA2B;MACzB;IAFY;;IAId,KAAKqX,MAAL;EA3yBa;;EAq1BfmoC,qBAAqBC,QAArB,EAA+BC,QAA/B,EAA2E;IAAA,IAAlCC,QAAkC,uEAAvB,KAAuB;IAAA,IAAhBC,MAAgB,uEAAP,KAAO;IACzE,KAAKhC,kBAAL,GAA0B8B,SAASj9C,QAATi9C,EAA1B;;IAEA,2BAAI,IAAJ,oCAAI,IAAJ,EAAsBD,QAAtB,GAAiC;MAC/B,IAAIG,MAAJ,EAAY;QACV,KAAKvgD,QAAL,CAAcwC,QAAd,CAAuB,eAAvB,EAAwC;UACtCC,QAAQ,IAD8B;UAEtCiiB,OAAO07B,QAF+B;UAGtCt6B,aAAau6B;QAHyB,CAAxC;MAF6B;;MAQ/B;IAXuE;;IAczExoD,mBAASe,WAATf,CACE,gBADFA,EAEEuoD,WAAWpB,wBAAcC,gBAF3BpnD;;IAKA,MAAM4/C,aAAa;MAAE/yB,OAAO07B;IAAT,CAAnB;;IACA,WAAW/8B,QAAX,IAAuB,KAAK26B,MAA5B,EAAoC;MAClC36B,SAASrL,MAATqL,CAAgBo0B,UAAhBp0B;IArBuE;;IAuBzE,KAAKg7B,aAAL,GAAqB+B,QAArB;;IAEA,IAAI,CAACE,QAAL,EAAe;MACb,IAAIz/C,OAAO,KAAK66B,kBAAhB;MAAA,IACEx6B,IADF;;MAEA,IACE,KAAK4+C,SAAL,IACA,EAAE,KAAK9vC,oBAAL,IAA6B,KAAKikC,0BAApC,CAFF,EAGE;QACApzC,OAAO,KAAKi/C,SAAL,CAAer+C,UAAtBZ;QACAK,OAAO,CACL,IADK,EAEL;UAAE7C,MAAM;QAAR,CAFK,EAGL,KAAKyhD,SAAL,CAAetxD,IAHV,EAIL,KAAKsxD,SAAL,CAAexxD,GAJV,EAKL,IALK,CAAP4S;MARW;;MAgBb,KAAKW,kBAAL,CAAwB;QACtBJ,YAAYZ,IADU;QAEtBmC,WAAW9B,IAFW;QAGtB+B,qBAAqB;MAHC,CAAxB;IAzCuE;;IAgDzE,KAAKjD,QAAL,CAAcwC,QAAd,CAAuB,eAAvB,EAAwC;MACtCC,QAAQ,IAD8B;MAEtCiiB,OAAO07B,QAF+B;MAGtCt6B,aAAay6B,SAASF,QAAT,GAAoB9xD;IAHK,CAAxC;;IAMA,IAAI,KAAKqvD,qBAAT,EAAgC;MAC9B,KAAK5lC,MAAL;IAvDuE;;IAyDzE,KAAK+M,wBAAL;EA94Ba;;EAo5Bf,IAAIy7B,qBAAJ,GAA4B;IAC1B,IACE,KAAKrE,WAAL,KAAqB/vD,qBAAWjB,IAAhC,IACA,KAAK+wD,WAAL,KAAqBnwD,qBAAWE,UAFlC,EAGE;MACA,OAAO,CAAP;IALwB;;IAO1B,OAAO,CAAP;EA35Ba;;EA85BfqyD,UAAUruD,KAAV,EAAmC;IAAA,IAAlBqwD,QAAkB,uEAAP,KAAO;IACjC,IAAI57B,QAAQ3hB,WAAW9S,KAAX,CAAZ;;IAEA,IAAIy0B,QAAQ,CAAZ,EAAe;MACb,KAAKy7B,oBAAL,CAA0Bz7B,KAA1B,EAAiCz0B,KAAjC,EAAwCqwD,QAAxC,EAAiE,KAAjE;IADF,OAEO;MACL,MAAM17B,cAAc,KAAKo5B,MAAL,CAAY,KAAKtiB,kBAAL,GAA0B,CAAtC,CAApB;;MACA,IAAI,CAAC9W,WAAL,EAAkB;QAChB;MAHG;;MAKL,IAAI67B,WAAWn2D,2BAAf;MAAA,IACEo2D,WAAWn2D,0BADb;;MAGA,IAAI,KAAKylB,oBAAT,EAA+B;QAC7BywC,WAAWC,WAAW,CAAtBD;MADF,OAEO,IAAI,KAAK/C,iBAAT,EAA4B;QACjC+C,WAAWC,WAAW,CAAtBD;MADK,OAEA,IAAI,KAAKvE,WAAL,KAAqBnwD,qBAAWE,UAApC,EAAgD;QACrD,CAACw0D,QAAD,EAAWC,QAAX,IAAuB,CAACA,QAAD,EAAWD,QAAX,CAAvB;MAbG;;MAeL,MAAME,iBACD,MAAK5nD,SAAL,CAAe/K,WAAf,GAA6ByyD,QAA7B,IAAyC77B,YAAY7xB,KAArD,GACD6xB,YAAYF,KADX,GAEH,KAAK87B,qBAHP;MAIA,MAAMI,kBACF,MAAK7nD,SAAL,CAAejL,YAAf,GAA8B4yD,QAA9B,IAA0C97B,YAAY5xB,MAAtD,GACF4xB,YAAYF,KAFd;;MAGA,QAAQz0B,KAAR;QACE,KAAK,aAAL;UACEy0B,QAAQ,CAARA;UACA;;QACF,KAAK,YAAL;UACEA,QAAQi8B,cAARj8B;UACA;;QACF,KAAK,aAAL;UACEA,QAAQk8B,eAARl8B;UACA;;QACF,KAAK,UAAL;UACEA,QAAQpzB,KAAK6G,GAAL7G,CAASqvD,cAATrvD,EAAyBsvD,eAAzBtvD,CAARozB;UACA;;QACF,KAAK,MAAL;UAGE,MAAMm8B,kBAAkBrpD,qCAAsBotB,WAAtBptB,IACpBmpD,cADoBnpD,GAEpBlG,KAAK6G,GAAL7G,CAASsvD,eAATtvD,EAA0BqvD,cAA1BrvD,CAFJ;UAGAozB,QAAQpzB,KAAK6G,GAAL7G,CAASjH,wBAATiH,EAAyBuvD,eAAzBvvD,CAARozB;UACA;;QACF;UACEp3B,QAAQC,KAARD,CAAe,eAAc2C,KAAM,6BAAnC3C;UACA;MAvBJ;;MAyBA,KAAK6yD,oBAAL,CAA0Bz7B,KAA1B,EAAiCz0B,KAAjC,EAAwCqwD,QAAxC,EAAiE,IAAjE;IApD+B;EA95BpB;;EAw+Bf5+C,sBAAsBqa,KAAtB,EAA6B;IAC3B,IAAI,CAAC,KAAK87B,WAAV,EAAuB;MACrB,OAAO,IAAP;IAFyB;;IAI3B,MAAMvkD,IAAI,KAAKukD,WAAL,CAAiBxgB,OAAjB,CAAyBtb,KAAzB,CAAV;;IACA,IAAIzoB,IAAI,CAAR,EAAW;MACT,OAAO,IAAP;IANyB;;IAQ3B,OAAOA,IAAI,CAAX;EAh/Ba;;EAkgCfuO,0BAKG;IAAA,IALgB;MACjBJ,UADiB;MAEjBuB,YAAY,IAFK;MAGjBC,sBAAsB,KAHL;MAIjBnH,wBAAwB;IAJP,CAKhB;;IACD,IAAI,CAAC,KAAKsE,WAAV,EAAuB;MACrB;IAFD;;IAID,MAAMijB,WACJrsB,OAAOC,SAAPD,CAAiByK,UAAjBzK,KAAgC,KAAKgnD,MAAL,CAAYv8C,aAAa,CAAzB,CADlC;;IAEA,IAAI,CAAC4hB,QAAL,EAAe;MACb/1B,QAAQC,KAARD,CACG,wBAAuBmU,UAAW,wCADrCnU;MAGA;IAVD;;IAaD,IAAI,KAAK0iB,oBAAL,IAA6B,CAAChN,SAAlC,EAA6C;MAC3C,KAAKm7C,qBAAL,CAA2B18C,UAA3B,EAAoE,IAApE;;MACA;IAfD;;IAiBD,IAAIpQ,IAAI,CAAR;IAAA,IACEiE,IAAI,CADN;IAEA,IAAIvC,QAAQ,CAAZ;IAAA,IACEC,SAAS,CADX;IAAA,IAEE8tD,UAFF;IAAA,IAGEC,WAHF;IAIA,MAAMjuD,oBAAoBuwB,SAAStiB,QAATsiB,GAAoB,GAApBA,KAA4B,CAAtD;IACA,MAAMq2B,YACH,qBAAoBr2B,SAASrwB,MAA7B,GAAsCqwB,SAAStwB,KAA/C,IACDswB,SAASqB,KADR,GAEDs6B,wBAAcC,gBAHhB;IAIA,MAAMtF,aACH,qBAAoBt2B,SAAStwB,KAA7B,GAAqCswB,SAASrwB,MAA9C,IACDqwB,SAASqB,KADR,GAEDs6B,wBAAcC,gBAHhB;IAIA,IAAIv6B,QAAQ,CAAZ;;IACA,QAAQ1hB,UAAU,CAAV,EAAa3E,IAArB;MACE,KAAK,KAAL;QACEhN,IAAI2R,UAAU,CAAV,CAAJ3R;QACAiE,IAAI0N,UAAU,CAAV,CAAJ1N;QACAovB,QAAQ1hB,UAAU,CAAV,CAAR0hB;QAKArzB,IAAIA,MAAM,IAANA,GAAaA,CAAbA,GAAiB,CAArBA;QACAiE,IAAIA,MAAM,IAANA,GAAaA,CAAbA,GAAiBqkD,UAArBrkD;QACA;;MACF,KAAK,KAAL;MACA,KAAK,MAAL;QACEovB,QAAQ,UAARA;QACA;;MACF,KAAK,MAAL;MACA,KAAK,OAAL;QACEpvB,IAAI0N,UAAU,CAAV,CAAJ1N;QACAovB,QAAQ,YAARA;;QAGA,IAAIpvB,MAAM,IAANA,IAAc,KAAKwqD,SAAvB,EAAkC;UAChCzuD,IAAI,KAAKyuD,SAAL,CAAetxD,IAAnB6C;UACAiE,IAAI,KAAKwqD,SAAL,CAAexxD,GAAnBgH;QAFF,OAGO,IAAI,OAAOA,CAAP,KAAa,QAAb,IAAyBA,IAAI,CAAjC,EAAoC;UAGzCA,IAAIqkD,UAAJrkD;QAXJ;;QAaE;;MACF,KAAK,MAAL;MACA,KAAK,OAAL;QACEjE,IAAI2R,UAAU,CAAV,CAAJ3R;QACA0B,QAAQ2mD,SAAR3mD;QACAC,SAAS2mD,UAAT3mD;QACA0xB,QAAQ,aAARA;QACA;;MACF,KAAK,MAAL;QACErzB,IAAI2R,UAAU,CAAV,CAAJ3R;QACAiE,IAAI0N,UAAU,CAAV,CAAJ1N;QACAvC,QAAQiQ,UAAU,CAAV,IAAe3R,CAAvB0B;QACAC,SAASgQ,UAAU,CAAV,IAAe1N,CAAxBtC;QACA,MAAMytD,WAAW,KAAK/C,iBAAL,GAAyB,CAAzB,GAA6BpzD,2BAA9C;QACA,MAAMo2D,WAAW,KAAKhD,iBAAL,GAAyB,CAAzB,GAA6BnzD,0BAA9C;QAEAu2D,aACG,MAAK/nD,SAAL,CAAe/K,WAAf,GAA6ByyD,QAA7B,IACD1tD,KADC,GAEDisD,wBAAcC,gBAHhB6B;QAIAC,cACG,MAAKhoD,SAAL,CAAejL,YAAf,GAA8B4yD,QAA9B,IACD1tD,MADC,GAEDgsD,wBAAcC,gBAHhB8B;QAIAr8B,QAAQpzB,KAAK6G,GAAL7G,CAASA,KAAKwE,GAALxE,CAASwvD,UAATxvD,CAATA,EAA+BA,KAAKwE,GAALxE,CAASyvD,WAATzvD,CAA/BA,CAARozB;QACA;;MACF;QACEp3B,QAAQC,KAARD,CACG,wBAAuB0V,UAAU,CAAV,EAAa3E,IAAK,oCAD5C/Q;QAGA;IA5DJ;;IA+DA,IAAI,CAACwO,qBAAL,EAA4B;MAC1B,IAAI4oB,SAASA,UAAU,KAAK25B,aAA5B,EAA2C;QACzC,KAAKhuC,iBAAL,GAAyBqU,KAAzB;MADF,OAEO,IAAI,KAAK25B,aAAL,KAAuBj0D,uBAA3B,EAA0C;QAC/C,KAAKimB,iBAAL,GAAyBtmB,6BAAzB;MAJwB;IAhG3B;;IAwGD,IAAI26B,UAAU,UAAVA,IAAwB,CAAC1hB,UAAU,CAAV,CAA7B,EAA2C;MACzC,2EAAqBqgB,QAArB;;MACA;IA1GD;;IA6GD,MAAM29B,eAAe,CACnB39B,SAAS20B,QAAT30B,CAAkB49B,sBAAlB59B,CAAyChyB,CAAzCgyB,EAA4C/tB,CAA5C+tB,CADmB,EAEnBA,SAAS20B,QAAT30B,CAAkB49B,sBAAlB59B,CAAyChyB,IAAI0B,KAA7CswB,EAAoD/tB,IAAItC,MAAxDqwB,CAFmB,CAArB;IAIA,IAAI70B,OAAO8C,KAAK6G,GAAL7G,CAAS0vD,aAAa,CAAb,EAAgB,CAAhBA,CAAT1vD,EAA6B0vD,aAAa,CAAb,EAAgB,CAAhBA,CAA7B1vD,CAAX;IACA,IAAIhD,MAAMgD,KAAK6G,GAAL7G,CAAS0vD,aAAa,CAAb,EAAgB,CAAhBA,CAAT1vD,EAA6B0vD,aAAa,CAAb,EAAgB,CAAhBA,CAA7B1vD,CAAV;;IAEA,IAAI,CAAC2R,mBAAL,EAA0B;MAIxBzU,OAAO8C,KAAKyD,GAALzD,CAAS9C,IAAT8C,EAAe,CAAfA,CAAP9C;MACAF,MAAMgD,KAAKyD,GAALzD,CAAShD,GAATgD,EAAc,CAAdA,CAANhD;IAzHD;;IA2HD,2EAAqB+0B,QAArB,EAAgD;MAAE70B,IAAF;MAAQF;IAAR,CAAhD;EAloCa;;EAqoCf4yD,gBAAgBC,SAAhB,EAA2B;IACzB,MAAM76B,eAAe,KAAK+3B,aAA1B;IACA,MAAMhuC,oBAAoB,KAAKkuC,kBAA/B;IACA,MAAM6C,uBACJr+C,WAAWsN,iBAAX,MAAkCiW,YAAlCvjB,GACIzR,KAAKe,KAALf,CAAWg1B,eAAe,KAA1Bh1B,IAAmC,GADvCyR,GAEIsN,iBAHN;IAKA,MAAM5O,aAAa0/C,UAAU9rD,EAA7B;IACA,MAAMgsD,kBAAkB,KAAKrD,MAAL,CAAYv8C,aAAa,CAAzB,CAAxB;IACA,MAAM1I,YAAY,KAAKA,SAAvB;IACA,MAAMuoD,UAAUD,gBAAgBE,YAAhBF,CACdtoD,UAAUtK,UAAVsK,GAAuBooD,UAAU9vD,CADnBgwD,EAEdtoD,UAAUrK,SAAVqK,GAAsBooD,UAAU7rD,CAFlB+rD,CAAhB;IAIA,MAAMG,UAAUlwD,KAAKe,KAALf,CAAWgwD,QAAQ,CAAR,CAAXhwD,CAAhB;IACA,MAAMmwD,SAASnwD,KAAKe,KAALf,CAAWgwD,QAAQ,CAAR,CAAXhwD,CAAf;IAEA,IAAIqzB,gBAAiB,SAAQljB,UAAT,EAApB;;IACA,IAAI,CAAC,KAAKuO,oBAAV,EAAgC;MAC9B2U,iBAAkB,SAAQy8B,oBAAqB,IAAGI,OAAQ,IAAGC,MAA5C,EAAjB98B;IApBuB;;IAuBzB,KAAKm7B,SAAL,GAAiB;MACfr+C,UADe;MAEfijB,OAAO08B,oBAFQ;MAGf9yD,KAAKmzD,MAHU;MAIfjzD,MAAMgzD,OAJS;MAKfzgD,UAAU,KAAK46B,cALA;MAMfhX;IANe,CAAjB;EA5pCa;;EAsqCf3M,SAAS;IACP,MAAM9jB,UAAU,KAAKwtD,gBAAL,EAAhB;;IACA,MAAMC,eAAeztD,QAAQf,KAA7B;IAAA,MACEyuD,kBAAkBD,aAAa1wD,MADjC;;IAGA,IAAI2wD,oBAAoB,CAAxB,EAA2B;MACzB;IANK;;IAQP,MAAMC,eAAevwD,KAAKyD,GAALzD,CAASgrD,kBAAThrD,EAA6B,IAAIswD,eAAJ,GAAsB,CAAnDtwD,CAArB;;IACA,qCAAa2rD,MAAb,CAAoB4E,YAApB,EAAkC3tD,QAAQC,GAA1C;;IAEA,KAAKkZ,cAAL,CAAoB+P,qBAApB,CAA0ClpB,OAA1C;IAEA,MAAM4tD,iBACJ,KAAK3F,WAAL,KAAqB/vD,qBAAWjB,IAAhC,KACC,KAAK+wD,WAAL,KAAqBnwD,qBAAWI,IAAhC,IACC,KAAK+vD,WAAL,KAAqBnwD,qBAAWC,QAFlC,CADF;IAIA,MAAM+1D,YAAY,KAAKrmB,kBAAvB;IACA,IAAIsmB,oBAAoB,KAAxB;;IAEA,WAAWnhD,IAAX,IAAmB8gD,YAAnB,EAAiC;MAC/B,IAAI9gD,KAAK1L,OAAL0L,GAAe,GAAnB,EAAwB;QACtB;MAF6B;;MAI/B,IAAIA,KAAKxL,EAALwL,KAAYkhD,SAAZlhD,IAAyBihD,cAA7B,EAA6C;QAC3CE,oBAAoB,IAApBA;QACA;MAN6B;IApB1B;;IA6BP,KAAK7D,qBAAL,CACE6D,oBAAoBD,SAApB,GAAgCJ,aAAa,CAAb,EAAgBtsD,EADlD;;IAIA,KAAK6rD,eAAL,CAAqBhtD,QAAQuB,KAA7B;;IACA,KAAKuK,QAAL,CAAcwC,QAAd,CAAuB,gBAAvB,EAAyC;MACvCC,QAAQ,IAD+B;MAEvCuE,UAAU,KAAK84C;IAFwB,CAAzC;EAxsCa;;EA8sCf14B,gBAAgBn6B,OAAhB,EAAyB;IACvB,OAAO,KAAK8L,SAAL,CAAe5K,QAAf,CAAwBlB,OAAxB,CAAP;EA/sCa;;EAktCf4qB,QAAQ;IACN,KAAK9e,SAAL,CAAe8e,KAAf;EAntCa;;EAstCf,IAAIoqC,eAAJ,GAAsB;IACpB,OAAO7zD,iBAAiB,KAAK2K,SAAtB,EAAiCmpD,SAAjC9zD,KAA+C,KAAtD;EAvtCa;;EA0tCf,IAAI4hB,oBAAJ,GAA2B;IACzB,OAAO,KAAKwU,qBAAL,KAA+B35B,gCAAsBI,UAA5D;EA3tCa;;EA8tCf,IAAIgpD,0BAAJ,GAAiC;IAC/B,OAAO,KAAKzvB,qBAAL,KAA+B35B,gCAAsBG,QAA5D;EA/tCa;;EAkuCf,IAAIw9B,4BAAJ,GAAmC;IACjC,OAAO,KAAKxY,oBAAL,GACH,KADG,GAEH,KAAKjX,SAAL,CAAe9K,WAAf,GAA6B,KAAK8K,SAAL,CAAe/K,WAFhD;EAnuCa;;EAwuCf,IAAIu6B,0BAAJ,GAAiC;IAC/B,OAAO,KAAKvY,oBAAL,GACH,KADG,GAEH,KAAKjX,SAAL,CAAehL,YAAf,GAA8B,KAAKgL,SAAL,CAAejL,YAFjD;EAzuCa;;EA8uCf4zD,mBAAmB;IACjB,MAAMvuD,QACF,KAAK+oD,WAAL,KAAqBnwD,qBAAWI,IAAhC,GACI,kDAA0B+zD,KAD9B,GAEI,KAAKlC,MAHb;IAAA,MAIEtqD,aAAa,KAAKwoD,WAAL,KAAqBnwD,qBAAWE,UAJ/C;IAAA,MAKE0H,MAAMD,cAAc,KAAKuuD,eAL3B;IAOA,OAAO1uD,kCAAmB;MACxBC,UAAU,KAAKuF,SADS;MAExB5F,KAFwB;MAGxBM,kBAAkB,IAHM;MAIxBC,UAJwB;MAKxBC;IALwB,CAAnBJ,CAAP;EAtvCa;;EAkwCf4Q,cAAc1C,UAAd,EAA0B;IACxB,IAAI,CAAC,KAAKrB,WAAV,EAAuB;MACrB,OAAO,KAAP;IAFsB;;IAIxB,IACE,EACEpJ,OAAOC,SAAPD,CAAiByK,UAAjBzK,KACAyK,aAAa,CADbzK,IAEAyK,cAAc,KAAKd,UAHrB,CADF,EAME;MACArT,QAAQC,KAARD,CAAe,mBAAkBmU,UAAW,wBAA5CnU;MACA,OAAO,KAAP;IAZsB;;IAcxB,OAAO,KAAKo0D,gBAAL,GAAwBvtD,GAAxB,CAA4BoO,GAA5B,CAAgCd,UAAhC,CAAP;EAhxCa;;EAsxCf2C,aAAa3C,UAAb,EAAyB;IACvB,IAAI,CAAC,KAAKrB,WAAV,EAAuB;MACrB,OAAO,KAAP;IAFqB;;IAIvB,IACE,EACEpJ,OAAOC,SAAPD,CAAiByK,UAAjBzK,KACAyK,aAAa,CADbzK,IAEAyK,cAAc,KAAKd,UAHrB,CADF,EAME;MACArT,QAAQC,KAARD,CAAe,kBAAiBmU,UAAW,wBAA3CnU;MACA,OAAO,KAAP;IAZqB;;IAcvB,MAAM+1B,WAAW,KAAK26B,MAAL,CAAYv8C,aAAa,CAAzB,CAAjB;IACA,OAAO,qCAAac,GAAb,CAAiB8gB,QAAjB,CAAP;EAryCa;;EAwyCfpR,UAAU;IACR,WAAWoR,QAAX,IAAuB,KAAK26B,MAA5B,EAAoC;MAClC,IAAI36B,SAASyB,cAATzB,KAA4B74B,0BAAgBI,QAAhD,EAA0D;QACxDy4B,SAASrR,KAATqR;MAFgC;IAD5B;EAxyCK;;EAmzCfy0B,mBAAmB;IACjB,WAAWz0B,QAAX,IAAuB,KAAK26B,MAA5B,EAAoC;MAClC36B,SAASi1B,eAATj1B;IAFe;EAnzCJ;;EAg3CfjU,eAAeyhC,qBAAf,EAAsC;IACpC,MAAM8Q,eAAe9Q,yBAAyB,KAAK6Q,gBAAL,EAA9C;;IACA,MAAMjJ,qCAAc,IAAd,0CAAc,IAAd,EAAmCkJ,YAAnC,CAAN;;IACA,MAAM3Q,iBACJ,KAAKmL,WAAL,KAAqB/vD,qBAAWjB,IAAhC,IACA,KAAK+wD,WAAL,KAAqBnwD,qBAAWE,UAFlC;IAIA,MAAMo3B,WAAW,KAAKhW,cAAL,CAAoByjC,kBAApB,CACf6Q,YADe,EAEf,KAAK3D,MAFU,EAGfvF,WAHe,EAIfzH,cAJe,CAAjB;;IAMA,+FAA+B2Q,aAAaxtD,GAA5C;;IAEA,IAAIkvB,QAAJ,EAAc;MACZ,qFAA0BA,QAA1B,EAAoC7e,IAApC,CAAyC,MAAM;QAC7C,KAAK6I,cAAL,CAAoBskC,UAApB,CAA+BtuB,QAA/B;MADF;;MAGA,OAAO,IAAP;IAnBkC;;IAqBpC,OAAO,KAAP;EAr4Ca;;EAu5Cf8+B,8BAQG;IAAA,IARoB;MACrBC,YADqB;MAErB39C,SAFqB;MAGrBuzC,QAHqB;MAIrBqK,uBAAuB,KAJF;MAKrBriD,QALqB;MAMrBsiD,WANqB;MAOrBC,uBAAuB;IAPF,CAQpB;IACD,OAAO,IAAIC,oCAAJ,CAAqB;MAC1BJ,YAD0B;MAE1BpiD,QAF0B;MAG1ByE,SAH0B;MAI1BuzC,QAJ0B;MAK1BqK,sBAAsB,KAAKryC,oBAAL,GAClB,KADkB,GAElBqyC,oBAPsB;MAQ1BC,WAR0B;MAS1BC;IAT0B,CAArB,CAAP;EAh6Ca;;EAu7CfE,6BAA+C;IAAA,IAAzB;MAAEh+C,SAAF;MAAazE;IAAb,CAAyB;IAC7C,OAAO,IAAI0iD,iCAAJ,CAAoB;MACzB1iD,QADyB;MAEzByE,SAFyB;MAGzB+H,gBAAgB,KAAKwD,oBAAL,GAA4B,IAA5B,GAAmC,KAAKxD;IAH/B,CAApB,CAAP;EAx7Ca;;EAu9Cfm2C,oCAaG;IAAA;;IAAA,IAb0B;MAC3BC,OAD2B;MAE3B5rC,OAF2B;MAG3BtF,yCAAoB,KAAKtR,WAAzB,sDAAoB,kBAAkBsR,iBAHX;MAI3B3V,qBAAqB,EAJM;MAK3Bmf,cAAc,IALa;MAM3BzS,OAAOk1C,oBANoB;MAO3BjiD,kBAAkB,KAAKA,eAPI;MAQ3BmnD,4CAAsB,KAAKziD,WAA3B,uDAAsB,mBAAkB0iD,YAAlB,EARK;MAS3B/O,sCAAa,KAAK0J,iBAAlB,0DAAa,sBAAwB1J,UATV;MAU3BgP,4CAAsB,KAAK3iD,WAA3B,uDAAsB,mBAAkByyC,eAAlB,EAVK;MAW3BmQ,sBAAsB,IAXK;MAY3BT,uBAAuB;IAZI,CAa1B;IACD,OAAO,IAAIU,gDAAJ,CAA2B;MAChCL,OADgC;MAEhC5rC,OAFgC;MAGhCtF,iBAHgC;MAIhC3V,kBAJgC;MAKhCmf,WALgC;MAMhCxO,aAAa,KAAKA,WANc;MAOhCtE,iBAAiB,KAAKA,eAPU;MAQhCK,IARgC;MAShC/M,eATgC;MAUhCmnD,mBAVgC;MAWhC9O,UAXgC;MAYhCgP,mBAZgC;MAahCC,mBAbgC;MAchCT;IAdgC,CAA3B,CAAP;EAr+Ca;;EAsgDfW,0CAOG;IAAA;;IAAA,IAPgC;MACjCC,kCAAY,IAAZ,6BADiC;MAEjCP,OAFiC;MAGjC5rC,OAHiC;MAIjCurC,uBAAuB,IAJU;MAKjC95C,IALiC;MAMjCiJ,0CAAoB,KAAKtR,WAAzB,uDAAoB,mBAAkBsR;IANL,CAOhC;IACD,OAAO,IAAI0xC,6DAAJ,CAAiC;MACtCD,SADsC;MAEtCP,OAFsC;MAGtC5rC,OAHsC;MAItCtF,iBAJsC;MAKtC6wC,oBALsC;MAMtC95C;IANsC,CAAjC,CAAP;EA9gDa;;EAoiDf46C,6BAIG;IAAA;;IAAA,IAJmB;MACpBT,OADoB;MAEpB5rC,OAFoB;MAGpBtF,0CAAoB,KAAKtR,WAAzB,uDAAoB,mBAAkBsR;IAHlB,CAInB;IACD,OAAO,IAAI4xC,kCAAJ,CAAoB;MACzBV,OADyB;MAEzB5rC,OAFyB;MAGzBtF,iBAHyB;MAIzBhF,aAAa,KAAKA;IAJO,CAApB,CAAP;EAziDa;;EA0jDf62C,oCAA0C;IAAA,IAAb;MAAEvsC;IAAF,CAAa;IACxC,OAAO,IAAIwsC,iDAAJ,CAA2B;MAChCxsC;IADgC,CAA3B,CAAP;EA3jDa;;EAokDf,IAAIe,iBAAJ,GAAwB;IACtB,MAAM0nC,gBAAgB,KAAKzB,MAAL,CAAY,CAAZ,CAAtB;;IACA,KAAK,IAAI1qD,IAAI,CAAR,EAAWkY,KAAK,KAAKwyC,MAAL,CAAY/sD,MAAjC,EAAyCqC,IAAIkY,EAA7C,EAAiD,EAAElY,CAAnD,EAAsD;MACpD,MAAM+vB,WAAW,KAAK26B,MAAL,CAAY1qD,CAAZ,CAAjB;;MACA,IACE+vB,SAAStwB,KAATswB,KAAmBo8B,cAAc1sD,KAAjCswB,IACAA,SAASrwB,MAATqwB,KAAoBo8B,cAAczsD,MAFpC,EAGE;QACA,OAAO,KAAP;MANkD;IAFhC;;IAWtB,OAAO,IAAP;EA/kDa;;EAslDf2qB,mBAAmB;IACjB,OAAO,KAAKqgC,MAAL,CAAYptB,GAAZ,CAAgBvN,YAAY;MACjC,MAAM20B,WAAW30B,SAASrM,OAATqM,CAAiB40B,WAAjB50B,CAA6B;QAAEqB,OAAO;MAAT,CAA7BrB,CAAjB;;MAEA,IAAI,CAAC,KAAK5nB,qBAAN,IAA+BjE,qCAAsBwgD,QAAtBxgD,CAAnC,EAAoE;QAClE,OAAO;UACLzE,OAAOilD,SAASjlD,KADX;UAELC,QAAQglD,SAAShlD,MAFZ;UAGL+N,UAAUi3C,SAASj3C;QAHd,CAAP;MAJ+B;;MAWjC,OAAO;QACLhO,OAAOilD,SAAShlD,MADX;QAELA,QAAQglD,SAASjlD,KAFZ;QAGLgO,UAAW,UAASA,QAATi3C,GAAoB,EAApB,IAA0B;MAHhC,CAAP;IAXK,EAAP;EAvlDa;;EA6mDf,IAAIx/B,4BAAJ,GAAmC;IACjC,IAAI,CAAC,KAAKpY,WAAV,EAAuB;MACrB,OAAOzI,QAAQC,OAARD,CAAgB,IAAhBA,CAAP;IAF+B;;IAIjC,IAAI,CAAC,KAAK6hD,6BAAV,EAAyC;MACvClsD,QAAQC,KAARD,CAAc,oDAAdA;MAGA,OAAO,KAAK8S,WAAL,CAAiBwsC,wBAAjB,EAAP;IAR+B;;IAUjC,OAAO,KAAK4M,6BAAZ;EAvnDa;;EA8nDf,IAAIhhC,4BAAJ,CAAiC3I,OAAjC,EAA0C;IACxC,IAAI,EAAEA,mBAAmBlY,OAArB,CAAJ,EAAmC;MACjC,MAAM,IAAIW,KAAJ,CAAW,yCAAwCuX,OAAzC,EAAV,CAAN;IAFsC;;IAIxC,IAAI,CAAC,KAAKzP,WAAV,EAAuB;MACrB;IALsC;;IAOxC,IAAI,CAAC,KAAKo5C,6BAAV,EAAyC;MAGvC;IAVsC;;IAYxC,KAAKA,6BAAL,GAAqC3pC,OAArC;IAEA,MAAM4nC,aAAa;MAAEj/B,8BAA8B3I;IAAhC,CAAnB;;IACA,WAAWwT,QAAX,IAAuB,KAAK26B,MAA5B,EAAoC;MAClC36B,SAASrL,MAATqL,CAAgBo0B,UAAhBp0B;IAhBsC;;IAkBxC,KAAKrL,MAAL;IAEA,KAAKhY,QAAL,CAAcwC,QAAd,CAAuB,8BAAvB,EAAuD;MACrDC,QAAQ,IAD6C;MAErDoN;IAFqD,CAAvD;EAlpDa;;EA2pDf,IAAIhW,UAAJ,GAAiB;IACf,OAAO,KAAKqiD,WAAZ;EA5pDa;;EAoqDf,IAAIriD,UAAJ,CAAe1C,IAAf,EAAqB;IACnB,IAAI,KAAK+kD,WAAL,KAAqB/kD,IAAzB,EAA+B;MAC7B;IAFiB;;IAInB,IAAI,CAACD,iCAAkBC,IAAlBD,CAAL,EAA8B;MAC5B,MAAM,IAAIoB,KAAJ,CAAW,wBAAuBnB,IAAxB,EAAV,CAAN;IALiB;;IAOnB,IAAI,KAAKwJ,UAAL,GAAkB67C,gBAAgBC,sBAAtC,EAA8D;MAC5D;IARiB;;IAUnB,KAAKsD,mBAAL,GAA2B,KAAK7D,WAAhC;IAEA,KAAKA,WAAL,GAAmB/kD,IAAnB;IACA,KAAK6I,QAAL,CAAcwC,QAAd,CAAuB,mBAAvB,EAA4C;MAAEC,QAAQ,IAAV;MAAgBtL;IAAhB,CAA5C;;IAEA,KAAKilD,iBAAL,CAA0C,KAAK1gB,kBAA/C;EAnrDa;;EAsrDf0gB,oBAAqC;IAAA,IAAnB36C,UAAmB,uEAAN,IAAM;IACnC,MAAM5H,aAAa,KAAKqiD,WAAxB;IAAA,MACEpjD,SAAS,KAAKA,MADhB;IAGAA,OAAO5K,SAAP4K,CAAiByrB,MAAjBzrB,CACE,kBADFA,EAEEe,eAAe9N,qBAAWE,UAF5B6M;IAIAA,OAAO5K,SAAP4K,CAAiByrB,MAAjBzrB,CAAwB,eAAxBA,EAAyCe,eAAe9N,qBAAWG,OAAnE4M;;IAEA,IAAI,CAAC,KAAKsH,WAAN,IAAqB,CAACqB,UAA1B,EAAsC;MACpC;IAXiC;;IAcnC,IAAI5H,eAAe9N,qBAAWI,IAA9B,EAAoC;MAClC;IADF,OAEO,IAAI,KAAK4zD,mBAAL,KAA6Bh0D,qBAAWI,IAA5C,EAAkD;MAGvD,KAAKkwD,iBAAL;IAnBiC;;IAwBnC,IAAI,KAAKkC,kBAAL,IAA2B7lD,MAAM,KAAK6lD,kBAAX,CAA/B,EAA+D;MAC7D,KAAKD,SAAL,CAAe,KAAKC,kBAApB,EAAwC,IAAxC;IAzBiC;;IA2BnC,KAAKJ,qBAAL,CAA2B18C,UAA3B,EAAoE,IAApE;;IACA,KAAKuW,MAAL;EAltDa;;EAwtDf,IAAIle,UAAJ,GAAiB;IACf,OAAO,KAAKqiD,WAAZ;EAztDa;;EAiuDf,IAAIriD,UAAJ,CAAe3C,IAAf,EAAqB;IACnB,IAAI,KAAKglD,WAAL,KAAqBhlD,IAAzB,EAA+B;MAC7B;IAFiB;;IAInB,IAAI,CAACI,iCAAkBJ,IAAlBI,CAAL,EAA8B;MAC5B,MAAM,IAAIe,KAAJ,CAAW,wBAAuBnB,IAAxB,EAAV,CAAN;IALiB;;IAOnB,KAAKglD,WAAL,GAAmBhlD,IAAnB;IACA,KAAK6I,QAAL,CAAcwC,QAAd,CAAuB,mBAAvB,EAA4C;MAAEC,QAAQ,IAAV;MAAgBtL;IAAhB,CAA5C;;IAEA,KAAKklD,iBAAL,CAA0C,KAAK3gB,kBAA/C;EA3uDa;;EA8uDf2gB,oBAAqC;IAAA,IAAnB56C,UAAmB,uEAAN,IAAM;;IACnC,IAAI,CAAC,KAAKrB,WAAV,EAAuB;MACrB;IAFiC;;IAInC,MAAMtH,SAAS,KAAKA,MAApB;IAAA,MACEonD,QAAQ,KAAKlC,MADf;;IAGA,IAAI,KAAK9B,WAAL,KAAqBnwD,qBAAWI,IAApC,EAA0C;MACxC;IADF,OAEO;MAEL2M,OAAOoc,WAAPpc,GAAqB,EAArBA;;MAEA,IAAI,KAAKqjD,WAAL,KAAqB/vD,qBAAWjB,IAApC,EAA0C;QACxC,WAAWk4B,QAAX,IAAuB,KAAK26B,MAA5B,EAAoC;UAClCllD,OAAO8zB,MAAP9zB,CAAcuqB,SAASlxB,GAAvB2G;QAFsC;MAA1C,OAIO;QACL,MAAM2qD,SAAS,KAAKtH,WAAL,GAAmB,CAAlC;QACA,IAAIn/B,SAAS,IAAb;;QACA,KAAK,IAAI1pB,IAAI,CAAR,EAAWkY,KAAK00C,MAAMjvD,MAA3B,EAAmCqC,IAAIkY,EAAvC,EAA2C,EAAElY,CAA7C,EAAgD;UAC9C,IAAI0pB,WAAW,IAAf,EAAqB;YACnBA,SAASllB,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAATklB;YACAA,OAAO0O,SAAP1O,GAAmB,QAAnBA;YACAlkB,OAAO8zB,MAAP9zB,CAAckkB,MAAdlkB;UAHF,OAIO,IAAIxF,IAAI,CAAJA,KAAUmwD,MAAd,EAAsB;YAC3BzmC,SAASA,OAAO0mC,SAAP1mC,CAAiB,KAAjBA,CAATA;YACAlkB,OAAO8zB,MAAP9zB,CAAckkB,MAAdlkB;UAP4C;;UAS9CkkB,OAAO4P,MAAP5P,CAAckjC,MAAM5sD,CAAN,EAASnB,GAAvB6qB;QAZG;MARF;IAT4B;;IAkCnC,IAAI,CAACvb,UAAL,EAAiB;MACf;IAnCiC;;IAwCnC,IAAI,KAAK88C,kBAAL,IAA2B7lD,MAAM,KAAK6lD,kBAAX,CAA/B,EAA+D;MAC7D,KAAKD,SAAL,CAAe,KAAKC,kBAApB,EAAwC,IAAxC;IAzCiC;;IA2CnC,KAAKJ,qBAAL,CAA2B18C,UAA3B,EAAoE,IAApE;;IACA,KAAKuW,MAAL;EA1xDa;;EAgyDf2rC,gBAAgB7iD,iBAAhB,EAAqD;IAAA,IAAlB4kB,QAAkB,uEAAP,KAAO;;IACnD,QAAQ,KAAKw2B,WAAb;MACE,KAAKnwD,qBAAWG,OAAhB;QAAyB;UACvB,MAAM;YAAEiH;UAAF,IAAY,KAAKuuD,gBAAL,EAAlB;UAAA,MACEtqC,aAAa,IAAIrnB,GAAJ,EADf;;UAIA,WAAW;YAAEsF,EAAF;YAAMC,CAAN;YAASH,OAAT;YAAkBI;UAAlB,CAAX,IAA+CpC,KAA/C,EAAsD;YACpD,IAAIgC,YAAY,CAAZA,IAAiBI,eAAe,GAApC,EAAyC;cACvC;YAFkD;;YAIpD,IAAIquD,SAASxsC,WAAWhZ,GAAXgZ,CAAe9hB,CAAf8hB,CAAb;;YACA,IAAI,CAACwsC,MAAL,EAAa;cACXxsC,WAAWjnB,GAAXinB,CAAe9hB,CAAf8hB,EAAmBwsC,MAAnBxsC,KAAmBwsC,MAAnBxsC,GAA8B,EAA9BA;YANkD;;YAQpDwsC,OAAOxuD,IAAPwuD,CAAYvuD,EAAZuuD;UAbqB;;UAgBvB,WAAWA,MAAX,IAAqBxsC,WAAW/f,MAAX+f,EAArB,EAA0C;YACxC,MAAMlmB,eAAe0yD,OAAOvsB,OAAPusB,CAAe9iD,iBAAf8iD,CAArB;;YACA,IAAI1yD,iBAAiB,CAAC,CAAtB,EAAyB;cACvB;YAHsC;;YAKxC,MAAM0P,WAAWgjD,OAAO3yD,MAAxB;;YACA,IAAI2P,aAAa,CAAjB,EAAoB;cAClB;YAPsC;;YAUxC,IAAI8kB,QAAJ,EAAc;cACZ,KAAK,IAAIpyB,IAAIpC,eAAe,CAAvB,EAA0Bsa,KAAK,CAApC,EAAuClY,KAAKkY,EAA5C,EAAgDlY,GAAhD,EAAqD;gBACnD,MAAMyuD,YAAY6B,OAAOtwD,CAAP,CAAlB;gBAAA,MACEuwD,aAAaD,OAAOtwD,IAAI,CAAX,IAAgB,CAD/B;;gBAEA,IAAIyuD,YAAY8B,UAAhB,EAA4B;kBAC1B,OAAO/iD,oBAAoB+iD,UAA3B;gBAJiD;cADzC;YAAd,OAQO;cACL,KAAK,IAAIvwD,IAAIpC,eAAe,CAAvB,EAA0Bsa,KAAK5K,QAApC,EAA8CtN,IAAIkY,EAAlD,EAAsDlY,GAAtD,EAA2D;gBACzD,MAAMyuD,YAAY6B,OAAOtwD,CAAP,CAAlB;gBAAA,MACEuwD,aAAaD,OAAOtwD,IAAI,CAAX,IAAgB,CAD/B;;gBAEA,IAAIyuD,YAAY8B,UAAhB,EAA4B;kBAC1B,OAAOA,aAAa/iD,iBAApB;gBAJuD;cADtD;YAlBiC;;YA4BxC,IAAI4kB,QAAJ,EAAc;cACZ,MAAM0rB,UAAUwS,OAAO,CAAP,CAAhB;;cACA,IAAIxS,UAAUtwC,iBAAd,EAAiC;gBAC/B,OAAOA,oBAAoBswC,OAApBtwC,GAA8B,CAArC;cAHU;YAAd,OAKO;cACL,MAAMuwC,SAASuS,OAAOhjD,WAAW,CAAlB,CAAf;;cACA,IAAIywC,SAASvwC,iBAAb,EAAgC;gBAC9B,OAAOuwC,SAASvwC,iBAATuwC,GAA6B,CAApC;cAHG;YAjCiC;;YAuCxC;UAvDqB;;UAyDvB;QA1DJ;;MA4DE,KAAKtlD,qBAAWE,UAAhB;QAA4B;UAC1B;QA7DJ;;MA+DE,KAAKF,qBAAWI,IAAhB;MACA,KAAKJ,qBAAWC,QAAhB;QAA0B;UACxB,IAAI,KAAKmwD,WAAL,KAAqB/vD,qBAAWjB,IAApC,EAA0C;YACxC;UAFsB;;UAIxB,MAAMs4D,SAAS,KAAKtH,WAAL,GAAmB,CAAlC;;UAEA,IAAIz2B,YAAY5kB,oBAAoB,CAApBA,KAA0B2iD,MAA1C,EAAkD;YAChD;UADF,OAEO,IAAI,CAAC/9B,QAAD,IAAa5kB,oBAAoB,CAApBA,KAA0B2iD,MAA3C,EAAmD;YACxD;UATsB;;UAWxB,MAAM;YAAEtwD;UAAF,IAAY,KAAKuuD,gBAAL,EAAlB;UAAA,MACEmC,aAAan+B,WAAW5kB,oBAAoB,CAA/B,GAAmCA,oBAAoB,CADtE;;UAGA,WAAW;YAAEzL,EAAF;YAAMF,OAAN;YAAeI;UAAf,CAAX,IAA4CpC,KAA5C,EAAmD;YACjD,IAAIkC,OAAOwuD,UAAX,EAAuB;cACrB;YAF+C;;YAIjD,IAAI1uD,UAAU,CAAVA,IAAeI,iBAAiB,GAApC,EAAyC;cACvC,OAAO,CAAP;YAL+C;;YAOjD;UArBsB;;UAuBxB;QAvFJ;IAAA;;IA0FA,OAAO,CAAP;EA33Da;;EAk4DfmO,WAAW;IACT,MAAM5C,oBAAoB,KAAK46B,kBAA/B;IAAA,MACE/6B,aAAa,KAAKA,UADpB;;IAGA,IAAIG,qBAAqBH,UAAzB,EAAqC;MACnC,OAAO,KAAP;IALO;;IAOT,MAAMmjD,UACJ,KAAKH,eAAL,CAAqB7iD,iBAArB,EAAyD,KAAzD,KAAmE,CADrE;IAGA,KAAKA,iBAAL,GAAyBxP,KAAK6G,GAAL7G,CAASwP,oBAAoBgjD,OAA7BxyD,EAAsCqP,UAAtCrP,CAAzB;IACA,OAAO,IAAP;EA74Da;;EAo5DfqS,eAAe;IACb,MAAM7C,oBAAoB,KAAK46B,kBAA/B;;IAEA,IAAI56B,qBAAqB,CAAzB,EAA4B;MAC1B,OAAO,KAAP;IAJW;;IAMb,MAAMgjD,UACJ,KAAKH,eAAL,CAAqB7iD,iBAArB,EAAyD,IAAzD,KAAkE,CADpE;IAGA,KAAKA,iBAAL,GAAyBxP,KAAKyD,GAALzD,CAASwP,oBAAoBgjD,OAA7BxyD,EAAsC,CAAtCA,CAAzB;IACA,OAAO,IAAP;EA95Da;;EAq6Df2e,gBAAyB;IAAA,IAAXF,KAAW,uEAAH,CAAG;IACvB,IAAIqwC,WAAW,KAAK/B,aAApB;;IACA,GAAG;MACD+B,WAAY,YAAWn2D,6BAAX,EAAgC85D,OAAhC,CAAwC,CAAxC,CAAZ3D;MACAA,WAAW9uD,KAAK0yD,IAAL1yD,CAAU8uD,WAAW,EAArB9uD,IAA2B,EAAtC8uD;MACAA,WAAW9uD,KAAK6G,GAAL7G,CAASnH,mBAATmH,EAAoB8uD,QAApB9uD,CAAX8uD;IAHF,SAIS,EAAErwC,KAAF,GAAU,CAAV,IAAeqwC,WAAWj2D,mBAJnC;;IAKA,KAAKkmB,iBAAL,GAAyB+vC,QAAzB;EA56Da;;EAm7DfjwC,gBAAyB;IAAA,IAAXJ,KAAW,uEAAH,CAAG;IACvB,IAAIqwC,WAAW,KAAK/B,aAApB;;IACA,GAAG;MACD+B,WAAY,YAAWn2D,6BAAX,EAAgC85D,OAAhC,CAAwC,CAAxC,CAAZ3D;MACAA,WAAW9uD,KAAKC,KAALD,CAAW8uD,WAAW,EAAtB9uD,IAA4B,EAAvC8uD;MACAA,WAAW9uD,KAAKyD,GAALzD,CAASpH,mBAAToH,EAAoB8uD,QAApB9uD,CAAX8uD;IAHF,SAIS,EAAErwC,KAAF,GAAU,CAAV,IAAeqwC,WAAWl2D,mBAJnC;;IAKA,KAAKmmB,iBAAL,GAAyB+vC,QAAzB;EA17Da;;EA67Dfr7B,2BAA2B;IACzB,MAAM/xB,SAAS,KAAK+F,SAAL,CAAejL,YAA9B;;IAEA,IAAIkF,iCAAW,IAAX,2BAAJ,EAA8C;MAC5C,sDAAgCA,MAAhC;;MAEA6E,mBAASe,WAATf,CAAqB,2BAArBA,EAAkD,GAAG7E,MAAO,IAA5D6E;IANuB;EA77DZ;;EA08Df,IAAIoD,oBAAJ,GAA2B;IACzB,OAAO,gFACH,IADG,2BAEH6S,+BAAqBliB,OAFzB;EA38Da;;EAm9Df,IAAIqP,oBAAJ,CAAyB9D,IAAzB,EAA+B;IAC7B,IAAI,uBAAC,IAAD,6BAAJ,EAAsC;MACpC,MAAM,IAAImB,KAAJ,CAAW,sCAAX,CAAN;IAF2B;;IAI7B,IAAI,uDAA+BnB,IAAnC,EAAyC;MACvC;IAL2B;;IAO7B,IAAI,CAACylD,4BAA4BzlD,IAA5B,CAAL,EAAwC;MACtC,MAAM,IAAImB,KAAJ,CAAW,kCAAiCnB,IAAlC,EAAV,CAAN;IAR2B;;IAU7B,IAAI,CAAC,KAAKiJ,WAAV,EAAuB;MACrB;IAX2B;;IAa7B,mDAA6BjJ,IAA7B;;IACA,KAAK6I,QAAL,CAAcwC,QAAd,CAAuB,6BAAvB,EAAsD;MACpDC,QAAQ,IAD4C;MAEpDtL;IAFoD,CAAtD;;IAKA,wDAAgC2nD,UAAhC,CAA2C3nD,IAA3C;EAt+Da;;EA0+Df,IAAIuR,sBAAJ,SAA4C;IAAA,IAAjB;MAAEwL,IAAF;MAAQjkB;IAAR,CAAiB;;IAC1C,IAAI,uBAAC,IAAD,6BAAJ,EAAsC;MACpC,MAAM,IAAIqI,KAAJ,CAAW,sCAAX,CAAN;IAFwC;;IAI1C,wDAAgC2rD,YAAhC,CAA6C/vC,IAA7C,EAAmDjkB,KAAnD;EA9+Da;;EAi/Dfg2B,UAAU;IACR,IAAI,CAAC,KAAK7lB,WAAV,EAAuB;MACrB;IAFM;;IAIR,MAAMq3C,aAAa,EAAnB;;IACA,WAAWp0B,QAAX,IAAuB,KAAK26B,MAA5B,EAAoC;MAClC36B,SAASrL,MAATqL,CAAgBo0B,UAAhBp0B;IANM;;IAQR,KAAKrL,MAAL;EAz/Da;;AAAA;;;;iCAmVQ4mC,aAAa;EAClC,MAAM9uD,SAAS;IACbmL,4CAAsB,IAAtB,wBADa;IAEbE,sCAAgB,IAAhB,kBAFa;IAGbqB,eAAe,KAAKA;EAHP,CAAf;;EAKA,IAAI,CAACoiD,WAAL,EAAkB;IAChB,OAAO9uD,MAAP;EAPgC;;EAUlC,IAAI,CAAC8uD,YAAYtnD,QAAZsnD,CAAqBsF,yBAAeC,IAApCvF,CAAL,EAAgD;IAC9C,KAAK9lD,MAAL,CAAY5K,SAAZ,CAAsBsH,GAAtB,CAA0B+mD,wBAA1B;EAXgC;;EAclC,IAAI,CAACqC,YAAYtnD,QAAZsnD,CAAqBsF,yBAAeE,eAApCxF,CAAL,EAA2D;IACzD9uD,OAAOmL,oBAAPnL,GAA8Bge,+BAAqBliB,OAAnDkE;EAfgC;;EAkBlC,IACE,CAAC8uD,YAAYtnD,QAAZsnD,CAAqBsF,yBAAeG,kBAApCzF,CAAD,IACA,CAACA,YAAYtnD,QAAZsnD,CAAqBsF,yBAAeI,sBAApC1F,CADD,IAEA,iDAAyBtB,yBAAeC,YAH1C,EAIE;IACAztD,OAAOqL,cAAPrL,GAAwBwtD,yBAAezxD,MAAvCiE;EAvBgC;;EA0BlC,OAAOA,MAAP;AA7Wa;;yCAgXgB;EAW7B,IACEgI,SAASouB,eAATpuB,KAA6B,QAA7BA,IACA,CAAC,KAAKiB,SAAL,CAAe1L,YADhByK,IAEA,KAAK4pD,gBAAL,GAAwBvuD,KAAxB,CAA8BlC,MAA9B,KAAyC,CAH3C,EAIE;IACA,OAAO0G,QAAQC,OAARD,EAAP;EAhB2B;;EAqB7B,MAAM4sD,0BAA0B,IAAI5sD,OAAJ,CAAYC,WAAW;IACrD,iDAA2B,MAAM;MAC/B,IAAIE,SAASouB,eAATpuB,KAA6B,QAAjC,EAA2C;QACzC;MAF6B;;MAI/BF;MAEAE,SAAS2kB,mBAAT3kB,CACE,kBADFA,wBAEE,IAFFA;;MAIA,iDAA2B,IAA3B;IAVF;;IAYAA,SAASnI,gBAATmI,CAA0B,kBAA1BA,wBAA8C,IAA9CA;EAb8B,EAAhC;EAgBA,OAAOH,QAAQmgB,IAARngB,CAAa,CAClB,KAAK6mD,0BAAL,CAAgC3uC,OADd,EAElB00C,uBAFkB,CAAb5sD,CAAP;AArZa;;mCAwuBU;EACvB,IAAI,KAAKukD,WAAL,KAAqBnwD,qBAAWI,IAApC,EAA0C;IACxC,MAAM,IAAImM,KAAJ,CAAU,mDAAV,CAAN;EAFqB;;EAIvB,MAAMmJ,aAAa,KAAKi6B,kBAAxB;EAAA,MACErsC,8BAAQ,IAAR,uBADF;EAAA,MAEEyJ,SAAS,KAAKA,MAFhB;;EAKAA,OAAOoc,WAAPpc,GAAqB,EAArBA;EAEAzJ,MAAM6wD,KAAN7wD,CAAY4B,MAAZ5B,GAAqB,CAArBA;;EAEA,IAAI,KAAK8sD,WAAL,KAAqB/vD,qBAAWjB,IAAhC,IAAwC,CAAC,KAAK6kB,oBAAlD,EAAwE;IAEtE,MAAMqT,WAAW,KAAK26B,MAAL,CAAYv8C,aAAa,CAAzB,CAAjB;IACA3I,OAAO8zB,MAAP9zB,CAAcuqB,SAASlxB,GAAvB2G;IAEAzJ,MAAM6wD,KAAN7wD,CAAY+F,IAAZ/F,CAAiBg0B,QAAjBh0B;EALF,OAMO;IACL,MAAMm1D,eAAe,IAAIpwD,GAAJ,EAArB;IAAA,MACEqvD,SAAS,KAAKtH,WAAL,GAAmB,CAD9B;;IAIA,IAAIsH,WAAW,CAAC,CAAhB,EAAmB;MAEjBe,aAAahvD,GAAbgvD,CAAiB/iD,aAAa,CAA9B+iD;IAFF,OAGO,IAAI/iD,aAAa,CAAbA,KAAmBgiD,MAAvB,EAA+B;MAEpCe,aAAahvD,GAAbgvD,CAAiB/iD,aAAa,CAA9B+iD;MACAA,aAAahvD,GAAbgvD,CAAiB/iD,UAAjB+iD;IAHK,OAIA;MAELA,aAAahvD,GAAbgvD,CAAiB/iD,aAAa,CAA9B+iD;MACAA,aAAahvD,GAAbgvD,CAAiB/iD,aAAa,CAA9B+iD;IAfG;;IAmBL,MAAMxnC,SAASllB,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAf;IACAklB,OAAO0O,SAAP1O,GAAmB,QAAnBA;;IAEA,IAAI,KAAKhN,oBAAT,EAA+B;MAC7B,MAAMy0C,YAAY3sD,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAlB;MACA2sD,UAAU/4B,SAAV+4B,GAAsB,WAAtBA;MACAznC,OAAO4P,MAAP5P,CAAcynC,SAAdznC;IAzBG;;IA4BL,WAAW1pB,CAAX,IAAgBkxD,YAAhB,EAA8B;MAC5B,MAAMnhC,WAAW,KAAK26B,MAAL,CAAY1qD,CAAZ,CAAjB;;MACA,IAAI,CAAC+vB,QAAL,EAAe;QACb;MAH0B;;MAK5BrG,OAAO4P,MAAP5P,CAAcqG,SAASlxB,GAAvB6qB;MAEA3tB,MAAM6wD,KAAN7wD,CAAY+F,IAAZ/F,CAAiBg0B,QAAjBh0B;IAnCG;;IAqCLyJ,OAAO8zB,MAAP9zB,CAAckkB,MAAdlkB;EAxDqB;;EA2DvBzJ,MAAM4wD,UAAN5wD,GAAmBoS,cAAcpS,MAAM2wD,kBAAvC3wD;EACAA,MAAM2wD,kBAAN3wD,GAA2BoS,UAA3BpS;AApyBa;;0BA8yBCg0B,UAA2B;EAAA,IAAjBqhC,QAAiB,uEAAN,IAAM;EACzC,MAAM;IAAEvyD,GAAF;IAAOkD;EAAP,IAAcguB,QAApB;;EAEA,IAAI,KAAK64B,WAAL,KAAqBnwD,qBAAWI,IAApC,EAA0C;IAExC,KAAKgyD,qBAAL,CAA2B9oD,EAA3B;;IAEA;;IAGA,KAAK2iB,MAAL;EAVuC;;EAazC,IAAI,CAAC0sC,QAAD,IAAa,CAAC,KAAK10C,oBAAvB,EAA6C;IAC3C,MAAMxhB,OAAO2D,IAAIvE,UAAJuE,GAAiBA,IAAItE,UAAlC;IAAA,MACEyB,QAAQd,OAAO2D,IAAInE,WADrB;IAEA,MAAM;MAAES,UAAF;MAAcT;IAAd,IAA8B,KAAK+K,SAAzC;;IACA,IACE,KAAKmjD,WAAL,KAAqBnwD,qBAAWE,UAAhC,IACAuC,OAAOC,UADP,IAEAa,QAAQb,aAAaT,WAHvB,EAIE;MACA02D,WAAW;QAAEl2D,MAAM,CAAR;QAAWF,KAAK;MAAhB,CAAXo2D;IATyC;EAbJ;;EAyBzC13D,8BAAemF,GAAfnF,EAAoB03D,QAApB13D;AAv0Ba;;uBA80BFozD,UAAU;EACrB,OACEA,aAAa,KAAK/B,aAAlB+B,IACA9uD,KAAKwE,GAALxE,CAAS8uD,WAAW,KAAK/B,aAAzB/sD,IAA0C,KAF5C;AA/0Ba;;kCAy9BS;EACtB,MAAM+xB,WAAW,KAAK26B,MAAL,CAAY,KAAKtiB,kBAAL,GAA0B,CAAtC,CAAjB;;EAEA,IAAI,KAAK1rB,oBAAT,EAA+B;IAE7B,KAAKsuC,SAAL,CAAe,KAAKC,kBAApB,EAAwC,IAAxC;EALoB;;EAOtB,2EAAqBl7B,QAArB;AAh+Ba;;qCA6zCYA,UAAU;EACnC,IAAIA,SAASrM,OAAb,EAAsB;IACpB,OAAOqM,SAASrM,OAAhB;EAFiC;;EAInC,IAAI;IAAA;;IACF,MAAMA,UAAU,MAAM,KAAK5W,WAAL,CAAiBm8B,OAAjB,CAAyBlZ,SAAShuB,EAAlC,CAAtB;;IACA,IAAI,CAACguB,SAASrM,OAAd,EAAuB;MACrBqM,SAASg1B,UAATh1B,CAAoBrM,OAApBqM;IAHA;;IAKF,IAAI,2BAAC,0BAAK3W,WAAL,EAAiBxI,iBAAlB,kDAAC,8CAAqC8S,QAAQ0oC,GAA7C,CAAD,CAAJ,EAAwD;MACtD,KAAKhzC,WAAL,CAAiB9I,YAAjB,CAA8Byf,SAAShuB,EAAvC,EAA2C2hB,QAAQ0oC,GAAnD;IANA;;IAQF,OAAO1oC,OAAP;EARF,EASE,OAAOxM,MAAP,EAAe;IACfld,QAAQC,KAARD,CAAc,kCAAdA,EAAkDkd,MAAlDld;IACA,OAAO,IAAP;EAfiC;AA7zCtB;;0BAg1CC4G,SAAS;EAAA;;EACvB,IAAIA,2BAAQuB,KAARvB,kEAAemB,EAAfnB,MAAsB,CAA1B,EAA6B;IAC3B,OAAO,IAAP;EADF,OAEO,IAAIA,0BAAQwB,IAARxB,gEAAcmB,EAAdnB,MAAqB,KAAKyM,UAA9B,EAA0C;IAC/C,OAAO,KAAP;EAJqB;;EAMvB,QAAQ,KAAKu7C,WAAb;IACE,KAAKnwD,qBAAWI,IAAhB;MACE,OAAO,kDAA0B8zD,UAAjC;;IACF,KAAKl0D,qBAAWE,UAAhB;MACE,OAAO,KAAK8wB,MAAL,CAAYztB,KAAnB;EAJJ;;EAMA,OAAO,KAAKytB,MAAL,CAAYttB,IAAnB;AA51Ca;;oCAk2CW6hD,YAAY;EACpC,WAAWj8C,EAAX,IAAiBi8C,UAAjB,EAA6B;IAC3B,MAAMjuB,WAAW,KAAK26B,MAAL,CAAY3oD,KAAK,CAAjB,CAAjB;IACAguB,6DAAUshC,wBAAVthC,CAAuD,IAAvDA;EAHkC;;EAKpC,WAAWA,QAAX,0BAAuB,IAAvB,YAAqC;IACnC,IAAIiuB,WAAW/uC,GAAX+uC,CAAejuB,SAAShuB,EAAxBi8C,CAAJ,EAAiC;MAE/B;IAHiC;;IAKnCjuB,SAASshC,wBAATthC,CAAsD,KAAtDA;EAVkC;AAl2CvB;;;;;;;;;;;;;AC9LjB;;AACA;;;;;;;;;;;;;;;;;;AAaA,MAAM+/B,4BAAN,CAAmC;EAMjC32D,YAAYgS,OAAZ,EAAqB;IAAA;MAAA;MAAA;IAAA;;IACnB,KAAKmkD,OAAL,GAAenkD,QAAQmkD,OAAvB;IACA,KAAK5rC,OAAL,GAAevY,QAAQuY,OAAvB;IACA,KAAKtF,iBAAL,GAAyBjT,QAAQiT,iBAARjT,IAA6B,IAAtD;IACA,KAAK8jD,oBAAL,GAA4B9jD,QAAQ8jD,oBAApC;IACA,KAAK95C,IAAL,GAAYhK,QAAQgK,IAARhK,IAAgBk/C,oBAA5B;IACA,KAAKiH,qBAAL,GAA6B,IAA7B;IACA,KAAKzyD,GAAL,GAAW,IAAX;IACA,KAAK0yD,UAAL,GAAkB,KAAlB;;IACA,wCAAkBpmD,QAAQ0kD,SAA1B;EAf+B;;EAsBjC,MAAM9qC,MAAN,CAAa2/B,QAAb,EAA2C;IAAA,IAApB8M,MAAoB,uEAAX,SAAW;;IACzC,IAAIA,WAAW,SAAf,EAA0B;MACxB;IAFuC;;IAKzC,IAAI,KAAKD,UAAT,EAAqB;MACnB;IANuC;;IASzC,MAAME,iBAAiB/M,SAAS5gB,KAAT4gB,CAAe;MAAEgN,UAAU;IAAZ,CAAfhN,CAAvB;;IACA,IAAI,KAAK7lD,GAAT,EAAc;MACZ,KAAKyyD,qBAAL,CAA2B5sC,MAA3B,CAAkC;QAAEggC,UAAU+M;MAAZ,CAAlC;MACA,KAAK3rD,IAAL;MACA;IAbuC;;IAiBzC,KAAKjH,GAAL,GAAW2F,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAX;IACA,KAAK3F,GAAL,CAASu5B,SAAT,GAAqB,uBAArB;IACA,KAAKv5B,GAAL,CAASuhC,QAAT,GAAoB,CAApB;IACA,KAAKkvB,OAAL,CAAah2B,MAAb,CAAoB,KAAKz6B,GAAzB;IAEA,KAAKyyD,qBAAL,GAA6B,IAAIK,+BAAJ,CAA0B;MACrD9B,iCAAW,IAAX,aADqD;MAErDhxD,KAAK,KAAKA,GAF2C;MAGrDuf,mBAAmB,KAAKA,iBAH6B;MAIrD6wC,sBAAsB,KAAKA,oBAJ0B;MAKrD99C,WAAW,KAAKuS,OAAL,CAAakuC,UAL6B;MAMrDz8C,MAAM,KAAKA,IAN0C;MAOrDuvC,UAAU+M;IAP2C,CAA1B,CAA7B;IAUA,MAAMvyC,aAAa;MACjBwlC,UAAU+M,cADO;MAEjB5yD,KAAK,KAAKA,GAFO;MAGjBgzD,aAAa,IAHI;MAIjBL;IAJiB,CAAnB;IAOA,KAAKF,qBAAL,CAA2BvsC,MAA3B,CAAkC7F,UAAlC;EA7D+B;;EAgEjC6nC,SAAS;IACP,KAAKwK,UAAL,GAAkB,IAAlB;IACA,KAAK/yC,OAAL;EAlE+B;;EAqEjC3Y,OAAO;IACL,IAAI,CAAC,KAAKhH,GAAV,EAAe;MACb;IAFG;;IAIL,KAAKA,GAAL,CAASgf,MAAT,GAAkB,IAAlB;EAzE+B;;EA4EjC/X,OAAO;IACL,IAAI,CAAC,KAAKjH,GAAV,EAAe;MACb;IAFG;;IAIL,KAAKA,GAAL,CAASgf,MAAT,GAAkB,KAAlB;EAhF+B;;EAmFjCW,UAAU;IACR,IAAI,CAAC,KAAK3f,GAAV,EAAe;MACb;IAFM;;IAIR,KAAKywD,OAAL,GAAe,IAAf;IACA,KAAKgC,qBAAL,CAA2B9yC,OAA3B;IACA,KAAK3f,GAAL,CAASwG,MAAT;EAzF+B;;AAAA;;;;;;;;;;;;;;;;ACvBnC,MAAMysD,uBAAuB;EAC3BC,UAAU,mBADiB;EAE3BC,eAAe,oCAFY;EAI3BC,wBAAwB,mCAJG;EAK3BC,wBAAwB,mCALG;EAM3BC,iCAAiC,oBANN;EAO3BC,2CAA2C,IAPhB;EAQ3BC,gDAAgD,IARrB;EAS3BC,oDAAoD,UATzB;EAU3BC,qDAAqD,WAV1B;EAW3BC,uCAAuC,IAXZ;EAY3BC,uCAAuC,IAZZ;EAa3BC,2CAA2C,QAbhB;EAc3BC,0CAA0C,OAdf;EAe3BC,gDACE,mDAhByB;EAiB3BC,qDACE,6DAlByB;EAmB3BC,oCAAoC,KAnBT;EAoB3BC,mCAAmC,IApBR;EAsB3BC,wBAAwB,eAtBG;EAwB3B,wBAAwB,gBAxBG;EAyB3B,sCACE,+DA1ByB;EA4B3BC,mBAAmB,mBA5BQ;EA6B3BC,eAAe,eA7BY;EA8B3BC,kBAAkB,eA9BS;EA+B3BC,mBAAmB,4BA/BQ;EAiC3BC,kBAAkB,gDAjCS;EAkC3BC,qBAAqB,6CAlCM;EAmC3B,yBAAyB,gCAnCE;EAoC3B,2BAA2B,kCApCA;EAqC3B,+BAA+B,2BArCJ;EAsC3B,iCAAiC,6BAtCN;EAuC3BC,gBAAgB,kBAvCW;EAyC3BC,oBAAoB,wCAzCO;EA0C3BC,eAAe,sBA1CY;EA2C3BC,aAAa,kBA3Cc;EA4C3BC,YAAY,gBA5Ce;EA6C3BC,YAAY,gBA7Ce;EA8C3BC,iBAAiB,6CA9CU;EAgD3BC,kBAAkB,YAhDS;EAiD3BC,gBAAgB,UAjDW;EAkD3BC,iBAAiB,gBAlDU;EAmD3BC,mBAAmB,aAnDQ;EAoD3BC,oBAAoB,YApDO;EAsD3B3iC,SAAS,UAtDkB;EAuD3B4iC,eAAe,0CAvDY;EAwD3BC,oBAAoB,gCAxDO;EAyD3BC,oBAAoB,mBAzDO;EA0D3BC,2BAA2B,6BA1DA;EA4D3BC,wBACE,2DA7DyB;EA8D3BC,oBAAoB,oDA9DO;EA+D3BC,oBACE,2DAhEyB;EAkE3BC,2BAA2B,aAlEA;EAmE3BC,6BAA6B,iBAnEF;EAoE3BC,uBAAuB,YApEI;EAqE3BC,8BAA8B;AArEH,CAA7B;;AAwEA,SAASC,eAAT,CAAyBp4D,GAAzB,EAA8BqiB,IAA9B,EAAoC;EAClC,QAAQriB,GAAR;IACE,KAAK,kBAAL;MACEA,MAAO,oBAAmBqiB,KAAKa,KAALb,KAAe,CAAfA,GAAmB,KAAnBA,GAA2B,OAAQ,GAA7DriB;MACA;;IACF,KAAK,wBAAL;MACEA,MAAO,0BAAyBqiB,KAAK5gB,KAAL4gB,KAAe,CAAfA,GAAmB,KAAnBA,GAA2B,OAAQ,GAAnEriB;MACA;EANJ;;EAQA,OAAOo1D,qBAAqBp1D,GAArB,KAA6B,EAApC;AAnGF;;AAsGA,MAAMq4D,qBAAqB;EACzBC,IAAI,OADqB;EAEzBC,IAAI,OAFqB;EAGzBC,IAAI,OAHqB;EAIzBC,IAAI,OAJqB;EAKzBC,IAAI,OALqB;EAMzBC,IAAI,OANqB;EAOzBC,IAAI,OAPqB;EAQzBC,IAAI,OARqB;EASzBC,IAAI,OATqB;EAUzBC,IAAI,OAVqB;EAWzBC,IAAI,OAXqB;EAYzBC,IAAI,OAZqB;EAazBC,IAAI,OAbqB;EAczBC,IAAI;AAdqB,CAA3B;;AAkBA,SAASC,aAAT,CAAuBC,QAAvB,EAAiC;EAC/B,OAAOhB,mBAAmBgB,QAAnB,aAAmBA,QAAnB,uBAAmBA,SAAUj5D,WAAVi5D,EAAnB,KAA+CA,QAAtD;AAzHF;;AA6HA,SAASC,eAAT,CAAyBroB,IAAzB,EAA+B5uB,IAA/B,EAAqC;EACnC,IAAI,CAACA,IAAL,EAAW;IACT,OAAO4uB,IAAP;EAFiC;;EAInC,OAAOA,KAAKvwC,OAALuwC,CAAa,sBAAbA,EAAqC,CAAC/uB,GAAD,EAAM7T,IAAN,KAAe;IACzD,OAAOA,QAAQgU,IAARhU,GAAegU,KAAKhU,IAAL,CAAfA,GAA4B,OAAOA,IAAP,GAAc,IAAjD;EADK,EAAP;AAjIF;;AA0IA,MAAMs/C,WAAW;EACf,MAAM9hB,WAAN,GAAoB;IAClB,OAAO,OAAP;EAFa;;EAKf,MAAM3wB,YAAN,GAAqB;IACnB,OAAO,KAAP;EANa;;EASf,MAAM9M,GAAN,CAAUpO,GAAV,EAAmE;IAAA,IAApDqiB,IAAoD,uEAA7C,IAA6C;IAAA,IAAvCgB,QAAuC,uEAA5B+0C,gBAAgBp4D,GAAhB,EAAqBqiB,IAArB,CAA4B;IACjE,OAAOi3C,gBAAgBj2C,QAAhB,EAA0BhB,IAA1B,CAAP;EAVa;;EAaf,MAAM/H,SAAN,CAAgBrd,OAAhB,EAAyB,CAbV;;AAAA,CAAjB;;;;;;;;;;;;;;AClHA;;AACA;;AAsBA,MAAMg2D,sBAAN,CAA6B;EAI3Bx2D,kBAeG;IAAA,IAfS;MACVm2D,OADU;MAEV5rC,OAFU;MAGVtK,WAHU;MAIVtE,eAJU;MAKVsJ,oBAAoB,IALV;MAMV3V,qBAAqB,EANX;MAOVmf,cAAc,IAPJ;MAQVzS,OAAOk1C,oBARG;MASVjiD,kBAAkB,KATR;MAUVmnD,sBAAsB,IAVZ;MAWVE,sBAAsB,IAXZ;MAYVhP,aAAa,IAZH;MAaViP,sBAAsB,IAbZ;MAcVT,uBAAuB;IAdb,CAeT;IACD,KAAKK,OAAL,GAAeA,OAAf;IACA,KAAK5rC,OAAL,GAAeA,OAAf;IACA,KAAKtK,WAAL,GAAmBA,WAAnB;IACA,KAAKtE,eAAL,GAAuBA,eAAvB;IACA,KAAKrM,kBAAL,GAA0BA,kBAA1B;IACA,KAAKmf,WAAL,GAAmBA,WAAnB;IACA,KAAKzS,IAAL,GAAYA,IAAZ;IACA,KAAKiJ,iBAAL,GAAyBA,iBAAzB;IACA,KAAKhW,eAAL,GAAuBA,eAAvB;IACA,KAAK6tD,oBAAL,GAA4B1G,mBAA5B;IACA,KAAK2G,oBAAL,GAA4BzG,mBAA5B;IACA,KAAK3Q,WAAL,GAAmB2B,UAAnB;IACA,KAAK0V,oBAAL,GAA4BzG,mBAA5B;IACA,KAAK0G,qBAAL,GAA6BnH,oBAA7B;IAEA,KAAKpwD,GAAL,GAAW,IAAX;IACA,KAAK0yD,UAAL,GAAkB,KAAlB;EApCyB;;EA6C3B,MAAMxsC,MAAN,CAAa2/B,QAAb,EAA2C;IAAA,IAApB8M,MAAoB,uEAAX,SAAW;IACzC,MAAM,CAACK,WAAD,EAAcrC,eAAe,KAA7B,EAAoC6G,eAAe,IAAnD,IACJ,MAAMhyD,QAAQua,GAARva,CAAY,CAChB,KAAKqf,OAAL,CAAa4yC,cAAb,CAA4B;MAAE9E;IAAF,CAA5B,CADgB,EAEhB,KAAKyE,oBAFW,EAGhB,KAAKC,oBAHW,CAAZ7xD,CADR;;IAOA,IAAI,KAAKktD,UAAL,IAAmBM,YAAYl0D,MAAZk0D,KAAuB,CAA9C,EAAiD;MAC/C;IATuC;;IAYzC,MAAM3yC,aAAa;MACjBwlC,UAAUA,SAAS5gB,KAAT4gB,CAAe;QAAEgN,UAAU;MAAZ,CAAfhN,CADO;MAEjB7lD,KAAK,KAAKA,GAFO;MAGjBgzD,WAHiB;MAIjBtkD,MAAM,KAAKmW,OAJM;MAKjBjb,oBAAoB,KAAKA,kBALR;MAMjBmf,aAAa,KAAKA,WAND;MAOjBxO,aAAa,KAAKA,WAPD;MAQjBtE,iBAAiB,KAAKA,eARL;MASjBsJ,mBAAmB,KAAKA,iBATP;MAUjBhW,iBAAiB,KAAKA,eAVL;MAWjBonD,YAXiB;MAYjB6G,YAZiB;MAajB5V,YAAY,KAAK3B,WAbA;MAcjB4Q,qBAAqB,KAAKyG,oBAdT;MAejBlH,sBAAsB,KAAKmH;IAfV,CAAnB;;IAkBA,IAAI,KAAKv3D,GAAT,EAAc;MAGZ03D,0BAAgB7xC,MAAhB6xC,CAAuBr3C,UAAvBq3C;IAHF,OAIO;MAGL,KAAK13D,GAAL,GAAW2F,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAX;MACA,KAAK3F,GAAL,CAASu5B,SAAT,GAAqB,iBAArB;MACA,KAAKk3B,OAAL,CAAah2B,MAAb,CAAoB,KAAKz6B,GAAzB;MACAqgB,WAAWrgB,GAAXqgB,GAAiB,KAAKrgB,GAAtBqgB;;MAEAq3C,0BAAgBxxC,MAAhBwxC,CAAuBr3C,UAAvBq3C;;MACA,KAAKphD,IAAL,CAAU6B,SAAV,CAAoB,KAAKnY,GAAzB;IA3CuC;EA7ChB;;EA4F3BkoD,SAAS;IACP,KAAKwK,UAAL,GAAkB,IAAlB;EA7FyB;;EAgG3B1rD,OAAO;IACL,IAAI,CAAC,KAAKhH,GAAV,EAAe;MACb;IAFG;;IAIL,KAAKA,GAAL,CAASgf,MAAT,GAAkB,IAAlB;EApGyB;;AAAA;;;;;;;;;;;;;;;ACb7B;;AAOA;;AAUA;;AACA;;AACA;;;;;;;;;;;;;;;;AAyCA,MAAM24C,oBAAoB9vD,iCAAoBU,eAApBV,IAAuC,QAAjE;;;;;;AAKA,MAAMslD,WAAN,CAAkB;EAWhB7yD,YAAYgS,OAAZ,EAAqB;IAAA;;IAAA;MAAA;MAAA,OAVH6+C,yBAAeC;IAUZ;;IAAA;MAAA;MAAA,OARC;QACpBwM,wBAAwB,IADJ;QAEpBC,oBAAoB;MAFA;IAQD;;IACnB,MAAMjxD,YAAY0F,QAAQ1F,SAA1B;IACA,MAAMo/C,kBAAkB15C,QAAQ05C,eAAhC;IAEA,KAAK9iD,EAAL,GAAUoJ,QAAQpJ,EAAlB;IACA,KAAKs7C,WAAL,GAAmB,SAAS,KAAKt7C,EAAjC;IAEA,KAAK2hB,OAAL,GAAe,IAAf;IACA,KAAK+O,SAAL,GAAiB,IAAjB;IACA,KAAKhlB,QAAL,GAAgB,CAAhB;IACA,KAAK2jB,KAAL,GAAajmB,QAAQimB,KAARjmB,IAAiBzU,uBAA9B;IACA,KAAKguD,QAAL,GAAgBG,eAAhB;IACA,KAAKoB,aAAL,GAAqBpB,gBAAgBp3C,QAArC;IACA,KAAKy4C,6BAAL,GACE/6C,QAAQ+Z,4BAAR/Z,IAAwC,IAD1C;IAEA,KAAKwrD,oBAAL,GAA4B,KAA5B;IACA,KAAKztD,aAAL,4BAAqBiC,QAAQjC,aAA7B,yEAA8C7Q,wBAAcE,MAA5D;;IACA,sEACE4S,QAAQtD,cADV,yEAC4BmiD,yBAAeC,YAD3C;;IAEA,KAAKxhD,kBAAL,GAA0B0C,QAAQ1C,kBAAR0C,IAA8B,EAAxD;IACA,KAAKhC,cAAL,GAAsBgC,QAAQhC,cAARgC,IAA0B,KAAhD;IACA,KAAK/D,eAAL,GAAuB+D,QAAQ/D,eAAR+D,IAA2BqrD,iBAAlD;IACA,KAAK/8C,UAAL,GAAkBtO,QAAQsO,UAARtO,IAAsB,IAAxC;IAEA,KAAKuB,QAAL,GAAgBvB,QAAQuB,QAAxB;IACA,KAAKqN,cAAL,GAAsB5O,QAAQ4O,cAA9B;IACA,KAAK6xC,gBAAL,GAAwBzgD,QAAQygD,gBAAhC;IACA,KAAKC,sBAAL,GAA8B1gD,QAAQ0gD,sBAAtC;IACA,KAAKE,4BAAL,GAAoC5gD,QAAQ4gD,4BAA5C;IACA,KAAKD,eAAL,GAAuB3gD,QAAQ2gD,eAA/B;IACA,KAAK8K,eAAL,4BACEzrD,QAAQ8gD,sBADV,0DACE9gD,sBAAgCgkD,qBAAhChkD,CAAsD;MACpDgG,WAAW,KAAKpP,EAAL,GAAU,CAD+B;MAEpD2K,UAAU,KAAKA;IAFqC,CAAtDvB,CADF;IAKA,KAAK+gD,sBAAL,GAA8B/gD,QAAQ+gD,sBAAtC;IAKE,KAAKxhD,QAAL,GAAgBS,QAAQT,QAARS,IAAoBjT,uBAAaC,MAAjD;IAEF,KAAKgd,IAAL,GAAYhK,QAAQgK,IAARhK,IAAgBk/C,oBAA5B;IAEA,KAAKwM,SAAL,GAAiB,IAAjB;IACA,KAAKC,kBAAL,GAA0B,IAAI18B,OAAJ,EAA1B;IACA,KAAK5I,cAAL,GAAsBt6B,0BAAgBC,OAAtC;IACA,KAAKmnD,MAAL,GAAc,IAAd;IACA,KAAKyY,YAAL,GAAoB,IAApB;IAKE,KAAKC,aAAL,GAAqB,0BAAC,KAAKj9C,cAAN,iDAAC,qBAAqBujC,SAArB,EAAD,CAArB;IAGF,KAAK6Y,oBAAL,GAA4B,IAA5B;IAEA,KAAKc,eAAL,GAAuB,IAAvB;IACA,KAAK3F,qBAAL,GAA6B,IAA7B;IACA,KAAK4F,SAAL,GAAiB,IAAjB;IACA,KAAKC,SAAL,GAAiB,IAAjB;IACA,KAAKC,QAAL,GAAgB,IAAhB;IACA,KAAKC,eAAL,GAAuB,IAAvB;IAEA,MAAMx4D,MAAM2F,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAZ;IACA3F,IAAIu5B,SAAJv5B,GAAgB,MAAhBA;IACAA,IAAI6F,KAAJ7F,CAAUY,KAAVZ,GAAkBb,KAAKC,KAALD,CAAW,KAAK0mD,QAAL,CAAcjlD,KAAzBzB,IAAkC,IAApDa;IACAA,IAAI6F,KAAJ7F,CAAUa,MAAVb,GAAmBb,KAAKC,KAALD,CAAW,KAAK0mD,QAAL,CAAchlD,MAAzB1B,IAAmC,IAAtDa;IACAA,IAAI6/B,YAAJ7/B,CAAiB,kBAAjBA,EAAqC,KAAKkD,EAA1ClD;IACAA,IAAI6/B,YAAJ7/B,CAAiB,MAAjBA,EAAyB,QAAzBA;IACA,KAAKsW,IAAL,CAAUrK,GAAV,CAAc,eAAd,EAA+B;MAAEyC,MAAM,KAAKxL;IAAb,CAA/B,EAAkDmP,IAAlD,CAAuDkP,OAAO;MAC5DvhB,IAAI6/B,YAAJ7/B,CAAiB,YAAjBA,EAA+BuhB,GAA/BvhB;IADF;IAGA,KAAKA,GAAL,GAAWA,GAAX;IAEA4G,gEAAW6zB,MAAX7zB,CAAkB5G,GAAlB4G;;IAEA,IAGE,KAAKuxD,aAHP,EAIE;MACA,MAAM;QAAE9xC;MAAF,IAAmC/Z,OAAzC;;MACA,IAAI+Z,4BAAJ,EAAkC;QAGhCA,6BAA6BhU,IAA7BgU,CAAkCC,yBAAyB;UACzD,IACED,iCAAiC,KAAKghC,6BADxC,EAEE;YACA;UAJuD;;UAMzD,iDAAyBuQ,sBAAzB,GACEtxC,sBAAsBmyC,oBADxB;QANF;MALF;IAlFiB;EAXL;;EA+GhBvS,WAAWrhC,OAAX,EAAoB;IAClB,KAAKA,OAAL,GAAeA,OAAf;IACA,KAAKuiC,aAAL,GAAqBviC,QAAQvkB,MAA7B;IAEA,MAAMynD,gBAAiB,MAAKn5C,QAAL,GAAgB,KAAKw4C,aAArB,IAAsC,GAA7D;IACA,KAAKvB,QAAL,GAAgBhhC,QAAQihC,WAARjhC,CAAoB;MAClC0N,OAAO,KAAKA,KAAL,GAAas6B,wBAAcC,gBADA;MAElCl+C,UAAUm5C;IAFwB,CAApBljC,CAAhB;IAIA,KAAKhF,KAAL;EAxHc;;EA2HhBF,UAAU;IACR,KAAKE,KAAL;;IACA,IAAI,KAAKgF,OAAT,EAAkB;MAChB,KAAKA,OAAL,CAAa/E,OAAb;IAHM;EA3HM;;EAqIhB,MAAM44C,sBAAN,GAA+B;IAC7B,IAAIt9D,QAAQ,IAAZ;;IACA,IAAI;MACF,MAAM,KAAKg9D,eAAL,CAAqBlyC,MAArB,CAA4B,KAAK2/B,QAAjC,EAA2C,SAA3C,CAAN;IADF,EAEE,OAAO30C,EAAP,EAAW;MACX/V,QAAQC,KAARD,CAAe,4BAA2B+V,EAAG,IAA7C/V;MACAC,QAAQ8V,EAAR9V;IAJF,UAKU;MACR,KAAKyS,QAAL,CAAcwC,QAAd,CAAuB,yBAAvB,EAAkD;QAChDC,QAAQ,IADwC;QAEhDhB,YAAY,KAAKpM,EAF+B;QAGhD9H;MAHgD,CAAlD;IAR2B;EArIf;;EAwJhB,MAAMu9D,4BAAN,GAAqC;IACnC,IAAIv9D,QAAQ,IAAZ;;IACA,IAAI;MACF,MAAM,KAAKq3D,qBAAL,CAA2BvsC,MAA3B,CAAkC,KAAK2/B,QAAvC,EAAiD,SAAjD,CAAN;IADF,EAEE,OAAO30C,EAAP,EAAW;MACX/V,QAAQC,KAARD,CAAe,kCAAiC+V,EAAG,IAAnD/V;MACAC,QAAQ8V,EAAR9V;IAJF,UAKU;MACR,KAAKyS,QAAL,CAAcwC,QAAd,CAAuB,+BAAvB,EAAwD;QACtDC,QAAQ,IAD8C;QAEtDhB,YAAY,KAAKpM,EAFqC;QAGtD9H;MAHsD,CAAxD;IARiC;EAxJrB;;EA2KhB,MAAMw9D,eAAN,GAAwB;IACtB,IAAIx9D,QAAQ,IAAZ;;IACA,IAAI;MACF,MAAM0E,SAAS,MAAM,KAAKy4D,QAAL,CAAcryC,MAAd,CAAqB,KAAK2/B,QAA1B,EAAoC,SAApC,CAArB;;MACA,IAAI,KAAKkS,eAAT,EAA0B;QACxB,KAAKc,yBAAL,CAA+B/4D,OAAOg5D,QAAtC;MAHA;IAAJ,EAKE,OAAO5nD,EAAP,EAAW;MACX/V,QAAQC,KAARD,CAAe,qBAAoB+V,EAAG,IAAtC/V;MACAC,QAAQ8V,EAAR9V;IAPF,UAQU;MACR,KAAKyS,QAAL,CAAcwC,QAAd,CAAuB,kBAAvB,EAA2C;QACzCC,QAAQ,IADiC;QAEzChB,YAAY,KAAKpM,EAFwB;QAGzC9H;MAHyC,CAA3C;IAXoB;EA3KR;;EA8LhB,MAAMy9D,yBAAN,CAAgCC,QAAhC,EAA0C;IACxC,MAAMhqB,OAAO,MAAM,KAAKjqB,OAAL,CAAakvB,cAAb,EAAnB;IACA,MAAMt1C,QAAQ,EAAd;;IACA,WAAW+oC,IAAX,IAAmBsH,KAAKrwC,KAAxB,EAA+B;MAC7BA,MAAMwE,IAANxE,CAAW+oC,KAAKnpC,GAAhBI;IAJsC;;IAMxC,KAAKs5D,eAAL,CAAqBgB,cAArB,CAAoCD,QAApC,EAA8Cr6D,KAA9C;IACA,KAAKs5D,eAAL,CAAqBiB,MAArB;EArMc;;EA2MhBC,kBAAuC;IAAA,IAAvBC,aAAuB,uEAAP,KAAO;;IACrC,IAAI,CAAC,KAAKZ,SAAV,EAAqB;MACnB;IAFmC;;IAIrC,MAAMa,kBAAkB,KAAKb,SAAL,CAAeh3B,UAAvC;IACA,KAAK22B,kBAAL,CAAwBxxC,MAAxB,CAA+B0yC,eAA/B;IAGAA,gBAAgBv4D,KAAhBu4D,GAAwB,CAAxBA;IACAA,gBAAgBt4D,MAAhBs4D,GAAyB,CAAzBA;;IAEA,IAAID,aAAJ,EAAmB;MAEjB,KAAKZ,SAAL,CAAe9xD,MAAf;IAbmC;;IAerC,KAAK8xD,SAAL,GAAiB,IAAjB;EA1Nc;;EA6NhBz4C,QAKQ;IAAA;;IAAA,IALF;MACJu5C,gBAAgB,KADZ;MAEJC,sBAAsB,KAFlB;MAGJC,4BAA4B,KAHxB;MAIJC,eAAe;IAJX,CAKE,uEAAJ,EAAI;IACN,KAAKpT,eAAL,CAAqB;MACnBkT,mBADmB;MAEnBC,yBAFmB;MAGnBC;IAHmB,CAArB;IAKA,KAAK5mC,cAAL,GAAsBt6B,0BAAgBC,OAAtC;IAEA,MAAM0H,MAAM,KAAKA,GAAjB;IACAA,IAAI6F,KAAJ7F,CAAUY,KAAVZ,GAAkBb,KAAKC,KAALD,CAAW,KAAK0mD,QAAL,CAAcjlD,KAAzBzB,IAAkC,IAApDa;IACAA,IAAI6F,KAAJ7F,CAAUa,MAAVb,GAAmBb,KAAKC,KAALD,CAAW,KAAK0mD,QAAL,CAAchlD,MAAzB1B,IAAmC,IAAtDa;IAEA,MAAMw5D,aAAax5D,IAAIw5D,UAAvB;IAAA,MACEC,gBAAiBL,iBAAiB,KAAKd,SAAtBc,IAAoC,IADvD;IAAA,MAEEM,sBACGL,iDAAuB,KAAKjB,eAA5B,0DAAuB,sBAAsBp4D,GAA7C,KAAqD,IAH1D;IAAA,MAIE25D,4BACGL,uDAA6B,KAAK7G,qBAAlC,0DAA6B,sBAA4BzyD,GAAzD,KAAiE,IALtE;IAAA,MAME45D,eAAgBL,mCAAgB,KAAKhB,QAArB,mDAAgB,eAAev4D,GAA/B,KAAuC,IANzD;;IAOA,KAAK,IAAImB,IAAIq4D,WAAW16D,MAAX06D,GAAoB,CAAjC,EAAoCr4D,KAAK,CAAzC,EAA4CA,GAA5C,EAAiD;MAC/C,MAAMq4B,OAAOggC,WAAWr4D,CAAX,CAAb;;MACA,QAAQq4B,IAAR;QACE,KAAKigC,aAAL;QACA,KAAKC,mBAAL;QACA,KAAKC,yBAAL;QACA,KAAKC,YAAL;UACE;MALJ;;MAOApgC,KAAKhzB,MAALgzB;IA5BI;;IA8BNx5B,IAAImhC,eAAJnhC,CAAoB,aAApBA;;IAEA,IAAI05D,mBAAJ,EAAyB;MAGvB,KAAKtB,eAAL,CAAqBpxD,IAArB;IAnCI;;IAsCN,IAAI2yD,yBAAJ,EAA+B;MAC7B,KAAKlH,qBAAL,CAA2BzrD,IAA3B;IADF,OAEO;MAAA;;MACL,+BAAKyrD,qBAAL,kFAA4B9yC,OAA5B;IAzCI;;IA2CN,IAAIi6C,YAAJ,EAAkB;MAGhB,KAAKrB,QAAL,CAAcvxD,IAAd;IA9CI;;IAiDN,IAAI,CAACyyD,aAAL,EAAoB;MAClB,IAAI,KAAKzR,MAAT,EAAiB;QACf,KAAKiQ,kBAAL,CAAwBxxC,MAAxB,CAA+B,KAAKuhC,MAApC;QAGA,KAAKA,MAAL,CAAYpnD,KAAZ,GAAoB,CAApB;QACA,KAAKonD,MAAL,CAAYnnD,MAAZ,GAAqB,CAArB;QACA,OAAO,KAAKmnD,MAAZ;MAPgB;;MASlB,KAAKiR,eAAL;IA1DI;;IA4DN,IAGE,KAAKY,GAHP,EAIE;MACA,KAAK5B,kBAAL,CAAwBxxC,MAAxB,CAA+B,KAAKozC,GAApC;MACA,OAAO,KAAKA,GAAZ;IAlEI;;IAqEN,KAAKC,cAAL,GAAsBn0D,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAtB;IACA,KAAKm0D,cAAL,CAAoBvgC,SAApB,GAAgC,wBAAhC;;IACA,IAGE,KAAK4+B,aAHP,EAIE;MACA,KAAK3F,wBAAL,CAAkD,IAAlD;IA5EI;;IA8EN,KAAKsH,cAAL,CAAoBj6B,YAApB,CAAiC,MAAjC,EAAyC,KAAzC;IACA,KAAKvpB,IAAL,CAAUrK,GAAV,CAAc,SAAd,EAAyBoG,IAAzB,CAA8BkP,OAAO;MAAA;;MACnC,6BAAKu4C,cAAL,8EAAqBj6B,YAArB,CAAkC,YAAlC,EAAgDte,GAAhD;IADF;IAGAvhB,IAAIy6B,MAAJz6B,CAAW,KAAK85D,cAAhB95D;EApTc;;EAuThB6lB,aAA4E;IAAA,IAArE;MAAE0M,QAAQ,CAAV;MAAa3jB,WAAW,IAAxB;MAA8ByX,+BAA+B;IAA7D,CAAqE;IAC1E,KAAKkM,KAAL,GAAaA,SAAS,KAAKA,KAA3B;;IACA,IAAI,OAAO3jB,QAAP,KAAoB,QAAxB,EAAkC;MAChC,KAAKA,QAAL,GAAgBA,QAAhB;IAHwE;;IAK1E,IAAIyX,wCAAwC7gB,OAA5C,EAAqD;MACnD,KAAK6hD,6BAAL,GAAqChhC,4BAArC;MAIAA,6BAA6BhU,IAA7BgU,CAAkCC,yBAAyB;QACzD,IACED,iCAAiC,KAAKghC,6BADxC,EAEE;UACA;QAJuD;;QAMzD,iDAAyBuQ,sBAAzB,GACEtxC,sBAAsBmyC,oBADxB;MANF;IAVwE;;IAqB1E,MAAM1Q,gBAAiB,MAAKn5C,QAAL,GAAgB,KAAKw4C,aAArB,IAAsC,GAA7D;IACA,KAAKvB,QAAL,GAAgB,KAAKA,QAAL,CAAc5gB,KAAd,CAAoB;MAClC1S,OAAO,KAAKA,KAAL,GAAas6B,wBAAcC,gBADA;MAElCl+C,UAAUm5C;IAFwB,CAApB,CAAhB;;IAKA,IAGE,KAAKoQ,aAHP,EAIE;MACAzyD,mBAASe,WAATf,CAAqB,gBAArBA,EAAuC,KAAKmgD,QAAL,CAActzB,KAArD7sB;IAhCwE;;IAmC1E,IAGE,KAAKm0D,GAHP,EAIE;MACA,KAAKrN,YAAL,CAAkB;QAChBp/C,QAAQ,KAAKysD,GADG;QAEhBE,uBAAuB,IAFP;QAGhBC,6BAA6B,IAHb;QAIhBC,gBAAgB;MAJA,CAAlB;MAOA,KAAKpsD,QAAL,CAAcwC,QAAd,CAAuB,cAAvB,EAAuC;QACrCC,QAAQ,IAD6B;QAErChB,YAAY,KAAKpM,EAFoB;QAGrCspD,cAAc,IAHuB;QAIrCzmC,WAAWyyB,YAAYqE,GAAZrE,EAJ0B;QAKrCp9C,OAAO,KAAK88D;MALyB,CAAvC;MAOA;IAtDwE;;IAyD1E,IAAIgC,sBAAsB,KAA1B;;IACA,IAAI,KAAKlS,MAAL,IAAe,KAAKz/C,eAAL,GAAuB,CAA1C,EAA6C;MAC3C,MAAM8/C,cAAc,KAAKA,WAAzB;;MACA,IACG,CAAClpD,KAAKC,KAALD,CAAW,KAAK0mD,QAAL,CAAcjlD,KAAzBzB,IAAkCkpD,YAAY3tD,EAA9CyE,GAAoD,CAArD,KACGA,KAAKC,KAALD,CAAW,KAAK0mD,QAAL,CAAchlD,MAAzB1B,IAAmCkpD,YAAY1tD,EAA/CwE,GAAqD,CADxD,IAED,KAAKoJ,eAHP,EAIE;QACA2xD,sBAAsB,IAAtBA;MAPyC;IA1D6B;;IAqE1E,IAAI,KAAKlS,MAAT,EAAiB;MACf,IACE,KAAK19C,cAAL,IACC,KAAKwtD,oBAAL,IAA6BoC,mBAFhC,EAGE;QACA,KAAK1N,YAAL,CAAkB;UAChBp/C,QAAQ,KAAK46C,MADG;UAEhB+R,uBAAuB,IAFP;UAGhBC,6BAA6B,IAHb;UAIhBC,gBAAgB;QAJA,CAAlB;QAOA,KAAKpsD,QAAL,CAAcwC,QAAd,CAAuB,cAAvB,EAAuC;UACrCC,QAAQ,IAD6B;UAErChB,YAAY,KAAKpM,EAFoB;UAGrCspD,cAAc,IAHuB;UAIrCzmC,WAAWyyB,YAAYqE,GAAZrE,EAJ0B;UAKrCp9C,OAAO,KAAK88D;QALyB,CAAvC;QAOA;MAnBa;;MAqBf,IAAI,CAAC,KAAKI,SAAN,IAAmB,CAAC,KAAKtQ,MAAL,CAAYhpC,MAApC,EAA4C;QAC1C,KAAKs5C,SAAL,GAAiB,KAAKtQ,MAAL,CAAYnhD,UAA7B;QACA,KAAKyxD,SAAL,CAAezyD,KAAf,CAAqB63B,QAArB,GAAgC,UAAhC;MAvBa;IArEyD;;IA+F1E,IAAI,KAAK46B,SAAT,EAAoB;MAClB,KAAK9L,YAAL,CAAkB;QAAEp/C,QAAQ,KAAKkrD,SAAL,CAAeh3B;MAAzB,CAAlB;IAhGwE;;IAkG1E,KAAKzhB,KAAL,CAAW;MACTu5C,eAAe,IADN;MAETC,qBAAqB,IAFZ;MAGTC,2BAA2B,IAHlB;MAITC,cAAc;IAJL,CAAX;EAzZc;;EAqahBpT,kBAIQ;IAAA,IAJQ;MACdkT,sBAAsB,KADR;MAEdC,4BAA4B,KAFd;MAGdC,eAAe;IAHD,CAIR,uEAAJ,EAAI;;IACN,IAAI,KAAKvB,SAAT,EAAoB;MAClB,KAAKA,SAAL,CAAe9P,MAAf;MACA,KAAK8P,SAAL,GAAiB,IAAjB;IAHI;;IAKN,KAAKvY,MAAL,GAAc,IAAd;;IAEA,IAAI,KAAK4Y,SAAT,EAAoB;MAClB,KAAKA,SAAL,CAAenQ,MAAf;MACA,KAAKmQ,SAAL,GAAiB,IAAjB;IATI;;IAWN,IACE,KAAKD,eAAL,KACC,CAACiB,mBAAD,IAAwB,CAAC,KAAKjB,eAAL,CAAqBp4D,GAD/C,CADF,EAGE;MACA,KAAKo4D,eAAL,CAAqBlQ,MAArB;MACA,KAAKkQ,eAAL,GAAuB,IAAvB;MACA,KAAKd,oBAAL,GAA4B,IAA5B;IAjBI;;IAmBN,IACE,KAAK7E,qBAAL,KACC,CAAC6G,yBAAD,IAA8B,CAAC,KAAK7G,qBAAL,CAA2BzyD,GAD3D,CADF,EAGE;MACA,KAAKyyD,qBAAL,CAA2BvK,MAA3B;MACA,KAAKuK,qBAAL,GAA6B,IAA7B;IAxBI;;IA0BN,IAAI,KAAK8F,QAAL,KAAkB,CAACgB,YAAD,IAAiB,CAAC,KAAKhB,QAAL,CAAcv4D,GAAlD,CAAJ,EAA4D;MAAA;;MAC1D,KAAKu4D,QAAL,CAAcrQ,MAAd;MACA,KAAKqQ,QAAL,GAAgB,IAAhB;MACA,8BAAKR,eAAL,gFAAsBoC,OAAtB;IA7BI;;IA+BN,IAAI,KAAKC,oBAAT,EAA+B;MAC7B,KAAKvsD,QAAL,CAAc6hB,IAAd,CAAmB,mBAAnB,EAAwC,KAAK0qC,oBAA7C;;MACA,KAAKA,oBAAL,GAA4B,IAA5B;IAjCI;EAzaQ;;EA8chB5N,oBAKG;IAAA,IALU;MACXp/C,MADW;MAEX2sD,wBAAwB,KAFb;MAGXC,8BAA8B,KAHnB;MAIXC,iBAAiB;IAJN,CAKV;IAED,MAAMr5D,QAAQ,KAAKilD,QAAL,CAAcjlD,KAA5B;IACA,MAAMC,SAAS,KAAKglD,QAAL,CAAchlD,MAA7B;IACA,MAAMb,MAAM,KAAKA,GAAjB;IACAoN,OAAOvH,KAAPuH,CAAaxM,KAAbwM,GACEA,OAAOvG,UAAPuG,CAAkBvH,KAAlBuH,CAAwBxM,KAAxBwM,GACApN,IAAI6F,KAAJ7F,CAAUY,KAAVZ,GACEb,KAAKC,KAALD,CAAWyB,KAAXzB,IAAoB,IAHxBiO;IAIAA,OAAOvH,KAAPuH,CAAavM,MAAbuM,GACEA,OAAOvG,UAAPuG,CAAkBvH,KAAlBuH,CAAwBvM,MAAxBuM,GACApN,IAAI6F,KAAJ7F,CAAUa,MAAVb,GACEb,KAAKC,KAALD,CAAW0B,MAAX1B,IAAqB,IAHzBiO;IAKA,MAAMitD,mBACJ,KAAKxU,QAAL,CAAcj3C,QAAd,GAAyB,KAAKqpD,kBAAL,CAAwBhsD,GAAxB,CAA4BmB,MAA5B,EAAoCwB,QAD/D;IAEA,MAAM0rD,cAAcn7D,KAAKwE,GAALxE,CAASk7D,gBAATl7D,CAApB;IACA,IAAIo7D,SAAS,CAAb;IAAA,IACEC,SAAS,CADX;;IAEA,IAAIF,gBAAgB,EAAhBA,IAAsBA,gBAAgB,GAA1C,EAA+C;MAE7CC,SAAS15D,SAASD,KAAlB25D;MACAC,SAAS55D,QAAQC,MAAjB25D;IAtBD;;IAwBDptD,OAAOvH,KAAPuH,CAAak7C,SAAbl7C,GAA0B,UAASitD,gBAAiB,cAAaE,MAAO,KAAIC,MAAO,GAAnFptD;;IAEA,IAAI,KAAKirD,SAAT,EAAoB;MAKlB,MAAMoC,oBAAoB,KAAKpC,SAAL,CAAexS,QAAzC;MACA,MAAM6U,uBACJ,KAAK7U,QAAL,CAAcj3C,QAAd,GAAyB6rD,kBAAkB7rD,QAD7C;MAEA,MAAM+rD,kBAAkBx7D,KAAKwE,GAALxE,CAASu7D,oBAATv7D,CAAxB;MACA,IAAIozB,QAAQ3xB,QAAQ65D,kBAAkB75D,KAAtC;;MACA,IAAI+5D,oBAAoB,EAApBA,IAA0BA,oBAAoB,GAAlD,EAAuD;QACrDpoC,QAAQ3xB,QAAQ65D,kBAAkB55D,MAAlC0xB;MAXgB;;MAalB,MAAM09B,eAAe,KAAKoI,SAAL,CAAepI,YAApC;MACA,IAAI2K,MAAJ,EAAYC,MAAZ;;MACA,QAAQF,eAAR;QACE,KAAK,CAAL;UACEC,SAASC,SAAS,CAAlBD;UACA;;QACF,KAAK,EAAL;UACEA,SAAS,CAATA;UACAC,SAAS,MAAM5K,aAAapqD,KAAboqD,CAAmBpvD,MAAlCg6D;UACA;;QACF,KAAK,GAAL;UACED,SAAS,MAAM3K,aAAapqD,KAAboqD,CAAmBrvD,KAAlCg6D;UACAC,SAAS,MAAM5K,aAAapqD,KAAboqD,CAAmBpvD,MAAlCg6D;UACA;;QACF,KAAK,GAAL;UACED,SAAS,MAAM3K,aAAapqD,KAAboqD,CAAmBrvD,KAAlCg6D;UACAC,SAAS,CAATA;UACA;;QACF;UACE1/D,QAAQC,KAARD,CAAc,qBAAdA;UACA;MAlBJ;;MAqBA80D,aAAapqD,KAAboqD,CAAmB3H,SAAnB2H,GACG,UAAS0K,eAAgB,OAA1B,GACC,SAAQpoC,KAAM,IADf,GAEC,aAAYqoC,MAAO,KAAIC,MAAO,GAHjC5K;MAIAA,aAAapqD,KAAboqD,CAAmB6K,eAAnB7K,GAAqC,OAArCA;IAlED;;IAqED,IAAI8J,yBAAyB,KAAK3B,eAAlC,EAAmD;MACjD,KAAKM,sBAAL;IAtED;;IAwED,IAAIsB,+BAA+B,KAAKvH,qBAAxC,EAA+D;MAC7D,KAAKkG,4BAAL;IAzED;;IA2ED,IAAIsB,kBAAkB,KAAK1B,QAA3B,EAAqC;MACnC,KAAKK,eAAL;IA5ED;EAnda;;EAmiBhB,IAAIh4D,KAAJ,GAAY;IACV,OAAO,KAAKilD,QAAL,CAAcjlD,KAArB;EApiBc;;EAuiBhB,IAAIC,MAAJ,GAAa;IACX,OAAO,KAAKglD,QAAL,CAAchlD,MAArB;EAxiBc;;EA2iBhBuuD,aAAalwD,CAAb,EAAgBiE,CAAhB,EAAmB;IACjB,OAAO,KAAK0iD,QAAL,CAAckV,iBAAd,CAAgC77D,CAAhC,EAAmCiE,CAAnC,CAAP;EA5iBc;;EAkjBhBqvD,2BAA8C;IAAA;;IAAA,IAArBwI,WAAqB,uEAAP,KAAO;IAC5C,8BAAKlB,cAAL,gFAAqB/9D,SAArB,CAA+Bq2B,MAA/B,CAAsC,YAAtC,EAAoD,CAAC4oC,WAArD;EAnjBc;;EAsjBhBtb,OAAO;IAAA;IAAA;IAAA;IAAA;;IACL,IAAI,KAAK/sB,cAAL,KAAwBt6B,0BAAgBC,OAA5C,EAAqD;MACnD6C,QAAQC,KAARD,CAAc,qCAAdA;MACA,KAAK0kB,KAAL;IAHG;;IAKL,MAAM;MAAE7f,GAAF;MAAO6kB;IAAP,IAAmB,IAAzB;;IAEA,IAAI,CAACA,OAAL,EAAc;MACZ,KAAK8N,cAAL,GAAsBt6B,0BAAgBI,QAAtC;;MAEA,IAAI,KAAKqhE,cAAT,EAAyB;QACvB,KAAKA,cAAL,CAAoBtzD,MAApB;QACA,OAAO,KAAKszD,cAAZ;MALU;;MAOZ,OAAOt0D,QAAQ8xB,MAAR9xB,CAAe,IAAIW,KAAJ,CAAU,uBAAV,CAAfX,CAAP;IAdG;;IAiBL,KAAKmtB,cAAL,GAAsBt6B,0BAAgBE,OAAtC;IAIA,MAAM0iE,gBAAgBt1D,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAtB;IACAs1D,cAAcp1D,KAAdo1D,CAAoBr6D,KAApBq6D,GAA4Bj7D,IAAI6F,KAAJ7F,CAAUY,KAAtCq6D;IACAA,cAAcp1D,KAAdo1D,CAAoBp6D,MAApBo6D,GAA6Bj7D,IAAI6F,KAAJ7F,CAAUa,MAAvCo6D;IACAA,cAAcl/D,SAAdk/D,CAAwB53D,GAAxB43D,CAA4B,eAA5BA;IAEA,MAAMC,uBACJ,gCAAK9C,eAAL,kFAAsBp4D,GAAtB,gCAA6B,KAAKyyD,qBAAlC,2DAA6B,uBAA4BzyD,GAAzD,CADF;;IAGA,IAAIk7D,oBAAJ,EAA0B;MAExBA,qBAAqBC,MAArBD,CAA4BD,aAA5BC;IAFF,OAGO;MACLl7D,IAAIy6B,MAAJz6B,CAAWi7D,aAAXj7D;IAjCG;;IAoCL,IAAIq4D,YAAY,IAAhB;;IACA,IAAI,KAAKhuD,aAAL,KAAuB7Q,wBAAcC,OAArC,IAAgD,KAAKszD,gBAAzD,EAA2E;MACzE,KAAKwK,qBAAL,UAAKA,qBAAL,GAA+B,IAAI6D,4CAAJ,EAA/B;MACA,MAAMnL,eAAetqD,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAArB;MACAsqD,aAAa12B,SAAb02B,GAAyB,WAAzBA;MACAA,aAAapqD,KAAboqD,CAAmBrvD,KAAnBqvD,GAA2BgL,cAAcp1D,KAAdo1D,CAAoBr6D,KAA/CqvD;MACAA,aAAapqD,KAAboqD,CAAmBpvD,MAAnBovD,GAA4BgL,cAAcp1D,KAAdo1D,CAAoBp6D,MAAhDovD;;MACA,IAAIiL,oBAAJ,EAA0B;QAExBA,qBAAqBC,MAArBD,CAA4BjL,YAA5BiL;MAFF,OAGO;QACLl7D,IAAIy6B,MAAJz6B,CAAWiwD,YAAXjwD;MAVuE;;MAazEq4D,YAAY,KAAKtL,gBAAL,CAAsBiD,sBAAtB,CAA6C;QACvDC,YADuD;QAEvD39C,WAAW,KAAKpP,EAAL,GAAU,CAFkC;QAGvD2iD,UAAU,KAAKA,QAHwC;QAIvDqK,sBACE,KAAK7lD,aAAL,KAAuB7Q,wBAAcG,cALgB;QAMvDkU,UAAU,KAAKA,QANwC;QAOvDsiD,aAAa,KAAK4H,eAPqC;QAQvD3H,sBAAsB,KAAKmH;MAR4B,CAA7C,CAAZc;IAlDG;;IA6DL,KAAKA,SAAL,GAAiBA,SAAjB;;IAEA,IACE,iDAAyBlN,yBAAe1xD,OAAxC,IACA,KAAKuzD,sBAFP,EAGE;MACA,KAAKsK,oBAAL,UAAKA,oBAAL,GAA8B,IAAI15D,GAAJ,EAA9B;MACA,KAAKw6D,eAAL,UAAKA,eAAL,GACE,KAAKpL,sBAAL,CAA4BwD,4BAA5B,CAAyD;QACvDC,SAASzwD,GAD8C;QAEvD6kB,OAFuD;QAGvDjb,oBAAoB,KAAKA,kBAH8B;QAIvDmf,aAAa,iDAAyBoiC,yBAAeC,YAJE;QAKvD90C,MAAM,KAAKA,IAL4C;QAMvDu6C,qBAAqB,KAAKyG,oBAN6B;QAOvDlH,sBAAsB,KAAKmH;MAP4B,CAAzD,CADF;IApEG;;IAgFL,uBAAI,KAAKgB,QAAT,4CAAI,gBAAev4D,GAAnB,EAAwB;MAEtBA,IAAIy6B,MAAJz6B,CAAW,KAAKu4D,QAAL,CAAcv4D,GAAzBA;IAlFG;;IAqFL,IAAI+oD,yBAAyB,IAA7B;;IACA,IAAI,KAAK7tC,cAAT,EAAyB;MACvB6tC,yBAAyBC,QAAQ;QAC/B,IAAI,CAAC,KAAK9tC,cAAL,CAAoBqjC,iBAApB,CAAsC,IAAtC,CAAL,EAAkD;UAChD,KAAK5rB,cAAL,GAAsBt6B,0BAAgBG,MAAtC;;UACA,KAAKinD,MAAL,GAAc,MAAM;YAClB,KAAK9sB,cAAL,GAAsBt6B,0BAAgBE,OAAtC;YACAywD;UAFF;;UAIA;QAP6B;;QAS/BA;MATF;IAvFG;;IAoGL,MAAMqS,kBAAkB,kBAAwB;MAAA,IAAjBjgE,KAAiB,uEAAT,IAAS;;MAI9C,IAAI48D,cAAc,MAAKA,SAAvB,EAAkC;QAChC,MAAKA,SAAL,GAAiB,IAAjB;MAL4C;;MAQ9C,IAAI58D,iBAAiBwkD,qCAArB,EAAkD;QAChD,MAAKsY,YAAL,GAAoB,IAApB;QACA;MAV4C;;MAY9C,MAAKA,YAAL,GAAoB98D,KAApB;MAEA,MAAKu3B,cAAL,GAAsBt6B,0BAAgBI,QAAtC;;MAEA,IAAI,MAAKqhE,cAAT,EAAyB;QACvB,MAAKA,cAAL,CAAoBtzD,MAApB;;QACA,OAAO,MAAKszD,cAAZ;MAlB4C;;MAoB9C,MAAKb,eAAL,CAA2C,IAA3C;;MAIA,kDAAyBpB,kBAAzB,GAA8C,CAACG,UAAUsD,cAAzD;;MAEA,MAAKztD,QAAL,CAAcwC,QAAd,CAAuB,cAAvB,EAAuC;QACrCC,QAAQ,KAD6B;QAErChB,YAAY,MAAKpM,EAFoB;QAGrCspD,cAAc,KAHuB;QAIrCzmC,WAAWyyB,YAAYqE,GAAZrE,EAJ0B;QAKrCp9C,OAAO,MAAK88D;MALyB,CAAvC;;MAQA,IAAI98D,KAAJ,EAAW;QACT,MAAMA,KAAN;MAnC4C;IAAhD;;IAuCA,MAAM48D,YAGJ,KAAKnsD,QAAL,KAAkBxS,uBAAaE,GAA/B,GACI,KAAKgiE,UAAL,CAAgBN,aAAhB,CADJ,GAEI,KAAKO,aAAL,CAAmBP,aAAnB,CALN;IAMAjD,UAAUyD,gBAAVzD,GAA6BjP,sBAA7BiP;IACA,KAAKA,SAAL,GAAiBA,SAAjB;IAEA,MAAM5O,gBAAgB4O,UAAUt6C,OAAVs6C,CAAkB3lD,IAAlB2lD,CACpB,MAAM;MACJ,OAAOqD,gBAAgB,IAAhB,EAAsBhpD,IAAtBgpD,CAA2B,MAAM;QACtC,IAAIhD,SAAJ,EAAe;UACb,MAAMqD,iBAAiB72C,QAAQ82C,iBAAR92C,CAA0B;YAC/C+2C,sBAAsB;UADyB,CAA1B/2C,CAAvB;UAGAwzC,UAAUwD,oBAAVxD,CAA+BqD,cAA/BrD;UACAA,UAAUnyC,MAAVmyC;QANoC;;QAStC,IAAI,KAAKD,eAAT,EAA0B;UACxB,KAAKM,sBAAL,GAA8BrmD,IAA9B,CAAmC,MAAM;YACvC,IAAI,KAAK66C,4BAAT,EAAuC;cACrC,KAAKuF,qBAAL,UAAKA,qBAAL,GACE,KAAKvF,4BAAL,CAAkC6D,kCAAlC,CACE;gBACEN,SAASzwD,GADX;gBAEE6kB,OAFF;gBAGEvO,MAAM,KAAKA,IAHb;gBAIE85C,sBAAsB,KAAKmH;cAJ7B,CADF,CADF;;cASA,KAAKoB,4BAAL;YAXqC;UAAzC;QAVoC;MAAjC,EAAP;IAFkB,GA6BpB,UAAUtgD,MAAV,EAAkB;MAChB,OAAOgjD,gBAAgBhjD,MAAhB,CAAP;IA9BkB,EAAtB;;IAkCA,IAAI,KAAK40C,eAAT,EAA0B;MACxB,KAAKsL,QAAL,UAAKA,QAAL,GAAkB,KAAKtL,eAAL,CAAqBiE,qBAArB,CAA2C;QAC3DT,SAASzwD,GADkD;QAE3D6kB;MAF2D,CAA3C,CAAlB;;MAIA,KAAK+zC,eAAL;IA3LG;;IAgML,IAAI,KAAKvL,sBAAL,IAA+B,KAAKgL,SAApC,IAAiD,KAAKrQ,MAA1D,EAAkE;MAGhE,KAAKoS,oBAAL,GAA4BnrC,SAAS;QACnC,IAAIA,MAAM3f,UAAN2f,KAAqB,KAAK/rB,EAA9B,EAAkC;UAChC;QAFiC;;QAInC,KAAK2K,QAAL,CAAc6hB,IAAd,CAAmB,mBAAnB,EAAwC,KAAK0qC,oBAA7C;;QACA,KAAKA,oBAAL,GAA4B,IAA5B;;QAEA,IAAI,CAAC,KAAKpS,MAAV,EAAkB;UAChB;QARiC;;QAUnC,KAAKnjC,OAAL,CAAai3C,aAAb,GAA6BzpD,IAA7B,CAAkC0pD,QAAQ;UACxC,IAAI,CAACA,IAAL,EAAW;YACT;UAFsC;;UAIxC,IAAI,CAAC,KAAK/T,MAAV,EAAkB;YAChB;UALsC;;UAOxC,MAAMgU,UAAU,KAAKxD,eAAL,CAAqBtyC,MAArB,CAA4B61C,IAA5B,CAAhB;UACAC,QAAQjgE,SAARigE,CAAkB34D,GAAlB24D,CAAsB,YAAtBA;UACA,KAAKhU,MAAL,CAAYvtB,MAAZ,CAAmBuhC,OAAnB;QATF;MAVF;;MAsBA,KAAKnuD,QAAL,CAAcgZ,GAAd,CAAkB,mBAAlB,EAAuC,KAAKuzC,oBAA5C;;MACA,KAAK5B,eAAL,GACE,KAAKnL,sBAAL,CAA4B+D,4BAA5B,CAAyD;QAAEvsC;MAAF,CAAzD,CADF;IA1NG;;IA8NL7kB,IAAI6/B,YAAJ7/B,CAAiB,aAAjBA,EAAgC,IAAhCA;IAEA,KAAK6N,QAAL,CAAcwC,QAAd,CAAuB,YAAvB,EAAqC;MACnCC,QAAQ,IAD2B;MAEnChB,YAAY,KAAKpM;IAFkB,CAArC;IAIA,OAAOkmD,aAAP;EA1xBc;;EA6xBhBoS,cAAcP,aAAd,EAA6B;IAC3B,MAAMgB,mBAAmBjnD,wCAAzB;IACA,MAAMlV,SAAS;MACb4d,SAASu+C,iBAAiBv+C,OADb;;MAEb+9C,iBAAiBzS,IAAjB,EAAuB;QACrBA;MAHW;;MAKbd,SAAS;QACPZ,WAAWY,MAAXZ;MANW;;MAQb,IAAIgU,cAAJ,GAAqB;QACnB,OAAOhU,WAAWgU,cAAlB;MATW;;IAAA,CAAf;IAaA,MAAMzV,WAAW,KAAKA,QAAtB;IACA,MAAMmC,SAASriD,SAAS2zB,aAAT3zB,CAAuB,QAAvBA,CAAf;IACAqiD,OAAOnoB,YAAPmoB,CAAoB,MAApBA,EAA4B,cAA5BA;IAIAA,OAAOhpC,MAAPgpC,GAAgB,IAAhBA;IACA,IAAIkU,iBAAiB,IAArB;;IACA,MAAMC,aAAa,YAAY;MAC7B,IAAID,cAAJ,EAAoB;QAClBlU,OAAOhpC,MAAPgpC,GAAgB,KAAhBA;QACAkU,iBAAiB,KAAjBA;MAH2B;IAA/B;;IAOAjB,cAAcxgC,MAAdwgC,CAAqBjT,MAArBiT;IACA,KAAKjT,MAAL,GAAcA,MAAd;IAEA,MAAMlB,MAAMkB,OAAOjB,UAAPiB,CAAkB,IAAlBA,EAAwB;MAAEhB,OAAO;IAAT,CAAxBgB,CAAZ;IACA,MAAMK,cAAe,KAAKA,WAAL,GAAmB,IAAIhuD,qBAAJ,EAAxC;;IAEA,IAAI,KAAKiQ,cAAT,EAAyB;MACvB,MAAM8xD,qBAAqBvW,SAAS5gB,KAAT4gB,CAAe;QACxCtzB,OAAOs6B,wBAAcC;MADmB,CAAfjH,CAA3B;MAKAwC,YAAY3tD,EAAZ2tD,IAAkB+T,mBAAmBx7D,KAAnBw7D,GAA2BvW,SAASjlD,KAAtDynD;MACAA,YAAY1tD,EAAZ0tD,IAAkB+T,mBAAmBv7D,MAAnBu7D,GAA4BvW,SAAShlD,MAAvDwnD;IA3CyB;;IA8C3B,IAAI,KAAK9/C,eAAL,GAAuB,CAA3B,EAA8B;MAC5B,MAAM8zD,mBAAmBxW,SAASjlD,KAATilD,GAAiBA,SAAShlD,MAAnD;MACA,MAAMy7D,WAAWn9D,KAAKo9D,IAALp9D,CAAU,KAAKoJ,eAAL,GAAuB8zD,gBAAjCl9D,CAAjB;;MACA,IAAIkpD,YAAY3tD,EAAZ2tD,GAAiBiU,QAAjBjU,IAA6BA,YAAY1tD,EAAZ0tD,GAAiBiU,QAAlD,EAA4D;QAC1DjU,YAAY3tD,EAAZ2tD,GAAiBiU,QAAjBjU;QACAA,YAAY1tD,EAAZ0tD,GAAiBiU,QAAjBjU;QACA,KAAKyP,oBAAL,GAA4B,IAA5B;MAHF,OAIO;QACL,KAAKA,oBAAL,GAA4B,KAA5B;MAR0B;IA9CH;;IA0D3B,MAAM0E,MAAMv9D,mCAAoBopD,YAAY3tD,EAAhCuE,CAAZ;IACA,MAAMw9D,MAAMx9D,mCAAoBopD,YAAY1tD,EAAhCsE,CAAZ;IACA+oD,OAAOpnD,KAAPonD,GAAejoD,6BAAc8lD,SAASjlD,KAATilD,GAAiBwC,YAAY3tD,EAA3CqF,EAA+Cy8D,IAAI,CAAJ,CAA/Cz8D,CAAfioD;IACAA,OAAOnnD,MAAPmnD,GAAgBjoD,6BAAc8lD,SAAShlD,MAATglD,GAAkBwC,YAAY1tD,EAA5CoF,EAAgD08D,IAAI,CAAJ,CAAhD18D,CAAhBioD;IACAA,OAAOniD,KAAPmiD,CAAapnD,KAAbonD,GAAqBjoD,6BAAc8lD,SAASjlD,KAAvBb,EAA8By8D,IAAI,CAAJ,CAA9Bz8D,IAAwC,IAA7DioD;IACAA,OAAOniD,KAAPmiD,CAAannD,MAAbmnD,GAAsBjoD,6BAAc8lD,SAAShlD,MAAvBd,EAA+B08D,IAAI,CAAJ,CAA/B18D,IAAyC,IAA/DioD;IAGA,KAAKiQ,kBAAL,CAAwBj6D,GAAxB,CAA4BgqD,MAA5B,EAAoCnC,QAApC;IAGA,MAAMyC,YAAYD,YAAYztD,MAAZytD,GACd,CAACA,YAAY3tD,EAAb,EAAiB,CAAjB,EAAoB,CAApB,EAAuB2tD,YAAY1tD,EAAnC,EAAuC,CAAvC,EAA0C,CAA1C,CADc0tD,GAEd,IAFJ;IAGA,MAAMY,gBAAgB;MACpBC,eAAepC,GADK;MAEpBwB,SAFoB;MAGpBzC,UAAU,KAAKA,QAHK;MAIpB78C,sCAAgB,IAAhB,kBAJoB;MAKpBqd,8BAA8B,KAAKghC,6BALf;MAMpBwJ,qBAAqB,KAAKyG,oBANN;MAOpB18C,YAAY,KAAKA;IAPG,CAAtB;IASA,MAAM0sC,aAAa,KAAKziC,OAAL,CAAaqB,MAAb,CAAoB+iC,aAApB,CAAnB;;IACA3B,WAAW6B,UAAX7B,GAAwB,UAAU0B,IAAV,EAAgB;MACtCmT;;MACA,IAAIr8D,OAAO27D,gBAAX,EAA6B;QAC3B37D,OAAO27D,gBAAP37D,CAAwBkpD,IAAxBlpD;MADF,OAEO;QACLkpD;MALoC;IAAxC;;IASA1B,WAAW5pC,OAAX4pC,CAAmBj1C,IAAnBi1C,CACE,YAAY;MACV6U;MACAF,iBAAiBx2D,OAAjBw2D;IAHJ,GAKE,UAAU7gE,KAAV,EAAiB;MACf+gE;MACAF,iBAAiB3kC,MAAjB2kC,CAAwB7gE,KAAxB6gE;IAPJ;IAUA,OAAOn8D,MAAP;EAl4Bc;;EAq4BhBy7D,WAAWmB,OAAX,EAAoB;IASlB,IAAIC,YAAY,KAAhB;;IACA,MAAMC,qBAAqB,MAAM;MAC/B,IAAID,SAAJ,EAAe;QACb,MAAM,IAAI/c,qCAAJ,CACH,6BAA4B,KAAK18C,EAAlC,EADI,EAEJ,KAFI,CAAN;MAF6B;IAAjC;;IASA,MAAM2hB,UAAU,KAAKA,OAArB;IACA,MAAMu3C,qBAAqB,KAAKvW,QAAL,CAAc5gB,KAAd,CAAoB;MAC7C1S,OAAOs6B,wBAAcC;IADwB,CAApB,CAA3B;IAGA,MAAMpvC,UAAUmH,QACbg4C,eADah4C,CACG;MACf7b,sCAAgB,IAAhB;IADe,CADH6b,EAIbxS,IAJawS,CAIRi4C,UAAU;MACdF;MACA,MAAMG,SAAS,IAAIC,qBAAJ,CAAgBn4C,QAAQo4C,UAAxB,EAAoCp4C,QAAQq4C,IAA5C,CAAf;MACA,OAAOH,OAAOI,MAAPJ,CAAcD,MAAdC,EAAsBX,kBAAtBW,EAA0C1qD,IAA1C0qD,CAA+ClD,OAAO;QAC3D+C;QACA,KAAK/C,GAAL,GAAWA,GAAX;QACA,KAAK5B,kBAAL,CAAwBj6D,GAAxB,CAA4B67D,GAA5B,EAAiCuC,kBAAjC;QAEAvC,IAAIh0D,KAAJg0D,CAAUj5D,KAAVi5D,GAAkB6C,QAAQ72D,KAAR62D,CAAc97D,KAAhCi5D;QACAA,IAAIh0D,KAAJg0D,CAAUh5D,MAAVg5D,GAAmB6C,QAAQ72D,KAAR62D,CAAc77D,MAAjCg5D;QACA,KAAKlnC,cAAL,GAAsBt6B,0BAAgBI,QAAtC;QACAikE,QAAQjiC,MAARiiC,CAAe7C,GAAf6C;MARK,EAAP;IAPY,EAAhB;IAmBA,OAAO;MACLh/C,OADK;;MAEL+9C,iBAAiBzS,IAAjB,EAAuB;QACrBA;MAHG;;MAKLd,SAAS;QACPyU,YAAY,IAAZA;MANG;;MAQL,IAAIrB,cAAJ,GAAqB;QACnB,OAAO,KAAP;MATG;;IAAA,CAAP;EA/6Bc;;EAg8BhBlV,aAAax8B,KAAb,EAAoB;IAClB,KAAKgK,SAAL,GAAiB,OAAOhK,KAAP,KAAiB,QAAjB,GAA4BA,KAA5B,GAAoC,IAArD;;IAEA,IAAI,KAAKgK,SAAL,KAAmB,IAAvB,EAA6B;MAC3B,KAAK5zB,GAAL,CAAS6/B,YAAT,CAAsB,iBAAtB,EAAyC,KAAKjM,SAA9C;IADF,OAEO;MACL,KAAK5zB,GAAL,CAASmhC,eAAT,CAAyB,iBAAzB;IANgB;EAh8BJ;;EA88BhB,IAAImoB,eAAJ,GAAsB;IACpB,MAAM;MAAEsO,sBAAF;MAA0BC;IAA1B,0BACJ,IADI,sBAAN;;IAEA,OAAOD,0BAA0BC,kBAA1BD,GAA+C,KAAK5P,MAApD4P,GAA6D,IAApE;EAj9Bc;;AAAA;;;;;;;;;;;;;;;ACpFlB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AASA,MAAMwD,wBAAN,CAA+B;EAAA;IAAA;;IAAA;MAAA;MAAA,OAClB;IADkB;;IAAA;MAAA;MAAA,OAGb;IAHa;;IAAA;MAAA;MAAA,OAKhB,IAAIx9D,GAAJ;IALgB;;IAAA;MAAA;MAAA,OAOV,IAAIA,GAAJ;IAPU;EAAA;;EAS7Bm7D,eAAeD,QAAf,EAAyB;IACvB,2CAAqBA,QAArB;EAV2B;;EA0D7BE,SAAS;IACP,0BAAI,IAAJ,aAAmB;MACjB,MAAM,IAAI7yD,KAAJ,CAAU,8CAAV,CAAN;IAFK;;IAIP,IAAI,uBAAC,IAAD,gBAAJ,EAAyB;MACvB,MAAM,IAAIA,KAAJ,CAAU,0CAAV,CAAN;IALK;;IAQP,sCAAgB,IAAhB;;IACA,2CAAqB,2CAAmB+xB,KAAnB,EAArB;;IACA,2CAAmBz0B,IAAnB,8BAAwB23D,wBAAxB,EApEEA,wBAoEF;;IAEA,IAAI,wCAAgB91D,IAAhB,GAAuB,CAA3B,EAA8B;MAG5B,MAAM83D,qCAAe,IAAf,gBAAN;;MACA,WAAW,CAACl6D,EAAD,EAAKm6D,SAAL,CAAX,0BAA8B,IAA9B,eAA+C;QAC7C,MAAMviE,UAAU6K,SAASU,cAATV,CAAwBzC,EAAxByC,CAAhB;;QACA,IAAI,CAAC7K,OAAL,EAAc;UAGZ,wCAAgB2rB,MAAhB,CAAuBvjB,EAAvB;;UACA;QAN2C;;QAQ7C,6EAAsBA,EAAtB,EAA0Bk6D,aAAaC,SAAb,CAA1B;MAZ0B;IAZvB;;IA4BP,WAAW,CAACviE,OAAD,EAAUwiE,WAAV,CAAX,0BAAqC,IAArC,qBAA4D;MAC1D,KAAKC,qBAAL,CAA2BziE,OAA3B,EAAoCwiE,WAApC;IA7BK;;IA+BP,8CAAsBjvD,KAAtB;EAzF2B;;EA4F7B8rD,UAAU;IACR,IAAI,uBAAC,IAAD,WAAJ,EAAoB;MAClB;IAFM;;IAQR,8CAAsB9rD,KAAtB;;IACA,2CAAqB,IAArB;;IACA,sCAAgB,KAAhB;EAtG2B;;EA6G7BmvD,yBAAyB1iE,OAAzB,EAAkC;IAAA;;IAChC,IAAI,uBAAC,IAAD,WAAJ,EAAoB;MAClB,8CAAsB2rB,MAAtB,CAA6B3rB,OAA7B;;MACA;IAH8B;;IAMhC,MAAM2iE,iCAAW,IAAX,gBAAN;;IACA,IAAI,CAACA,QAAD,IAAaA,SAAS3+D,MAAT2+D,KAAoB,CAArC,EAAwC;MACtC;IAR8B;;IAWhC,MAAM;MAAEv6D;IAAF,IAASpI,OAAf;;IACA,MAAMuiE,YAAY,wCAAgBpxD,GAAhB,CAAoB/I,EAApB,CAAlB;;IACA,IAAIm6D,cAAcjhE,SAAlB,EAA6B;MAC3B;IAd8B;;IAiBhC,MAAMo9B,OAAOikC,SAASJ,SAAT,CAAb;;IAEA,wCAAgB52C,MAAhB,CAAuBvjB,EAAvB;;IACA,IAAIw6D,OAAOlkC,KAAK6E,YAAL7E,CAAkB,WAAlBA,CAAX;;IACA,aAAIkkC,IAAJ,kCAAIA,MAAMv4D,QAANu4D,CAAex6D,EAAfw6D,CAAJ,EAAwB;MACtBA,OAAOA,KACJjtD,KADIitD,CACE,GADFA,EAEJC,MAFID,CAEGx+D,KAAKA,MAAMgE,EAFdw6D,EAGJp6C,IAHIo6C,CAGC,GAHDA,CAAPA;;MAIA,IAAIA,IAAJ,EAAU;QACRlkC,KAAKqG,YAALrG,CAAkB,WAAlBA,EAA+BkkC,IAA/BlkC;MADF,OAEO;QACLA,KAAK2H,eAAL3H,CAAqB,WAArBA;QACAA,KAAKqG,YAALrG,CAAkB,MAAlBA,EAA0B,cAA1BA;MAToB;IArBQ;EA7GL;;EA8J7B+jC,sBAAsBziE,OAAtB,EAA+BwiE,WAA/B,EAA4C;IAC1C,MAAM;MAAEp6D;IAAF,IAASpI,OAAf;;IACA,IAAI,CAACoI,EAAL,EAAS;MACP;IAHwC;;IAM1C,IAAI,uBAAC,IAAD,WAAJ,EAAoB;MAElB,8CAAsBlF,GAAtB,CAA0BlD,OAA1B,EAAmCwiE,WAAnC;;MACA;IATwC;;IAY1C,IAAIA,WAAJ,EAAiB;MACf,KAAKE,wBAAL,CAA8B1iE,OAA9B;IAbwC;;IAgB1C,MAAM2iE,iCAAW,IAAX,gBAAN;;IACA,IAAI,CAACA,QAAD,IAAaA,SAAS3+D,MAAT2+D,KAAoB,CAArC,EAAwC;MACtC;IAlBwC;;IAqB1C,MAAM18D,QAAQvC,qCACZi/D,QADYj/D,EAEZg7B,QACE4hC,uDAtLFA,wBAsLE,2DAAkDtgE,OAAlD,EAA2D0+B,IAA3D,IAAmE,CAHzDh7B,CAAd;IAMA,MAAM6+D,YAAYl+D,KAAKyD,GAALzD,CAAS,CAATA,EAAY4B,QAAQ,CAApB5B,CAAlB;;IACA,6EAAsB+D,EAAtB,EAA0Bu6D,SAASJ,SAAT,CAA1B;;IACA,wCAAgBr/D,GAAhB,CAAoBkF,EAApB,EAAwBm6D,SAAxB;EA3L2B;;EAkM7BO,iBAAiBh3D,SAAjB,EAA4B9L,OAA5B,EAAqC+iE,cAArC,EAAqDP,WAArD,EAAkE;IAChE,KAAKC,qBAAL,CAA2BM,cAA3B,EAA2CP,WAA3C;;IAEA,IAAI,CAAC12D,UAAUk3D,aAAVl3D,EAAL,EAAgC;MAC9BA,UAAU6zB,MAAV7zB,CAAiB9L,OAAjB8L;MACA;IAL8D;;IAQhE,MAAM62D,WAAWtuD,MAAM4uD,IAAN5uD,CAAWvI,UAAU4yD,UAArBrqD,EAAiCwuD,MAAjCxuD,CACfqqB,QAAQA,SAAS1+B,OADFqU,CAAjB;;IAIA,IAAIsuD,SAAS3+D,MAAT2+D,KAAoB,CAAxB,EAA2B;MACzB;IAb8D;;IAgBhE,MAAMO,mBAAmBH,kBAAkB/iE,OAA3C;IACA,MAAMiG,QAAQvC,qCACZi/D,QADYj/D,EAEZg7B,QACE4hC,uDAtNFA,wBAsNE,2DACE4C,gBADF,EAEExkC,IAFF,IAGI,CANMh7B,CAAd;;IASA,IAAIuC,UAAU,CAAd,EAAiB;MACf08D,SAAS,CAAT,EAAYtC,MAAZsC,CAAmB3iE,OAAnB2iE;IADF,OAEO;MACLA,SAAS18D,QAAQ,CAAjB,EAAoBk9D,KAApBR,CAA0B3iE,OAA1B2iE;IA7B8D;EAlMrC;;AAAA;;;;kCAqBGS,IAAIC,IAAI;EACtC,MAAMC,QAAQF,GAAGxpC,qBAAHwpC,EAAd;EACA,MAAMG,QAAQF,GAAGzpC,qBAAHypC,EAAd;;EAEA,IAAIC,MAAMx9D,KAANw9D,KAAgB,CAAhBA,IAAqBA,MAAMv9D,MAANu9D,KAAiB,CAA1C,EAA6C;IAC3C,OAAO,CAAC,CAAR;EALoC;;EAQtC,IAAIC,MAAMz9D,KAANy9D,KAAgB,CAAhBA,IAAqBA,MAAMx9D,MAANw9D,KAAiB,CAA1C,EAA6C;IAC3C,OAAO,CAAC,CAAR;EAToC;;EAYtC,MAAMC,OAAOF,MAAMj7D,CAAnB;EACA,MAAMo7D,OAAOH,MAAMj7D,CAANi7D,GAAUA,MAAMv9D,MAA7B;EACA,MAAM29D,OAAOJ,MAAMj7D,CAANi7D,GAAUA,MAAMv9D,MAANu9D,GAAe,CAAtC;EAEA,MAAMK,OAAOJ,MAAMl7D,CAAnB;EACA,MAAMu7D,OAAOL,MAAMl7D,CAANk7D,GAAUA,MAAMx9D,MAA7B;EACA,MAAM89D,OAAON,MAAMl7D,CAANk7D,GAAUA,MAAMx9D,MAANw9D,GAAe,CAAtC;;EAEA,IAAIG,QAAQC,IAARD,IAAgBG,QAAQJ,IAA5B,EAAkC;IAChC,OAAO,CAAC,CAAR;EArBoC;;EAwBtC,IAAII,QAAQL,IAARK,IAAgBH,QAAQE,IAA5B,EAAkC;IAChC,OAAO,CAAC,CAAR;EAzBoC;;EA4BtC,MAAME,WAAWR,MAAMl/D,CAANk/D,GAAUA,MAAMx9D,KAANw9D,GAAc,CAAzC;EACA,MAAMS,WAAWR,MAAMn/D,CAANm/D,GAAUA,MAAMz9D,KAANy9D,GAAc,CAAzC;EAEA,OAAOO,WAAWC,QAAlB;AApD2B;;2BAgJZ37D,IAAIs2B,MAAM;EACzB,MAAMkkC,OAAOlkC,KAAK6E,YAAL7E,CAAkB,WAAlBA,CAAb;;EACA,IAAI,EAACkkC,IAAD,aAACA,IAAD,eAACA,KAAMv4D,QAANu4D,CAAex6D,EAAfw6D,CAAD,CAAJ,EAAyB;IACvBlkC,KAAKqG,YAALrG,CAAkB,WAAlBA,EAA+BkkC,OAAO,GAAGA,IAAK,IAAGx6D,EAAX,EAAP,GAAyBA,EAAxDs2B;EAHuB;;EAKzBA,KAAK2H,eAAL3H,CAAqB,MAArBA;AArJ2B;;;;;;;;;;;;ACP/B,MAAMslC,wBAAwB;EAE5BC,UAAU,IAFkB;EAG5BC,kBAAkB,IAHU;EAK5BC,MAAM,OALsB;EAM5BC,MAAM,OANsB;EAO5BC,KAAK,OAPuB;EAQ5BC,OAAO,MARqB;EAS5BC,WAAW,MATiB;EAW5BC,GAAG,IAXyB;EAa5BC,GAAG,SAbyB;EAc5B92C,OAAO,IAdqB;EAe5B+2C,QAAQ,MAfoB;EAiB5BC,KAAK,OAjBuB;EAmB5BC,KAAK,IAnBuB;EAoB5BC,MAAM,IApBsB;EAqB5BC,IAAI,IArBwB;EAsB5BC,QAAQ,IAtBoB;EAuB5BC,MAAM,MAvBsB;EAwB5BC,OAAO,MAxBqB;EAyB5BC,MAAM,MAzBsB;EA2B5BC,MAAM,IA3BsB;EA4B5BC,IAAI,IA5BwB;EA6B5BC,IAAI,IA7BwB;EA8B5BC,IAAI,IA9BwB;EA+B5BC,SAAS,IA/BmB;EAgC5BC,IAAI,IAhCwB;EAiC5BC,IAAI,IAjCwB;EAmC5BC,GAAG,MAnCyB;EAoC5BC,IAAI,UApCwB;EAqC5BC,OAAO,IArCqB;EAuC5BC,OAAO,OAvCqB;EAwC5BC,IAAI,KAxCwB;EAyC5BC,IAAI,cAzCwB;EA0C5BC,IAAI,MA1CwB;EA2C5BC,OAAO,cA3CqB;EA4C5BC,OAAO,IA5CqB;EA6C5BC,OAAO,IA7CqB;EA+C5BC,SAAS,IA/CmB;EAiD5BC,QAAQ,QAjDoB;EAmD5BC,SAAS,IAnDmB;EAqD5BC,UAAU;AArDkB,CAA9B;AAwDA,MAAMC,kBAAkB,UAAxB;;AAOA,MAAMjQ,sBAAN,CAA6B;EAI3B/2D,kBAAyB;IAAA,IAAb;MAAEuqB;IAAF,CAAa;IACvB,KAAKA,OAAL,GAAeA,OAAf;EALyB;;EAQ3BqB,OAAOq7C,UAAP,EAAmB;IACjB,OAAO,KAAKC,KAAL,CAAWD,UAAX,CAAP;EATyB;;EAY3BE,eAAeC,aAAf,EAA8BC,WAA9B,EAA2C;IACzC,IAAID,cAAcE,GAAdF,KAAsBtlE,SAA1B,EAAqC;MACnCulE,YAAY9hC,YAAZ8hC,CAAyB,YAAzBA,EAAuCD,cAAcE,GAArDD;IAFuC;;IAIzC,IAAID,cAAcx+D,EAAdw+D,KAAqBtlE,SAAzB,EAAoC;MAClCulE,YAAY9hC,YAAZ8hC,CAAyB,WAAzBA,EAAsCD,cAAcx+D,EAApDy+D;IALuC;;IAOzC,IAAID,cAAchU,IAAdgU,KAAuBtlE,SAA3B,EAAsC;MACpCulE,YAAY9hC,YAAZ8hC,CAAyB,MAAzBA,EAAiCD,cAAchU,IAA/CiU;IARuC;EAZhB;;EAwB3BH,MAAMhoC,IAAN,EAAY;IACV,IAAI,CAACA,IAAL,EAAW;MACT,OAAO,IAAP;IAFQ;;IAKV,MAAM1+B,UAAU6K,SAAS2zB,aAAT3zB,CAAuB,MAAvBA,CAAhB;;IACA,IAAI,UAAU6zB,IAAd,EAAoB;MAClB,MAAM;QAAEqoC;MAAF,IAAWroC,IAAjB;MACA,MAAMsW,QAAQ+xB,KAAK/xB,KAAL+xB,CAAWP,eAAXO,CAAd;;MACA,IAAI/xB,KAAJ,EAAW;QACTh1C,QAAQ+kC,YAAR/kC,CAAqB,MAArBA,EAA6B,SAA7BA;QACAA,QAAQ+kC,YAAR/kC,CAAqB,YAArBA,EAAmCg1C,MAAM,CAAN,CAAnCh1C;MAFF,OAGO,IAAIgkE,sBAAsB+C,IAAtB,CAAJ,EAAiC;QACtC/mE,QAAQ+kC,YAAR/kC,CAAqB,MAArBA,EAA6BgkE,sBAAsB+C,IAAtB,CAA7B/mE;MAPgB;IANV;;IAiBV,KAAK2mE,cAAL,CAAoBjoC,IAApB,EAA0B1+B,OAA1B;;IAEA,IAAI0+B,KAAKikC,QAAT,EAAmB;MACjB,IAAIjkC,KAAKikC,QAALjkC,CAAc16B,MAAd06B,KAAyB,CAAzBA,IAA8B,QAAQA,KAAKikC,QAALjkC,CAAc,CAAdA,CAA1C,EAA4D;QAG1D,KAAKioC,cAAL,CAAoBjoC,KAAKikC,QAALjkC,CAAc,CAAdA,CAApB,EAAsC1+B,OAAtC;MAHF,OAIO;QACL,WAAWgnE,GAAX,IAAkBtoC,KAAKikC,QAAvB,EAAiC;UAC/B3iE,QAAQ2/B,MAAR3/B,CAAe,KAAK0mE,KAAL,CAAWM,GAAX,CAAfhnE;QAFG;MALU;IAnBT;;IA8BV,OAAOA,OAAP;EAtDyB;;AAAA;;;;;;;;;;;;;;;AClD7B,MAAMy1D,eAAN,CAAsB;EAIpBj2D,kBAAqD;IAAA,IAAzC;MAAE+f,cAAF;MAAkBxM,QAAlB;MAA4ByE;IAA5B,CAAyC;IACnD,KAAK+H,cAAL,GAAsBA,cAAtB;IACA,KAAKS,OAAL,GAAe,EAAf;IACA,KAAKjN,QAAL,GAAgBA,QAAhB;IACA,KAAKkkC,OAAL,GAAez/B,SAAf;IACA,KAAKyvD,yBAAL,GAAiC,IAAjC;IACA,KAAKjJ,QAAL,GAAgB,IAAhB;IACA,KAAKkJ,mBAAL,GAA2B,IAA3B;IACA,KAAK10D,OAAL,GAAe,KAAf;EAZkB;;EAwBpByrD,eAAekJ,IAAf,EAAqBC,KAArB,EAA4B;IAC1B,KAAKpJ,QAAL,GAAgBmJ,IAAhB;IACA,KAAKD,mBAAL,GAA2BE,KAA3B;EA1BkB;;EAiCpBlJ,SAAS;IACP,IAAI,CAAC,KAAKF,QAAN,IAAkB,CAAC,KAAKkJ,mBAA5B,EAAiD;MAC/C,MAAM,IAAI77D,KAAJ,CAAU,0CAAV,CAAN;IAFK;;IAIP,IAAI,KAAKmH,OAAT,EAAkB;MAChB,MAAM,IAAInH,KAAJ,CAAU,qCAAV,CAAN;IALK;;IAOP,KAAKmH,OAAL,GAAe,IAAf;;IACA,IAAI,CAAC,KAAKy0D,yBAAV,EAAqC;MACnC,KAAKA,yBAAL,GAAiCnlE,OAAO;QACtC,IAAIA,IAAI0V,SAAJ1V,KAAkB,KAAKm1C,OAAvBn1C,IAAkCA,IAAI0V,SAAJ1V,KAAkB,CAAC,CAAzD,EAA4D;UAC1D,KAAKulE,cAAL;QAFoC;MAAxC;;MAKA,KAAKt0D,QAAL,CAAcgZ,GAAd,CACE,wBADF,EAEE,KAAKk7C,yBAFP;IAdK;;IAmBP,KAAKI,cAAL;EApDkB;;EAuDpBhI,UAAU;IACR,IAAI,CAAC,KAAK7sD,OAAV,EAAmB;MACjB;IAFM;;IAIR,KAAKA,OAAL,GAAe,KAAf;;IACA,IAAI,KAAKy0D,yBAAT,EAAoC;MAClC,KAAKl0D,QAAL,CAAc6hB,IAAd,CACE,wBADF,EAEE,KAAKqyC,yBAFP;;MAIA,KAAKA,yBAAL,GAAiC,IAAjC;IAVM;EAvDU;;EAqEpBK,gBAAgBtnD,OAAhB,EAAyBs4B,aAAzB,EAAwC;IAEtC,IAAI,CAACt4B,OAAL,EAAc;MACZ,OAAO,EAAP;IAHoC;;IAKtC,MAAM;MAAEknD;IAAF,IAA0B,IAAhC;IAEA,IAAI7gE,IAAI,CAAR;IAAA,IACEkhE,SAAS,CADX;IAEA,MAAMxxB,MAAMmxB,oBAAoBljE,MAApBkjE,GAA6B,CAAzC;IACA,MAAMliE,SAAS,EAAf;;IAEA,KAAK,IAAIkvC,IAAI,CAAR,EAAWszB,KAAKxnD,QAAQhc,MAA7B,EAAqCkwC,IAAIszB,EAAzC,EAA6CtzB,GAA7C,EAAkD;MAEhD,IAAI8C,WAAWh3B,QAAQk0B,CAAR,CAAf;;MAGA,OAAO7tC,MAAM0vC,GAAN1vC,IAAa2wC,YAAYuwB,SAASL,oBAAoB7gE,CAApB,EAAuBrC,MAAhE,EAAwE;QACtEujE,UAAUL,oBAAoB7gE,CAApB,EAAuBrC,MAAjCujE;QACAlhE;MAP8C;;MAUhD,IAAIA,MAAM6gE,oBAAoBljE,MAA9B,EAAsC;QACpC3D,QAAQC,KAARD,CAAc,mCAAdA;MAX8C;;MAchD,MAAM20C,QAAQ;QACZyyB,OAAO;UACLC,QAAQrhE,CADH;UAELizC,QAAQtC,WAAWuwB;QAFd;MADK,CAAd;MAQAvwB,YAAYsB,cAAcpE,CAAd,CAAZ8C;;MAIA,OAAO3wC,MAAM0vC,GAAN1vC,IAAa2wC,WAAWuwB,SAASL,oBAAoB7gE,CAApB,EAAuBrC,MAA/D,EAAuE;QACrEujE,UAAUL,oBAAoB7gE,CAApB,EAAuBrC,MAAjCujE;QACAlhE;MA5B8C;;MA+BhD2uC,MAAMe,GAANf,GAAY;QACV0yB,QAAQrhE,CADE;QAEVizC,QAAQtC,WAAWuwB;MAFT,CAAZvyB;MAIAhwC,OAAOmD,IAAPnD,CAAYgwC,KAAZhwC;IA/CoC;;IAiDtC,OAAOA,MAAP;EAtHkB;;EAyHpB2iE,eAAe3nD,OAAf,EAAwB;IAEtB,IAAIA,QAAQhc,MAARgc,KAAmB,CAAvB,EAA0B;MACxB;IAHoB;;IAKtB,MAAM;MAAET,cAAF;MAAkB03B;IAAlB,IAA8B,IAApC;IACA,MAAM;MAAEiwB,mBAAF;MAAuBlJ;IAAvB,IAAoC,IAA1C;IAEA,MAAM4J,iBAAiB3wB,YAAY13B,eAAei3B,QAAfj3B,CAAwB03B,OAA3D;IACA,MAAM4wB,mBAAmBtoD,eAAei3B,QAAfj3B,CAAwBy3B,QAAjD;IACA,MAAM5e,eAAe7Y,eAAend,KAAfmd,CAAqB6Y,YAA1C;IACA,IAAI0vC,UAAU,IAAd;IACA,MAAMC,WAAW;MACfL,QAAQ,CAAC,CADM;MAEfpuB,QAAQh4C;IAFO,CAAjB;;IAKA,SAAS0mE,SAAT,CAAmBP,KAAnB,EAA0BhpC,SAA1B,EAAqC;MACnC,MAAMipC,SAASD,MAAMC,MAArB;MACA1J,SAAS0J,MAAT,EAAiBz/C,WAAjB+1C,GAA+B,EAA/BA;MACA,OAAOiK,gBAAgBP,MAAhB,EAAwB,CAAxB,EAA2BD,MAAMnuB,MAAjC,EAAyC7a,SAAzC,CAAP;IApBoB;;IAuBtB,SAASwpC,eAAT,CAAyBP,MAAzB,EAAiCQ,UAAjC,EAA6CC,QAA7C,EAAuD1pC,SAAvD,EAAkE;MAChE,IAAIv5B,MAAM84D,SAAS0J,MAAT,CAAV;;MACA,IAAIxiE,IAAIkjE,QAAJljE,KAAiB8kC,KAAKq+B,SAA1B,EAAqC;QACnC,MAAMC,OAAOz9D,SAAS2zB,aAAT3zB,CAAuB,MAAvBA,CAAb;QACA3F,IAAIm7D,MAAJn7D,CAAWojE,IAAXpjE;QACAojE,KAAK3oC,MAAL2oC,CAAYpjE,GAAZojE;QACAtK,SAAS0J,MAAT,IAAmBY,IAAnBtK;QACA94D,MAAMojE,IAANpjE;MAP8D;;MAShE,MAAMknC,UAAU86B,oBAAoBQ,MAApB,EAA4B1tD,SAA5BktD,CACdgB,UADchB,EAEdiB,QAFcjB,CAAhB;MAIA,MAAMxoC,OAAO7zB,SAAS09D,cAAT19D,CAAwBuhC,OAAxBvhC,CAAb;;MACA,IAAI4zB,SAAJ,EAAe;QACb,MAAM6pC,OAAOz9D,SAAS2zB,aAAT3zB,CAAuB,MAAvBA,CAAb;QACAy9D,KAAK7pC,SAAL6pC,GAAiB,GAAG7pC,SAAU,WAA9B6pC;QACAA,KAAK3oC,MAAL2oC,CAAY5pC,IAAZ4pC;QACApjE,IAAIy6B,MAAJz6B,CAAWojE,IAAXpjE;QACA,OAAOu5B,UAAUp0B,QAAVo0B,CAAmB,UAAnBA,IAAiC6pC,KAAK3nE,UAAtC89B,GAAmD,CAA1D;MAnB8D;;MAqBhEv5B,IAAIy6B,MAAJz6B,CAAWw5B,IAAXx5B;MACA,OAAO,CAAP;IA7CoB;;IAgDtB,IAAIsjE,KAAKX,gBAAT;IAAA,IACEY,KAAKD,KAAK,CADZ;;IAEA,IAAIpwC,YAAJ,EAAkB;MAChBowC,KAAK,CAALA;MACAC,KAAKzoD,QAAQhc,MAAbykE;IAFF,OAGO,IAAI,CAACb,cAAL,EAAqB;MAE1B;IAvDoB;;IA0DtB,KAAK,IAAIvhE,IAAImiE,EAAb,EAAiBniE,IAAIoiE,EAArB,EAAyBpiE,GAAzB,EAA8B;MAC5B,MAAM2uC,QAAQh1B,QAAQ3Z,CAAR,CAAd;MACA,MAAMohE,QAAQzyB,MAAMyyB,KAApB;MACA,MAAM1xB,MAAMf,MAAMe,GAAlB;MACA,MAAM2yB,aAAad,kBAAkBvhE,MAAMwhE,gBAA3C;MACA,MAAMc,kBAAkBD,aAAa,WAAb,GAA2B,EAAnD;MACA,IAAI7xB,eAAe,CAAnB;;MAGA,IAAI,CAACixB,OAAD,IAAYL,MAAMC,MAAND,KAAiBK,QAAQJ,MAAzC,EAAiD;QAE/C,IAAII,YAAY,IAAhB,EAAsB;UACpBG,gBAAgBH,QAAQJ,MAAxB,EAAgCI,QAAQxuB,MAAxC,EAAgDyuB,SAASzuB,MAAzD;QAH6C;;QAM/C0uB,UAAUP,KAAV;MANF,OAOO;QACLQ,gBAAgBH,QAAQJ,MAAxB,EAAgCI,QAAQxuB,MAAxC,EAAgDmuB,MAAMnuB,MAAtD;MAjB0B;;MAoB5B,IAAImuB,MAAMC,MAAND,KAAiB1xB,IAAI2xB,MAAzB,EAAiC;QAC/B7wB,eAAeoxB,gBACbR,MAAMC,MADO,EAEbD,MAAMnuB,MAFO,EAGbvD,IAAIuD,MAHS,EAIb,cAAcqvB,eAJD,CAAf9xB;MADF,OAOO;QACLA,eAAeoxB,gBACbR,MAAMC,MADO,EAEbD,MAAMnuB,MAFO,EAGbyuB,SAASzuB,MAHI,EAIb,oBAAoBqvB,eAJP,CAAf9xB;;QAMA,KAAK,IAAI+xB,KAAKnB,MAAMC,MAAND,GAAe,CAAxB,EAA2BoB,KAAK9yB,IAAI2xB,MAAzC,EAAiDkB,KAAKC,EAAtD,EAA0DD,IAA1D,EAAgE;UAC9D5K,SAAS4K,EAAT,EAAanqC,SAAbu/B,GAAyB,qBAAqB2K,eAA9C3K;QARG;;QAULgK,UAAUjyB,GAAV,EAAe,kBAAkB4yB,eAAjC;MArC0B;;MAuC5Bb,UAAU/xB,GAAV+xB;;MAEA,IAAIY,UAAJ,EAAgB;QAEdnpD,eAAeq3B,mBAAfr3B,CAAmC;UACjCvf,SAASg+D,SAASyJ,MAAMC,MAAf,CADwB;UAEjC7wB,YAFiC;UAGjCr/B,WAAWy/B,OAHsB;UAIjCH,YAAY+wB;QAJqB,CAAnCtoD;MA3C0B;IA1DR;;IA8GtB,IAAIuoD,OAAJ,EAAa;MACXG,gBAAgBH,QAAQJ,MAAxB,EAAgCI,QAAQxuB,MAAxC,EAAgDyuB,SAASzuB,MAAzD;IA/GoB;EAzHJ;;EA4OpB+tB,iBAAiB;IACf,IAAI,CAAC,KAAK70D,OAAV,EAAmB;MACjB;IAFa;;IAIf,MAAM;MAAE+M,cAAF;MAAkBS,OAAlB;MAA2Bi3B;IAA3B,IAAuC,IAA7C;IACA,MAAM;MAAEiwB,mBAAF;MAAuBlJ;IAAvB,IAAoC,IAA1C;IACA,IAAI8K,qBAAqB,CAAC,CAA1B;;IAGA,KAAK,IAAIziE,IAAI,CAAR,EAAWkY,KAAKyB,QAAQhc,MAA7B,EAAqCqC,IAAIkY,EAAzC,EAA6ClY,GAA7C,EAAkD;MAChD,MAAM2uC,QAAQh1B,QAAQ3Z,CAAR,CAAd;MACA,MAAMohE,QAAQpjE,KAAKyD,GAALzD,CAASykE,kBAATzkE,EAA6B2wC,MAAMyyB,KAANzyB,CAAY0yB,MAAzCrjE,CAAd;;MACA,KAAK,IAAI0kE,IAAItB,KAAR,EAAe1xB,MAAMf,MAAMe,GAANf,CAAU0yB,MAApC,EAA4CqB,KAAKhzB,GAAjD,EAAsDgzB,GAAtD,EAA2D;QACzD,MAAM7jE,MAAM84D,SAAS+K,CAAT,CAAZ;QACA7jE,IAAI+iB,WAAJ/iB,GAAkBgiE,oBAAoB6B,CAApB,CAAlB7jE;QACAA,IAAIu5B,SAAJv5B,GAAgB,EAAhBA;MAN8C;;MAQhD4jE,qBAAqB9zB,MAAMe,GAANf,CAAU0yB,MAAV1yB,GAAmB,CAAxC8zB;IAjBa;;IAoBf,IAAI,EAACvpD,cAAD,aAACA,cAAD,eAACA,eAAgB22B,gBAAjB,CAAJ,EAAuC;MACrC;IArBa;;IAyBf,MAAME,cAAc72B,eAAe62B,WAAf72B,CAA2B03B,OAA3B13B,KAAuC,IAA3D;IACA,MAAM+2B,oBAAoB/2B,eAAe+2B,iBAAf/2B,CAAiC03B,OAAjC13B,KAA6C,IAAvE;IAEA,KAAKS,OAAL,GAAe,KAAKsnD,eAAL,CAAqBlxB,WAArB,EAAkCE,iBAAlC,CAAf;;IACA,KAAKqxB,cAAL,CAAoB,KAAK3nD,OAAzB;EAzQkB;;AAAA;;;;;;;;;;;;;;;ACRtB;;AAEA,MAAMgpD,sBAAsB,GAA5B;;AAoBA,MAAMzT,gBAAN,CAAuB;EACrB/1D,kBAQG;IAAA,IARS;MACV21D,YADU;MAEVpiD,QAFU;MAGVyE,SAHU;MAIVuzC,QAJU;MAKVsK,cAAc,IALJ;MAMVD,uBAAuB,KANb;MAOVE,uBAAuB;IAPb,CAQT;IACD,KAAKH,YAAL,GAAoBA,YAApB;IACA,KAAKpiD,QAAL,GAAgBA,QAAhB;IACA,KAAKkV,WAAL,GAAmB,IAAnB;IACA,KAAKi/C,mBAAL,GAA2B,EAA3B;IACA,KAAK+B,iBAAL,GAAyB,IAAzB;IACA,KAAKC,aAAL,GAAqB,KAArB;IACA,KAAK10D,UAAL,GAAkBgD,YAAY,CAA9B;IACA,KAAKuzC,QAAL,GAAgBA,QAAhB;IACA,KAAKiT,QAAL,GAAgB,EAAhB;IACA,KAAKmL,mBAAL,GAA2B,IAA3B;IACA,KAAK9T,WAAL,GAAmBA,WAAnB;IACA,KAAKD,oBAAL,GAA4BA,oBAA5B;IACA,KAAKE,oBAAL,GAA4BA,oBAA5B;;IAEA,KAAK8T,UAAL;EAxBmB;;EA8BrBx8B,mBAAmB;IACjB,KAAKs8B,aAAL,GAAqB,IAArB;;IAEA,IAAI,CAAC,KAAK9T,oBAAV,EAAgC;MAC9B,MAAMiU,eAAex+D,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAArB;MACAw+D,aAAa5qC,SAAb4qC,GAAyB,cAAzBA;MACA,KAAKlU,YAAL,CAAkBx1B,MAAlB,CAAyB0pC,YAAzB;IANe;;IASjB,KAAKt2D,QAAL,CAAcwC,QAAd,CAAuB,mBAAvB,EAA4C;MAC1CC,QAAQ,IADkC;MAE1ChB,YAAY,KAAKA,UAFyB;MAG1C80D,aAAa,KAAKtL,QAAL,CAAch6D;IAHe,CAA5C;EAvCmB;;EAoDrBonB,SAAoB;IAAA;;IAAA,IAAbQ,OAAa,uEAAH,CAAG;;IAClB,IAAI,EAAE,KAAK3D,WAAL,IAAoB,KAAKghD,iBAA3B,KAAiD,KAAKC,aAA1D,EAAyE;MACvE;IAFgB;;IAIlB,KAAK9b,MAAL;IAEA,KAAK4Q,QAAL,CAAch6D,MAAd,GAAuB,CAAvB;IACA,0BAAKqxD,WAAL,wEAAkB4I,cAAlB,CAAiC,KAAKD,QAAtC,EAAgD,KAAKkJ,mBAArD;IACA,8BAAK5R,oBAAL,gFAA2B2I,cAA3B,CAA0C,KAAKD,QAA/C;IAEA,MAAMuL,gBAAgB1+D,SAAS4hC,sBAAT5hC,EAAtB;IACA,KAAKs+D,mBAAL,GAA2BK,+BAAgB;MACzCvhD,aAAa,KAAKA,WADuB;MAEzCghD,mBAAmB,KAAKA,iBAFiB;MAGzCn9D,WAAWy9D,aAH8B;MAIzCxe,UAAU,KAAKA,QAJ0B;MAKzCiT,UAAU,KAAKA,QAL0B;MAMzCkJ,qBAAqB,KAAKA,mBANe;MAOzCt7C,OAPyC;MAQzCwpC,sBAAsB,KAAKA;IARc,CAAhBoU,CAA3B;IAUA,KAAKL,mBAAL,CAAyBvmD,OAAzB,CAAiCrL,IAAjC,CACE,MAAM;MAAA;;MACJ,KAAK49C,YAAL,CAAkBx1B,MAAlB,CAAyB4pC,aAAzB;;MACA,KAAK38B,gBAAL;;MACA,2BAAKyoB,WAAL,0EAAkB6I,MAAlB;MACA,+BAAK5I,oBAAL,kFAA2B4I,MAA3B;IALJ,GAOE,UAAU3gD,MAAV,EAAkB,CAPpB;EAzEmB;;EAyFrB6vC,SAAS;IAAA;;IACP,IAAI,KAAK+b,mBAAT,EAA8B;MAC5B,KAAKA,mBAAL,CAAyB/b,MAAzB;MACA,KAAK+b,mBAAL,GAA2B,IAA3B;IAHK;;IAKP,2BAAK9T,WAAL,0EAAkBgK,OAAlB;IACA,+BAAK/J,oBAAL,kFAA2B+J,OAA3B;EA/FmB;;EAkGrB0B,qBAAqBH,cAArB,EAAqC;IACnC,KAAKxT,MAAL;IACA,KAAK6b,iBAAL,GAAyBrI,cAAzB;EApGmB;;EAuGrB6I,eAAexhD,WAAf,EAA4B;IAC1B,KAAKmlC,MAAL;IACA,KAAKnlC,WAAL,GAAmBA,WAAnB;EAzGmB;;EAmHrBmhD,aAAa;IACX,MAAMlkE,MAAM,KAAKiwD,YAAjB;IACA,IAAIuU,kBAAkB,IAAtB;IAEAxkE,IAAIxC,gBAAJwC,CAAqB,WAArBA,EAAkCpD,OAAO;MACvC,IAAI,KAAKszD,oBAAL,IAA6B,KAAK+T,mBAAtC,EAA2D;QACzD,KAAKA,mBAAL,CAAyBQ,cAAzB,CAAwC,IAAxC;;QACA,IAEED,eAFF,EAGE;UACA9gD,aAAa8gD,eAAb;UACAA,kBAAkB,IAAlBA;QAPuD;;QASzD;MAVqC;;MAavC,MAAM3zB,MAAM7wC,IAAIsH,aAAJtH,CAAkB,eAAlBA,CAAZ;;MACA,IAAI,CAAC6wC,GAAL,EAAU;QACR;MAfqC;;MAsBrC,IAAI6zB,YAAY9nE,IAAIwQ,MAAJxQ,KAAeoD,GAA/B;MAEE0kE,YACEA,aACAlqE,OACGyB,gBADHzB,CACoBq2C,GADpBr2C,EAEGuoC,gBAFHvoC,CAEoB,kBAFpBA,MAE4C,MAJ9CkqE;;MAMF,IAAIA,SAAJ,EAAe;QACb,MAAMC,YAAY3kE,IAAI00B,qBAAJ10B,EAAlB;QACA,MAAMC,IAAId,KAAKyD,GAALzD,CAAS,CAATA,EAAa,KAAIq+C,KAAJ5gD,GAAY+nE,UAAUxoE,GAAtB,IAA6BwoE,UAAU9jE,MAApD1B,CAAV;QACA0xC,IAAIhrC,KAAJgrC,CAAU10C,GAAV00C,GAAiB,KAAI,GAAJ,EAAS+gB,OAAT,CAAiB,CAAjB,IAAsB,GAAvC/gB;MAjCmC;;MAoCvCA,IAAI90C,SAAJ80C,CAAcxtC,GAAdwtC,CAAkB,QAAlBA;IApCF;IAuCA7wC,IAAIxC,gBAAJwC,CAAqB,SAArBA,EAAgC,MAAM;MACpC,IAAI,KAAKkwD,oBAAL,IAA6B,KAAK+T,mBAAtC,EAA2D;QAEvDO,kBAAkB7gD,WAAW,MAAM;UACjC,IAAI,KAAKsgD,mBAAT,EAA8B;YAC5B,KAAKA,mBAAL,CAAyBQ,cAAzB,CAAwC,KAAxC;UAF+B;;UAIjCD,kBAAkB,IAAlBA;QAJgB,GAKfV,mBALe,CAAlBU;QASF;MAZkC;;MAepC,MAAM3zB,MAAM7wC,IAAIsH,aAAJtH,CAAkB,eAAlBA,CAAZ;;MACA,IAAI,CAAC6wC,GAAL,EAAU;QACR;MAjBkC;;MAoBlCA,IAAIhrC,KAAJgrC,CAAU10C,GAAV00C,GAAgB,EAAhBA;MAEFA,IAAI90C,SAAJ80C,CAAcrqC,MAAdqqC,CAAqB,QAArBA;IAtBF;EA9JmB;;AAAA;;;;;;;;;;;;;;;ACxBvB;;AAWA,MAAMsgB,eAAN,CAAsB;EAIpB72D,kBAMG;IAAA,IANS;MACVm2D,OADU;MAEV5rC,OAFU;MAGVtF,oBAAoB,IAHV;MAIVhF,WAJU;MAKVqqD,UAAU;IALA,CAMT;IACD,KAAKnU,OAAL,GAAeA,OAAf;IACA,KAAK5rC,OAAL,GAAeA,OAAf;IACA,KAAKtF,iBAAL,GAAyBA,iBAAzB;IACA,KAAKhF,WAAL,GAAmBA,WAAnB;IACA,KAAKqqD,OAAL,GAAeA,OAAf;IAEA,KAAK5kE,GAAL,GAAW,IAAX;IACA,KAAK0yD,UAAL,GAAkB,KAAlB;EAlBkB;;EA4BpBxsC,OAAO2/B,QAAP,EAAqC;IAAA,IAApB8M,MAAoB,uEAAX,SAAW;;IACnC,IAAIA,WAAW,OAAf,EAAwB;MACtB,MAAMtyC,aAAa;QACjBwlC,UAAUA,SAAS5gB,KAAT4gB,CAAe;UAAEgN,UAAU;QAAZ,CAAfhN,CADO;QAEjB7lD,KAAK,KAAKA,GAFO;QAGjB4kE,SAAS,KAAKA,OAHG;QAIjBrlD,mBAAmB,KAAKA,iBAJP;QAKjBhF,aAAa,KAAKA,WALD;QAMjBo4C;MANiB,CAAnB;MAUA,MAAM3yD,MAAM2F,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAZ;MACA,KAAK8qD,OAAL,CAAah2B,MAAb,CAAoBz6B,GAApB;MACAqgB,WAAWrgB,GAAXqgB,GAAiBrgB,GAAjBqgB;;MAEA,MAAMvgB,SAAS+kE,mBAAS3+C,MAAT2+C,CAAgBxkD,UAAhBwkD,CAAf;;MACA,OAAOr/D,QAAQC,OAARD,CAAgB1F,MAAhB0F,CAAP;IAjBiC;;IAqBnC,OAAO,KAAKqf,OAAL,CACJigD,MADI,GAEJzyD,IAFI,CAECuyD,WAAW;MACf,IAAI,KAAKlS,UAAL,IAAmB,CAACkS,OAAxB,EAAiC;QAC/B,OAAO;UAAE9L,UAAU;QAAZ,CAAP;MAFa;;MAKf,MAAMz4C,aAAa;QACjBwlC,UAAUA,SAAS5gB,KAAT4gB,CAAe;UAAEgN,UAAU;QAAZ,CAAfhN,CADO;QAEjB7lD,KAAK,KAAKA,GAFO;QAGjB4kE,OAHiB;QAIjBrlD,mBAAmB,KAAKA,iBAJP;QAKjBhF,aAAa,KAAKA,WALD;QAMjBo4C;MANiB,CAAnB;;MASA,IAAI,KAAK3yD,GAAT,EAAc;QACZ,OAAO6kE,mBAASh/C,MAATg/C,CAAgBxkD,UAAhBwkD,CAAP;MAfa;;MAkBf,KAAK7kE,GAAL,GAAW2F,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAX;MACA,KAAK8qD,OAAL,CAAah2B,MAAb,CAAoB,KAAKz6B,GAAzB;MACAqgB,WAAWrgB,GAAXqgB,GAAiB,KAAKrgB,GAAtBqgB;MACA,OAAOwkD,mBAAS3+C,MAAT2+C,CAAgBxkD,UAAhBwkD,CAAP;IAvBG,GAyBJtyD,KAzBI,CAyBEnX,SAAS;MACdD,QAAQC,KAARD,CAAcC,KAAdD;IA1BG,EAAP;EAjDkB;;EA+EpB+sD,SAAS;IACP,KAAKwK,UAAL,GAAkB,IAAlB;EAhFkB;;EAmFpB1rD,OAAO;IACL,IAAI,CAAC,KAAKhH,GAAV,EAAe;MACb;IAFG;;IAIL,KAAKA,GAAL,CAASgf,MAAT,GAAkB,IAAlB;EAvFkB;;AAAA;;;;;;;;;;;;;;;AChBtB;;AACA;;AACA;;;;;;;;;;;;;;;;;;AA+BA,MAAM9C,gBAAN,CAAuB;EAKrB5hB,YAAYgS,OAAZ,EAAqBuB,QAArB,EAA+B;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;;IAC7B,KAAKuI,OAAL,GAAe9J,QAAQ8J,OAAvB;IACA,KAAK8e,YAAL,GAAoB5oB,QAAQ4oB,YAA5B;IACA,KAAKiF,OAAL,GAAe,CACb;MACEr/B,SAASwR,QAAQulB,sBADnB;MAEE+F,WAAW,kBAFb;MAGExY,OAAO;IAHT,CADa,EAMb;MAAEtkB,SAASwR,QAAQslB,WAAnB;MAAgCgG,WAAW,OAA3C;MAAoDxY,OAAO;IAA3D,CANa,EAOb;MAAEtkB,SAASwR,QAAQy4D,cAAnB;MAAmCntC,WAAW,UAA9C;MAA0DxY,OAAO;IAAjE,CAPa,EAQb;MAAEtkB,SAASwR,QAAQ2S,kBAAnB;MAAuC2Y,WAAW,IAAlD;MAAwDxY,OAAO;IAA/D,CARa,EASb;MAAEtkB,SAASwR,QAAQ04D,eAAnB;MAAoCptC,WAAW,WAA/C;MAA4DxY,OAAO;IAAnE,CATa,EAUb;MAAEtkB,SAASwR,QAAQ24D,cAAnB;MAAmCrtC,WAAW,UAA9C;MAA0DxY,OAAO;IAAjE,CAVa,EAWb;MACEtkB,SAASwR,QAAQ44D,kBADnB;MAEEttC,WAAW,UAFb;MAGExY,OAAO;IAHT,CAXa,EAgBb;MACEtkB,SAASwR,QAAQ64D,mBADnB;MAEEvtC,WAAW,WAFb;MAGExY,OAAO;IAHT,CAhBa,EAqBb;MACEtkB,SAASwR,QAAQ84D,sBADnB;MAEExtC,WAAW,kBAFb;MAGEytC,cAAc;QAAE5sC,MAAMjC,6BAAWC;MAAnB,CAHhB;MAIErX,OAAO;IAJT,CArBa,EA2Bb;MACEtkB,SAASwR,QAAQg5D,oBADnB;MAEE1tC,WAAW,kBAFb;MAGEytC,cAAc;QAAE5sC,MAAMjC,6BAAWE;MAAnB,CAHhB;MAIEtX,OAAO;IAJT,CA3Ba,EAiCb;MACEtkB,SAASwR,QAAQi5D,gBADnB;MAEE3tC,WAAW,kBAFb;MAGEytC,cAAc;QAAErgE,MAAMpL,qBAAWI;MAAnB,CAHhB;MAIEolB,OAAO;IAJT,CAjCa,EAuCb;MACEtkB,SAASwR,QAAQk5D,oBADnB;MAEE5tC,WAAW,kBAFb;MAGEytC,cAAc;QAAErgE,MAAMpL,qBAAWC;MAAnB,CAHhB;MAIEulB,OAAO;IAJT,CAvCa,EA6Cb;MACEtkB,SAASwR,QAAQm5D,sBADnB;MAEE7tC,WAAW,kBAFb;MAGEytC,cAAc;QAAErgE,MAAMpL,qBAAWE;MAAnB,CAHhB;MAIEslB,OAAO;IAJT,CA7Ca,EAmDb;MACEtkB,SAASwR,QAAQo5D,mBADnB;MAEE9tC,WAAW,kBAFb;MAGEytC,cAAc;QAAErgE,MAAMpL,qBAAWG;MAAnB,CAHhB;MAIEqlB,OAAO;IAJT,CAnDa,EAyDb;MACEtkB,SAASwR,QAAQq5D,gBADnB;MAEE/tC,WAAW,kBAFb;MAGEytC,cAAc;QAAErgE,MAAM/K,qBAAWjB;MAAnB,CAHhB;MAIEomB,OAAO;IAJT,CAzDa,EA+Db;MACEtkB,SAASwR,QAAQs5D,eADnB;MAEEhuC,WAAW,kBAFb;MAGEytC,cAAc;QAAErgE,MAAM/K,qBAAWC;MAAnB,CAHhB;MAIEklB,OAAO;IAJT,CA/Da,EAqEb;MACEtkB,SAASwR,QAAQu5D,gBADnB;MAEEjuC,WAAW,kBAFb;MAGEytC,cAAc;QAAErgE,MAAM/K,qBAAWE;MAAnB,CAHhB;MAIEilB,OAAO;IAJT,CArEa,EA2Eb;MACEtkB,SAASwR,QAAQw5D,wBADnB;MAEEluC,WAAW,oBAFb;MAGExY,OAAO;IAHT,CA3Ea,CAAf;IAkFE,KAAK+a,OAAL,CAAal3B,IAAb,CAAkB;MAChBnI,SAASwR,QAAQy5D,cADD;MAEhBnuC,WAAW,UAFK;MAGhBxY,OAAO;IAHS,CAAlB;IAMF,KAAK3gB,KAAL,GAAa;MACXuwD,WAAW1iD,QAAQ04D,eADR;MAEXgB,UAAU15D,QAAQ24D,cAFP;MAGXgB,cAAc35D,QAAQ44D,kBAHX;MAIXgB,eAAe55D,QAAQ64D;IAJZ,CAAb;IAOA,KAAKt3D,QAAL,GAAgBA,QAAhB;IACA,KAAKyoB,MAAL,GAAc,KAAd;;IAIA;;IACA,6FAA8BhqB,OAA9B;;IACA,2FAA6BA,OAA7B;;IACA,2FAA6BA,OAA7B;;IAEA,KAAKuT,KAAL;EAjHmB;;EAuHrB,IAAImV,MAAJ,GAAa;IACX,OAAO,KAAKsB,MAAZ;EAxHmB;;EA2HrBxM,cAAcxa,UAAd,EAA0B;IACxB,KAAKA,UAAL,GAAkBA,UAAlB;;IACA;EA7HmB;;EAgIrB8U,cAAc5V,UAAd,EAA0B;IACxB,KAAKA,UAAL,GAAkBA,UAAlB;;IACA;EAlImB;;EAqIrBqR,QAAQ;IACN,KAAKvQ,UAAL,GAAkB,CAAlB;IACA,KAAKd,UAAL,GAAkB,CAAlB;;IACA;;IAGA,KAAKX,QAAL,CAAcwC,QAAd,CAAuB,uBAAvB,EAAgD;MAAEC,QAAQ;IAAV,CAAhD;EA3ImB;;EAmQrB0P,OAAO;IACL,IAAI,KAAKsW,MAAT,EAAiB;MACf;IAFG;;IAIL,KAAKA,MAAL,GAAc,IAAd;IACA,KAAKpB,YAAL,CAAkBn5B,SAAlB,CAA4BsH,GAA5B,CAAgC,SAAhC;IACA,KAAK6xB,YAAL,CAAkB2K,YAAlB,CAA+B,eAA/B,EAAgD,MAAhD;IACA,KAAKzpB,OAAL,CAAara,SAAb,CAAuByK,MAAvB,CAA8B,QAA9B;EA1QmB;;EA6QrB4Y,QAAQ;IACN,IAAI,CAAC,KAAKkX,MAAV,EAAkB;MAChB;IAFI;;IAIN,KAAKA,MAAL,GAAc,KAAd;IACA,KAAKlgB,OAAL,CAAara,SAAb,CAAuBsH,GAAvB,CAA2B,QAA3B;IACA,KAAK6xB,YAAL,CAAkBn5B,SAAlB,CAA4ByK,MAA5B,CAAmC,SAAnC;IACA,KAAK0uB,YAAL,CAAkB2K,YAAlB,CAA+B,eAA/B,EAAgD,OAAhD;EApRmB;;EAuRrBzN,SAAS;IACP,IAAI,KAAKkE,MAAT,EAAiB;MACf,KAAKlX,KAAL;IADF,OAEO;MACL,KAAKY,IAAL;IAJK;EAvRY;;AAAA;;;;2BA8IJ;EACf,KAAKvhB,KAAL,CAAWuwD,SAAX,CAAqB9L,QAArB,GAAgC,KAAK5zC,UAAL,IAAmB,CAAnD;EACA,KAAK7Q,KAAL,CAAWunE,QAAX,CAAoB9iB,QAApB,GAA+B,KAAK5zC,UAAL,IAAmB,KAAKd,UAAvD;EACA,KAAK/P,KAAL,CAAWwnE,YAAX,CAAwB/iB,QAAxB,GAAmC,KAAK10C,UAAL,KAAoB,CAAvD;EACA,KAAK/P,KAAL,CAAWynE,aAAX,CAAyBhjB,QAAzB,GAAoC,KAAK10C,UAAL,KAAoB,CAAxD;AAlJmB;;gCAqJC;EAEpB,KAAK0mB,YAAL,CAAkB13B,gBAAlB,CAAmC,OAAnC,EAA4C,KAAK40B,MAAL,CAAYhY,IAAZ,CAAiB,IAAjB,CAA5C;;EAGA,WAAW;IAAEtf,OAAF;IAAW88B,SAAX;IAAsBxY,KAAtB;IAA6BimD;EAA7B,CAAX,IAA0D,KAAKlrC,OAA/D,EAAwE;IACtEr/B,QAAQ0C,gBAAR1C,CAAyB,OAAzBA,EAAkC8B,OAAO;MACvC,IAAIg7B,cAAc,IAAlB,EAAwB;QACtB,MAAM0D,UAAU;UAAEhrB,QAAQ;QAAV,CAAhB;;QACA,WAAW61D,QAAX,IAAuBd,YAAvB,EAAqC;UACnC/pC,QAAQ6qC,QAAR,IAAoBd,aAAac,QAAb,CAApB7qC;QAHoB;;QAKtB,KAAKztB,QAAL,CAAcwC,QAAd,CAAuBunB,SAAvB,EAAkC0D,OAAlC;MANqC;;MAQvC,IAAIlc,KAAJ,EAAW;QACT,KAAKA,KAAL;MATqC;IAAzC;EANkB;AArJD;;yCA0KsD;EAAA,IAAlD;IAAEgmD,sBAAF;IAA0BE;EAA1B,CAAkD;;EACzE,KAAKz3D,QAAL,CAAcgZ,GAAd,CAAkB,mBAAlB,EAAuC,iBAAoB;IAAA,IAAV;MAAE4R;IAAF,CAAU;IACzD,MAAM2tC,WAAW3tC,SAASjC,6BAAWC,MAArC;IAAA,MACE4vC,SAAS5tC,SAASjC,6BAAWE,IAD/B;IAGA0uC,uBAAuBrpE,SAAvBqpE,CAAiChzC,MAAjCgzC,CAAwC,SAAxCA,EAAmDgB,QAAnDhB;IACAE,qBAAqBvpE,SAArBupE,CAA+BlzC,MAA/BkzC,CAAsC,SAAtCA,EAAiDe,MAAjDf;IAEAF,uBAAuBvlC,YAAvBulC,CAAoC,cAApCA,EAAoDgB,QAApDhB;IACAE,qBAAqBzlC,YAArBylC,CAAkC,cAAlCA,EAAkDe,MAAlDf;EARF;AA3KmB;;yCA+LlB;EAAA,IARqB;IACtBC,gBADsB;IAEtBC,oBAFsB;IAGtBC,sBAHsB;IAItBC,mBAJsB;IAKtBC,gBALsB;IAMtBC,eANsB;IAOtBC;EAPsB,CAQrB;;EACD,MAAMS,oBAAoB,SAAc;IAAA,IAAb;MAAEthE;IAAF,CAAa;IACtC,MAAMuhE,SAASvhE,SAASpL,qBAAWI,IAAnC;IAAA,MACEwsE,aAAaxhE,SAASpL,qBAAWC,QADnC;IAAA,MAEE4sE,eAAezhE,SAASpL,qBAAWE,UAFrC;IAAA,MAGE4sE,YAAY1hE,SAASpL,qBAAWG,OAHlC;IAKAwrE,iBAAiBxpE,SAAjBwpE,CAA2BnzC,MAA3BmzC,CAAkC,SAAlCA,EAA6CgB,MAA7ChB;IACAC,qBAAqBzpE,SAArBypE,CAA+BpzC,MAA/BozC,CAAsC,SAAtCA,EAAiDgB,UAAjDhB;IACAC,uBAAuB1pE,SAAvB0pE,CAAiCrzC,MAAjCqzC,CAAwC,SAAxCA,EAAmDgB,YAAnDhB;IACAC,oBAAoB3pE,SAApB2pE,CAA8BtzC,MAA9BszC,CAAqC,SAArCA,EAAgDgB,SAAhDhB;IAEAH,iBAAiB1lC,YAAjB0lC,CAA8B,cAA9BA,EAA8CgB,MAA9ChB;IACAC,qBAAqB3lC,YAArB2lC,CAAkC,cAAlCA,EAAkDgB,UAAlDhB;IACAC,uBAAuB5lC,YAAvB4lC,CAAoC,cAApCA,EAAoDgB,YAApDhB;IACAC,oBAAoB7lC,YAApB6lC,CAAiC,cAAjCA,EAAiDgB,SAAjDhB;IAIA,MAAMiB,sBACJ,KAAKn4D,UAAL,GAAkB67C,6BAAgBC,sBADpC;IAEAib,iBAAiBriB,QAAjBqiB,GAA4BoB,mBAA5BpB;IACAC,qBAAqBtiB,QAArBsiB,GAAgCmB,mBAAhCnB;IACAC,uBAAuBviB,QAAvBuiB,GAAkCkB,mBAAlClB;IACAC,oBAAoBxiB,QAApBwiB,GAA+BiB,mBAA/BjB;IAIAC,iBAAiBziB,QAAjByiB,GAA4Bc,YAA5Bd;IACAC,gBAAgB1iB,QAAhB0iB,GAA2Ba,YAA3Bb;IACAC,iBAAiB3iB,QAAjB2iB,GAA4BY,YAA5BZ;EA7BF;;EA+BA,KAAKh4D,QAAL,CAAcgZ,GAAd,CAAkB,mBAAlB,EAAuCy/C,iBAAvC;;EAEA,KAAKz4D,QAAL,CAAcgZ,GAAd,CAAkB,uBAAlB,EAA2CjqB,OAAO;IAChD,IAAIA,IAAI0T,MAAJ1T,KAAe,IAAnB,EAAyB;MACvB0pE,kBAAkB;QAAEthE,MAAMpL,qBAAWC;MAAnB,CAAlB;IAF8C;EAAlD;AAjOmB;;yCA4OlB;EAAA,IAJqB;IACtB8rE,gBADsB;IAEtBC,eAFsB;IAGtBC;EAHsB,CAIrB;;EACD,SAASe,iBAAT,QAAqC;IAAA,IAAV;MAAE5hE;IAAF,CAAU;IACnC,MAAM6hE,SAAS7hE,SAAS/K,qBAAWjB,IAAnC;IAAA,MACE8tE,QAAQ9hE,SAAS/K,qBAAWC,GAD9B;IAAA,MAEE6sE,SAAS/hE,SAAS/K,qBAAWE,IAF/B;IAIAwrE,iBAAiB5pE,SAAjB4pE,CAA2BvzC,MAA3BuzC,CAAkC,SAAlCA,EAA6CkB,MAA7ClB;IACAC,gBAAgB7pE,SAAhB6pE,CAA0BxzC,MAA1BwzC,CAAiC,SAAjCA,EAA4CkB,KAA5ClB;IACAC,iBAAiB9pE,SAAjB8pE,CAA2BzzC,MAA3ByzC,CAAkC,SAAlCA,EAA6CkB,MAA7ClB;IAEAF,iBAAiB9lC,YAAjB8lC,CAA8B,cAA9BA,EAA8CkB,MAA9ClB;IACAC,gBAAgB/lC,YAAhB+lC,CAA6B,cAA7BA,EAA6CkB,KAA7ClB;IACAC,iBAAiBhmC,YAAjBgmC,CAA8B,cAA9BA,EAA8CkB,MAA9ClB;EAZD;;EAcD,KAAKh4D,QAAL,CAAcgZ,GAAd,CAAkB,mBAAlB,EAAuC+/C,iBAAvC;;EAEA,KAAK/4D,QAAL,CAAcgZ,GAAd,CAAkB,uBAAlB,EAA2CjqB,OAAO;IAChD,IAAIA,IAAI0T,MAAJ1T,KAAe,IAAnB,EAAyB;MACvBgqE,kBAAkB;QAAE5hE,MAAM/K,qBAAWjB;MAAnB,CAAlB;IAF8C;EAAlD;AA5PmB;;;;;;;;;;;;;ACjCvB;;AASA;;;;;;;;;;;;;;;;;;;;AAEA,MAAMguE,gCAAgC,sBAAtC;;;;;;;;;;;;AA2BA,MAAM/qD,OAAN,CAAc;EAQZ3hB,YAAYgS,QAAZ,EAAqBuB,QAArB,EAA+ByI,KAA/B,EAAqC;IAAA;;IAAA;;IAAA;;IAAA;;IAAA;MAAA;MAAA,OAPrB;IAOqB;;IACnC,KAAKF,OAAL,GAAe9J,SAAQ1F,SAAvB;IACA,KAAKiH,QAAL,GAAgBA,QAAhB;IACA,KAAKyI,IAAL,GAAYA,KAAZ;IACA,KAAK6jB,OAAL,GAAe,CACb;MAAEr/B,SAASwR,SAAQinB,QAAnB;MAA6BqE,WAAW;IAAxC,CADa,EAEb;MAAE98B,SAASwR,SAAQ4+C,IAAnB;MAAyBtzB,WAAW;IAApC,CAFa,EAGb;MAAE98B,SAASwR,SAAQqR,MAAnB;MAA2Bia,WAAW;IAAtC,CAHa,EAIb;MAAE98B,SAASwR,SAAQyR,OAAnB;MAA4B6Z,WAAW;IAAvC,CAJa,EAKb;MAAE98B,SAASwR,SAAQ8e,KAAnB;MAA0BwM,WAAW;IAArC,CALa,EAMb;MACE98B,SAASwR,SAAQulB,sBADnB;MAEE+F,WAAW;IAFb,CANa,EAUb;MAAE98B,SAASwR,SAAQoV,QAAnB;MAA6BkW,WAAW;IAAxC,CAVa,EAWb;MAAE98B,SAASwR,SAAQyS,YAAnB;MAAiC6Y,WAAW;IAA5C,CAXa,EAYb;MACE98B,SAASwR,SAAQ26D,oBADnB;MAEErvC,WAAW,4BAFb;MAGEytC,cAAc;QACZ,IAAIrgE,IAAJ,GAAW;UACT,MAAM;YAAEjJ;UAAF,IAAgBuQ,SAAQ26D,oBAA9B;UACA,OAAOlrE,UAAUC,QAAVD,CAAmB,SAAnBA,IACH4f,+BAAqB3iB,IADlB+C,GAEH4f,+BAAqBurD,QAFzB;QAHU;;MAAA;IAHhB,CAZa,EAwBb;MACEpsE,SAASwR,SAAQ66D,eADnB;MAEEvvC,WAAW,4BAFb;MAGEytC,cAAc;QACZ,IAAIrgE,IAAJ,GAAW;UACT,MAAM;YAAEjJ;UAAF,IAAgBuQ,SAAQ66D,eAA9B;UACA,OAAOprE,UAAUC,QAAVD,CAAmB,SAAnBA,IACH4f,+BAAqB3iB,IADlB+C,GAEH4f,+BAAqByrD,GAFzB;QAHU;;MAAA;IAHhB,CAxBa,CAAf;IAsCE,KAAKjtC,OAAL,CAAal3B,IAAb,CAAkB;MAAEnI,SAASwR,SAAQ+6D,QAAnB;MAA6BzvC,WAAW;IAAxC,CAAlB;IAEF,KAAKn5B,KAAL,GAAa;MACXgQ,UAAUnC,SAAQmC,QADP;MAEXa,YAAYhD,SAAQgD,UAFT;MAGXg4D,aAAah7D,SAAQg7D,WAHV;MAIXC,mBAAmBj7D,SAAQi7D,iBAJhB;MAKXh0C,UAAUjnB,SAAQinB,QALP;MAMX23B,MAAM5+C,SAAQ4+C,IANH;MAOXvtC,QAAQrR,SAAQqR,MAPL;MAQXI,SAASzR,SAAQyR;IARN,CAAb;;IAYA,yEAAoBzR,QAApB;;IAEA,KAAKuT,KAAL;EAlEU;;EAqEZiK,cAAcxa,UAAd,EAA0BskB,SAA1B,EAAqC;IACnC,KAAKtkB,UAAL,GAAkBA,UAAlB;IACA,KAAKskB,SAAL,GAAiBA,SAAjB;;IACA,yEAAoB,KAApB;EAxEU;;EA2EZxP,cAAc5V,UAAd,EAA0Bg5D,aAA1B,EAAyC;IACvC,KAAKh5D,UAAL,GAAkBA,UAAlB;IACA,KAAKg5D,aAAL,GAAqBA,aAArB;;IACA,yEAAoB,IAApB;EA9EU;;EAiFZ9zC,aAAa+zC,cAAb,EAA6BC,SAA7B,EAAwC;IACtC,KAAKD,cAAL,GAAuB,mBAAkBC,SAAlB,EAA6Bz2D,QAA7B,EAAvB;IACA,KAAKy2D,SAAL,GAAiBA,SAAjB;;IACA,yEAAoB,KAApB;EApFU;;EAuFZ7nD,QAAQ;IACN,KAAKvQ,UAAL,GAAkB,CAAlB;IACA,KAAKskB,SAAL,GAAiB,IAAjB;IACA,KAAK4zC,aAAL,GAAqB,KAArB;IACA,KAAKh5D,UAAL,GAAkB,CAAlB;IACA,KAAKi5D,cAAL,GAAsB7vE,6BAAtB;IACA,KAAK8vE,SAAL,GAAiB7vE,uBAAjB;;IACA,yEAAoB,IAApB;;IACA,KAAKk6B,2BAAL;IAGA,KAAKlkB,QAAL,CAAcwC,QAAd,CAAuB,cAAvB,EAAuC;MAAEC,QAAQ;IAAV,CAAvC;EAlGU;;EAiQZyhB,8BAA6C;IAAA,IAAjBW,OAAiB,uEAAP,KAAO;IAC3C,MAAM;MAAEpjB;IAAF,IAAiB,KAAK7Q,KAA5B;IAEA6Q,WAAWvT,SAAXuT,CAAqB8iB,MAArB9iB,CAA4B03D,6BAA5B13D,EAA2DojB,OAA3DpjB;EApQU;;AAAA;;;;yBAqGGhD,SAAS;EACtB,MAAM;IAAEgD,UAAF;IAAcg4D;EAAd,IAA8B,KAAK7oE,KAAzC;EACA,MAAMmyB,OAAO,IAAb;;EAGA,WAAW;IAAE91B,OAAF;IAAW88B,SAAX;IAAsBytC;EAAtB,CAAX,IAAmD,KAAKlrC,OAAxD,EAAiE;IAC/Dr/B,QAAQ0C,gBAAR1C,CAAyB,OAAzBA,EAAkC8B,OAAO;MACvC,IAAIg7B,cAAc,IAAlB,EAAwB;QACtB,MAAM0D,UAAU;UAAEhrB,QAAQ;QAAV,CAAhB;;QACA,IAAI+0D,YAAJ,EAAkB;UAChB,WAAWc,QAAX,IAAuBd,YAAvB,EAAqC;YACnC/pC,QAAQ6qC,QAAR,IAAoBd,aAAac,QAAb,CAApB7qC;UAFc;QAFI;;QAOtB,KAAKztB,QAAL,CAAcwC,QAAd,CAAuBunB,SAAvB,EAAkC0D,OAAlC;MARqC;IAAzC;EANoB;;EAmBtBhsB,WAAW9R,gBAAX8R,CAA4B,OAA5BA,EAAqC,YAAY;IAC/C,KAAK6iB,MAAL;EADF;EAGA7iB,WAAW9R,gBAAX8R,CAA4B,QAA5BA,EAAsC,YAAY;IAChDshB,KAAK/iB,QAAL+iB,CAAcvgB,QAAdugB,CAAuB,mBAAvBA,EAA4C;MAC1CtgB,QAAQsgB,IADkC;MAE1C9yB,OAAO,KAAKA;IAF8B,CAA5C8yB;EADF;EAOA02C,YAAY9pE,gBAAZ8pE,CAA6B,QAA7BA,EAAuC,YAAY;IACjD,IAAI,KAAKxpE,KAAL,KAAe,QAAnB,EAA6B;MAC3B;IAF+C;;IAIjD8yB,KAAK/iB,QAAL+iB,CAAcvgB,QAAdugB,CAAuB,cAAvBA,EAAuC;MACrCtgB,QAAQsgB,IAD6B;MAErC9yB,OAAO,KAAKA;IAFyB,CAAvC8yB;EAJF;EAWA02C,YAAY9pE,gBAAZ8pE,CAA6B,OAA7BA,EAAsC,UAAU1qE,GAAV,EAAe;IACnD,MAAMwQ,SAASxQ,IAAIwQ,MAAnB;;IAGA,IACE,KAAKtP,KAAL,KAAe8yB,KAAK62C,cAApB,IACAr6D,OAAO2oB,OAAP3oB,CAAe4oB,WAAf5oB,OAAiC,QAFnC,EAGE;MACA,KAAK8sB,IAAL;IARiD;EAArD;EAYAotC,YAAYlkD,aAAZkkD,GAA4B1jE,8BAA5B0jE;;EAEA,KAAKz5D,QAAL,CAAcgZ,GAAd,CAAkB,WAAlB,EAA+B,MAAM;IACnC,2CAAqB,IAArB;;IACA;;IACA,yEAAoB,IAApB;EAHF;;EAMA,6FAA8Bva,OAA9B;AAjKU;;yCAyKT;EAAA,IALsB;IACvB26D,oBADuB;IAEvBU,2BAFuB;IAGvBR,eAHuB;IAIvBS;EAJuB,CAKtB;;EACD,MAAMC,oBAAoB,UAACjrE,GAAD,EAAiC;IAAA,IAA3BkrE,cAA2B,uEAAV,KAAU;IACzD,MAAMC,gBAAgB,CACpB;MACE/iE,MAAM2W,+BAAqBurD,QAD7B;MAEEztC,QAAQwtC,oBAFV;MAGE7wD,SAASuxD;IAHX,CADoB,EAMpB;MACE3iE,MAAM2W,+BAAqByrD,GAD7B;MAEE3tC,QAAQ0tC,eAFV;MAGE/wD,SAASwxD;IAHX,CANoB,CAAtB;;IAaA,WAAW;MAAE5iE,IAAF;MAAQy0B,MAAR;MAAgBrjB;IAAhB,CAAX,IAAwC2xD,aAAxC,EAAuD;MACrD,MAAM76B,UAAUloC,SAASpI,IAAIoI,IAA7B;MACAy0B,OAAO19B,SAAP09B,CAAiBrH,MAAjBqH,CAAwB,SAAxBA,EAAmCyT,OAAnCzT;MACAA,OAAOoG,YAAPpG,CAAoB,cAApBA,EAAoCyT,OAApCzT;MACAA,OAAOypB,QAAPzpB,GAAkBquC,cAAlBruC;MACArjB,0DAASra,SAATqa,CAAmBgc,MAAnBhc,CAA0B,QAA1BA,EAAoC,CAAC82B,OAArC92B;IAnBuD;EAA3D;;EAsBA,KAAKvI,QAAL,CAAcgZ,GAAd,CAAkB,6BAAlB,EAAiDghD,iBAAjD;;EAEA,KAAKh6D,QAAL,CAAcgZ,GAAd,CAAkB,cAAlB,EAAkCjqB,OAAO;IACvC,IAAIA,IAAI0T,MAAJ1T,KAAe,IAAnB,EAAyB;MACvBirE,kBACE;QAAE7iE,MAAM2W,+BAAqB3iB;MAA7B,CADF,EAEyB,IAFzB;IAFqC;EAAzC;AAlMU;;2BA4M0B;EAAA,IAAvBgvE,aAAuB,uEAAP,KAAO;;EACpC,IAAI,uBAAC,IAAD,gBAAJ,EAAyB;IAEvB;EAHkC;;EAKpC,MAAM;IAAE14D,UAAF;IAAcd,UAAd;IAA0Bi5D,cAA1B;IAA0CC,SAA1C;IAAqDjpE;EAArD,IAA+D,IAArE;;EAEA,IAAIupE,aAAJ,EAAmB;IACjB,IAAI,KAAKR,aAAT,EAAwB;MACtB/oE,MAAM6Q,UAAN7Q,CAAiBsjB,IAAjBtjB,GAAwB,MAAxBA;IADF,OAEO;MACLA,MAAM6Q,UAAN7Q,CAAiBsjB,IAAjBtjB,GAAwB,QAAxBA;MACA,KAAK6X,IAAL,CAAUrK,GAAV,CAAc,UAAd,EAA0B;QAAEuC;MAAF,CAA1B,EAA0C6D,IAA1C,CAA+CkP,OAAO;QACpD9iB,MAAMgQ,QAANhQ,CAAeskB,WAAftkB,GAA6B8iB,GAA7B9iB;MADF;IALe;;IASjBA,MAAM6Q,UAAN7Q,CAAiBmE,GAAjBnE,GAAuB+P,UAAvB/P;EAhBkC;;EAmBpC,IAAI,KAAK+oE,aAAT,EAAwB;IACtB/oE,MAAM6Q,UAAN7Q,CAAiBX,KAAjBW,GAAyB,KAAKm1B,SAA9Bn1B;IACA,KAAK6X,IAAL,CAAUrK,GAAV,CAAc,eAAd,EAA+B;MAAEqD,UAAF;MAAcd;IAAd,CAA/B,EAA2D6D,IAA3D,CAAgEkP,OAAO;MACrE9iB,MAAMgQ,QAANhQ,CAAeskB,WAAftkB,GAA6B8iB,GAA7B9iB;IADF;EAFF,OAKO;IACLA,MAAM6Q,UAAN7Q,CAAiBX,KAAjBW,GAAyB6Q,UAAzB7Q;EAzBkC;;EA4BpCA,MAAM80B,QAAN90B,CAAeykD,QAAfzkD,GAA0B6Q,cAAc,CAAxC7Q;EACAA,MAAMysD,IAANzsD,CAAWykD,QAAXzkD,GAAsB6Q,cAAcd,UAApC/P;EAEAA,MAAMsf,OAANtf,CAAcykD,QAAdzkD,GAAyBipE,aAAa3vE,mBAAtC0G;EACAA,MAAMkf,MAANlf,CAAaykD,QAAbzkD,GAAwBipE,aAAa1vE,mBAArCyG;EAEA,KAAK6X,IAAL,CACGrK,GADH,CACO,oBADP,EAC6B;IAAEsmB,OAAOpzB,KAAKe,KAALf,CAAWuoE,YAAY,KAAvBvoE,IAAgC;EAAzC,CAD7B,EAEGkT,IAFH,CAEQkP,OAAO;IACX,IAAI0mD,uBAAuB,KAA3B;;IACA,WAAWC,MAAX,IAAqBzpE,MAAM6oE,WAAN7oE,CAAkB6N,OAAvC,EAAgD;MAC9C,IAAI47D,OAAOpqE,KAAPoqE,KAAiBT,cAArB,EAAqC;QACnCS,OAAO52B,QAAP42B,GAAkB,KAAlBA;QACA;MAH4C;;MAK9CA,OAAO52B,QAAP42B,GAAkB,IAAlBA;MACAD,uBAAuB,IAAvBA;IARS;;IAUX,IAAI,CAACA,oBAAL,EAA2B;MACzBxpE,MAAM8oE,iBAAN9oE,CAAwBskB,WAAxBtkB,GAAsC8iB,GAAtC9iB;MACAA,MAAM8oE,iBAAN9oE,CAAwB6yC,QAAxB7yC,GAAmC,IAAnCA;IAZS;EAFf;AA9OU;;oCA2Qc;EACxB,MAAM;IAAEA,KAAF;IAAS6X;EAAT,IAAkB,IAAxB;EAEA,MAAM6xD,0BAA0B3iE,QAAQua,GAARva,CAAY,CAC1C8Q,KAAKrK,GAALqK,CAAS,iBAATA,CAD0C,EAE1CA,KAAKrK,GAALqK,CAAS,mBAATA,CAF0C,EAG1CA,KAAKrK,GAALqK,CAAS,gBAATA,CAH0C,EAI1CA,KAAKrK,GAALqK,CAAS,kBAATA,CAJ0C,CAAZ9Q,CAAhC;EAMA,MAAMD,0BAAN;EAEA,MAAMM,QAAQ5J,iBAAiBwC,MAAM6oE,WAAvB,CAAd;EAAA,MACEc,4BAA4B7iD,SAC1B1f,MAAMk9B,gBAANl9B,CAAuB,gCAAvBA,CAD0B,EAE1B,EAF0B,CAD9B;EAAA,MAKEwiE,sBAAsB9iD,SACpB1f,MAAMk9B,gBAANl9B,CAAuB,yBAAvBA,CADoB,EAEpB,EAFoB,CALxB;EAWA,MAAMmiD,SAASriD,SAAS2zB,aAAT3zB,CAAuB,QAAvBA,CAAf;EACA,MAAMmhD,MAAMkB,OAAOjB,UAAPiB,CAAkB,IAAlBA,EAAwB;IAAEhB,OAAO;EAAT,CAAxBgB,CAAZ;EACAlB,IAAIwhB,IAAJxhB,GAAW,GAAGjhD,MAAM0iE,QAAS,IAAG1iE,MAAM2iE,UAA3B,EAAX1hB;EAEA,IAAIxC,WAAW,CAAf;;EACA,WAAWmkB,eAAX,IAA8B,MAAMN,uBAApC,EAA6D;IAC3D,MAAM;MAAEvnE;IAAF,IAAYkmD,IAAI4hB,WAAJ5hB,CAAgB2hB,eAAhB3hB,CAAlB;;IACA,IAAIlmD,QAAQ0jD,QAAZ,EAAsB;MACpBA,WAAW1jD,KAAX0jD;IAHyD;EA3BrC;;EAiCxBA,YAAY,IAAI+jB,mBAAhB/jB;;EAEA,IAAIA,WAAW8jB,yBAAf,EAA0C;IACxC1iE,mBAASe,WAATf,CAAqB,gCAArBA,EAAuD,GAAG4+C,QAAS,IAAnE5+C;EApCsB;;EAwCxBsiD,OAAOpnD,KAAPonD,GAAe,CAAfA;EACAA,OAAOnnD,MAAPmnD,GAAgB,CAAhBA;AApTU;;;;;;;;;;;;ACtCd,MAAM2gB,kCAAkC,EAAxC;;AAWA,MAAMlkD,WAAN,CAAkB;EAChBnqB,YAAY+qB,WAAZ,EAAsE;IAAA,IAA7CujD,SAA6C,uEAAjCD,+BAAiC;IACpE,KAAKtjD,WAAL,GAAmBA,WAAnB;IACA,KAAKujD,SAAL,GAAiBA,SAAjB;IAEA,KAAKC,mBAAL,GAA2B,KAAKC,gBAAL,GAAwBz2D,IAAxB,CAA6B02D,eAAe;MACrE,MAAMC,WAAWj5D,KAAKiB,KAALjB,CAAWg5D,eAAe,IAA1Bh5D,CAAjB;MACA,IAAIhP,QAAQ,CAAC,CAAb;;MACA,IAAI,CAACoO,MAAMC,OAAND,CAAc65D,SAASx3C,KAAvBriB,CAAL,EAAoC;QAClC65D,SAASx3C,KAATw3C,GAAiB,EAAjBA;MADF,OAEO;QACL,OAAOA,SAASx3C,KAATw3C,CAAelqE,MAAfkqE,IAAyB,KAAKJ,SAArC,EAAgD;UAC9CI,SAASx3C,KAATw3C,CAAenjC,KAAfmjC;QAFG;;QAKL,KAAK,IAAI7nE,IAAI,CAAR,EAAWkY,KAAK2vD,SAASx3C,KAATw3C,CAAelqE,MAApC,EAA4CqC,IAAIkY,EAAhD,EAAoDlY,GAApD,EAAyD;UACvD,MAAM8nE,SAASD,SAASx3C,KAATw3C,CAAe7nE,CAAf6nE,CAAf;;UACA,IAAIC,OAAO5jD,WAAP4jD,KAAuB,KAAK5jD,WAAhC,EAA6C;YAC3CtkB,QAAQI,CAARJ;YACA;UAJqD;QALpD;MAL8D;;MAkBrE,IAAIA,UAAU,CAAC,CAAf,EAAkB;QAChBA,QAAQioE,SAASx3C,KAATw3C,CAAe/lE,IAAf+lE,CAAoB;UAAE3jD,aAAa,KAAKA;QAApB,CAApB2jD,IAAyD,CAAjEjoE;MAnBmE;;MAqBrE,KAAKkf,IAAL,GAAY+oD,SAASx3C,KAATw3C,CAAejoE,KAAfioE,CAAZ;MACA,KAAKA,QAAL,GAAgBA,QAAhB;IAtByB,EAA3B;EALc;;EA+BhB,MAAME,eAAN,GAAwB;IACtB,MAAMH,cAAch5D,KAAKC,SAALD,CAAe,KAAKi5D,QAApBj5D,CAApB;IAMAo5D,aAAaC,OAAbD,CAAqB,eAArBA,EAAsCJ,WAAtCI;EAtCc;;EAyChB,MAAML,gBAAN,GAAyB;IAIvB,OAAOK,aAAaE,OAAbF,CAAqB,eAArBA,CAAP;EA7Cc;;EAgDhB,MAAMnrE,GAAN,CAAUkO,IAAV,EAAgB5F,GAAhB,EAAqB;IACnB,MAAM,KAAKuiE,mBAAX;IACA,KAAK5oD,IAAL,CAAU/T,IAAV,IAAkB5F,GAAlB;IACA,OAAO,KAAK4iE,eAAL,EAAP;EAnDc;;EAsDhB,MAAM52C,WAAN,CAAkBg3C,UAAlB,EAA8B;IAC5B,MAAM,KAAKT,mBAAX;;IACA,WAAW38D,IAAX,IAAmBo9D,UAAnB,EAA+B;MAC7B,KAAKrpD,IAAL,CAAU/T,IAAV,IAAkBo9D,WAAWp9D,IAAX,CAAlB;IAH0B;;IAK5B,OAAO,KAAKg9D,eAAL,EAAP;EA3Dc;;EA8DhB,MAAMj9D,GAAN,CAAUC,IAAV,EAAgBq9D,YAAhB,EAA8B;IAC5B,MAAM,KAAKV,mBAAX;IACA,MAAMviE,MAAM,KAAK2Z,IAAL,CAAU/T,IAAV,CAAZ;IACA,OAAO5F,QAAQlK,SAARkK,GAAoBA,GAApBA,GAA0BijE,YAAjC;EAjEc;;EAoEhB,MAAM5kD,WAAN,CAAkB2kD,UAAlB,EAA8B;IAC5B,MAAM,KAAKT,mBAAX;IACA,MAAM3jE,SAASD,OAAO6C,MAAP7C,CAAc,IAAdA,CAAf;;IAEA,WAAWiH,IAAX,IAAmBo9D,UAAnB,EAA+B;MAC7B,MAAMhjE,MAAM,KAAK2Z,IAAL,CAAU/T,IAAV,CAAZ;MACAhH,OAAOgH,IAAP,IAAe5F,QAAQlK,SAARkK,GAAoBA,GAApBA,GAA0BgjE,WAAWp9D,IAAX,CAAzChH;IAN0B;;IAQ5B,OAAOA,MAAP;EA5Ec;;AAAA;;;;;;;;;;;;;;;ACXlB;;AACA;;AACA;;AACA;;AACA;;AAEA;AAMA,MAAMskE,aAAa,EAAnB;;;AAEA,MAAMC,kBAAN,SAAiCC,4BAAjC,CAAiD;EAC/C,MAAMR,eAAN,CAAsBS,OAAtB,EAA+B;IAC7BR,aAAaC,OAAbD,CAAqB,mBAArBA,EAA0Cp5D,KAAKC,SAALD,CAAe45D,OAAf55D,CAA1Co5D;EAF6C;;EAK/C,MAAML,gBAAN,CAAuBa,OAAvB,EAAgC;IAC9B,OAAO55D,KAAKiB,KAALjB,CAAWo5D,aAAaE,OAAbF,CAAqB,mBAArBA,CAAXp5D,CAAP;EAN6C;;AAAA;;AAUjD,MAAM65D,uBAAN,SAAsCp2D,4BAAtC,CAA8D;EAC5D,OAAOO,qBAAP,CAA6BzH,OAA7B,EAAsC;IACpC,OAAO,IAAIu9D,iCAAJ,EAAP;EAF0D;;EAK5D,OAAO71D,iBAAP,GAA2B;IACzB,OAAO,IAAIy1D,kBAAJ,EAAP;EAN0D;;EAS5D,OAAOx1D,UAAP,OAAwC;IAAA,IAAtB;MAAEtI,SAAS;IAAX,CAAsB;IACtC,OAAO,IAAIm+D,wBAAJ,CAAgBn+D,MAAhB,CAAP;EAV0D;;EAa5D,OAAOuI,eAAP,QAA6C;IAAA,IAAtB;MAAEpI;IAAF,CAAsB;IAC3C,OAAO,IAAIi+D,mCAAJ,CAAqBj+D,gBAArB,CAAP;EAd0D;;AAAA;;AAiB9D6I,0BAAqBiC,gBAArBjC,GAAwCi1D,uBAAxCj1D;;;;;;;;;;;;;ACzCA;;;;;;;;;;;;;;;;;;;;;;AAOA,MAAM+0D,eAAN,CAAsB;EAWpBpvE,cAAc;IAAA;MAAA;MAAA,OAVF2K,OAAOqlC,MAAPrlC,CAGN;kCAAA;2BAAA;6BAAA;8BAAA;kCAAA;kCAAA;qCAAA;+BAAA;+BAAA;iCAAA;sCAAA;gCAAA;wCAAA;4CAAA;8BAAA;+BAAA;8BAAA;8BAAA;0BAAA;+BAAA;2BAAA;uBAAA;iCAAA;gCAAA;6BAAA;8BAAA;yBAAA;;MAAA,CAHMA;IAUE;;IAAA;MAAA;MAAA,OAJLA,OAAO6C,MAAP7C,CAAc,IAAdA;IAIK;;IAAA;MAAA;MAAA,OAFQ;IAER;;IACZ,IAAI,KAAK3K,WAAL,KAAqBovE,eAAzB,EAA0C;MACxC,MAAM,IAAIvjE,KAAJ,CAAU,oCAAV,CAAN;IAFU;;IAaZ,iDAA2B,KAAK2iE,gBAAL,uBAAsB,IAAtB,cAAsCz2D,IAAtC,CACzB23D,SAAS;MACP,WAAW99D,IAAX,0BAAmB,IAAnB,cAAmC;QACjC,MAAM+9D,YAAYD,KAAZ,aAAYA,KAAZ,uBAAYA,MAAQ99D,IAAR,CAAlB;;QAEA,IAAI,OAAO+9D,SAAP,KAAqB,OAAO,uCAAe/9D,IAAf,CAAhC,EAAsD;UACpD,oCAAYA,IAAZ,IAAoB+9D,SAApB;QAJ+B;MAD5B;IADgB,EAA3B;EAxBkB;;EA2CpB,MAAMf,eAAN,CAAsBS,OAAtB,EAA+B;IAC7B,MAAM,IAAIxjE,KAAJ,CAAU,kCAAV,CAAN;EA5CkB;;EAqDpB,MAAM2iE,gBAAN,CAAuBa,OAAvB,EAAgC;IAC9B,MAAM,IAAIxjE,KAAJ,CAAU,mCAAV,CAAN;EAtDkB;;EA8DpB,MAAM0Z,KAAN,GAAc;IACZ,4BAAM,IAAN;;IACA,MAAMmqD,8BAAQ,IAAR,SAAN;;IAEA,oCAAc/kE,OAAO6C,MAAP7C,CAAc,IAAdA,CAAd;;IACA,OAAO,KAAKikE,eAAL,uBAAqB,IAArB,cAAqC32D,KAArC,CAA2C8F,UAAU;MAE1D,oCAAc2xD,KAAd;;MACA,MAAM3xD,MAAN;IAHK,EAAP;EAnEkB;;EAiFpB,MAAMra,GAAN,CAAUkO,IAAV,EAAgBpO,KAAhB,EAAuB;IACrB,4BAAM,IAAN;;IACA,MAAMyrE,eAAe,uCAAer9D,IAAf,CAArB;IAAA,MACE89D,8BAAQ,IAAR,SADF;;IAGA,IAAIT,iBAAiBntE,SAArB,EAAgC;MAC9B,MAAM,IAAI+J,KAAJ,CAAW,oBAAmB+F,IAAK,iBAAnC,CAAN;IADF,OAEO,IAAIpO,UAAU1B,SAAd,EAAyB;MAC9B,MAAM,IAAI+J,KAAJ,CAAU,wCAAV,CAAN;IARmB;;IAUrB,MAAMoG,YAAY,OAAOzO,KAAzB;IAAA,MACEosE,cAAc,OAAOX,YADvB;;IAGA,IAAIh9D,cAAc29D,WAAlB,EAA+B;MAC7B,IAAI39D,cAAc,QAAdA,IAA0B29D,gBAAgB,QAA9C,EAAwD;QACtDpsE,QAAQA,MAAMmT,QAANnT,EAARA;MADF,OAEO;QACL,MAAM,IAAIqI,KAAJ,CACH,oBAAmBrI,KAAM,UAASyO,SAAU,gBAAe29D,WAAY,GADpE,CAAN;MAJ2B;IAA/B,OAQO;MACL,IAAI39D,cAAc,QAAdA,IAA0B,CAAC1H,OAAOC,SAAPD,CAAiB/G,KAAjB+G,CAA/B,EAAwD;QACtD,MAAM,IAAIsB,KAAJ,CAAW,oBAAmBrI,KAAM,uBAApC,CAAN;MAFG;IArBc;;IA2BrB,oCAAYoO,IAAZ,IAAoBpO,KAApB;IACA,OAAO,KAAKorE,eAAL,uBAAqB,IAArB,WAAkC32D,KAAlC,CAAwC8F,UAAU;MAEvD,oCAAc2xD,KAAd;;MACA,MAAM3xD,MAAN;IAHK,EAAP;EA7GkB;;EA0HpB,MAAMpM,GAAN,CAAUC,IAAV,EAAgB;IAAA;;IACd,4BAAM,IAAN;;IACA,MAAMq9D,eAAe,uCAAer9D,IAAf,CAArB;;IAEA,IAAIq9D,iBAAiBntE,SAArB,EAAgC;MAC9B,MAAM,IAAI+J,KAAJ,CAAW,oBAAmB+F,IAAK,iBAAnC,CAAN;IALY;;IAOd,iCAAO,oCAAYA,IAAZ,CAAP,2EAA4Bq9D,YAA5B;EAjIkB;;EAyIpB,MAAMl9D,MAAN,GAAe;IACb,4BAAM,IAAN;IACA,MAAM89D,MAAMllE,OAAO6C,MAAP7C,CAAc,IAAdA,CAAZ;;IAEA,WAAWiH,IAAX,0BAAmB,IAAnB,cAAmC;MAAA;;MACjCi+D,IAAIj+D,IAAJ,8BAAY,oCAAYA,IAAZ,CAAZi+D,2EAAiC,uCAAej+D,IAAf,CAAjCi+D;IALW;;IAOb,OAAOA,GAAP;EAhJkB;;AAAA;;;;;;;;;;;;;;;ACLtB;;AAEA;;AAOA,SAASzoD,QAAT,CAAkB0oD,OAAlB,EAA2BzoD,QAA3B,EAAqC;EACnC,MAAMniB,IAAImG,SAAS2zB,aAAT3zB,CAAuB,GAAvBA,CAAV;;EACA,IAAI,CAACnG,EAAEuzB,KAAP,EAAc;IACZ,MAAM,IAAI5sB,KAAJ,CAAU,gDAAV,CAAN;EAHiC;;EAKnC3G,EAAEgO,IAAFhO,GAAS4qE,OAAT5qE;EACAA,EAAE4N,MAAF5N,GAAW,SAAXA;;EAGA,IAAI,cAAcA,CAAlB,EAAqB;IACnBA,EAAEkiB,QAAFliB,GAAamiB,QAAbniB;EAViC;;EAclC,UAASg7B,IAAT70B,IAAiBA,SAASC,eAA1B,EAA2C60B,MAA3C,CAAkDj7B,CAAlD;EACDA,EAAEuzB,KAAFvzB;EACAA,EAAEgH,MAAFhH;AA1CF;;AAgDA,MAAMqqE,eAAN,CAAsB;EACpBvvE,cAAc;IACZ,KAAK+vE,aAAL,GAAqB,IAAI9uC,OAAJ,EAArB;EAFkB;;EAKpB9c,YAAYtR,GAAZ,EAAiBwU,QAAjB,EAA2B;IACzB,IAAI,CAAC2oD,sCAAuBn9D,GAAvBm9D,EAA4B,oBAA5BA,CAAL,EAAwD;MACtDnvE,QAAQC,KAARD,CAAe,kCAAiCgS,GAAlC,EAAdhS;MACA;IAHuB;;IAKzBumB,SAASvU,MAAM,wBAAf,EAAyCwU,QAAzC;EAVkB;;EAapB4oD,aAAa72D,IAAb,EAAmBiO,QAAnB,EAA6B6oD,WAA7B,EAA0C;IACxC,MAAMJ,UAAUjjD,IAAI2L,eAAJ3L,CACd,IAAIrF,IAAJ,CAAS,CAACpO,IAAD,CAAT,EAAiB;MAAEqO,MAAMyoD;IAAR,CAAjB,CADcrjD,CAAhB;IAGAzF,SAAS0oD,OAAT,EAAkBzoD,QAAlB;EAjBkB;;EAuBpBwlB,mBAAmBrsC,OAAnB,EAA4B4Y,IAA5B,EAAkCiO,QAAlC,EAA4C;IAC1C,MAAM8oD,YAAYC,yBAAU/oD,QAAV+oD,CAAlB;IACA,MAAMF,cAAcC,YAAY,iBAAZ,GAAgC,EAApD;;IAEA,IAAIA,SAAJ,EAAe;MACb,IAAIL,UAAU,KAAKC,aAAL,CAAmBp+D,GAAnB,CAAuBnR,OAAvB,CAAd;;MACA,IAAI,CAACsvE,OAAL,EAAc;QACZA,UAAUjjD,IAAI2L,eAAJ3L,CAAoB,IAAIrF,IAAJ,CAAS,CAACpO,IAAD,CAAT,EAAiB;UAAEqO,MAAMyoD;QAAR,CAAjB,CAApBrjD,CAAVijD;;QACA,KAAKC,aAAL,CAAmBrsE,GAAnB,CAAuBlD,OAAvB,EAAgCsvE,OAAhC;MAJW;;MAMb,IAAIO,SAAJ;MAGEA,YAAY,WAAWC,mBAAmBR,UAAU,GAAVA,GAAgBzoD,QAAnC,CAAvBgpD;;MAWF,IAAI;QACFnwE,OAAOwlB,IAAPxlB,CAAYmwE,SAAZnwE;QACA,OAAO,IAAP;MAFF,EAGE,OAAO0W,EAAP,EAAW;QACX/V,QAAQC,KAARD,CAAe,uBAAsB+V,EAAvB,EAAd/V;QAGAgsB,IAAI0jD,eAAJ1jD,CAAoBijD,OAApBjjD;;QACA,KAAKkjD,aAAL,CAAmB5jD,MAAnB,CAA0B3rB,OAA1B;MA5BW;IAJ2B;;IAoC1C,KAAKyvE,YAAL,CAAkB72D,IAAlB,EAAwBiO,QAAxB,EAAkC6oD,WAAlC;IACA,OAAO,KAAP;EA5DkB;;EA+DpB9oD,SAASG,IAAT,EAAe1U,GAAf,EAAoBwU,QAApB,EAA8B;IAC5B,MAAMyoD,UAAUjjD,IAAI2L,eAAJ3L,CAAoBtF,IAApBsF,CAAhB;IACAzF,SAAS0oD,OAAT,EAAkBzoD,QAAlB;EAjEkB;;AAAA;;;;;;;;;;;;;;;AC/BtB;;AACA;;AAEA,MAAMmpD,UAAUnlE,SAASmlE,OAAzB;;AAKA,MAAMhB,WAAN,CAAkB;EAChBxvE,YAAYozD,IAAZ,EAAkB;IAChB,KAAKqd,KAAL,GAAard,IAAb;IACA,KAAKxN,MAAL,GAAc,IAAI16C,OAAJ,CAAY,CAACC,OAAD,EAAU6xB,MAAV,KAAqB;MAC7CwzC,QAAQE,WAARF,CAAoB7T,+BAAcvJ,IAAduJ,CAApB6T,EAAyC,MAAM;QAC7CrlE,QAAQqlE,OAAR;MADF;IADY,EAAd;EAHc;;EAUhB,MAAMphC,WAAN,GAAoB;IAClB,MAAMpzB,OAAO,MAAM,KAAK4pC,MAAxB;IACA,OAAO5pC,KAAKozB,WAALpzB,EAAP;EAZc;;EAehB,MAAMyC,YAAN,GAAqB;IACnB,MAAMzC,OAAO,MAAM,KAAK4pC,MAAxB;IACA,OAAO5pC,KAAKyC,YAALzC,EAAP;EAjBc;;EAoBhB,MAAMrK,GAAN,CAAUpO,GAAV,EAAmE;IAAA,IAApDqiB,IAAoD,uEAA7C,IAA6C;IAAA,IAAvCgB,QAAuC,uEAA5B+0C,iCAAgBp4D,GAAhBo4D,EAAqB/1C,IAArB+1C,CAA4B;IACjE,MAAM3/C,OAAO,MAAM,KAAK4pC,MAAxB;IACA,OAAO5pC,KAAKrK,GAALqK,CAASzY,GAATyY,EAAc4J,IAAd5J,EAAoB4K,QAApB5K,CAAP;EAtBc;;EAyBhB,MAAM6B,SAAN,CAAgBrd,OAAhB,EAAyB;IACvB,MAAMwb,OAAO,MAAM,KAAK4pC,MAAxB;IACA,OAAO5pC,KAAK6B,SAAL7B,CAAexb,OAAfwb,CAAP;EA3Bc;;AAAA;;;;;;;;ACUL;;AAEb3Q,SAASmlE,OAATnlE,GAAoB,UAASnL,MAAT,EAAiBmL,QAAjB,EAA2BvJ,SAA3B,EAAsC;EACxD,IAAI6uE,YAAY,EAAhB;EACA,IAAIC,YAAY,EAAhB;EACA,IAAIC,YAAY,aAAhB;EACA,IAAIC,YAAY,EAAhB;EACA,IAAIC,UAAU,EAAd;EACA,IAAIC,cAAc,SAAlB;EAeA,IAAIC,wBAAwB,IAA5B;;EAUA,SAASC,oBAAT,GAAgC;IAC9B,OAAO7lE,SAASi5B,gBAATj5B,CAA0B,+BAA1BA,CAAP;EAhCsD;;EAmCxD,SAAS8lE,iBAAT,GAA6B;IAC3B,IAAIC,SAAS/lE,SAAS2B,aAAT3B,CAAuB,iCAAvBA,CAAb;IAEA,OAAO+lE,SAAS37D,KAAKiB,KAALjB,CAAW27D,OAAOC,SAAlB57D,CAAT,GAAwC,IAA/C;EAtCsD;;EAyCxD,SAAS67D,uBAAT,CAAiC9wE,OAAjC,EAA0C;IACxC,OAAOA,UAAUA,QAAQ8jC,gBAAR9jC,CAAyB,iBAAzBA,CAAV,GAAwD,EAA/D;EA1CsD;;EA6CxD,SAAS+wE,iBAAT,CAA2B/wE,OAA3B,EAAoC;IAClC,IAAI,CAACA,OAAL,EACE,OAAO,EAAP;IAEF,IAAIgxE,SAAShxE,QAAQujC,YAARvjC,CAAqB,cAArBA,CAAb;IACA,IAAIixE,WAAWjxE,QAAQujC,YAARvjC,CAAqB,gBAArBA,CAAf;IACA,IAAIolB,OAAO,EAAX;;IACA,IAAI6rD,QAAJ,EAAc;MACZ,IAAI;QACF7rD,OAAOnQ,KAAKiB,KAALjB,CAAWg8D,QAAXh8D,CAAPmQ;MADF,EAEE,OAAOyZ,CAAP,EAAU;QACVx+B,QAAQid,IAARjd,CAAa,oCAAoC2wE,MAAjD3wE;MAJU;IAPoB;;IAclC,OAAO;MAAE+H,IAAI4oE,MAAN;MAAc5rD,MAAMA;IAApB,CAAP;EA3DsD;;EA8DxD,SAAS8rD,WAAT,CAAqB7+D,GAArB,EAA0B8+D,SAA1B,EAAqCC,SAArC,EAAgD;IAC9CD,YAAYA,aAAa,SAASE,UAAT,CAAoBz4D,IAApB,EAA0B,CAAnD;;IACAw4D,YAAYA,aAAa,SAASE,UAAT,GAAsB,CAA/C;;IAEA,IAAIC,MAAM,IAAIC,cAAJ,EAAV;IACAD,IAAIrsD,IAAJqsD,CAAS,KAATA,EAAgBl/D,GAAhBk/D,EAAqBd,qBAArBc;;IACA,IAAIA,IAAIE,gBAAR,EAA0B;MACxBF,IAAIE,gBAAJF,CAAqB,2BAArBA;IAP4C;;IAS9CA,IAAIG,kBAAJH,GAAyB,YAAW;MAClC,IAAIA,IAAII,UAAJJ,IAAkB,CAAtB,EAAyB;QACvB,IAAIA,IAAIl/B,MAAJk/B,IAAc,GAAdA,IAAqBA,IAAIl/B,MAAJk/B,KAAe,CAAxC,EAA2C;UACzCJ,UAAUI,IAAIK,YAAd;QADF,OAEO;UACLR;QAJqB;MADS;IAApC;;IASAG,IAAIM,OAAJN,GAAcH,SAAdG;IACAA,IAAIO,SAAJP,GAAgBH,SAAhBG;;IAIA,IAAI;MACFA,IAAIQ,IAAJR,CAAS,IAATA;IADF,EAEE,OAAO1yC,CAAP,EAAU;MACVuyC;IA1B4C;EA9DQ;;EAoHxD,SAASY,aAAT,CAAuBt/D,IAAvB,EAA6BkgD,IAA7B,EAAmCqf,eAAnC,EAAoDC,eAApD,EAAqE;IACnE,IAAIjmD,UAAUvZ,KAAKjP,OAALiP,CAAa,SAAbA,EAAwB,EAAxBA,KAA+B,IAA7C;;IAGA,SAASy/D,UAAT,CAAoBn+B,IAApB,EAA0B;MACxB,IAAIA,KAAKo+B,WAALp+B,CAAiB,IAAjBA,IAAyB,CAA7B,EACE,OAAOA,IAAP;MACF,OAAOA,KAAKvwC,OAALuwC,CAAa,OAAbA,EAAsB,IAAtBA,EACKvwC,OADLuwC,CACa,MADbA,EACqB,IADrBA,EAEKvwC,OAFLuwC,CAEa,MAFbA,EAEqB,IAFrBA,EAGKvwC,OAHLuwC,CAGa,MAHbA,EAGqB,IAHrBA,EAIKvwC,OAJLuwC,CAIa,MAJbA,EAIqB,IAJrBA,EAKKvwC,OALLuwC,CAKa,MALbA,EAKqB,IALrBA,EAMKvwC,OANLuwC,CAMa,MANbA,EAMqB,GANrBA,EAOKvwC,OAPLuwC,CAOa,MAPbA,EAOqB,GAPrBA,EAQKvwC,OARLuwC,CAQa,MARbA,EAQqB,GARrBA,EASKvwC,OATLuwC,CASa,MATbA,EASqB,GATrBA,CAAP;IAPiE;;IAsBnE,SAASq+B,eAAT,CAAyBr+B,IAAzB,EAA+Bs+B,wBAA/B,EAAyD;MACvD,IAAIC,aAAa,EAAjB;MAGA,IAAIC,UAAU,WAAd;MACA,IAAIC,YAAY,aAAhB;MACA,IAAIC,YAAY,kBAAhB;MACA,IAAIC,WAAW,gCAAf;MACA,IAAIC,UAAU,wBAAd;;MAGA,SAASC,aAAT,CAAuBC,OAAvB,EAAgCC,cAAhC,EAAgDC,sBAAhD,EAAwE;QACtE,IAAIC,UAAUH,QAAQrvE,OAARqvE,CAAgBN,OAAhBM,EAAyB,EAAzBA,EAA6Bn9D,KAA7Bm9D,CAAmC,SAAnCA,CAAd;QACA,IAAII,cAAc,GAAlB;QACA,IAAIC,cAAcvgB,KAAKj9C,KAALi9C,CAAW,GAAXA,EAAgB,CAAhBA,EAAmB,CAAnBA,CAAlB;QACA,IAAIwgB,WAAW,KAAf;QACA,IAAIp+B,QAAQ,EAAZ;;QAEA,SAASq+B,SAAT,GAAqB;UAGnB,OAAO,IAAP,EAAa;YACX,IAAI,CAACJ,QAAQjvE,MAAb,EAAqB;cACnBgvE;cACA;YAHS;;YAKX,IAAIlrD,OAAOmrD,QAAQloC,KAARkoC,EAAX;YAGA,IAAIR,UAAUnlE,IAAVmlE,CAAe3qD,IAAf2qD,CAAJ,EACE;;YAGF,IAAIM,cAAJ,EAAoB;cAClB/9B,QAAQ09B,UAAU7zD,IAAV6zD,CAAe5qD,IAAf4qD,CAAR19B;;cACA,IAAIA,KAAJ,EAAW;gBAITk+B,cAAcl+B,MAAM,CAAN,EAAS7xC,WAAT6xC,EAAdk+B;gBACAE,WAAYF,gBAAgB,GAAhBA,IACPA,gBAAgBtgB,IADTsgB,IACmBA,gBAAgBC,WAD/CC;gBAEA;cAPF,OAQO,IAAIA,QAAJ,EAAc;gBACnB;cAXgB;;cAalBp+B,QAAQ29B,SAAS9zD,IAAT8zD,CAAc7qD,IAAd6qD,CAAR39B;;cACA,IAAIA,KAAJ,EAAW;gBACTs+B,WAAWrnD,UAAU+oB,MAAM,CAAN,CAArB,EAA+Bq+B,SAA/B;gBACA;cAhBgB;YAZT;;YAiCX,IAAIE,MAAMzrD,KAAKktB,KAALltB,CAAW8qD,OAAX9qD,CAAV;;YACA,IAAIyrD,OAAOA,IAAIvvE,MAAJuvE,IAAc,CAAzB,EAA4B;cAC1BhB,WAAWgB,IAAI,CAAJ,CAAX,IAAqBpB,WAAWoB,IAAI,CAAJ,CAAX,CAArBhB;YAnCS;UAHM;QAPiD;;QAiDtEc;MA5DqD;;MAgEvD,SAASC,UAAT,CAAoBjhE,GAApB,EAAyBzQ,QAAzB,EAAmC;QACjCsvE,YAAY7+D,GAAZ,EAAiB,UAAS+5B,OAAT,EAAkB;UACjCymC,cAAczmC,OAAd,EAAuB,KAAvB,EAA8BxqC,QAA9B;QADF,GAEG,YAAY;UACbvB,QAAQid,IAARjd,CAAagS,MAAM,aAAnBhS;UACAuB;QAJF;MAjEqD;;MA0EvDixE,cAAc7+B,IAAd,EAAoB,IAApB,EAA0B,YAAW;QACnCs+B,yBAAyBC,UAAzB;MADF;IAhGiE;;IAsGnErB,YAAYx+D,IAAZ,EAAkB,UAAS8gE,QAAT,EAAmB;MACnCpD,aAAaoD,QAAbpD;MAGAiC,gBAAgBmB,QAAhB,EAA0B,UAAS56D,IAAT,EAAe;QAGvC,SAAS7V,GAAT,IAAgB6V,IAAhB,EAAsB;UACpB,IAAIxQ,EAAJ;UAAA,IAAQqrE,IAAR;UAAA,IAAcxtE,QAAQlD,IAAIqvE,WAAJrvE,CAAgB,GAAhBA,CAAtB;;UACA,IAAIkD,QAAQ,CAAZ,EAAe;YACbmC,KAAKrF,IAAIiX,SAAJjX,CAAc,CAAdA,EAAiBkD,KAAjBlD,CAALqF;YACAqrE,OAAO1wE,IAAIiX,SAAJjX,CAAckD,QAAQ,CAAtBlD,CAAP0wE;UAFF,OAGO;YACLrrE,KAAKrF,GAALqF;YACAqrE,OAAOpD,SAAPoD;UAPkB;;UASpB,IAAI,CAACtD,UAAU/nE,EAAV,CAAL,EAAoB;YAClB+nE,UAAU/nE,EAAV,IAAgB,EAAhB+nE;UAVkB;;UAYpBA,UAAU/nE,EAAV,EAAcqrE,IAAdtD,IAAsBv3D,KAAK7V,GAAL,CAAtBotE;QAfqC;;QAmBvC,IAAI8B,eAAJ,EAAqB;UACnBA;QApBqC;MAAzC;IAJF,GA2BGC,eA3BH;EA1NsD;;EAyPxD,SAASwB,UAAT,CAAoB9gB,IAApB,EAA0BhxD,QAA1B,EAAoC;IAGlC,IAAIgxD,IAAJ,EAAU;MACRA,OAAOA,KAAKzvD,WAALyvD,EAAPA;IAJgC;;IAOlChxD,WAAWA,YAAY,SAAS+xE,SAAT,GAAqB,CAA5C;;IAEApgE;IACA+8D,YAAY1d,IAAZ0d;IAIA,IAAIsD,YAAYlD,sBAAhB;IACA,IAAImD,YAAYD,UAAU5vE,MAA1B;;IACA,IAAI6vE,cAAc,CAAlB,EAAqB;MAEnB,IAAIC,OAAOnD,mBAAX;;MACA,IAAImD,QAAQA,KAAKC,OAAbD,IAAwBA,KAAKE,cAAjC,EAAiD;QAC/C3zE,QAAQgtB,GAARhtB,CAAY,kDAAZA;QACA8vE,YAAY2D,KAAKC,OAALD,CAAalhB,IAAbkhB,CAAZ3D;;QACA,IAAI,CAACA,SAAL,EAAgB;UACd,IAAI8D,gBAAgBH,KAAKE,cAALF,CAAoB3wE,WAApB2wE,EAApB;;UACA,SAASI,WAAT,IAAwBJ,KAAKC,OAA7B,EAAsC;YACpCG,cAAcA,YAAY/wE,WAAZ+wE,EAAdA;;YACA,IAAIA,gBAAgBthB,IAApB,EAA0B;cACxBud,YAAY2D,KAAKC,OAALD,CAAalhB,IAAbkhB,CAAZ3D;cACA;YAFF,OAGO,IAAI+D,gBAAgBD,aAApB,EAAmC;cACxC9D,YAAY2D,KAAKC,OAALD,CAAaG,aAAbH,CAAZ3D;YANkC;UAFxB;QAH+B;;QAe/CvuE;MAfF,OAgBO;QACLvB,QAAQgtB,GAARhtB,CAAY,oCAAZA;MApBiB;;MAuBnBmwE,cAAc,UAAdA;MACA;IAxCgC;;IA4ClC,IAAI2D,mBAAmB,IAAvB;IACA,IAAIC,iBAAiB,CAArB;;IACAD,mBAAmB,YAAW;MAC5BC;;MACA,IAAIA,kBAAkBP,SAAtB,EAAiC;QAC/BjyE;QACA4uE,cAAc,UAAdA;MAJ0B;IAA9B;;IASA,SAAS6D,gBAAT,CAA0BjiE,IAA1B,EAAgC;MAC9B,IAAIM,OAAON,KAAKM,IAAhB;;MAGA,KAAK2T,IAAL,GAAY,UAASusC,IAAT,EAAehxD,QAAf,EAAyB;QACnCowE,cAAct/D,IAAd,EAAoBkgD,IAApB,EAA0BhxD,QAA1B,EAAoC,YAAW;UAC7CvB,QAAQid,IAARjd,CAAaqS,OAAO,aAApBrS;UAEAA,QAAQid,IAARjd,CAAa,MAAMuyD,IAAN,GAAa,sBAA1BvyD;UACAiwE,YAAY,EAAZA;UAEA1uE;QANF;MADF;IA3DgC;;IAuElC,KAAK,IAAIyE,IAAI,CAAb,EAAgBA,IAAIwtE,SAApB,EAA+BxtE,GAA/B,EAAoC;MAClC,IAAIiuE,WAAW,IAAID,gBAAJ,CAAqBT,UAAUvtE,CAAV,CAArB,CAAf;MACAiuE,SAASjuD,IAATiuD,CAAc1hB,IAAd0hB,EAAoBH,gBAApBG;IAzEgC;EAzPoB;;EAuUxD,SAAS/gE,KAAT,GAAiB;IACf48D,YAAY,EAAZA;IACAC,YAAY,EAAZA;IACAE,YAAY,EAAZA;EA1UsD;;EAgWxD,SAASiE,cAAT,CAAwB3hB,IAAxB,EAA8B;IAC5B,IAAI4hB,gBAAgB;MAClB,MAAM,CADY;MAElB,MAAM,CAFY;MAGlB,MAAM,CAHY;MAIlB,MAAM,CAJY;MAKlB,OAAO,CALW;MAMlB,MAAM,CANY;MAOlB,MAAM,EAPY;MAQlB,OAAO,CARW;MASlB,OAAO,CATW;MAUlB,MAAM,CAVY;MAWlB,MAAM,CAXY;MAYlB,MAAM,CAZY;MAalB,MAAM,CAbY;MAclB,MAAM,CAdY;MAelB,MAAM,EAfY;MAgBlB,OAAO,CAhBW;MAiBlB,MAAM,EAjBY;MAkBlB,MAAM,CAlBY;MAmBlB,OAAO,CAnBW;MAoBlB,OAAO,CApBW;MAqBlB,MAAM,EArBY;MAsBlB,MAAM,EAtBY;MAuBlB,MAAM,CAvBY;MAwBlB,MAAM,CAxBY;MAyBlB,MAAM,CAzBY;MA0BlB,MAAM,CA1BY;MA2BlB,MAAM,CA3BY;MA4BlB,MAAM,CA5BY;MA6BlB,MAAM,CA7BY;MA8BlB,MAAM,CA9BY;MA+BlB,MAAM,CA/BY;MAgClB,MAAM,CAhCY;MAiClB,MAAM,CAjCY;MAkClB,MAAM,CAlCY;MAmClB,MAAM,CAnCY;MAoClB,MAAM,CApCY;MAqClB,OAAO,CArCW;MAsClB,MAAM,CAtCY;MAuClB,MAAM,CAvCY;MAwClB,OAAO,CAxCW;MAyClB,MAAM,CAzCY;MA0ClB,MAAM,CA1CY;MA2ClB,MAAM,EA3CY;MA4ClB,MAAM,CA5CY;MA6ClB,OAAO,CA7CW;MA8ClB,MAAM,CA9CY;MA+ClB,OAAO,CA/CW;MAgDlB,MAAM,EAhDY;MAiDlB,MAAM,CAjDY;MAkDlB,OAAO,CAlDW;MAmDlB,MAAM,CAnDY;MAoDlB,MAAM,CApDY;MAqDlB,MAAM,EArDY;MAsDlB,MAAM,CAtDY;MAuDlB,MAAM,CAvDY;MAwDlB,MAAM,CAxDY;MAyDlB,MAAM,CAzDY;MA0DlB,MAAM,CA1DY;MA2DlB,MAAM,CA3DY;MA4DlB,MAAM,CA5DY;MA6DlB,MAAM,CA7DY;MA8DlB,OAAO,CA9DW;MA+DlB,MAAM,CA/DY;MAgElB,MAAM,CAhEY;MAiElB,OAAO,CAjEW;MAkElB,OAAO,CAlEW;MAmElB,OAAO,CAnEW;MAoElB,OAAO,CApEW;MAqElB,OAAO,CArEW;MAsElB,MAAM,CAtEY;MAuElB,MAAM,CAvEY;MAwElB,MAAM,CAxEY;MAyElB,MAAM,CAzEY;MA0ElB,MAAM,CA1EY;MA2ElB,OAAO,CA3EW;MA4ElB,OAAO,EA5EW;MA6ElB,MAAM,CA7EY;MA8ElB,MAAM,CA9EY;MA+ElB,OAAO,EA/EW;MAgFlB,MAAM,CAhFY;MAiFlB,MAAM,CAjFY;MAkFlB,MAAM,CAlFY;MAmFlB,MAAM,CAnFY;MAoFlB,MAAM,EApFY;MAqFlB,MAAM,CArFY;MAsFlB,OAAO,CAtFW;MAuFlB,MAAM,CAvFY;MAwFlB,MAAM,EAxFY;MAyFlB,MAAM,CAzFY;MA0FlB,MAAM,CA1FY;MA2FlB,MAAM,CA3FY;MA4FlB,MAAM,CA5FY;MA6FlB,MAAM,CA7FY;MA8FlB,MAAM,EA9FY;MA+FlB,MAAM,CA/FY;MAgGlB,OAAO,CAhGW;MAiGlB,OAAO,CAjGW;MAkGlB,MAAM,CAlGY;MAmGlB,MAAM,CAnGY;MAoGlB,MAAM,CApGY;MAqGlB,MAAM,CArGY;MAsGlB,MAAM,CAtGY;MAuGlB,MAAM,CAvGY;MAwGlB,MAAM,CAxGY;MAyGlB,OAAO,CAzGW;MA0GlB,MAAM,CA1GY;MA2GlB,OAAO,CA3GW;MA4GlB,MAAM,CA5GY;MA6GlB,MAAM,CA7GY;MA8GlB,MAAM,CA9GY;MA+GlB,OAAO,CA/GW;MAgHlB,MAAM,EAhHY;MAiHlB,MAAM,CAjHY;MAkHlB,MAAM,CAlHY;MAmHlB,MAAM,CAnHY;MAoHlB,MAAM,CApHY;MAqHlB,OAAO,CArHW;MAsHlB,MAAM,EAtHY;MAuHlB,OAAO,CAvHW;MAwHlB,OAAO,CAxHW;MAyHlB,OAAO,CAzHW;MA0HlB,MAAM,CA1HY;MA2HlB,OAAO,CA3HW;MA4HlB,OAAO,CA5HW;MA6HlB,MAAM,CA7HY;MA8HlB,MAAM,EA9HY;MA+HlB,OAAO,EA/HW;MAgIlB,MAAM,EAhIY;MAiIlB,MAAM,EAjIY;MAkIlB,OAAO,CAlIW;MAmIlB,OAAO,CAnIW;MAoIlB,OAAO,CApIW;MAqIlB,OAAO,CArIW;MAsIlB,OAAO,CAtIW;MAuIlB,MAAM,CAvIY;MAwIlB,MAAM,CAxIY;MAyIlB,MAAM,CAzIY;MA0IlB,MAAM,EA1IY;MA2IlB,MAAM,CA3IY;MA4IlB,OAAO,CA5IW;MA6IlB,MAAM,CA7IY;MA8IlB,MAAM,CA9IY;MA+IlB,MAAM,CA/IY;MAgJlB,OAAO,CAhJW;MAiJlB,MAAM,CAjJY;MAkJlB,MAAM,CAlJY;MAmJlB,OAAO,CAnJW;MAoJlB,MAAM,CApJY;MAqJlB,MAAM,CArJY;MAsJlB,OAAO,CAtJW;MAuJlB,MAAM,CAvJY;MAwJlB,MAAM,CAxJY;MAyJlB,MAAM,CAzJY;MA0JlB,MAAM,CA1JY;MA2JlB,MAAM,CA3JY;MA4JlB,MAAM,CA5JY;MA6JlB,OAAO,EA7JW;MA8JlB,MAAM,EA9JY;MA+JlB,MAAM,CA/JY;MAgKlB,MAAM,CAhKY;MAiKlB,MAAM,CAjKY;MAkKlB,OAAO,CAlKW;MAmKlB,MAAM,CAnKY;MAoKlB,OAAO,CApKW;MAqKlB,MAAM,CArKY;MAsKlB,MAAM,CAtKY;MAuKlB,OAAO,CAvKW;MAwKlB,MAAM,CAxKY;MAyKlB,MAAM,CAzKY;MA0KlB,MAAM;IA1KY,CAApB;;IA8KA,SAASC,IAAT,CAAc1L,CAAd,EAAiB2L,IAAjB,EAAuB;MACrB,OAAOA,KAAKtqC,OAALsqC,CAAa3L,CAAb2L,MAAoB,CAAC,CAA5B;IAhL0B;;IAkL5B,SAASC,SAAT,CAAmB5L,CAAnB,EAAsBllE,KAAtB,EAA6BkyC,GAA7B,EAAkC;MAChC,OAAOlyC,SAASklE,CAATllE,IAAcklE,KAAKhzB,GAA1B;IAnL0B;;IAwL5B,IAAI6+B,cAAc;MAChB,KAAK,UAAS7L,CAAT,EAAY;QACf,OAAO,OAAP;MAFc;MAIhB,KAAK,UAASA,CAAT,EAAY;QACf,IAAK4L,UAAW5L,IAAI,GAAf,EAAqB,CAArB,EAAwB,EAAxB,CAAL,EACE,OAAO,KAAP;QACF,IAAIA,MAAM,CAAV,EACE,OAAO,MAAP;QACF,IAAK4L,UAAW5L,IAAI,GAAf,EAAqB,EAArB,EAAyB,EAAzB,CAAL,EACE,OAAO,MAAP;QACF,IAAIA,KAAK,CAAT,EACE,OAAO,KAAP;QACF,IAAIA,KAAK,CAAT,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MAfc;MAiBhB,KAAK,UAASA,CAAT,EAAY;QACf,IAAIA,MAAM,CAANA,IAAYA,IAAI,EAAJA,KAAY,CAA5B,EACE,OAAO,MAAP;QACF,IAAIA,KAAK,CAAT,EACE,OAAO,KAAP;QACF,IAAIA,KAAK,CAAT,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MAxBc;MA0BhB,KAAK,UAASA,CAAT,EAAY;QACf,IAAIA,KAAK,CAAT,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MA7Bc;MA+BhB,KAAK,UAASA,CAAT,EAAY;QACf,IAAK4L,UAAU5L,CAAV,EAAa,CAAb,EAAgB,CAAhB,CAAL,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MAlCc;MAoChB,KAAK,UAASA,CAAT,EAAY;QACf,IAAK4L,UAAU5L,CAAV,EAAa,CAAb,EAAgB,CAAhB,KAAuBA,KAAK,CAAjC,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MAvCc;MAyChB,KAAK,UAASA,CAAT,EAAY;QACf,IAAIA,MAAM,CAAV,EACE,OAAO,MAAP;QACF,IAAKA,IAAI,EAAJA,IAAW,CAAXA,IAAiBA,IAAI,GAAJA,IAAY,EAAlC,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MA9Cc;MAgDhB,KAAK,UAASA,CAAT,EAAY;QACf,IAAIA,KAAK,CAAT,EACE,OAAO,KAAP;QACF,IAAIA,KAAK,CAAT,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MArDc;MAuDhB,KAAK,UAASA,CAAT,EAAY;QACf,IAAK4L,UAAU5L,CAAV,EAAa,CAAb,EAAgB,CAAhB,CAAL,EACE,OAAO,KAAP;QACF,IAAK4L,UAAU5L,CAAV,EAAa,CAAb,EAAgB,EAAhB,CAAL,EACE,OAAO,MAAP;QACF,IAAIA,KAAK,CAAT,EACE,OAAO,KAAP;QACF,IAAIA,KAAK,CAAT,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MAhEc;MAkEhB,KAAK,UAASA,CAAT,EAAY;QACf,IAAIA,MAAM,CAANA,IAAWA,KAAK,CAALA,IAAW4L,UAAW5L,IAAI,GAAf,EAAqB,CAArB,EAAwB,EAAxB,CAA1B,EACE,OAAO,KAAP;QACF,IAAIA,KAAK,CAAT,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MAvEc;MAyEhB,MAAM,UAASA,CAAT,EAAY;QAChB,IAAK4L,UAAW5L,IAAI,EAAf,EAAoB,CAApB,EAAuB,CAAvB,KAA8B,CAAE4L,UAAW5L,IAAI,GAAf,EAAqB,EAArB,EAAyB,EAAzB,CAArC,EACE,OAAO,KAAP;QACF,IAAKA,IAAI,EAAJA,IAAW,CAAXA,IAAgB,CAAE4L,UAAW5L,IAAI,GAAf,EAAqB,EAArB,EAAyB,EAAzB,CAAvB,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MA9Ec;MAgFhB,MAAM,UAASA,CAAT,EAAY;QAChB,IAAK4L,UAAW5L,IAAI,EAAf,EAAoB,CAApB,EAAuB,CAAvB,KAA8B,CAAE4L,UAAW5L,IAAI,GAAf,EAAqB,EAArB,EAAyB,EAAzB,CAArC,EACE,OAAO,KAAP;QACF,IAAKA,IAAI,EAAJA,KAAY,CAAZA,IACA4L,UAAW5L,IAAI,EAAf,EAAoB,CAApB,EAAuB,CAAvB,CADAA,IAEA4L,UAAW5L,IAAI,GAAf,EAAqB,EAArB,EAAyB,EAAzB,CAFL,EAGE,OAAO,MAAP;QACF,IAAKA,IAAI,EAAJA,IAAW,CAAXA,IAAiBA,IAAI,GAAJA,IAAY,EAAlC,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MAzFc;MA2FhB,MAAM,UAASA,CAAT,EAAY;QAChB,IAAK4L,UAAU5L,CAAV,EAAa,CAAb,EAAgB,CAAhB,CAAL,EACE,OAAO,KAAP;QACF,IAAIA,KAAK,CAAT,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MAhGc;MAkGhB,MAAM,UAASA,CAAT,EAAY;QAChB,IAAK4L,UAAW5L,IAAI,EAAf,EAAoB,CAApB,EAAuB,CAAvB,KAA8B,CAAE4L,UAAW5L,IAAI,GAAf,EAAqB,EAArB,EAAyB,EAAzB,CAArC,EACE,OAAO,KAAP;QACF,IAAIA,KAAK,CAALA,IAAW4L,UAAW5L,IAAI,EAAf,EAAoB,CAApB,EAAuB,CAAvB,CAAXA,IACC4L,UAAW5L,IAAI,EAAf,EAAoB,CAApB,EAAuB,CAAvB,CADDA,IAEC4L,UAAW5L,IAAI,GAAf,EAAqB,EAArB,EAAyB,EAAzB,CAFL,EAGE,OAAO,MAAP;QACF,IAAIA,KAAK,CAAT,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MA3Gc;MA6GhB,MAAM,UAASA,CAAT,EAAY;QAChB,IAAK4L,UAAW5L,IAAI,GAAf,EAAqB,CAArB,EAAwB,CAAxB,CAAL,EACE,OAAO,KAAP;QACF,IAAKA,IAAI,GAAJA,IAAY,CAAjB,EACE,OAAO,KAAP;QACF,IAAKA,IAAI,GAAJA,IAAY,CAAjB,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MApHc;MAsHhB,MAAM,UAASA,CAAT,EAAY;QAChB,IAAIA,MAAM,CAANA,IAAY4L,UAAW5L,IAAI,GAAf,EAAqB,CAArB,EAAwB,EAAxB,CAAhB,EACE,OAAO,KAAP;QACF,IAAK4L,UAAW5L,IAAI,GAAf,EAAqB,EAArB,EAAyB,EAAzB,CAAL,EACE,OAAO,MAAP;QACF,IAAIA,KAAK,CAAT,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MA7Hc;MA+HhB,MAAM,UAASA,CAAT,EAAY;QAChB,IAAKA,IAAI,EAAJA,IAAW,CAAXA,IAAgBA,KAAK,EAA1B,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MAlIc;MAoIhB,MAAM,UAASA,CAAT,EAAY;QAChB,IAAIA,KAAK,CAAT,EACE,OAAO,KAAP;QACF,IAAIA,MAAM,CAAV,EACE,OAAO,MAAP;QACF,IAAIA,KAAK,CAAT,EACE,OAAO,MAAP;QACF,IAAIA,KAAK,CAAT,EACE,OAAO,KAAP;QACF,IAAIA,KAAK,CAAT,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MA/Ic;MAiJhB,MAAM,UAASA,CAAT,EAAY;QAChB,IAAIA,MAAM,CAAV,EACE,OAAO,MAAP;QACF,IAAK4L,UAAU5L,CAAV,EAAa,CAAb,EAAgB,CAAhB,KAAuBA,MAAM,CAA7B4L,IAAkC5L,KAAK,CAA5C,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MAtJc;MAwJhB,MAAM,UAASA,CAAT,EAAY;QAChB,IAAK4L,UAAU5L,CAAV,EAAa,CAAb,EAAgB,EAAhB,CAAL,EACE,OAAO,KAAP;QACF,IAAK4L,UAAU5L,CAAV,EAAa,CAAb,EAAgB,CAAhB,CAAL,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MA7Jc;MA+JhB,MAAM,UAASA,CAAT,EAAY;QAChB,IAAK,WAAWA,IAAI,EAAf,EAAoB,CAApB,EAAuB,CAAvB,KAA+BA,IAAI,EAAJA,IAAW,CAA1C,KAAiD,EAClD4L,UAAW5L,IAAI,GAAf,EAAqB,EAArB,EAAyB,EAAzB,KACA4L,UAAW5L,IAAI,GAAf,EAAqB,EAArB,EAAyB,EAAzB,CADA4L,IAEAA,UAAW5L,IAAI,GAAf,EAAqB,EAArB,EAAyB,EAAzB,CAHkD,CAAtD,EAKE,OAAO,KAAP;QACF,IAAKA,IAAI,OAAJA,KAAiB,CAAjBA,IAAsBA,MAAM,CAAjC,EACE,OAAO,MAAP;QACF,IAAKA,IAAI,EAAJA,IAAW,CAAXA,IAAgB,CAAC0L,KAAM1L,IAAI,GAAV,EAAgB,CAAC,EAAD,EAAK,EAAL,EAAS,EAAT,CAAhB,CAAtB,EACE,OAAO,KAAP;QACF,IAAKA,IAAI,EAAJA,IAAW,CAAXA,IAAgB,CAAC0L,KAAM1L,IAAI,GAAV,EAAgB,CAAC,EAAD,EAAK,EAAL,EAAS,EAAT,CAAhB,CAAtB,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MA5Kc;MA8KhB,MAAM,UAASA,CAAT,EAAY;QAChB,IAAIA,MAAM,CAAV,EACE,OAAO,MAAP;QACF,IAAIA,KAAK,CAAT,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MAnLc;MAqLhB,MAAM,UAASA,CAAT,EAAY;QAChB,IAAK4L,UAAU5L,CAAV,EAAa,CAAb,EAAgB,CAAhB,KAAwB4L,UAAU5L,CAAV,EAAa,EAAb,EAAiB,EAAjB,CAA7B,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MAxLc;MA0LhB,MAAM,UAASA,CAAT,EAAY;QAChB,IAAK4L,UAAW5L,IAAI,EAAf,EAAoB,CAApB,EAAuB,CAAvB,KAA+BA,IAAI,EAAJA,KAAY,CAAhD,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MA7Lc;MA+LhB,MAAM,UAASA,CAAT,EAAY;QAChB,IAAK4L,UAAU5L,CAAV,EAAa,CAAb,EAAgB,EAAhB,KAAuB4L,UAAU5L,CAAV,EAAa,EAAb,EAAiB,EAAjB,CAA5B,EACE,OAAO,KAAP;QACF,IAAI0L,KAAK1L,CAAL,EAAQ,CAAC,CAAD,EAAI,EAAJ,CAAR,CAAJ,EACE,OAAO,KAAP;QACF,IAAI0L,KAAK1L,CAAL,EAAQ,CAAC,CAAD,EAAI,EAAJ,CAAR,CAAJ,EACE,OAAO,KAAP;QACF,OAAO,OAAP;MAtMc;IAAA,CAAlB;IA2MA,IAAI9iE,QAAQuuE,cAAc5hB,KAAKnvD,OAALmvD,CAAa,MAAbA,EAAqB,EAArBA,CAAd,CAAZ;;IACA,IAAI,EAAE3sD,SAAS2uE,WAAX,CAAJ,EAA6B;MAC3Bv0E,QAAQid,IAARjd,CAAa,8BAA8BuyD,IAA9B,GAAqC,GAAlDvyD;MACA,OAAO,YAAW;QAAE,OAAO,OAAP;MAApB;IAtY0B;;IAwY5B,OAAOu0E,YAAY3uE,KAAZ,CAAP;EAxuBsD;;EA4uBxDsqE,QAAQsE,MAARtE,GAAiB,UAAShtE,GAAT,EAAcsU,KAAd,EAAqB9U,GAArB,EAA0B0wE,IAA1B,EAAgC;IAC/C,IAAI1K,IAAIjzD,WAAW+B,KAAX,CAAR;IACA,IAAIpM,MAAMs9D,CAAN,CAAJ,EACE,OAAOxlE,GAAP;IAGF,IAAIkwE,QAAQpD,SAAZ,EACE,OAAO9sE,GAAP;;IAGF,IAAI,CAACgtE,QAAQuE,YAAb,EAA2B;MACzBvE,QAAQuE,YAARvE,GAAuBgE,eAAejE,SAAf,CAAvBC;IAX6C;;IAa/C,IAAItqE,QAAQ,MAAMsqE,QAAQuE,YAARvE,CAAqBxH,CAArBwH,CAAN,GAAgC,GAA5C;;IAGA,IAAIxH,MAAM,CAANA,IAAYhmE,MAAM,QAANA,IAAmBotE,SAAnC,EAA8C;MAC5C5sE,MAAM4sE,UAAUptE,MAAM,QAAhB,EAA0B0wE,IAA1BtD,CAAN5sE;IADF,OAEO,IAAIwlE,KAAK,CAALA,IAAWhmE,MAAM,OAANA,IAAkBotE,SAAjC,EAA4C;MACjD5sE,MAAM4sE,UAAUptE,MAAM,OAAhB,EAAyB0wE,IAAzBtD,CAAN5sE;IADK,OAEA,IAAIwlE,KAAK,CAALA,IAAWhmE,MAAM,OAANA,IAAkBotE,SAAjC,EAA4C;MACjD5sE,MAAM4sE,UAAUptE,MAAM,OAAhB,EAAyB0wE,IAAzBtD,CAAN5sE;IADK,OAEA,IAAKR,MAAMkD,KAANlD,IAAgBotE,SAArB,EAAgC;MACrC5sE,MAAM4sE,UAAUptE,MAAMkD,KAAhB,EAAuBwtE,IAAvBtD,CAAN5sE;IADK,OAEA,IAAKR,MAAM,SAANA,IAAoBotE,SAAzB,EAAoC;MACzC5sE,MAAM4sE,UAAUptE,MAAM,SAAhB,EAA2B0wE,IAA3BtD,CAAN5sE;IAzB6C;;IA4B/C,OAAOA,GAAP;EA5BF;;EAqCA,SAASwxE,WAAT,CAAqBhyE,GAArB,EAA0BqiB,IAA1B,EAAgCgB,QAAhC,EAA0C;IACxC,IAAIxN,OAAOu3D,UAAUptE,GAAV,CAAX;;IACA,IAAI,CAAC6V,IAAL,EAAW;MACTvY,QAAQid,IAARjd,CAAa,MAAM0C,GAAN,GAAY,gBAAzB1C;;MACA,IAAI,CAAC+lB,QAAL,EAAe;QACb,OAAO,IAAP;MAHO;;MAKTxN,OAAOwN,QAAPxN;IAPsC;;IAexC,IAAIo8D,KAAK,EAAT;;IACA,SAASvB,IAAT,IAAiB76D,IAAjB,EAAuB;MACrB,IAAIrV,MAAMqV,KAAK66D,IAAL,CAAV;MACAlwE,MAAM0xE,aAAa1xE,GAAb,EAAkB6hB,IAAlB,EAAwBriB,GAAxB,EAA6B0wE,IAA7B,CAANlwE;MACAA,MAAM2xE,eAAe3xE,GAAf,EAAoB6hB,IAApB,EAA0BriB,GAA1B,CAANQ;MACAyxE,GAAGvB,IAAH,IAAWlwE,GAAXyxE;IApBsC;;IAsBxC,OAAOA,EAAP;EAvyBsD;;EA2yBxD,SAASC,YAAT,CAAsB1xE,GAAtB,EAA2B6hB,IAA3B,EAAiCriB,GAAjC,EAAsC0wE,IAAtC,EAA4C;IAC1C,IAAI0B,UAAU,0CAAd;IACA,IAAIC,UAAUD,QAAQt2D,IAARs2D,CAAa5xE,GAAb4xE,CAAd;IACA,IAAI,CAACC,OAAD,IAAY,CAACA,QAAQpxE,MAAzB,EACE,OAAOT,GAAP;IAIF,IAAI8xE,YAAYD,QAAQ,CAAR,CAAhB;IACA,IAAIE,YAAYF,QAAQ,CAAR,CAAhB;IACA,IAAIv9D,KAAJ;;IACA,IAAIuN,QAAQkwD,aAAalwD,IAAzB,EAA+B;MAC7BvN,QAAQuN,KAAKkwD,SAAL,CAARz9D;IADF,OAEO,IAAIy9D,aAAanF,SAAjB,EAA4B;MACjCt4D,QAAQs4D,UAAUmF,SAAV,CAARz9D;IAdwC;;IAkB1C,IAAIw9D,aAAa9E,OAAjB,EAA0B;MACxB,IAAIgF,QAAQhF,QAAQ8E,SAAR,CAAZ;MACA9xE,MAAMgyE,MAAMhyE,GAAN,EAAWsU,KAAX,EAAkB9U,GAAlB,EAAuB0wE,IAAvB,CAANlwE;IApBwC;;IAsB1C,OAAOA,GAAP;EAj0BsD;;EAq0BxD,SAAS2xE,cAAT,CAAwB3xE,GAAxB,EAA6B6hB,IAA7B,EAAmCriB,GAAnC,EAAwC;IACtC,IAAIyyE,SAAS,sBAAb;IACA,OAAOjyE,IAAIE,OAAJF,CAAYiyE,MAAZjyE,EAAoB,UAASkyE,YAAT,EAAuBC,GAAvB,EAA4B;MACrD,IAAItwD,QAAQswD,OAAOtwD,IAAnB,EAAyB;QACvB,OAAOA,KAAKswD,GAAL,CAAP;MAFmD;;MAIrD,IAAIA,OAAOvF,SAAX,EAAsB;QACpB,OAAOA,UAAUuF,GAAV,CAAP;MALmD;;MAOrDr1E,QAAQgtB,GAARhtB,CAAY,gBAAgBq1E,GAAhB,GAAsB,UAAtB,GAAmC3yE,GAAnC,GAAyC,gBAArD1C;MACA,OAAOo1E,YAAP;IARK,EAAP;EAv0BsD;;EAo1BxD,SAASE,gBAAT,CAA0B31E,OAA1B,EAAmC;IACjC,IAAIwb,OAAOu1D,kBAAkB/wE,OAAlB,CAAX;IACA,IAAI,CAACwb,KAAKpT,EAAV,EACE;IAGF,IAAIwQ,OAAOm8D,YAAYv5D,KAAKpT,EAAjB,EAAqBoT,KAAK4J,IAA1B,CAAX;;IACA,IAAI,CAACxM,IAAL,EAAW;MACTvY,QAAQid,IAARjd,CAAa,MAAMmb,KAAKpT,EAAX,GAAgB,gBAA7B/H;MACA;IAT+B;;IAajC,IAAIuY,KAAKy3D,SAAL,CAAJ,EAAqB;MACnB,IAAIuF,qBAAqB51E,OAArB,MAAkC,CAAtC,EAAyC;QACvCA,QAAQqwE,SAAR,IAAqBz3D,KAAKy3D,SAAL,CAArBrwE;MADF,OAEO;QAGL,IAAI2iE,WAAW3iE,QAAQ0+D,UAAvB;QACA,IAAIjlB,QAAQ,KAAZ;;QACA,KAAK,IAAIpzC,IAAI,CAAR,EAAWwvE,IAAIlT,SAAS3+D,MAA7B,EAAqCqC,IAAIwvE,CAAzC,EAA4CxvE,GAA5C,EAAiD;UAC/C,IAAIs8D,SAASt8D,CAAT,EAAY+hE,QAAZzF,KAAyB,CAAzBA,IAA8B,KAAKr1D,IAAL,CAAUq1D,SAASt8D,CAAT,EAAYyvE,SAAtB,CAAlC,EAAoE;YAClE,IAAIr8B,KAAJ,EAAW;cACTkpB,SAASt8D,CAAT,EAAYyvE,SAAZnT,GAAwB,EAAxBA;YADF,OAEO;cACLA,SAASt8D,CAAT,EAAYyvE,SAAZnT,GAAwB/pD,KAAKy3D,SAAL,CAAxB1N;cACAlpB,QAAQ,IAARA;YALgE;UADrB;QAL5C;;QAiBL,IAAI,CAACA,KAAL,EAAY;UACV,IAAIs8B,WAAWlrE,SAAS09D,cAAT19D,CAAwB+N,KAAKy3D,SAAL,CAAxBxlE,CAAf;UACA7K,QAAQmhC,OAARnhC,CAAgB+1E,QAAhB/1E;QAnBG;MAHY;;MAyBnB,OAAO4Y,KAAKy3D,SAAL,CAAP;IAtC+B;;IAyCjC,SAAS5tC,CAAT,IAAc7pB,IAAd,EAAoB;MAClB5Y,QAAQyiC,CAAR,IAAa7pB,KAAK6pB,CAAL,CAAbziC;IA1C+B;EAp1BqB;;EAm4BxD,SAAS41E,oBAAT,CAA8B51E,OAA9B,EAAuC;IACrC,IAAIA,QAAQ2iE,QAAZ,EAAsB;MACpB,OAAO3iE,QAAQ2iE,QAAR3iE,CAAiBgE,MAAxB;IAFmC;;IAIrC,IAAI,OAAOhE,QAAQg2E,iBAAf,KAAqC,WAAzC,EAAsD;MACpD,OAAOh2E,QAAQg2E,iBAAf;IALmC;;IAOrC,IAAI7oC,QAAQ,CAAZ;;IACA,KAAK,IAAI9mC,IAAI,CAAb,EAAgBA,IAAIrG,QAAQ0+D,UAAR1+D,CAAmBgE,MAAvC,EAA+CqC,GAA/C,EAAoD;MAClD8mC,SAASntC,QAAQooE,QAARpoE,KAAqB,CAArBA,GAAyB,CAAzBA,GAA6B,CAAtCmtC;IATmC;;IAWrC,OAAOA,KAAP;EA94BsD;;EAk5BxD,SAAS8oC,iBAAT,CAA2Bj2E,OAA3B,EAAoC;IAClCA,UAAUA,WAAW6K,SAASC,eAA9B9K;IAGA,IAAI2iE,WAAWmO,wBAAwB9wE,OAAxB,CAAf;IACA,IAAIk2E,eAAevT,SAAS3+D,MAA5B;;IACA,KAAK,IAAIqC,IAAI,CAAb,EAAgBA,IAAI6vE,YAApB,EAAkC7vE,GAAlC,EAAuC;MACrCsvE,iBAAiBhT,SAASt8D,CAAT,CAAjB;IAPgC;;IAWlCsvE,iBAAiB31E,OAAjB;EA75BsD;;EAg6BxD,OAAO;IAELmR,KAAK,UAASpO,GAAT,EAAcqiB,IAAd,EAAoB+wD,cAApB,EAAoC;MACvC,IAAIlwE,QAAQlD,IAAIqvE,WAAJrvE,CAAgB,GAAhBA,CAAZ;MACA,IAAI0wE,OAAOpD,SAAX;;MACA,IAAIpqE,QAAQ,CAAZ,EAAe;QACbwtE,OAAO1wE,IAAIiX,SAAJjX,CAAckD,QAAQ,CAAtBlD,CAAP0wE;QACA1wE,MAAMA,IAAIiX,SAAJjX,CAAc,CAAdA,EAAiBkD,KAAjBlD,CAANA;MALqC;;MAOvC,IAAIqjB,QAAJ;;MACA,IAAI+vD,cAAJ,EAAoB;QAClB/vD,WAAW,EAAXA;QACAA,SAASqtD,IAAT,IAAiB0C,cAAjB/vD;MAVqC;;MAYvC,IAAIxN,OAAOm8D,YAAYhyE,GAAZ,EAAiBqiB,IAAjB,EAAuBgB,QAAvB,CAAX;;MACA,IAAIxN,QAAQ66D,QAAQ76D,IAApB,EAA0B;QACxB,OAAOA,KAAK66D,IAAL,CAAP;MAdqC;;MAgBvC,OAAO,OAAO1wE,GAAP,GAAa,IAApB;IAlBG;IAsBL+jB,SAAS,YAAW;MAAE,OAAOqpD,SAAP;IAtBjB;IAuBLiG,SAAS,YAAW;MAAE,OAAOhG,SAAP;IAvBjB;IA0BLxhC,aAAa,YAAW;MAAE,OAAO0hC,SAAP;IA1BrB;IA2BLJ,aAAa,UAAStd,IAAT,EAAehxD,QAAf,EAAyB;MACpC8xE,WAAW9gB,IAAX,EAAiB,YAAW;QAC1B,IAAIhxD,QAAJ,EACEA;MAFJ;IA5BG;IAmCLqc,cAAc,YAAW;MAGvB,IAAIo4D,UAAU,CAAC,IAAD,EAAO,IAAP,EAAa,IAAb,EAAmB,IAAnB,EAAyB,IAAzB,CAAd;MACA,IAAIC,YAAYhG,UAAU36D,KAAV26D,CAAgB,GAAhBA,EAAqB,CAArBA,EAAwB,CAAxBA,CAAhB;MACA,OAAQ+F,QAAQjsC,OAARisC,CAAgBC,SAAhBD,KAA8B,CAA9BA,GAAmC,KAAnCA,GAA2C,KAAnD;IAxCG;IA4CLh5D,WAAW44D,iBA5CN;IA+CLM,eAAe,YAAW;MAAE,OAAO/F,WAAP;IA/CvB;IAgDLl7C,OAAO,UAAS1zB,QAAT,EAAmB;MACxB,IAAI,CAACA,QAAL,EAAe;QACb;MADF,OAEO,IAAI4uE,eAAe,UAAfA,IAA6BA,eAAe,aAAhD,EAA+D;QACpE9wE,OAAOmpB,UAAPnpB,CAAkB,YAAW;UAC3BkC;QADF;MADK,OAIA,IAAIiJ,SAASnI,gBAAb,EAA+B;QACpCmI,SAASnI,gBAATmI,CAA0B,WAA1BA,EAAuC,SAASmhB,IAAT,GAAgB;UACrDnhB,SAAS2kB,mBAAT3kB,CAA6B,WAA7BA,EAA0CmhB,IAA1CnhB;UACAjJ;QAFF;MARsB;IAhDrB;EAAA,CAAP;AAh6BiB,CAAC,CA+9BhBlC,MA/9BgB,EA+9BRmL,QA/9BQ,CAApBA;;;;;;;;;;;;;;ACtBA;;AAEA,eAAe+U,mBAAf,CAAmCzM,WAAnC,EAAgD;EAC9C,MAAMd,MAAM,EAAZ;EAAA,MACEa,UAAUb,IAAIsD,KAAJtD,CAAU,GAAVA,EAAe,CAAfA,CADZ;EAGA,IAAI;IAAE4a,IAAF;IAAQhR,QAAR;IAAkBiR,0BAAlB;IAA8CC;EAA9C,IACF,MAAMha,YAAYia,WAAZja,EADR;;EAGA,IAAI,CAACga,aAAL,EAAoB;IAClB,MAAM;MAAEnpB;IAAF,IAAa,MAAMmP,YAAY2V,eAAZ3V,EAAzB;IACAga,gBAAgBnpB,MAAhBmpB;EAT4C;;EAY9C,OAAO,EACL,GAAGF,IADE;IAELhB,SAAS/Y,OAFJ;IAGLgZ,UAAUiB,aAHL;IAILtG,UAAUqG,8BAA8BtJ,qCAAsBvR,GAAtBuR,CAJnC;IAKL3H,UAAUA,QAAV,aAAUA,QAAV,uBAAUA,SAAUkQ,MAAVlQ,EALL;IAMLmQ,SAASnQ,QAAT,aAASA,QAAT,uBAASA,SAAU9K,GAAV8K,CAAc,YAAdA,CANJ;IAOLtI,UAAUR,YAAYQ,QAPjB;IAQL0Y,KAAKha;EARA,CAAP;AA7BF;;AAyCA,MAAM48D,gBAAN,CAAuB;EACrBzvE,YAAYwR,gBAAZ,EAA8B;IAC5B,KAAKo0C,MAAL,GAAcxvB,0BACZ5kB,gBADY4kB,EAEgB,IAFhBA,EAGZre,IAHYqe,CAGP,MAAM;MACX,OAAOl2B,OAAO82E,YAAP92E,CAAoB+2E,cAApB/2E,EAAP;IAJY,EAAd;EAFmB;;EAUrB,MAAMgnD,aAAN,CAAoB9tC,IAApB,EAA0B;IACxB,MAAM89D,UAAU,MAAM,KAAKtxB,MAA3B;IACAsxB,QAAQ1pE,MAAR0pE,CAAe99D,IAAf89D;EAZmB;;EAerB,MAAMxwB,sBAAN,CAA6B/xB,KAA7B,EAAoC;IAClC,MAAMuiD,UAAU,MAAM,KAAKtxB,MAA3B;IACAv8B,WAAW,MAAM6tD,QAAQt0C,aAARs0C,CAAsBviD,KAAtBuiD,CAAjB,EAA+C,CAA/C;EAjBmB;;EAoBrB,MAAMnvB,cAAN,GAAuB;IACrB,MAAMmvB,UAAU,MAAM,KAAKtxB,MAA3B;IACAsxB,QAAQC,WAARD;EAtBmB;;AAAA;;;;;;;;;;;;;;;AC1BvB;;AACA;;AACA;;AAEA,IAAIE,gBAAgB,IAApB;AACA,IAAIj2C,SAAS,IAAb;AACA,IAAIvlB,iBAAiB,IAArB;;AAIA,SAASy7D,UAAT,CACEC,oBADF,EAEE3jE,WAFF,EAGEqB,UAHF,EAIEhK,IAJF,EAKE2E,eALF,EAMEoc,4BANF,EAOEwrD,6BAPF,EAQE;EACA,MAAMC,gBAAgBJ,cAAcI,aAApC;EAGA,MAAMC,cAAc9nE,kBAAkB4iD,wBAAcmlB,GAApD;EACAF,cAAclxE,KAAdkxE,GAAsB3yE,KAAKC,KAALD,CAAWmG,KAAK1E,KAAL0E,GAAaysE,WAAxB5yE,CAAtB2yE;EACAA,cAAcjxE,MAAdixE,GAAuB3yE,KAAKC,KAALD,CAAWmG,KAAKzE,MAALyE,GAAcysE,WAAzB5yE,CAAvB2yE;EAEA,MAAMhrB,MAAMgrB,cAAc/qB,UAAd+qB,CAAyB,IAAzBA,CAAZ;EACAhrB,IAAIrnC,IAAJqnC;EACAA,IAAIG,SAAJH,GAAgB,oBAAhBA;EACAA,IAAII,QAAJJ,CAAa,CAAbA,EAAgB,CAAhBA,EAAmBgrB,cAAclxE,KAAjCkmD,EAAwCgrB,cAAcjxE,MAAtDimD;EACAA,IAAIK,OAAJL;EAEA,OAAOthD,QAAQua,GAARva,CAAY,CACjByI,YAAYm8B,OAAZn8B,CAAoBqB,UAApBrB,CADiB,EAEjB4jE,6BAFiB,CAAZrsE,EAGJ6M,IAHI7M,CAGC,gBAA6C;IAAA,IAAnC,CAACqf,OAAD,EAAUotD,sBAAV,CAAmC;IACnD,MAAMhpB,gBAAgB;MACpBC,eAAepC,GADK;MAEpBwB,WAAW,CAACypB,WAAD,EAAc,CAAd,EAAiB,CAAjB,EAAoBA,WAApB,EAAiC,CAAjC,EAAoC,CAApC,CAFS;MAGpBlsB,UAAUhhC,QAAQihC,WAARjhC,CAAoB;QAAE0N,OAAO,CAAT;QAAY3jB,UAAUtJ,KAAKsJ;MAA3B,CAApBiW,CAHU;MAIpB8tC,QAAQ,OAJY;MAKpB3pD,gBAAgBmiD,yBAAe+mB,cALX;MAMpB7rD,4BANoB;MAOpB4rD;IAPoB,CAAtB;IASA,OAAOptD,QAAQqB,MAARrB,CAAeokC,aAAfpkC,EAA8BnH,OAArC;EAbK,EAAP;AA/CF;;AAgEA,SAASy0D,eAAT,CACElkE,WADF,EAEEsd,aAFF,EAGEE,cAHF,EAIExhB,eAJF,EAQE;EAAA,IAHAoc,4BAGA,uEAH+B,IAG/B;EAAA,IAFAwrD,6BAEA,uEAFgC,IAEhC;EAAA,IADAv7D,IACA;EACA,KAAKrI,WAAL,GAAmBA,WAAnB;EACA,KAAKsd,aAAL,GAAqBA,aAArB;EACA,KAAKE,cAAL,GAAsBA,cAAtB;EACA,KAAK2mD,gBAAL,GAAwBnoE,mBAAmB,GAA3C;EACA,KAAKo9C,6BAAL,GACEhhC,gCAAgCpY,YAAYwsC,wBAAZxsC,EADlC;EAEA,KAAKwJ,8BAAL,GACEo6D,iCAAiCrsE,QAAQC,OAARD,EADnC;EAEA,KAAK8Q,IAAL,GAAYA,IAAZ;EACA,KAAKmc,WAAL,GAAmB,CAAC,CAApB;EAEA,KAAKq/C,aAAL,GAAqBnsE,SAAS2zB,aAAT3zB,CAAuB,QAAvBA,CAArB;AApFF;;AAuFAwsE,gBAAgBr1C,SAAhBq1C,GAA4B;EAC1B1qE,SAAS;IACP,KAAK4qE,eAAL;IAEA,MAAM73C,OAAO70B,SAAS2B,aAAT3B,CAAuB,MAAvBA,CAAb;IACA60B,KAAKqF,YAALrF,CAAkB,oBAAlBA,EAAwC,IAAxCA;IAEA,MAAM5U,oBAAoB,KAAK2F,aAAL,CAAmBwgC,KAAnB,CAAyB,UAAUzmD,IAAV,EAAgB;MACjE,OACEA,KAAK1E,KAAL0E,KAAe,KAAKimB,aAAL,CAAmB,CAAnB,EAAsB3qB,KAArC0E,IACAA,KAAKzE,MAALyE,KAAgB,KAAKimB,aAAL,CAAmB,CAAnB,EAAsB1qB,MAFxC;IADwB,GAKvB,IALuB,CAA1B;;IAMA,IAAI,CAAC+kB,iBAAL,EAAwB;MACtBzqB,QAAQid,IAARjd,CACE,mDACE,0BAFJA;IAbK;;IA4BP,KAAKm3E,cAAL,GAAsB3sE,SAAS2zB,aAAT3zB,CAAuB,OAAvBA,CAAtB;IACA,MAAMqkC,WAAW,KAAKze,aAAL,CAAmB,CAAnB,CAAjB;IACA,KAAK+mD,cAAL,CAAoBvvD,WAApB,GACE,mBAAmBinB,SAASppC,KAA5B,GAAoC,KAApC,GAA4CopC,SAASnpC,MAArD,GAA8D,MADhE;IAEA25B,KAAKC,MAALD,CAAY,KAAK83C,cAAjB93C;EAjCwB;;EAoC1B7a,UAAU;IACR,IAAI+xD,kBAAkB,IAAtB,EAA4B;MAG1B;IAJM;;IAMR,KAAKjmD,cAAL,CAAoB1I,WAApB,GAAkC,EAAlC;IAEA,MAAMyX,OAAO70B,SAAS2B,aAAT3B,CAAuB,MAAvBA,CAAb;IACA60B,KAAK2G,eAAL3G,CAAqB,oBAArBA;;IAEA,IAAI,KAAK83C,cAAT,EAAyB;MACvB,KAAKA,cAAL,CAAoB9rE,MAApB;MACA,KAAK8rE,cAAL,GAAsB,IAAtB;IAbM;;IAeR,KAAKR,aAAL,CAAmBlxE,KAAnB,GAA2B,KAAKkxE,aAAL,CAAmBjxE,MAAnB,GAA4B,CAAvD;IACA,KAAKixE,aAAL,GAAqB,IAArB;IACAJ,gBAAgB,IAAhBA;IACAa,gBAAgBlgE,IAAhBkgE,CAAqB,YAAY;MAC/B,IAAIr8D,eAAeif,MAAfjf,KAA0BulB,MAA9B,EAAsC;QACpCvlB,eAAekJ,KAAflJ,CAAqBulB,MAArBvlB;MAF6B;IAAjC;EAtDwB;;EA6D1Bs8D,cAAc;IACZ,IAAI,KAAKvkE,WAAL,CAAiB4a,SAArB,EAAgC;MAC9B4pD,wCAAsB,KAAKhnD,cAA3BgnD,EAA2C,KAAKxkE,WAAhDwkE;MACA,OAAOjtE,QAAQC,OAARD,EAAP;IAHU;;IAMZ,MAAMslC,YAAY,KAAKvf,aAAL,CAAmBzsB,MAArC;;IACA,MAAM4zE,iBAAiB,CAACjtE,OAAD,EAAU6xB,MAAV,KAAqB;MAC1C,KAAK+6C,eAAL;;MACA,IAAI,EAAE,KAAK5/C,WAAP,IAAsBqY,SAA1B,EAAqC;QACnC6nC,eAAe7nC,SAAf,EAA0BA,SAA1B,EAAqC,KAAKx0B,IAA1C;QACA7Q;QACA;MALwC;;MAO1C,MAAM1E,QAAQ,KAAK0xB,WAAnB;MACAkgD,eAAe5xE,KAAf,EAAsB+pC,SAAtB,EAAiC,KAAKx0B,IAAtC;MACAq7D,WACE,IADF,EAEE,KAAK1jE,WAFP,EAGqBlN,QAAQ,CAH7B,EAIE,KAAKwqB,aAAL,CAAmBxqB,KAAnB,CAJF,EAKE,KAAKqxE,gBALP,EAME,KAAK/qB,6BANP,EAOE,KAAK5vC,8BAPP,EASGpF,IATHs/D,CASQ,KAAKiB,eAAL,CAAqBx4D,IAArB,CAA0B,IAA1B,CATRu3D,EAUGt/D,IAVHs/D,CAUQ,YAAY;QAChBe,eAAejtE,OAAf,EAAwB6xB,MAAxB;MAXJ,GAYKA,MAZLq6C;IATF;;IAuBA,OAAO,IAAInsE,OAAJ,CAAYktE,cAAZ,CAAP;EA3FwB;;EA8F1BE,kBAAkB;IAChB,KAAKP,eAAL;IACA,MAAM9oB,MAAM5jD,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAZ;IACA,MAAMmsE,gBAAgB,KAAKA,aAA3B;;IACA,IAAI,YAAYA,aAAhB,EAA+B;MAC7BA,cAAce,MAAdf,CAAqB,UAAUjwD,IAAV,EAAgB;QACnC0nC,IAAIZ,GAAJY,GAAUpiC,IAAI2L,eAAJ3L,CAAoBtF,IAApBsF,CAAVoiC;MADF;IADF,OAIO;MACLA,IAAIZ,GAAJY,GAAUuoB,cAAclpB,SAAdkpB,EAAVvoB;IATc;;IAYhB,MAAMmT,UAAU/2D,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAhB;IACA+2D,QAAQnjC,SAARmjC,GAAoB,aAApBA;IACAA,QAAQjiC,MAARiiC,CAAenT,GAAfmT;IACA,KAAKjxC,cAAL,CAAoBgP,MAApB,CAA2BiiC,OAA3B;IAEA,OAAO,IAAIl3D,OAAJ,CAAY,UAAUC,OAAV,EAAmB6xB,MAAnB,EAA2B;MAC5CiyB,IAAIupB,MAAJvpB,GAAa9jD,OAAb8jD;MACAA,IAAIojB,OAAJpjB,GAAcjyB,MAAdiyB;IAFK,EAAP;EA/GwB;;EAqH1BwpB,eAAe;IACb,KAAKV,eAAL;IACA,OAAO,IAAI7sE,OAAJ,CAAYC,WAAW;MAI5Bke,WAAW,MAAM;QACf,IAAI,CAAC,KAAKwR,MAAV,EAAkB;UAChB1vB;UACA;QAHa;;QAKf2lB,MAAMsa,IAANta,CAAW5wB,MAAX4wB;QAEAzH,WAAWle,OAAX,EAAoB,EAApB;MAPF,GAQG,CARH;IAJK,EAAP;EAvHwB;;EAuI1B,IAAI0vB,MAAJ,GAAa;IACX,OAAO,SAASu8C,aAAhB;EAxIwB;;EA2I1BW,kBAAkB;IAChB,IAAI,CAAC,KAAKl9C,MAAV,EAAkB;MAChB,MAAM,IAAIhvB,KAAJ,CAAU,gDAAV,CAAN;IAFc;EA3IQ;;AAAA,CAA5BgsE;AAkJA,MAAM/mD,QAAQ5wB,OAAO4wB,KAArB;;AACA5wB,OAAO4wB,KAAP5wB,GAAe,YAAY;EACzB,IAAIk3E,aAAJ,EAAmB;IACjBv2E,QAAQid,IAARjd,CAAa,wDAAbA;IACA;EAHuB;;EAKzBo3E,gBAAgBlgE,IAAhBkgE,CAAqB,YAAY;IAC/B,IAAIb,aAAJ,EAAmB;MACjBx7D,eAAe8J,IAAf9J,CAAoBulB,MAApBvlB;IAF6B;EAAjC;;EAMA,IAAI;IACFgnB,cAAc,aAAd;EADF,UAEU;IACR,IAAI,CAACw0C,aAAL,EAAoB;MAClBv2E,QAAQC,KAARD,CAAc,2CAAdA;MACAo3E,gBAAgBlgE,IAAhBkgE,CAAqB,YAAY;QAC/B,IAAIr8D,eAAeif,MAAfjf,KAA0BulB,MAA9B,EAAsC;UACpCvlB,eAAekJ,KAAflJ,CAAqBulB,MAArBvlB;QAF6B;MAAjC;MAKA;IARM;;IAUR,MAAM07D,uBAAuBF,aAA7B;IACAA,cACGc,WADHd,GAEGr/D,IAFHq/D,CAEQ,YAAY;MAChB,OAAOE,qBAAqBmB,YAArBnB,EAAP;IAHJ,GAKGr/D,KALHm/D,CAKS,YAAY,CALrB,GAQGr/D,IARHq/D,CAQQ,YAAY;MAMhB,IAAIE,qBAAqBz8C,MAAzB,EAAiC;QAC/B69C;MAPc;IARpB;EAxBuB;AAA3B;;AA6CA,SAAS91C,aAAT,CAAuB+1C,SAAvB,EAAkC;EAChC,MAAMhkD,QAAQtpB,SAAS+2B,WAAT/2B,CAAqB,aAArBA,CAAd;EACAspB,MAAM0N,eAAN1N,CAAsBgkD,SAAtBhkD,EAAiC,KAAjCA,EAAwC,KAAxCA,EAA+C,QAA/CA;EACAz0B,OAAO0iC,aAAP1iC,CAAqBy0B,KAArBz0B;AA1RF;;AA6RA,SAASw4E,KAAT,GAAiB;EACf,IAAItB,aAAJ,EAAmB;IACjBA,cAAc/xD,OAAd+xD;IACAx0C,cAAc,YAAd;EAHa;AA7RjB;;AAoSA,SAASy1C,cAAT,CAAwB5xE,KAAxB,EAA+BggB,KAA/B,EAAsCzK,IAAtC,EAA4C;EAC1CmlB,oBAAW91B,SAASU,cAATV,CAAwB,oBAAxBA,CAAX;EACA,MAAMqb,WAAW7hB,KAAKe,KAALf,CAAY,MAAM4B,KAAN,GAAeggB,KAA3B5hB,CAAjB;EACA,MAAM+zE,cAAcz3C,OAAOn0B,aAAPm0B,CAAqB,UAArBA,CAApB;EACA,MAAM03C,eAAe13C,OAAOn0B,aAAPm0B,CAAqB,oBAArBA,CAArB;EACAy3C,YAAYp1E,KAAZo1E,GAAoBlyD,QAApBkyD;EACA58D,KAAKrK,GAALqK,CAAS,wBAATA,EAAmC;IAAE0K;EAAF,CAAnC1K,EAAiDjE,IAAjDiE,CAAsDiL,OAAO;IAC3D4xD,aAAapwD,WAAbowD,GAA2B5xD,GAA3B4xD;EADF;AA1SF;;AA+SA34E,OAAOgD,gBAAPhD,CACE,SADFA,EAEE,UAAUy0B,KAAV,EAAiB;EAGf,IACEA,MAAMyG,OAANzG,KAA2B,EAA3BA,KACCA,MAAM1a,OAAN0a,IAAiBA,MAAMza,OADxBya,KAEA,CAACA,MAAMuG,MAFPvG,KAGC,CAACA,MAAMwG,QAAP,IAAmBj7B,OAAO44E,MAA1B,IAAoC54E,OAAO64E,KAH5CpkD,CADF,EAKE;IACAz0B,OAAO4wB,KAAP5wB;IAIAy0B,MAAMprB,cAANorB;;IACA,IAAIA,MAAMqkD,wBAAV,EAAoC;MAClCrkD,MAAMqkD,wBAANrkD;IADF,OAEO;MACLA,MAAM+K,eAAN/K;IATF;EARa;AAFnB,GAuBE,IAvBFz0B;;AA0BA,IAAI,mBAAmBA,MAAvB,EAA+B;EAG7B,MAAM+4E,0BAA0B,UAAUtkD,KAAV,EAAiB;IAC/C,IAAIA,MAAMC,MAAND,KAAiB,QAAjBA,IAA6BA,MAAMqkD,wBAAvC,EAAiE;MAC/DrkD,MAAMqkD,wBAANrkD;IAF6C;EAAjD;;EAKAz0B,OAAOgD,gBAAPhD,CAAwB,aAAxBA,EAAuC+4E,uBAAvC/4E;EACAA,OAAOgD,gBAAPhD,CAAwB,YAAxBA,EAAsC+4E,uBAAtC/4E;AAlVF;;AAqVA,IAAIg5E,cAAJ;;AACA,SAASjB,aAAT,GAAyB;EACvB,IAAI,CAACiB,cAAL,EAAqB;IACnBt9D,iBAAiBvB,0BAAqBuB,cAAtCA;;IACA,IAAI,CAACA,cAAL,EAAqB;MACnB,MAAM,IAAI/P,KAAJ,CAAU,mDAAV,CAAN;IAHiB;;IAKnBs1B,oBAAW91B,SAASU,cAATV,CAAwB,oBAAxBA,CAAX;IAEA6tE,iBAAiBt9D,eAAeslB,QAAftlB,CACfulB,MADevlB,EAEO,IAFPA,CAAjBs9D;IAKA7tE,SAASU,cAATV,CAAwB,aAAxBA,EAAuC+H,OAAvC/H,GAAiDqtE,KAAjDrtE;IACA81B,OAAOj+B,gBAAPi+B,CAAwB,OAAxBA,EAAiCu3C,KAAjCv3C;EAdqB;;EAgBvB,OAAO+3C,cAAP;AAtWF;;AAyWAp1D,4BAAuBC,QAAvBD,GAAkC;EAChCD,kBAAkB,IADc;;EAGhCuN,mBACEzd,WADF,EAEEsd,aAFF,EAGEE,cAHF,EAIExhB,eAJF,EAKEoc,4BALF,EAMEwrD,6BANF,EAOEv7D,IAPF,EAQE;IACA,IAAIo7D,aAAJ,EAAmB;MACjB,MAAM,IAAIvrE,KAAJ,CAAU,0CAAV,CAAN;IAFF;;IAIAurE,gBAAgB,IAAIS,eAAJ,CACdlkE,WADc,EAEdsd,aAFc,EAGdE,cAHc,EAIdxhB,eAJc,EAKdoc,4BALc,EAMdwrD,6BANc,EAOdv7D,IAPc,CAAhBo7D;IASA,OAAOA,aAAP;EAxB8B;;AAAA,CAAlCtzD;;;;;;;;;;;;;AC1VA;;AACA;;AACA;;AAEA,SAASq0D,qBAAT,CAA+BhnD,cAA/B,EAA+Cxd,WAA/C,EAA4D;EAC1D,MAAM22D,UAAU32D,YAAYwlE,UAA5B;EACA,MAAMl5D,cAAc,IAAI3H,mCAAJ,EAApB;EACA,MAAM2f,QAAQpzB,KAAKe,KAALf,CAAW0tD,wBAAcC,gBAAdD,GAAiC,GAA5C1tD,IAAmD,GAAjE;;EAEA,WAAWu0E,OAAX,IAAsB9O,QAAQnH,QAA9B,EAAwC;IACtC,MAAM/uD,OAAO/I,SAAS2zB,aAAT3zB,CAAuB,KAAvBA,CAAb;IACA+I,KAAK6qB,SAAL7qB,GAAiB,gBAAjBA;IACA+c,eAAegP,MAAfhP,CAAsB/c,IAAtB+c;IAEA,MAAMkoD,UAAU,IAAIxiB,kCAAJ,CAAoB;MAClCV,SAAS/hD,IADyB;MAElCmW,SAAS,IAFyB;MAGlCtF,mBAAmBtR,YAAYsR,iBAHG;MAIlChF,WAJkC;MAKlCqqD,SAAS8O;IALyB,CAApB,CAAhB;IAOA,MAAM7tB,WAAW+tB,kCAAmBF,OAAnBE,EAA4B;MAAErhD;IAAF,CAA5BqhD,CAAjB;IAEAD,QAAQztD,MAARytD,CAAe9tB,QAAf8tB,EAAyB,OAAzBA;EAnBwD;AAnB5D;;;;;UCAA;UACA;;UAEA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;UAEA;UACA;;UAEA;UACA;UACA;;;;;;;;;;;;;;;;;;;;;;;;;;ACPA;;AACA;;AACA;;AACA;;;;AAGA,MAAME,eAC8B,UADpC;AAGA,MAAMC,aAC8B,WADpC;AAGA,MAAMC,eAEA;EAAEnnE,UAAF,EAAEA,4BAAF;EAAcvU,eAAd,EAAcA,yBAAd;EAA+BuB,UAA/B,EAA+BA,oBAA/B;EAA2CK,UAA3C,EAA2CA;AAA3C,CAFN;;AAKAO,OAAOma,oBAAPna,GAA8Bma,yBAA9Bna;AACAA,OAAOw5E,6BAAPx5E,GAAuCu5E,YAAvCv5E;AACAA,OAAOy5E,2BAAPz5E,GAAqCwR,uBAArCxR;AAEA;AAoBA;AAIiE;EAC/DqhC,mBAAOA,CAAC,EAAR;AA7DF;AA+DA;AAG2E;EACzEA,mBAAOA,CAAC,EAAR;AAnEF;;AAsEA,SAASq4C,sBAAT,GAAkC;EAChC,IAAI50D,eAAe,IAAnB;EAEEA,eAAe;IACb1Y,WAAWjB,SAASU,cAATV,CAAwB,cAAxBA,CADE;IAEbmd,cAAcnd,SAASU,cAATV,CAAwB,cAAxBA,CAFD;IAGbqd,aAAard,SAASU,cAATV,CAAwB,YAAxBA,CAHA;IAIbsd,eAAetd,SAASU,cAATV,CAAwB,eAAxBA,CAJF;IAKbud,gBAAgBvd,SAASU,cAATV,CAAwB,eAAxBA,CALH;IAMbwd,gBAAgBxd,SAASU,cAATV,CAAwB,eAAxBA;EANH,CAAf2Z;EAUF,OAAO;IACLpH,cAAcvS,SAAS60B,IADlB;IAELjiB,eAAe5S,SAASU,cAATV,CAAwB,iBAAxBA,CAFV;IAGL6S,iBAAiB7S,SAASU,cAATV,CAAwB,QAAxBA,CAHZ;IAILyQ,SAAS;MACPxP,WAAWjB,SAASU,cAATV,CAAwB,eAAxBA,CADJ;MAEP8I,UAAU9I,SAASU,cAATV,CAAwB,UAAxBA,CAFH;MAGP2J,YAAY3J,SAASU,cAATV,CAAwB,YAAxBA,CAHL;MAIP2hE,aAAa3hE,SAASU,cAATV,CAAwB,aAAxBA,CAJN;MAKP4hE,mBAAmB5hE,SAASU,cAATV,CAAwB,mBAAxBA,CALZ;MAMP4tB,UAAU5tB,SAASU,cAATV,CAAwB,UAAxBA,CANH;MAOPulD,MAAMvlD,SAASU,cAATV,CAAwB,MAAxBA,CAPC;MAQPgY,QAAQhY,SAASU,cAATV,CAAwB,QAAxBA,CARD;MASPoY,SAASpY,SAASU,cAATV,CAAwB,SAAxBA,CATF;MAUPmsB,UAAUnsB,SAASU,cAATV,CAAwB,UAAxBA,CAVH;MAWP0hE,UAEM1hE,SAASU,cAATV,CAAwB,UAAxBA,CAbC;MAePylB,OAAOzlB,SAASU,cAATV,CAAwB,OAAxBA,CAfA;MAgBPshE,sBAAsBthE,SAASU,cAATV,CAAwB,gBAAxBA,CAhBf;MAiBPgiE,6BAA6BhiE,SAASU,cAATV,CAC3B,6BAD2BA,CAjBtB;MAoBPwhE,iBAAiBxhE,SAASU,cAATV,CAAwB,WAAxBA,CApBV;MAqBPiiE,wBAAwBjiE,SAASU,cAATV,CAAwB,wBAAxBA,CArBjB;MAsBPksB,wBAAwBlsB,SAASU,cAATV,CAAwB,kBAAxBA,CAtBjB;MAuBP+b,UAAU/b,SAASU,cAATV,CAAwB,UAAxBA,CAvBH;MAwBPoZ,cAAcpZ,SAASU,cAATV,CAAwB,cAAxBA;IAxBP,CAJJ;IA8BL0Q,kBAAkB;MAChBD,SAASzQ,SAASU,cAATV,CAAwB,kBAAxBA,CADO;MAEhBuvB,cAAcvvB,SAASU,cAATV,CAAwB,wBAAxBA,CAFE;MAGhBksB,wBAAwBlsB,SAASU,cAATV,CACtB,2BADsBA,CAHR;MAMhBogE,gBAEMpgE,SAASU,cAATV,CAAwB,mBAAxBA,CARU;MAUhBisB,aAAajsB,SAASU,cAATV,CAAwB,gBAAxBA,CAVG;MAWhBo/D,gBAAgBp/D,SAASU,cAATV,CAAwB,mBAAxBA,CAXA;MAYhBsZ,oBAAoBtZ,SAASU,cAATV,CAAwB,uBAAxBA,CAZJ;MAahBq/D,iBAAiBr/D,SAASU,cAATV,CAAwB,WAAxBA,CAbD;MAchBs/D,gBAAgBt/D,SAASU,cAATV,CAAwB,UAAxBA,CAdA;MAehBu/D,oBAAoBv/D,SAASU,cAATV,CAAwB,cAAxBA,CAfJ;MAgBhBw/D,qBAAqBx/D,SAASU,cAATV,CAAwB,eAAxBA,CAhBL;MAiBhBy/D,wBAAwBz/D,SAASU,cAATV,CAAwB,kBAAxBA,CAjBR;MAkBhB2/D,sBAAsB3/D,SAASU,cAATV,CAAwB,gBAAxBA,CAlBN;MAmBhB4/D,kBAAkB5/D,SAASU,cAATV,CAAwB,YAAxBA,CAnBF;MAoBhB6/D,sBAAsB7/D,SAASU,cAATV,CAAwB,gBAAxBA,CApBN;MAqBhB8/D,wBAAwB9/D,SAASU,cAATV,CAAwB,kBAAxBA,CArBR;MAsBhB+/D,qBAAqB//D,SAASU,cAATV,CAAwB,eAAxBA,CAtBL;MAuBhBggE,kBAAkBhgE,SAASU,cAATV,CAAwB,YAAxBA,CAvBF;MAwBhBigE,iBAAiBjgE,SAASU,cAATV,CAAwB,WAAxBA,CAxBD;MAyBhBkgE,kBAAkBlgE,SAASU,cAATV,CAAwB,YAAxBA,CAzBF;MA0BhBmgE,0BAA0BngE,SAASU,cAATV,CAAwB,oBAAxBA;IA1BV,CA9Bb;IA0DL0V,SAAS;MAEPmnC,gBAAgB78C,SAASU,cAATV,CAAwB,gBAAxBA,CAFT;MAGP88C,kBAAkB98C,SAASU,cAATV,CAAwB,kBAAxBA,CAHX;MAIPuvB,cAAcvvB,SAASU,cAATV,CAAwB,eAAxBA,CAJP;MAMP+8C,iBAAiB/8C,SAASU,cAATV,CAAwB,eAAxBA,CANV;MAOPg9C,eAAeh9C,SAASU,cAATV,CAAwB,aAAxBA,CAPR;MAQPi9C,mBAAmBj9C,SAASU,cAATV,CAAwB,iBAAxBA,CARZ;MASPk9C,cAAcl9C,SAASU,cAATV,CAAwB,YAAxBA,CATP;MAWP2V,eAAe3V,SAASU,cAATV,CAAwB,eAAxBA,CAXR;MAYP8W,aAAa9W,SAASU,cAATV,CAAwB,aAAxBA,CAZN;MAaPgX,iBAAiBhX,SAASU,cAATV,CAAwB,iBAAxBA,CAbV;MAcPkX,YAAYlX,SAASU,cAATV,CAAwB,YAAxBA,CAdL;MAgBPo9C,yBAAyBp9C,SAASU,cAATV,CACvB,yBADuBA,CAhBlB;MAmBPs9C,0BAA0Bt9C,SAASU,cAATV,CAAwB,oBAAxBA;IAnBnB,CA1DJ;IA+ELwX,gBAAgB;MACdqlC,gBAAgB78C,SAASU,cAATV,CAAwB,gBAAxBA,CADF;MAEdu+C,SAASv+C,SAASU,cAATV,CAAwB,gBAAxBA;IAFK,CA/EX;IAmFL8V,SAAS;MACPrV,KAAKT,SAASU,cAATV,CAAwB,SAAxBA,CADE;MAEPuvB,cAAcvvB,SAASU,cAATV,CAAwB,UAAxBA,CAFP;MAGP6mC,WAAW7mC,SAASU,cAATV,CAAwB,WAAxBA,CAHJ;MAIP8mC,sBAAsB9mC,SAASU,cAATV,CAAwB,kBAAxBA,CAJf;MAKP+mC,uBAAuB/mC,SAASU,cAATV,CAAwB,eAAxBA,CALhB;MAMPgnC,yBAAyBhnC,SAASU,cAATV,CAAwB,qBAAxBA,CANlB;MAOPinC,oBAAoBjnC,SAASU,cAATV,CAAwB,gBAAxBA,CAPb;MAQPknC,SAASlnC,SAASU,cAATV,CAAwB,SAAxBA,CARF;MASPmnC,kBAAkBnnC,SAASU,cAATV,CAAwB,kBAAxBA,CATX;MAUPonC,oBAAoBpnC,SAASU,cAATV,CAAwB,cAAxBA,CAVb;MAWPqnC,gBAAgBrnC,SAASU,cAATV,CAAwB,UAAxBA;IAXT,CAnFJ;IAgGL4W,iBAAiB;MACfkf,QAAQ91B,SAASU,cAATV,CAAwB,gBAAxBA,CADO;MAEfikB,OAAOjkB,SAASU,cAATV,CAAwB,cAAxBA,CAFQ;MAGfugC,OAAOvgC,SAASU,cAATV,CAAwB,UAAxBA,CAHQ;MAIfwgC,cAAcxgC,SAASU,cAATV,CAAwB,gBAAxBA,CAJC;MAKfygC,cAAczgC,SAASU,cAATV,CAAwB,gBAAxBA;IALC,CAhGZ;IAuGLmW,oBAAoB;MAClB2f,QAAQ91B,SAASU,cAATV,CAAwB,0BAAxBA,CADU;MAElBqd,aAAard,SAASU,cAATV,CAAwB,yBAAxBA,CAFK;MAGlB0jC,QAAQ;QACNO,UAAUjkC,SAASU,cAATV,CAAwB,eAAxBA,CADJ;QAENkkC,UAAUlkC,SAASU,cAATV,CAAwB,eAAxBA,CAFJ;QAGN8H,OAAO9H,SAASU,cAATV,CAAwB,YAAxBA,CAHD;QAIN4kC,QAAQ5kC,SAASU,cAATV,CAAwB,aAAxBA,CAJF;QAKN8kC,SAAS9kC,SAASU,cAATV,CAAwB,cAAxBA,CALH;QAMNglC,UAAUhlC,SAASU,cAATV,CAAwB,eAAxBA,CANJ;QAONmkC,cAAcnkC,SAASU,cAATV,CAAwB,mBAAxBA,CAPR;QAQNokC,kBAAkBpkC,SAASU,cAATV,CAAwB,uBAAxBA,CARZ;QASNklC,SAASllC,SAASU,cAATV,CAAwB,cAAxBA,CATH;QAUNyjB,UAAUzjB,SAASU,cAATV,CAAwB,eAAxBA,CAVJ;QAWN6c,SAAS7c,SAASU,cAATV,CAAwB,cAAxBA,CAXH;QAYNmlC,WAAWnlC,SAASU,cAATV,CAAwB,gBAAxBA,CAZL;QAaNqkC,UAAUrkC,SAASU,cAATV,CAAwB,eAAxBA,CAbJ;QAcNolC,YAAYplC,SAASU,cAATV,CAAwB,iBAAxBA;MAdN;IAHU,CAvGf;IA2HL4Q,wBAAwB;MACtBmkB,wBAAwB/0B,SAASU,cAATV,CAAwB,wBAAxBA,CADF;MAEtBg1B,qBAAqBh1B,SAASU,cAATV,CAAwB,qBAAxBA,CAFC;MAGtBi1B,gBAAgBj1B,SAASU,cAATV,CAAwB,gBAAxBA,CAHM;MAItBk1B,oBAAoBl1B,SAASU,cAATV,CAAwB,oBAAxBA,CAJE;MAKtBm1B,kBAAkBn1B,SAASU,cAATV,CAAwB,kBAAxBA;IALI,CA3HnB;IAkIL2Z,YAlIK;IAmILmM,gBAAgB9lB,SAASU,cAATV,CAAwB,gBAAxBA,CAnIX;IAoIL4rB,eAEM5rB,SAASU,cAATV,CAAwB,WAAxBA,CAtID;IAwILkrB,oBAAoB;EAxIf,CAAP;AAnFF;;AA+NA,SAASsjD,aAAT,GAAyB;EACvB,MAAM92D,SAAS62D,wBAAf;EAqBI,MAAMjlD,QAAQtpB,SAAS+2B,WAAT/2B,CAAqB,aAArBA,CAAd;EACAspB,MAAM0N,eAAN1N,CAAsB,iBAAtBA,EAAyC,IAAzCA,EAA+C,IAA/CA,EAAqD;IACnD3e,QAAQ9V;EAD2C,CAArDy0B;;EAGA,IAAI;IAIFh0B,OAAO0K,QAAP1K,CAAgBiiC,aAAhBjiC,CAA8Bg0B,KAA9Bh0B;EAJF,EAKE,OAAOiW,EAAP,EAAW;IAGX/V,QAAQC,KAARD,CAAe,oBAAmB+V,EAApB,EAAd/V;IACAwK,SAASu3B,aAATv3B,CAAuBspB,KAAvBtpB;EAnCiB;;EAuCrBgP,0BAAqByI,GAArBzI,CAAyB0I,MAAzB1I;AAtQJ;;AA4QAhP,gDAASqqB,kBAATrqB,gGAA8B,IAA9BA;;AAEA,IACEA,SAAS8mE,UAAT9mE,KAAwB,aAAxBA,IACAA,SAAS8mE,UAAT9mE,KAAwB,UAF1B,EAGE;EACAwuE;AAJF,OAKO;EACLxuE,SAASnI,gBAATmI,CAA0B,kBAA1BA,EAA8CwuE,aAA9CxuE,EAA6D,IAA7DA;AApRF","sources":["webpack://pdf.js/web/ui_utils.js","webpack://pdf.js/web/app_options.js","webpack://pdf.js/web/pdf_link_service.js","webpack://pdf.js/web/app.js","webpack://pdf.js/web/pdfjs.js","webpack://pdf.js/web/event_utils.js","webpack://pdf.js/web/pdf_cursor_tools.js","webpack://pdf.js/web/grab_to_pan.js","webpack://pdf.js/web/annotation_editor_params.js","webpack://pdf.js/web/overlay_manager.js","webpack://pdf.js/node_modules/dialog-polyfill/dist/dialog-polyfill.js","webpack://pdf.js/web/password_prompt.js","webpack://pdf.js/web/pdf_attachment_viewer.js","webpack://pdf.js/web/base_tree_viewer.js","webpack://pdf.js/web/pdf_document_properties.js","webpack://pdf.js/web/pdf_find_bar.js","webpack://pdf.js/web/pdf_find_controller.js","webpack://pdf.js/web/pdf_find_utils.js","webpack://pdf.js/web/pdf_history.js","webpack://pdf.js/web/pdf_layer_viewer.js","webpack://pdf.js/web/pdf_outline_viewer.js","webpack://pdf.js/web/pdf_presentation_mode.js","webpack://pdf.js/web/pdf_rendering_queue.js","webpack://pdf.js/web/pdf_scripting_manager.js","webpack://pdf.js/web/pdf_sidebar.js","webpack://pdf.js/web/pdf_sidebar_resizer.js","webpack://pdf.js/web/pdf_thumbnail_viewer.js","webpack://pdf.js/web/pdf_thumbnail_view.js","webpack://pdf.js/web/pdf_viewer.js","webpack://pdf.js/web/base_viewer.js","webpack://pdf.js/web/annotation_editor_layer_builder.js","webpack://pdf.js/web/l10n_utils.js","webpack://pdf.js/web/annotation_layer_builder.js","webpack://pdf.js/web/pdf_page_view.js","webpack://pdf.js/web/text_accessibility.js","webpack://pdf.js/web/struct_tree_layer_builder.js","webpack://pdf.js/web/text_highlighter.js","webpack://pdf.js/web/text_layer_builder.js","webpack://pdf.js/web/xfa_layer_builder.js","webpack://pdf.js/web/secondary_toolbar.js","webpack://pdf.js/web/toolbar.js","webpack://pdf.js/web/view_history.js","webpack://pdf.js/web/genericcom.js","webpack://pdf.js/web/preferences.js","webpack://pdf.js/web/download_manager.js","webpack://pdf.js/web/genericl10n.js","webpack://pdf.js/external/webL10n/l10n.js","webpack://pdf.js/web/generic_scripting.js","webpack://pdf.js/web/pdf_print_service.js","webpack://pdf.js/web/print_utils.js","webpack://pdf.js/webpack/bootstrap","webpack://pdf.js/web/viewer.js"],"sourcesContent":["/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nconst DEFAULT_SCALE_VALUE = \"auto\";\nconst DEFAULT_SCALE = 1.0;\nconst DEFAULT_SCALE_DELTA = 1.1;\nconst MIN_SCALE = 0.1;\nconst MAX_SCALE = 10.0;\nconst UNKNOWN_SCALE = 0;\nconst MAX_AUTO_SCALE = 1.25;\nconst SCROLLBAR_PADDING = 40;\nconst VERTICAL_PADDING = 5;\n\nconst RenderingStates = {\n INITIAL: 0,\n RUNNING: 1,\n PAUSED: 2,\n FINISHED: 3,\n};\n\nconst PresentationModeState = {\n UNKNOWN: 0,\n NORMAL: 1,\n CHANGING: 2,\n FULLSCREEN: 3,\n};\n\nconst SidebarView = {\n UNKNOWN: -1,\n NONE: 0,\n THUMBS: 1, // Default value.\n OUTLINE: 2,\n ATTACHMENTS: 3,\n LAYERS: 4,\n};\n\nconst RendererType =\n typeof PDFJSDev === \"undefined\" || PDFJSDev.test(\"!PRODUCTION || GENERIC\")\n ? {\n CANVAS: \"canvas\",\n SVG: \"svg\",\n }\n : null;\n\nconst TextLayerMode = {\n DISABLE: 0,\n ENABLE: 1,\n ENABLE_ENHANCE: 2,\n};\n\nconst ScrollMode = {\n UNKNOWN: -1,\n VERTICAL: 0, // Default value.\n HORIZONTAL: 1,\n WRAPPED: 2,\n PAGE: 3,\n};\n\nconst SpreadMode = {\n UNKNOWN: -1,\n NONE: 0, // Default value.\n ODD: 1,\n EVEN: 2,\n};\n\n// Used by `PDFViewerApplication`, and by the API unit-tests.\nconst AutoPrintRegExp = /\\bprint\\s*\\(/;\n\n/**\n * Scale factors for the canvas, necessary with HiDPI displays.\n */\nclass OutputScale {\n constructor() {\n const pixelRatio = window.devicePixelRatio || 1;\n\n /**\n * @type {number} Horizontal scale.\n */\n this.sx = pixelRatio;\n\n /**\n * @type {number} Vertical scale.\n */\n this.sy = pixelRatio;\n }\n\n /**\n * @type {boolean} Returns `true` when scaling is required, `false` otherwise.\n */\n get scaled() {\n return this.sx !== 1 || this.sy !== 1;\n }\n}\n\n/**\n * Scrolls specified element into view of its parent.\n * @param {Object} element - The element to be visible.\n * @param {Object} spot - An object with optional top and left properties,\n * specifying the offset from the top left edge.\n * @param {boolean} [scrollMatches] - When scrolling search results into view,\n * ignore elements that either: Contains marked content identifiers,\n * or have the CSS-rule `overflow: hidden;` set. The default value is `false`.\n */\nfunction scrollIntoView(element, spot, scrollMatches = false) {\n // Assuming offsetParent is available (it's not available when viewer is in\n // hidden iframe or object). We have to scroll: if the offsetParent is not set\n // producing the error. See also animationStarted.\n let parent = element.offsetParent;\n if (!parent) {\n console.error(\"offsetParent is not set -- cannot scroll\");\n return;\n }\n let offsetY = element.offsetTop + element.clientTop;\n let offsetX = element.offsetLeft + element.clientLeft;\n while (\n (parent.clientHeight === parent.scrollHeight &&\n parent.clientWidth === parent.scrollWidth) ||\n (scrollMatches &&\n (parent.classList.contains(\"markedContent\") ||\n getComputedStyle(parent).overflow === \"hidden\"))\n ) {\n offsetY += parent.offsetTop;\n offsetX += parent.offsetLeft;\n\n parent = parent.offsetParent;\n if (!parent) {\n return; // no need to scroll\n }\n }\n if (spot) {\n if (spot.top !== undefined) {\n offsetY += spot.top;\n }\n if (spot.left !== undefined) {\n offsetX += spot.left;\n parent.scrollLeft = offsetX;\n }\n }\n parent.scrollTop = offsetY;\n}\n\n/**\n * Helper function to start monitoring the scroll event and converting them into\n * PDF.js friendly one: with scroll debounce and scroll direction.\n */\nfunction watchScroll(viewAreaElement, callback) {\n const debounceScroll = function (evt) {\n if (rAF) {\n return;\n }\n // schedule an invocation of scroll for next animation frame.\n rAF = window.requestAnimationFrame(function viewAreaElementScrolled() {\n rAF = null;\n\n const currentX = viewAreaElement.scrollLeft;\n const lastX = state.lastX;\n if (currentX !== lastX) {\n state.right = currentX > lastX;\n }\n state.lastX = currentX;\n const currentY = viewAreaElement.scrollTop;\n const lastY = state.lastY;\n if (currentY !== lastY) {\n state.down = currentY > lastY;\n }\n state.lastY = currentY;\n callback(state);\n });\n };\n\n const state = {\n right: true,\n down: true,\n lastX: viewAreaElement.scrollLeft,\n lastY: viewAreaElement.scrollTop,\n _eventHandler: debounceScroll,\n };\n\n let rAF = null;\n viewAreaElement.addEventListener(\"scroll\", debounceScroll, true);\n return state;\n}\n\n/**\n * Helper function to parse query string (e.g. ?param1=value¶m2=...).\n * @param {string}\n * @returns {Map}\n */\nfunction parseQueryString(query) {\n const params = new Map();\n for (const [key, value] of new URLSearchParams(query)) {\n params.set(key.toLowerCase(), value);\n }\n return params;\n}\n\nconst NullCharactersRegExp = /\\x00/g;\nconst InvisibleCharactersRegExp = /[\\x01-\\x1F]/g;\n\n/**\n * @param {string} str\n * @param {boolean} [replaceInvisible]\n */\nfunction removeNullCharacters(str, replaceInvisible = false) {\n if (typeof str !== \"string\") {\n console.error(`The argument must be a string.`);\n return str;\n }\n if (replaceInvisible) {\n str = str.replace(InvisibleCharactersRegExp, \" \");\n }\n return str.replace(NullCharactersRegExp, \"\");\n}\n\n/**\n * Use binary search to find the index of the first item in a given array which\n * passes a given condition. The items are expected to be sorted in the sense\n * that if the condition is true for one item in the array, then it is also true\n * for all following items.\n *\n * @returns {number} Index of the first array element to pass the test,\n * or |items.length| if no such element exists.\n */\nfunction binarySearchFirstItem(items, condition, start = 0) {\n let minIndex = start;\n let maxIndex = items.length - 1;\n\n if (maxIndex < 0 || !condition(items[maxIndex])) {\n return items.length;\n }\n if (condition(items[minIndex])) {\n return minIndex;\n }\n\n while (minIndex < maxIndex) {\n const currentIndex = (minIndex + maxIndex) >> 1;\n const currentItem = items[currentIndex];\n if (condition(currentItem)) {\n maxIndex = currentIndex;\n } else {\n minIndex = currentIndex + 1;\n }\n }\n return minIndex; /* === maxIndex */\n}\n\n/**\n * Approximates float number as a fraction using Farey sequence (max order\n * of 8).\n * @param {number} x - Positive float number.\n * @returns {Array} Estimated fraction: the first array item is a numerator,\n * the second one is a denominator.\n */\nfunction approximateFraction(x) {\n // Fast paths for int numbers or their inversions.\n if (Math.floor(x) === x) {\n return [x, 1];\n }\n const xinv = 1 / x;\n const limit = 8;\n if (xinv > limit) {\n return [1, limit];\n } else if (Math.floor(xinv) === xinv) {\n return [1, xinv];\n }\n\n const x_ = x > 1 ? xinv : x;\n // a/b and c/d are neighbours in Farey sequence.\n let a = 0,\n b = 1,\n c = 1,\n d = 1;\n // Limiting search to order 8.\n while (true) {\n // Generating next term in sequence (order of q).\n const p = a + c,\n q = b + d;\n if (q > limit) {\n break;\n }\n if (x_ <= p / q) {\n c = p;\n d = q;\n } else {\n a = p;\n b = q;\n }\n }\n let result;\n // Select closest of the neighbours to x.\n if (x_ - a / b < c / d - x_) {\n result = x_ === x ? [a, b] : [b, a];\n } else {\n result = x_ === x ? [c, d] : [d, c];\n }\n return result;\n}\n\nfunction roundToDivide(x, div) {\n const r = x % div;\n return r === 0 ? x : Math.round(x - r + div);\n}\n\n/**\n * @typedef {Object} GetPageSizeInchesParameters\n * @property {number[]} view\n * @property {number} userUnit\n * @property {number} rotate\n */\n\n/**\n * @typedef {Object} PageSize\n * @property {number} width - In inches.\n * @property {number} height - In inches.\n */\n\n/**\n * Gets the size of the specified page, converted from PDF units to inches.\n * @param {GetPageSizeInchesParameters} params\n * @returns {PageSize}\n */\nfunction getPageSizeInches({ view, userUnit, rotate }) {\n const [x1, y1, x2, y2] = view;\n // We need to take the page rotation into account as well.\n const changeOrientation = rotate % 180 !== 0;\n\n const width = ((x2 - x1) / 72) * userUnit;\n const height = ((y2 - y1) / 72) * userUnit;\n\n return {\n width: changeOrientation ? height : width,\n height: changeOrientation ? width : height,\n };\n}\n\n/**\n * Helper function for getVisibleElements.\n *\n * @param {number} index - initial guess at the first visible element\n * @param {Array} views - array of pages, into which `index` is an index\n * @param {number} top - the top of the scroll pane\n * @returns {number} less than or equal to `index` that is definitely at or\n * before the first visible element in `views`, but not by too much. (Usually,\n * this will be the first element in the first partially visible row in\n * `views`, although sometimes it goes back one row further.)\n */\nfunction backtrackBeforeAllVisibleElements(index, views, top) {\n // binarySearchFirstItem's assumption is that the input is ordered, with only\n // one index where the conditions flips from false to true: [false ...,\n // true...]. With vertical scrolling and spreads, it is possible to have\n // [false ..., true, false, true ...]. With wrapped scrolling we can have a\n // similar sequence, with many more mixed true and false in the middle.\n //\n // So there is no guarantee that the binary search yields the index of the\n // first visible element. It could have been any of the other visible elements\n // that were preceded by a hidden element.\n\n // Of course, if either this element or the previous (hidden) element is also\n // the first element, there's nothing to worry about.\n if (index < 2) {\n return index;\n }\n\n // That aside, the possible cases are represented below.\n //\n // **** = fully hidden\n // A*B* = mix of partially visible and/or hidden pages\n // CDEF = fully visible\n //\n // (1) Binary search could have returned A, in which case we can stop.\n // (2) Binary search could also have returned B, in which case we need to\n // check the whole row.\n // (3) Binary search could also have returned C, in which case we need to\n // check the whole previous row.\n //\n // There's one other possibility:\n //\n // **** = fully hidden\n // ABCD = mix of fully and/or partially visible pages\n //\n // (4) Binary search could only have returned A.\n\n // Initially assume that we need to find the beginning of the current row\n // (case 1, 2, or 4), which means finding a page that is above the current\n // page's top. If the found page is partially visible, we're definitely not in\n // case 3, and this assumption is correct.\n let elt = views[index].div;\n let pageTop = elt.offsetTop + elt.clientTop;\n\n if (pageTop >= top) {\n // The found page is fully visible, so we're actually either in case 3 or 4,\n // and unfortunately we can't tell the difference between them without\n // scanning the entire previous row, so we just conservatively assume that\n // we do need to backtrack to that row. In both cases, the previous page is\n // in the previous row, so use its top instead.\n elt = views[index - 1].div;\n pageTop = elt.offsetTop + elt.clientTop;\n }\n\n // Now we backtrack to the first page that still has its bottom below\n // `pageTop`, which is the top of a page in the first visible row (unless\n // we're in case 4, in which case it's the row before that).\n // `index` is found by binary search, so the page at `index - 1` is\n // invisible and we can start looking for potentially visible pages from\n // `index - 2`. (However, if this loop terminates on its first iteration,\n // which is the case when pages are stacked vertically, `index` should remain\n // unchanged, so we use a distinct loop variable.)\n for (let i = index - 2; i >= 0; --i) {\n elt = views[i].div;\n if (elt.offsetTop + elt.clientTop + elt.clientHeight <= pageTop) {\n // We have reached the previous row, so stop now.\n // This loop is expected to terminate relatively quickly because the\n // number of pages per row is expected to be small.\n break;\n }\n index = i;\n }\n return index;\n}\n\n/**\n * @typedef {Object} GetVisibleElementsParameters\n * @property {HTMLElement} scrollEl - A container that can possibly scroll.\n * @property {Array} views - Objects with a `div` property that contains an\n * HTMLElement, which should all be descendants of `scrollEl` satisfying the\n * relevant layout assumptions.\n * @property {boolean} sortByVisibility - If `true`, the returned elements are\n * sorted in descending order of the percent of their padding box that is\n * visible. The default value is `false`.\n * @property {boolean} horizontal - If `true`, the elements are assumed to be\n * laid out horizontally instead of vertically. The default value is `false`.\n * @property {boolean} rtl - If `true`, the `scrollEl` container is assumed to\n * be in right-to-left mode. The default value is `false`.\n */\n\n/**\n * Generic helper to find out what elements are visible within a scroll pane.\n *\n * Well, pretty generic. There are some assumptions placed on the elements\n * referenced by `views`:\n * - If `horizontal`, no left of any earlier element is to the right of the\n * left of any later element.\n * - Otherwise, `views` can be split into contiguous rows where, within a row,\n * no top of any element is below the bottom of any other element, and\n * between rows, no bottom of any element in an earlier row is below the\n * top of any element in a later row.\n *\n * (Here, top, left, etc. all refer to the padding edge of the element in\n * question. For pages, that ends up being equivalent to the bounding box of the\n * rendering canvas. Earlier and later refer to index in `views`, not page\n * layout.)\n *\n * @param {GetVisibleElementsParameters}\n * @returns {Object} `{ first, last, views: [{ id, x, y, view, percent }] }`\n */\nfunction getVisibleElements({\n scrollEl,\n views,\n sortByVisibility = false,\n horizontal = false,\n rtl = false,\n}) {\n const top = scrollEl.scrollTop,\n bottom = top + scrollEl.clientHeight;\n const left = scrollEl.scrollLeft,\n right = left + scrollEl.clientWidth;\n\n // Throughout this \"generic\" function, comments will assume we're working with\n // PDF document pages, which is the most important and complex case. In this\n // case, the visible elements we're actually interested is the page canvas,\n // which is contained in a wrapper which adds no padding/border/margin, which\n // is itself contained in `view.div` which adds no padding (but does add a\n // border). So, as specified in this function's doc comment, this function\n // does all of its work on the padding edge of the provided views, starting at\n // offsetLeft/Top (which includes margin) and adding clientLeft/Top (which is\n // the border). Adding clientWidth/Height gets us the bottom-right corner of\n // the padding edge.\n function isElementBottomAfterViewTop(view) {\n const element = view.div;\n const elementBottom =\n element.offsetTop + element.clientTop + element.clientHeight;\n return elementBottom > top;\n }\n function isElementNextAfterViewHorizontally(view) {\n const element = view.div;\n const elementLeft = element.offsetLeft + element.clientLeft;\n const elementRight = elementLeft + element.clientWidth;\n return rtl ? elementLeft < right : elementRight > left;\n }\n\n const visible = [],\n ids = new Set(),\n numViews = views.length;\n let firstVisibleElementInd = binarySearchFirstItem(\n views,\n horizontal\n ? isElementNextAfterViewHorizontally\n : isElementBottomAfterViewTop\n );\n\n // Please note the return value of the `binarySearchFirstItem` function when\n // no valid element is found (hence the `firstVisibleElementInd` check below).\n if (\n firstVisibleElementInd > 0 &&\n firstVisibleElementInd < numViews &&\n !horizontal\n ) {\n // In wrapped scrolling (or vertical scrolling with spreads), with some page\n // sizes, isElementBottomAfterViewTop doesn't satisfy the binary search\n // condition: there can be pages with bottoms above the view top between\n // pages with bottoms below. This function detects and corrects that error;\n // see it for more comments.\n firstVisibleElementInd = backtrackBeforeAllVisibleElements(\n firstVisibleElementInd,\n views,\n top\n );\n }\n\n // lastEdge acts as a cutoff for us to stop looping, because we know all\n // subsequent pages will be hidden.\n //\n // When using wrapped scrolling or vertical scrolling with spreads, we can't\n // simply stop the first time we reach a page below the bottom of the view;\n // the tops of subsequent pages on the same row could still be visible. In\n // horizontal scrolling, we don't have that issue, so we can stop as soon as\n // we pass `right`, without needing the code below that handles the -1 case.\n let lastEdge = horizontal ? right : -1;\n\n for (let i = firstVisibleElementInd; i < numViews; i++) {\n const view = views[i],\n element = view.div;\n const currentWidth = element.offsetLeft + element.clientLeft;\n const currentHeight = element.offsetTop + element.clientTop;\n const viewWidth = element.clientWidth,\n viewHeight = element.clientHeight;\n const viewRight = currentWidth + viewWidth;\n const viewBottom = currentHeight + viewHeight;\n\n if (lastEdge === -1) {\n // As commented above, this is only needed in non-horizontal cases.\n // Setting lastEdge to the bottom of the first page that is partially\n // visible ensures that the next page fully below lastEdge is on the\n // next row, which has to be fully hidden along with all subsequent rows.\n if (viewBottom >= bottom) {\n lastEdge = viewBottom;\n }\n } else if ((horizontal ? currentWidth : currentHeight) > lastEdge) {\n break;\n }\n\n if (\n viewBottom <= top ||\n currentHeight >= bottom ||\n viewRight <= left ||\n currentWidth >= right\n ) {\n continue;\n }\n\n const hiddenHeight =\n Math.max(0, top - currentHeight) + Math.max(0, viewBottom - bottom);\n const hiddenWidth =\n Math.max(0, left - currentWidth) + Math.max(0, viewRight - right);\n\n const fractionHeight = (viewHeight - hiddenHeight) / viewHeight,\n fractionWidth = (viewWidth - hiddenWidth) / viewWidth;\n const percent = (fractionHeight * fractionWidth * 100) | 0;\n\n visible.push({\n id: view.id,\n x: currentWidth,\n y: currentHeight,\n view,\n percent,\n widthPercent: (fractionWidth * 100) | 0,\n });\n ids.add(view.id);\n }\n\n const first = visible[0],\n last = visible.at(-1);\n\n if (sortByVisibility) {\n visible.sort(function (a, b) {\n const pc = a.percent - b.percent;\n if (Math.abs(pc) > 0.001) {\n return -pc;\n }\n return a.id - b.id; // ensure stability\n });\n }\n return { first, last, views: visible, ids };\n}\n\n/**\n * Event handler to suppress context menu.\n */\nfunction noContextMenuHandler(evt) {\n evt.preventDefault();\n}\n\nfunction normalizeWheelEventDirection(evt) {\n let delta = Math.hypot(evt.deltaX, evt.deltaY);\n const angle = Math.atan2(evt.deltaY, evt.deltaX);\n if (-0.25 * Math.PI < angle && angle < 0.75 * Math.PI) {\n // All that is left-up oriented has to change the sign.\n delta = -delta;\n }\n return delta;\n}\n\nfunction normalizeWheelEventDelta(evt) {\n let delta = normalizeWheelEventDirection(evt);\n\n const MOUSE_DOM_DELTA_PIXEL_MODE = 0;\n const MOUSE_DOM_DELTA_LINE_MODE = 1;\n const MOUSE_PIXELS_PER_LINE = 30;\n const MOUSE_LINES_PER_PAGE = 30;\n\n // Converts delta to per-page units\n if (evt.deltaMode === MOUSE_DOM_DELTA_PIXEL_MODE) {\n delta /= MOUSE_PIXELS_PER_LINE * MOUSE_LINES_PER_PAGE;\n } else if (evt.deltaMode === MOUSE_DOM_DELTA_LINE_MODE) {\n delta /= MOUSE_LINES_PER_PAGE;\n }\n return delta;\n}\n\nfunction isValidRotation(angle) {\n return Number.isInteger(angle) && angle % 90 === 0;\n}\n\nfunction isValidScrollMode(mode) {\n return (\n Number.isInteger(mode) &&\n Object.values(ScrollMode).includes(mode) &&\n mode !== ScrollMode.UNKNOWN\n );\n}\n\nfunction isValidSpreadMode(mode) {\n return (\n Number.isInteger(mode) &&\n Object.values(SpreadMode).includes(mode) &&\n mode !== SpreadMode.UNKNOWN\n );\n}\n\nfunction isPortraitOrientation(size) {\n return size.width <= size.height;\n}\n\n/**\n * Promise that is resolved when DOM window becomes visible.\n */\nconst animationStarted = new Promise(function (resolve) {\n if (\n typeof PDFJSDev !== \"undefined\" &&\n PDFJSDev.test(\"LIB\") &&\n typeof window === \"undefined\"\n ) {\n // Prevent \"ReferenceError: window is not defined\" errors when running the\n // unit-tests in Node.js environments.\n setTimeout(resolve, 20);\n return;\n }\n window.requestAnimationFrame(resolve);\n});\n\nconst docStyle =\n typeof PDFJSDev !== \"undefined\" &&\n PDFJSDev.test(\"LIB\") &&\n typeof document === \"undefined\"\n ? null\n : document.documentElement.style;\n\nfunction clamp(v, min, max) {\n return Math.min(Math.max(v, min), max);\n}\n\nclass ProgressBar {\n #classList = null;\n\n #percent = 0;\n\n #visible = true;\n\n constructor(id) {\n if (\n (typeof PDFJSDev === \"undefined\" || PDFJSDev.test(\"GENERIC\")) &&\n arguments.length > 1\n ) {\n throw new Error(\n \"ProgressBar no longer accepts any additional options, \" +\n \"please use CSS rules to modify its appearance instead.\"\n );\n }\n const bar = document.getElementById(id);\n this.#classList = bar.classList;\n }\n\n get percent() {\n return this.#percent;\n }\n\n set percent(val) {\n this.#percent = clamp(val, 0, 100);\n\n if (isNaN(val)) {\n this.#classList.add(\"indeterminate\");\n return;\n }\n this.#classList.remove(\"indeterminate\");\n\n docStyle.setProperty(\"--progressBar-percent\", `${this.#percent}%`);\n }\n\n setWidth(viewer) {\n if (!viewer) {\n return;\n }\n const container = viewer.parentNode;\n const scrollbarWidth = container.offsetWidth - viewer.offsetWidth;\n if (scrollbarWidth > 0) {\n docStyle.setProperty(\"--progressBar-end-offset\", `${scrollbarWidth}px`);\n }\n }\n\n hide() {\n if (!this.#visible) {\n return;\n }\n this.#visible = false;\n this.#classList.add(\"hidden\");\n }\n\n show() {\n if (this.#visible) {\n return;\n }\n this.#visible = true;\n this.#classList.remove(\"hidden\");\n }\n}\n\n/**\n * Get the active or focused element in current DOM.\n *\n * Recursively search for the truly active or focused element in case there are\n * shadow DOMs.\n *\n * @returns {Element} the truly active or focused element.\n */\nfunction getActiveOrFocusedElement() {\n let curRoot = document;\n let curActiveOrFocused =\n curRoot.activeElement || curRoot.querySelector(\":focus\");\n\n while (curActiveOrFocused?.shadowRoot) {\n curRoot = curActiveOrFocused.shadowRoot;\n curActiveOrFocused =\n curRoot.activeElement || curRoot.querySelector(\":focus\");\n }\n\n return curActiveOrFocused;\n}\n\n/**\n * Converts API PageLayout values to the format used by `BaseViewer`.\n * NOTE: This is supported to the extent that the viewer implements the\n * necessary Scroll/Spread modes (since SinglePage, TwoPageLeft,\n * and TwoPageRight all suggests using non-continuous scrolling).\n * @param {string} mode - The API PageLayout value.\n * @returns {Object}\n */\nfunction apiPageLayoutToViewerModes(layout) {\n let scrollMode = ScrollMode.VERTICAL,\n spreadMode = SpreadMode.NONE;\n\n switch (layout) {\n case \"SinglePage\":\n scrollMode = ScrollMode.PAGE;\n break;\n case \"OneColumn\":\n break;\n case \"TwoPageLeft\":\n scrollMode = ScrollMode.PAGE;\n /* falls through */\n case \"TwoColumnLeft\":\n spreadMode = SpreadMode.ODD;\n break;\n case \"TwoPageRight\":\n scrollMode = ScrollMode.PAGE;\n /* falls through */\n case \"TwoColumnRight\":\n spreadMode = SpreadMode.EVEN;\n break;\n }\n return { scrollMode, spreadMode };\n}\n\n/**\n * Converts API PageMode values to the format used by `PDFSidebar`.\n * NOTE: There's also a \"FullScreen\" parameter which is not possible to support,\n * since the Fullscreen API used in browsers requires that entering\n * fullscreen mode only occurs as a result of a user-initiated event.\n * @param {string} mode - The API PageMode value.\n * @returns {number} A value from {SidebarView}.\n */\nfunction apiPageModeToSidebarView(mode) {\n switch (mode) {\n case \"UseNone\":\n return SidebarView.NONE;\n case \"UseThumbs\":\n return SidebarView.THUMBS;\n case \"UseOutlines\":\n return SidebarView.OUTLINE;\n case \"UseAttachments\":\n return SidebarView.ATTACHMENTS;\n case \"UseOC\":\n return SidebarView.LAYERS;\n }\n return SidebarView.NONE; // Default value.\n}\n\nexport {\n animationStarted,\n apiPageLayoutToViewerModes,\n apiPageModeToSidebarView,\n approximateFraction,\n AutoPrintRegExp,\n backtrackBeforeAllVisibleElements, // only exported for testing\n binarySearchFirstItem,\n DEFAULT_SCALE,\n DEFAULT_SCALE_DELTA,\n DEFAULT_SCALE_VALUE,\n docStyle,\n getActiveOrFocusedElement,\n getPageSizeInches,\n getVisibleElements,\n isPortraitOrientation,\n isValidRotation,\n isValidScrollMode,\n isValidSpreadMode,\n MAX_AUTO_SCALE,\n MAX_SCALE,\n MIN_SCALE,\n noContextMenuHandler,\n normalizeWheelEventDelta,\n normalizeWheelEventDirection,\n OutputScale,\n parseQueryString,\n PresentationModeState,\n ProgressBar,\n removeNullCharacters,\n RendererType,\n RenderingStates,\n roundToDivide,\n SCROLLBAR_PADDING,\n scrollIntoView,\n ScrollMode,\n SidebarView,\n SpreadMode,\n TextLayerMode,\n UNKNOWN_SCALE,\n VERTICAL_PADDING,\n watchScroll,\n};\n","/* Copyright 2018 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nconst compatibilityParams = Object.create(null);\nif (typeof PDFJSDev === \"undefined\" || PDFJSDev.test(\"GENERIC\")) {\n if (\n typeof PDFJSDev !== \"undefined\" &&\n PDFJSDev.test(\"LIB\") &&\n typeof navigator === \"undefined\"\n ) {\n globalThis.navigator = Object.create(null);\n }\n const userAgent = navigator.userAgent || \"\";\n const platform = navigator.platform || \"\";\n const maxTouchPoints = navigator.maxTouchPoints || 1;\n\n const isAndroid = /Android/.test(userAgent);\n const isIOS =\n /\\b(iPad|iPhone|iPod)(?=;)/.test(userAgent) ||\n (platform === \"MacIntel\" && maxTouchPoints > 1);\n\n // Limit canvas size to 5 mega-pixels on mobile.\n // Support: Android, iOS\n (function checkCanvasSizeLimitation() {\n if (isIOS || isAndroid) {\n compatibilityParams.maxCanvasPixels = 5242880;\n }\n })();\n}\n\nconst OptionKind = {\n VIEWER: 0x02,\n API: 0x04,\n WORKER: 0x08,\n PREFERENCE: 0x80,\n};\n\n/**\n * NOTE: These options are used to generate the `default_preferences.json` file,\n * see `OptionKind.PREFERENCE`, hence the values below must use only\n * primitive types and cannot rely on any imported types.\n */\nconst defaultOptions = {\n annotationEditorMode: {\n /** @type {boolean} */\n value:\n typeof PDFJSDev === \"undefined\" || PDFJSDev.test(\"!PRODUCTION || TESTING\")\n ? 0\n : -1,\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n },\n annotationMode: {\n /** @type {number} */\n value: 2,\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n },\n cursorToolOnLoad: {\n /** @type {number} */\n value: 0,\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n },\n defaultZoomValue: {\n /** @type {string} */\n value: \"\",\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n },\n disableHistory: {\n /** @type {boolean} */\n value: false,\n kind: OptionKind.VIEWER,\n },\n disablePageLabels: {\n /** @type {boolean} */\n value: false,\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n },\n enablePermissions: {\n /** @type {boolean} */\n value: false,\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n },\n enablePrintAutoRotate: {\n /** @type {boolean} */\n value: true,\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n },\n enableScripting: {\n /** @type {boolean} */\n value: typeof PDFJSDev === \"undefined\" || !PDFJSDev.test(\"CHROME\"),\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n },\n externalLinkRel: {\n /** @type {string} */\n value: \"noopener noreferrer nofollow\",\n kind: OptionKind.VIEWER,\n },\n externalLinkTarget: {\n /** @type {number} */\n value: 0,\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n },\n historyUpdateUrl: {\n /** @type {boolean} */\n value: false,\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n },\n ignoreDestinationZoom: {\n /** @type {boolean} */\n value: false,\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n },\n imageResourcesPath: {\n /** @type {string} */\n value: \"./images/\",\n kind: OptionKind.VIEWER,\n },\n maxCanvasPixels: {\n /** @type {number} */\n value: 16777216,\n kind: OptionKind.VIEWER,\n },\n forcePageColors: {\n /** @type {boolean} */\n value: false,\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n },\n pageColorsBackground: {\n /** @type {string} */\n value: \"Canvas\",\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n },\n pageColorsForeground: {\n /** @type {string} */\n value: \"CanvasText\",\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n },\n pdfBugEnabled: {\n /** @type {boolean} */\n value: typeof PDFJSDev === \"undefined\" || !PDFJSDev.test(\"PRODUCTION\"),\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n },\n printResolution: {\n /** @type {number} */\n value: 150,\n kind: OptionKind.VIEWER,\n },\n sidebarViewOnLoad: {\n /** @type {number} */\n value: -1,\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n },\n scrollModeOnLoad: {\n /** @type {number} */\n value: -1,\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n },\n spreadModeOnLoad: {\n /** @type {number} */\n value: -1,\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n },\n textLayerMode: {\n /** @type {number} */\n value: 1,\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n },\n useOnlyCssZoom: {\n /** @type {boolean} */\n value: false,\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n },\n viewerCssTheme: {\n /** @type {number} */\n value: typeof PDFJSDev !== \"undefined\" && PDFJSDev.test(\"CHROME\") ? 2 : 0,\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n },\n viewOnLoad: {\n /** @type {boolean} */\n value: 0,\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n },\n\n cMapPacked: {\n /** @type {boolean} */\n value: true,\n kind: OptionKind.API,\n },\n cMapUrl: {\n /** @type {string} */\n value:\n typeof PDFJSDev === \"undefined\" || !PDFJSDev.test(\"PRODUCTION\")\n ? \"../external/bcmaps/\"\n : \"../web/cmaps/\",\n kind: OptionKind.API,\n },\n disableAutoFetch: {\n /** @type {boolean} */\n value: false,\n kind: OptionKind.API + OptionKind.PREFERENCE,\n },\n disableFontFace: {\n /** @type {boolean} */\n value: false,\n kind: OptionKind.API + OptionKind.PREFERENCE,\n },\n disableRange: {\n /** @type {boolean} */\n value: false,\n kind: OptionKind.API + OptionKind.PREFERENCE,\n },\n disableStream: {\n /** @type {boolean} */\n value: false,\n kind: OptionKind.API + OptionKind.PREFERENCE,\n },\n docBaseUrl: {\n /** @type {string} */\n value: \"\",\n kind: OptionKind.API,\n },\n enableXfa: {\n /** @type {boolean} */\n value: true,\n kind: OptionKind.API + OptionKind.PREFERENCE,\n },\n fontExtraProperties: {\n /** @type {boolean} */\n value: false,\n kind: OptionKind.API,\n },\n isEvalSupported: {\n /** @type {boolean} */\n value: true,\n kind: OptionKind.API,\n },\n maxImageSize: {\n /** @type {number} */\n value: -1,\n kind: OptionKind.API,\n },\n pdfBug: {\n /** @type {boolean} */\n value: false,\n kind: OptionKind.API,\n },\n standardFontDataUrl: {\n /** @type {string} */\n value:\n typeof PDFJSDev === \"undefined\" || !PDFJSDev.test(\"PRODUCTION\")\n ? \"../external/standard_fonts/\"\n : \"../web/standard_fonts/\",\n kind: OptionKind.API,\n },\n verbosity: {\n /** @type {number} */\n value: 1,\n kind: OptionKind.API,\n },\n\n workerPort: {\n /** @type {Object} */\n value: null,\n kind: OptionKind.WORKER,\n },\n workerSrc: {\n /** @type {string} */\n value:\n typeof PDFJSDev === \"undefined\" || !PDFJSDev.test(\"PRODUCTION\")\n ? \"../src/worker_loader.js\"\n : \"../build/pdf.worker.js\",\n kind: OptionKind.WORKER,\n },\n};\nif (\n typeof PDFJSDev === \"undefined\" ||\n PDFJSDev.test(\"!PRODUCTION || GENERIC\")\n) {\n defaultOptions.defaultUrl = {\n /** @type {string} */\n value: \"compressed.tracemonkey-pldi-09.pdf\",\n kind: OptionKind.VIEWER,\n };\n defaultOptions.disablePreferences = {\n /** @type {boolean} */\n value: typeof PDFJSDev !== \"undefined\" && PDFJSDev.test(\"TESTING\"),\n kind: OptionKind.VIEWER,\n };\n defaultOptions.locale = {\n /** @type {string} */\n value: navigator.language || \"en-US\",\n kind: OptionKind.VIEWER,\n };\n defaultOptions.renderer = {\n /** @type {string} */\n value: \"canvas\",\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n };\n defaultOptions.sandboxBundleSrc = {\n /** @type {string} */\n value:\n typeof PDFJSDev === \"undefined\" || !PDFJSDev.test(\"PRODUCTION\")\n ? \"../build/dev-sandbox/pdf.sandbox.js\"\n : \"../build/pdf.sandbox.js\",\n kind: OptionKind.VIEWER,\n };\n} else if (PDFJSDev.test(\"CHROME\")) {\n defaultOptions.defaultUrl = {\n /** @type {string} */\n value: \"\",\n kind: OptionKind.VIEWER,\n };\n defaultOptions.disableTelemetry = {\n /** @type {boolean} */\n value: false,\n kind: OptionKind.VIEWER + OptionKind.PREFERENCE,\n };\n defaultOptions.sandboxBundleSrc = {\n /** @type {string} */\n value: \"../build/pdf.sandbox.js\",\n kind: OptionKind.VIEWER,\n };\n}\n\nconst userOptions = Object.create(null);\n\nclass AppOptions {\n constructor() {\n throw new Error(\"Cannot initialize AppOptions.\");\n }\n\n static get(name) {\n const userOption = userOptions[name];\n if (userOption !== undefined) {\n return userOption;\n }\n const defaultOption = defaultOptions[name];\n if (defaultOption !== undefined) {\n return compatibilityParams[name] ?? defaultOption.value;\n }\n return undefined;\n }\n\n static getAll(kind = null) {\n const options = Object.create(null);\n for (const name in defaultOptions) {\n const defaultOption = defaultOptions[name];\n if (kind) {\n if ((kind & defaultOption.kind) === 0) {\n continue;\n }\n if (kind === OptionKind.PREFERENCE) {\n const value = defaultOption.value,\n valueType = typeof value;\n\n if (\n valueType === \"boolean\" ||\n valueType === \"string\" ||\n (valueType === \"number\" && Number.isInteger(value))\n ) {\n options[name] = value;\n continue;\n }\n throw new Error(`Invalid type for preference: ${name}`);\n }\n }\n const userOption = userOptions[name];\n options[name] =\n userOption !== undefined\n ? userOption\n : compatibilityParams[name] ?? defaultOption.value;\n }\n return options;\n }\n\n static set(name, value) {\n userOptions[name] = value;\n }\n\n static setAll(options) {\n for (const name in options) {\n userOptions[name] = options[name];\n }\n }\n\n static remove(name) {\n delete userOptions[name];\n }\n\n /**\n * @ignore\n */\n static _hasUserOptions() {\n return Object.keys(userOptions).length > 0;\n }\n}\n\nexport { AppOptions, compatibilityParams, OptionKind };\n","/* Copyright 2015 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/** @typedef {import(\"./event_utils\").EventBus} EventBus */\n/** @typedef {import(\"./interfaces\").IPDFLinkService} IPDFLinkService */\n\nimport { parseQueryString, removeNullCharacters } from \"./ui_utils.js\";\n\nconst DEFAULT_LINK_REL = \"noopener noreferrer nofollow\";\n\nconst LinkTarget = {\n NONE: 0, // Default value.\n SELF: 1,\n BLANK: 2,\n PARENT: 3,\n TOP: 4,\n};\n\n/**\n * @typedef {Object} ExternalLinkParameters\n * @property {string} url - An absolute URL.\n * @property {LinkTarget} [target] - The link target. The default value is\n * `LinkTarget.NONE`.\n * @property {string} [rel] - The link relationship. The default value is\n * `DEFAULT_LINK_REL`.\n * @property {boolean} [enabled] - Whether the link should be enabled. The\n * default value is true.\n */\n\n/**\n * Adds various attributes (href, title, target, rel) to hyperlinks.\n * @param {HTMLAnchorElement} link - The link element.\n * @param {ExternalLinkParameters} params\n */\nfunction addLinkAttributes(link, { url, target, rel, enabled = true } = {}) {\n if (!url || typeof url !== \"string\") {\n throw new Error('A valid \"url\" parameter must provided.');\n }\n\n const urlNullRemoved = removeNullCharacters(url);\n if (enabled) {\n link.href = link.title = urlNullRemoved;\n } else {\n link.href = \"\";\n link.title = `Disabled: ${urlNullRemoved}`;\n link.onclick = () => {\n return false;\n };\n }\n\n let targetStr = \"\"; // LinkTarget.NONE\n switch (target) {\n case LinkTarget.NONE:\n break;\n case LinkTarget.SELF:\n targetStr = \"_self\";\n break;\n case LinkTarget.BLANK:\n targetStr = \"_blank\";\n break;\n case LinkTarget.PARENT:\n targetStr = \"_parent\";\n break;\n case LinkTarget.TOP:\n targetStr = \"_top\";\n break;\n }\n link.target = targetStr;\n\n link.rel = typeof rel === \"string\" ? rel : DEFAULT_LINK_REL;\n}\n\n/**\n * @typedef {Object} PDFLinkServiceOptions\n * @property {EventBus} eventBus - The application event bus.\n * @property {number} [externalLinkTarget] - Specifies the `target` attribute\n * for external links. Must use one of the values from {LinkTarget}.\n * Defaults to using no target.\n * @property {string} [externalLinkRel] - Specifies the `rel` attribute for\n * external links. Defaults to stripping the referrer.\n * @property {boolean} [ignoreDestinationZoom] - Ignores the zoom argument,\n * thus preserving the current zoom level in the viewer, when navigating\n * to internal destinations. The default value is `false`.\n */\n\n/**\n * Performs navigation functions inside PDF, such as opening specified page,\n * or destination.\n * @implements {IPDFLinkService}\n */\nclass PDFLinkService {\n #pagesRefCache = new Map();\n\n /**\n * @param {PDFLinkServiceOptions} options\n */\n constructor({\n eventBus,\n externalLinkTarget = null,\n externalLinkRel = null,\n ignoreDestinationZoom = false,\n } = {}) {\n this.eventBus = eventBus;\n this.externalLinkTarget = externalLinkTarget;\n this.externalLinkRel = externalLinkRel;\n this.externalLinkEnabled = true;\n this._ignoreDestinationZoom = ignoreDestinationZoom;\n\n this.baseUrl = null;\n this.pdfDocument = null;\n this.pdfViewer = null;\n this.pdfHistory = null;\n }\n\n setDocument(pdfDocument, baseUrl = null) {\n this.baseUrl = baseUrl;\n this.pdfDocument = pdfDocument;\n this.#pagesRefCache.clear();\n }\n\n setViewer(pdfViewer) {\n this.pdfViewer = pdfViewer;\n }\n\n setHistory(pdfHistory) {\n this.pdfHistory = pdfHistory;\n }\n\n /**\n * @type {number}\n */\n get pagesCount() {\n return this.pdfDocument ? this.pdfDocument.numPages : 0;\n }\n\n /**\n * @type {number}\n */\n get page() {\n return this.pdfViewer.currentPageNumber;\n }\n\n /**\n * @param {number} value\n */\n set page(value) {\n this.pdfViewer.currentPageNumber = value;\n }\n\n /**\n * @type {number}\n */\n get rotation() {\n return this.pdfViewer.pagesRotation;\n }\n\n /**\n * @param {number} value\n */\n set rotation(value) {\n this.pdfViewer.pagesRotation = value;\n }\n\n #goToDestinationHelper(rawDest, namedDest = null, explicitDest) {\n // Dest array looks like that: \n const destRef = explicitDest[0];\n let pageNumber;\n\n if (typeof destRef === \"object\" && destRef !== null) {\n pageNumber = this._cachedPageNumber(destRef);\n\n if (!pageNumber) {\n // Fetch the page reference if it's not yet available. This could\n // only occur during loading, before all pages have been resolved.\n this.pdfDocument\n .getPageIndex(destRef)\n .then(pageIndex => {\n this.cachePageRef(pageIndex + 1, destRef);\n this.#goToDestinationHelper(rawDest, namedDest, explicitDest);\n })\n .catch(() => {\n console.error(\n `PDFLinkService.#goToDestinationHelper: \"${destRef}\" is not ` +\n `a valid page reference, for dest=\"${rawDest}\".`\n );\n });\n return;\n }\n } else if (Number.isInteger(destRef)) {\n pageNumber = destRef + 1;\n } else {\n console.error(\n `PDFLinkService.#goToDestinationHelper: \"${destRef}\" is not ` +\n `a valid destination reference, for dest=\"${rawDest}\".`\n );\n return;\n }\n if (!pageNumber || pageNumber < 1 || pageNumber > this.pagesCount) {\n console.error(\n `PDFLinkService.#goToDestinationHelper: \"${pageNumber}\" is not ` +\n `a valid page number, for dest=\"${rawDest}\".`\n );\n return;\n }\n\n if (this.pdfHistory) {\n // Update the browser history before scrolling the new destination into\n // view, to be able to accurately capture the current document position.\n this.pdfHistory.pushCurrentPosition();\n this.pdfHistory.push({ namedDest, explicitDest, pageNumber });\n }\n\n this.pdfViewer.scrollPageIntoView({\n pageNumber,\n destArray: explicitDest,\n ignoreDestinationZoom: this._ignoreDestinationZoom,\n });\n }\n\n /**\n * This method will, when available, also update the browser history.\n *\n * @param {string|Array} dest - The named, or explicit, PDF destination.\n */\n async goToDestination(dest) {\n if (!this.pdfDocument) {\n return;\n }\n let namedDest, explicitDest;\n if (typeof dest === \"string\") {\n namedDest = dest;\n explicitDest = await this.pdfDocument.getDestination(dest);\n } else {\n namedDest = null;\n explicitDest = await dest;\n }\n if (!Array.isArray(explicitDest)) {\n console.error(\n `PDFLinkService.goToDestination: \"${explicitDest}\" is not ` +\n `a valid destination array, for dest=\"${dest}\".`\n );\n return;\n }\n this.#goToDestinationHelper(dest, namedDest, explicitDest);\n }\n\n /**\n * This method will, when available, also update the browser history.\n *\n * @param {number|string} val - The page number, or page label.\n */\n goToPage(val) {\n if (!this.pdfDocument) {\n return;\n }\n const pageNumber =\n (typeof val === \"string\" && this.pdfViewer.pageLabelToPageNumber(val)) ||\n val | 0;\n if (\n !(\n Number.isInteger(pageNumber) &&\n pageNumber > 0 &&\n pageNumber <= this.pagesCount\n )\n ) {\n console.error(`PDFLinkService.goToPage: \"${val}\" is not a valid page.`);\n return;\n }\n\n if (this.pdfHistory) {\n // Update the browser history before scrolling the new page into view,\n // to be able to accurately capture the current document position.\n this.pdfHistory.pushCurrentPosition();\n this.pdfHistory.pushPage(pageNumber);\n }\n\n this.pdfViewer.scrollPageIntoView({ pageNumber });\n }\n\n /**\n * Wrapper around the `addLinkAttributes` helper function.\n * @param {HTMLAnchorElement} link\n * @param {string} url\n * @param {boolean} [newWindow]\n */\n addLinkAttributes(link, url, newWindow = false) {\n addLinkAttributes(link, {\n url,\n target: newWindow ? LinkTarget.BLANK : this.externalLinkTarget,\n rel: this.externalLinkRel,\n enabled: this.externalLinkEnabled,\n });\n }\n\n /**\n * @param {string|Array} dest - The PDF destination object.\n * @returns {string} The hyperlink to the PDF object.\n */\n getDestinationHash(dest) {\n if (typeof dest === \"string\") {\n if (dest.length > 0) {\n return this.getAnchorUrl(\"#\" + escape(dest));\n }\n } else if (Array.isArray(dest)) {\n const str = JSON.stringify(dest);\n if (str.length > 0) {\n return this.getAnchorUrl(\"#\" + escape(str));\n }\n }\n return this.getAnchorUrl(\"\");\n }\n\n /**\n * Prefix the full url on anchor links to make sure that links are resolved\n * relative to the current URL instead of the one defined in .\n * @param {string} anchor - The anchor hash, including the #.\n * @returns {string} The hyperlink to the PDF object.\n */\n getAnchorUrl(anchor) {\n return (this.baseUrl || \"\") + anchor;\n }\n\n /**\n * @param {string} hash\n */\n setHash(hash) {\n if (!this.pdfDocument) {\n return;\n }\n let pageNumber, dest;\n if (hash.includes(\"=\")) {\n const params = parseQueryString(hash);\n if (params.has(\"search\")) {\n this.eventBus.dispatch(\"findfromurlhash\", {\n source: this,\n query: params.get(\"search\").replace(/\"/g, \"\"),\n phraseSearch: params.get(\"phrase\") === \"true\",\n });\n }\n // borrowing syntax from \"Parameters for Opening PDF Files\"\n if (params.has(\"page\")) {\n pageNumber = params.get(\"page\") | 0 || 1;\n }\n if (params.has(\"zoom\")) {\n // Build the destination array.\n const zoomArgs = params.get(\"zoom\").split(\",\"); // scale,left,top\n const zoomArg = zoomArgs[0];\n const zoomArgNumber = parseFloat(zoomArg);\n\n if (!zoomArg.includes(\"Fit\")) {\n // If the zoomArg is a number, it has to get divided by 100. If it's\n // a string, it should stay as it is.\n dest = [\n null,\n { name: \"XYZ\" },\n zoomArgs.length > 1 ? zoomArgs[1] | 0 : null,\n zoomArgs.length > 2 ? zoomArgs[2] | 0 : null,\n zoomArgNumber ? zoomArgNumber / 100 : zoomArg,\n ];\n } else {\n if (zoomArg === \"Fit\" || zoomArg === \"FitB\") {\n dest = [null, { name: zoomArg }];\n } else if (\n zoomArg === \"FitH\" ||\n zoomArg === \"FitBH\" ||\n zoomArg === \"FitV\" ||\n zoomArg === \"FitBV\"\n ) {\n dest = [\n null,\n { name: zoomArg },\n zoomArgs.length > 1 ? zoomArgs[1] | 0 : null,\n ];\n } else if (zoomArg === \"FitR\") {\n if (zoomArgs.length !== 5) {\n console.error(\n 'PDFLinkService.setHash: Not enough parameters for \"FitR\".'\n );\n } else {\n dest = [\n null,\n { name: zoomArg },\n zoomArgs[1] | 0,\n zoomArgs[2] | 0,\n zoomArgs[3] | 0,\n zoomArgs[4] | 0,\n ];\n }\n } else {\n console.error(\n `PDFLinkService.setHash: \"${zoomArg}\" is not a valid zoom value.`\n );\n }\n }\n }\n if (dest) {\n this.pdfViewer.scrollPageIntoView({\n pageNumber: pageNumber || this.page,\n destArray: dest,\n allowNegativeOffset: true,\n });\n } else if (pageNumber) {\n this.page = pageNumber; // simple page\n }\n if (params.has(\"pagemode\")) {\n this.eventBus.dispatch(\"pagemode\", {\n source: this,\n mode: params.get(\"pagemode\"),\n });\n }\n // Ensure that this parameter is *always* handled last, in order to\n // guarantee that it won't be overridden (e.g. by the \"page\" parameter).\n if (params.has(\"nameddest\")) {\n this.goToDestination(params.get(\"nameddest\"));\n }\n } else {\n // Named (or explicit) destination.\n dest = unescape(hash);\n try {\n dest = JSON.parse(dest);\n\n if (!Array.isArray(dest)) {\n // Avoid incorrectly rejecting a valid named destination, such as\n // e.g. \"4.3\" or \"true\", because `JSON.parse` converted its type.\n dest = dest.toString();\n }\n } catch (ex) {}\n\n if (\n typeof dest === \"string\" ||\n PDFLinkService.#isValidExplicitDestination(dest)\n ) {\n this.goToDestination(dest);\n return;\n }\n console.error(\n `PDFLinkService.setHash: \"${unescape(\n hash\n )}\" is not a valid destination.`\n );\n }\n }\n\n /**\n * @param {string} action\n */\n executeNamedAction(action) {\n // See PDF reference, table 8.45 - Named action\n switch (action) {\n case \"GoBack\":\n this.pdfHistory?.back();\n break;\n\n case \"GoForward\":\n this.pdfHistory?.forward();\n break;\n\n case \"NextPage\":\n this.pdfViewer.nextPage();\n break;\n\n case \"PrevPage\":\n this.pdfViewer.previousPage();\n break;\n\n case \"LastPage\":\n this.page = this.pagesCount;\n break;\n\n case \"FirstPage\":\n this.page = 1;\n break;\n\n default:\n break; // No action according to spec\n }\n\n this.eventBus.dispatch(\"namedaction\", {\n source: this,\n action,\n });\n }\n\n /**\n * @param {number} pageNum - page number.\n * @param {Object} pageRef - reference to the page.\n */\n cachePageRef(pageNum, pageRef) {\n if (!pageRef) {\n return;\n }\n const refStr =\n pageRef.gen === 0 ? `${pageRef.num}R` : `${pageRef.num}R${pageRef.gen}`;\n this.#pagesRefCache.set(refStr, pageNum);\n }\n\n /**\n * @ignore\n */\n _cachedPageNumber(pageRef) {\n if (!pageRef) {\n return null;\n }\n const refStr =\n pageRef.gen === 0 ? `${pageRef.num}R` : `${pageRef.num}R${pageRef.gen}`;\n return this.#pagesRefCache.get(refStr) || null;\n }\n\n /**\n * @param {number} pageNumber\n */\n isPageVisible(pageNumber) {\n return this.pdfViewer.isPageVisible(pageNumber);\n }\n\n /**\n * @param {number} pageNumber\n */\n isPageCached(pageNumber) {\n return this.pdfViewer.isPageCached(pageNumber);\n }\n\n static #isValidExplicitDestination(dest) {\n if (!Array.isArray(dest)) {\n return false;\n }\n const destLength = dest.length;\n if (destLength < 2) {\n return false;\n }\n const page = dest[0];\n if (\n !(\n typeof page === \"object\" &&\n Number.isInteger(page.num) &&\n Number.isInteger(page.gen)\n ) &&\n !(Number.isInteger(page) && page >= 0)\n ) {\n return false;\n }\n const zoom = dest[1];\n if (!(typeof zoom === \"object\" && typeof zoom.name === \"string\")) {\n return false;\n }\n let allowNull = true;\n switch (zoom.name) {\n case \"XYZ\":\n if (destLength !== 5) {\n return false;\n }\n break;\n case \"Fit\":\n case \"FitB\":\n return destLength === 2;\n case \"FitH\":\n case \"FitBH\":\n case \"FitV\":\n case \"FitBV\":\n if (destLength !== 3) {\n return false;\n }\n break;\n case \"FitR\":\n if (destLength !== 6) {\n return false;\n }\n allowNull = false;\n break;\n default:\n return false;\n }\n for (let i = 2; i < destLength; i++) {\n const param = dest[i];\n if (!(typeof param === \"number\" || (allowNull && param === null))) {\n return false;\n }\n }\n return true;\n }\n}\n\n/**\n * @implements {IPDFLinkService}\n */\nclass SimpleLinkService {\n constructor() {\n this.externalLinkEnabled = true;\n }\n\n /**\n * @type {number}\n */\n get pagesCount() {\n return 0;\n }\n\n /**\n * @type {number}\n */\n get page() {\n return 0;\n }\n\n /**\n * @param {number} value\n */\n set page(value) {}\n\n /**\n * @type {number}\n */\n get rotation() {\n return 0;\n }\n\n /**\n * @param {number} value\n */\n set rotation(value) {}\n\n /**\n * @param {string|Array} dest - The named, or explicit, PDF destination.\n */\n async goToDestination(dest) {}\n\n /**\n * @param {number|string} val - The page number, or page label.\n */\n goToPage(val) {}\n\n /**\n * @param {HTMLAnchorElement} link\n * @param {string} url\n * @param {boolean} [newWindow]\n */\n addLinkAttributes(link, url, newWindow = false) {\n addLinkAttributes(link, { url, enabled: this.externalLinkEnabled });\n }\n\n /**\n * @param dest - The PDF destination object.\n * @returns {string} The hyperlink to the PDF object.\n */\n getDestinationHash(dest) {\n return \"#\";\n }\n\n /**\n * @param hash - The PDF parameters/hash.\n * @returns {string} The hyperlink to the PDF object.\n */\n getAnchorUrl(hash) {\n return \"#\";\n }\n\n /**\n * @param {string} hash\n */\n setHash(hash) {}\n\n /**\n * @param {string} action\n */\n executeNamedAction(action) {}\n\n /**\n * @param {number} pageNum - page number.\n * @param {Object} pageRef - reference to the page.\n */\n cachePageRef(pageNum, pageRef) {}\n\n /**\n * @param {number} pageNumber\n */\n isPageVisible(pageNumber) {\n return true;\n }\n\n /**\n * @param {number} pageNumber\n */\n isPageCached(pageNumber) {\n return true;\n }\n}\n\nexport { LinkTarget, PDFLinkService, SimpleLinkService };\n","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n animationStarted,\n apiPageLayoutToViewerModes,\n apiPageModeToSidebarView,\n AutoPrintRegExp,\n DEFAULT_SCALE_VALUE,\n getActiveOrFocusedElement,\n isValidRotation,\n isValidScrollMode,\n isValidSpreadMode,\n noContextMenuHandler,\n normalizeWheelEventDirection,\n parseQueryString,\n ProgressBar,\n RendererType,\n RenderingStates,\n ScrollMode,\n SidebarView,\n SpreadMode,\n TextLayerMode,\n} from \"./ui_utils.js\";\nimport {\n AnnotationEditorType,\n build,\n createPromiseCapability,\n getDocument,\n getFilenameFromUrl,\n getPdfFilenameFromUrl,\n GlobalWorkerOptions,\n InvalidPDFException,\n isPdfFile,\n loadScript,\n MissingPDFException,\n OPS,\n PDFWorker,\n shadow,\n UnexpectedResponseException,\n UNSUPPORTED_FEATURES,\n version,\n} from \"pdfjs-lib\";\nimport { AppOptions, OptionKind } from \"./app_options.js\";\nimport { AutomationEventBus, EventBus } from \"./event_utils.js\";\nimport { CursorTool, PDFCursorTools } from \"./pdf_cursor_tools.js\";\nimport { LinkTarget, PDFLinkService } from \"./pdf_link_service.js\";\nimport { AnnotationEditorParams } from \"./annotation_editor_params.js\";\nimport { OverlayManager } from \"./overlay_manager.js\";\nimport { PasswordPrompt } from \"./password_prompt.js\";\nimport { PDFAttachmentViewer } from \"./pdf_attachment_viewer.js\";\nimport { PDFDocumentProperties } from \"./pdf_document_properties.js\";\nimport { PDFFindBar } from \"./pdf_find_bar.js\";\nimport { PDFFindController } from \"./pdf_find_controller.js\";\nimport { PDFHistory } from \"./pdf_history.js\";\nimport { PDFLayerViewer } from \"./pdf_layer_viewer.js\";\nimport { PDFOutlineViewer } from \"./pdf_outline_viewer.js\";\nimport { PDFPresentationMode } from \"./pdf_presentation_mode.js\";\nimport { PDFRenderingQueue } from \"./pdf_rendering_queue.js\";\nimport { PDFScriptingManager } from \"./pdf_scripting_manager.js\";\nimport { PDFSidebar } from \"./pdf_sidebar.js\";\nimport { PDFSidebarResizer } from \"./pdf_sidebar_resizer.js\";\nimport { PDFThumbnailViewer } from \"./pdf_thumbnail_viewer.js\";\nimport { PDFViewer } from \"./pdf_viewer.js\";\nimport { SecondaryToolbar } from \"./secondary_toolbar.js\";\nimport { Toolbar } from \"./toolbar.js\";\nimport { ViewHistory } from \"./view_history.js\";\n\nconst DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT = 5000; // ms\nconst FORCE_PAGES_LOADED_TIMEOUT = 10000; // ms\nconst WHEEL_ZOOM_DISABLED_TIMEOUT = 1000; // ms\n\nconst ViewOnLoad = {\n UNKNOWN: -1,\n PREVIOUS: 0, // Default value.\n INITIAL: 1,\n};\n\nconst ViewerCssTheme = {\n AUTOMATIC: 0, // Default value.\n LIGHT: 1,\n DARK: 2,\n};\n\n// Keep these in sync with mozilla-central's Histograms.json.\nconst KNOWN_VERSIONS = [\n \"1.0\",\n \"1.1\",\n \"1.2\",\n \"1.3\",\n \"1.4\",\n \"1.5\",\n \"1.6\",\n \"1.7\",\n \"1.8\",\n \"1.9\",\n \"2.0\",\n \"2.1\",\n \"2.2\",\n \"2.3\",\n];\n// Keep these in sync with mozilla-central's Histograms.json.\nconst KNOWN_GENERATORS = [\n \"acrobat distiller\",\n \"acrobat pdfwriter\",\n \"adobe livecycle\",\n \"adobe pdf library\",\n \"adobe photoshop\",\n \"ghostscript\",\n \"tcpdf\",\n \"cairo\",\n \"dvipdfm\",\n \"dvips\",\n \"pdftex\",\n \"pdfkit\",\n \"itext\",\n \"prince\",\n \"quarkxpress\",\n \"mac os x\",\n \"microsoft\",\n \"openoffice\",\n \"oracle\",\n \"luradocument\",\n \"pdf-xchange\",\n \"antenna house\",\n \"aspose.cells\",\n \"fpdf\",\n];\n\nclass DefaultExternalServices {\n constructor() {\n throw new Error(\"Cannot initialize DefaultExternalServices.\");\n }\n\n static updateFindControlState(data) {}\n\n static updateFindMatchesCount(data) {}\n\n static initPassiveLoading(callbacks) {}\n\n static reportTelemetry(data) {}\n\n static createDownloadManager(options) {\n throw new Error(\"Not implemented: createDownloadManager\");\n }\n\n static createPreferences() {\n throw new Error(\"Not implemented: createPreferences\");\n }\n\n static createL10n(options) {\n throw new Error(\"Not implemented: createL10n\");\n }\n\n static createScripting(options) {\n throw new Error(\"Not implemented: createScripting\");\n }\n\n static get supportsIntegratedFind() {\n return shadow(this, \"supportsIntegratedFind\", false);\n }\n\n static get supportsDocumentFonts() {\n return shadow(this, \"supportsDocumentFonts\", true);\n }\n\n static get supportedMouseWheelZoomModifierKeys() {\n return shadow(this, \"supportedMouseWheelZoomModifierKeys\", {\n ctrlKey: true,\n metaKey: true,\n });\n }\n\n static get isInAutomation() {\n return shadow(this, \"isInAutomation\", false);\n }\n\n static updateEditorStates(data) {\n throw new Error(\"Not implemented: updateEditorStates\");\n }\n}\n\nconst PDFViewerApplication = {\n initialBookmark: document.location.hash.substring(1),\n _initializedCapability: createPromiseCapability(),\n appConfig: null,\n pdfDocument: null,\n pdfLoadingTask: null,\n printService: null,\n /** @type {PDFViewer} */\n pdfViewer: null,\n /** @type {PDFThumbnailViewer} */\n pdfThumbnailViewer: null,\n /** @type {PDFRenderingQueue} */\n pdfRenderingQueue: null,\n /** @type {PDFPresentationMode} */\n pdfPresentationMode: null,\n /** @type {PDFDocumentProperties} */\n pdfDocumentProperties: null,\n /** @type {PDFLinkService} */\n pdfLinkService: null,\n /** @type {PDFHistory} */\n pdfHistory: null,\n /** @type {PDFSidebar} */\n pdfSidebar: null,\n /** @type {PDFSidebarResizer} */\n pdfSidebarResizer: null,\n /** @type {PDFOutlineViewer} */\n pdfOutlineViewer: null,\n /** @type {PDFAttachmentViewer} */\n pdfAttachmentViewer: null,\n /** @type {PDFLayerViewer} */\n pdfLayerViewer: null,\n /** @type {PDFCursorTools} */\n pdfCursorTools: null,\n /** @type {PDFScriptingManager} */\n pdfScriptingManager: null,\n /** @type {ViewHistory} */\n store: null,\n /** @type {DownloadManager} */\n downloadManager: null,\n /** @type {OverlayManager} */\n overlayManager: null,\n /** @type {Preferences} */\n preferences: null,\n /** @type {Toolbar} */\n toolbar: null,\n /** @type {SecondaryToolbar} */\n secondaryToolbar: null,\n /** @type {EventBus} */\n eventBus: null,\n /** @type {IL10n} */\n l10n: null,\n /** @type {AnnotationEditorParams} */\n annotationEditorParams: null,\n isInitialViewSet: false,\n downloadComplete: false,\n isViewerEmbedded: window.parent !== window,\n url: \"\",\n baseUrl: \"\",\n _downloadUrl: \"\",\n externalServices: DefaultExternalServices,\n _boundEvents: Object.create(null),\n documentInfo: null,\n metadata: null,\n _contentDispositionFilename: null,\n _contentLength: null,\n _saveInProgress: false,\n _docStats: null,\n _wheelUnusedTicks: 0,\n _idleCallbacks: new Set(),\n _PDFBug: null,\n _hasAnnotationEditors: false,\n _title: document.title,\n _printAnnotationStoragePromise: null,\n\n // Called once when the document is loaded.\n async initialize(appConfig) {\n this.preferences = this.externalServices.createPreferences();\n this.appConfig = appConfig;\n\n await this._readPreferences();\n await this._parseHashParameters();\n this._forceCssTheme();\n await this._initializeL10n();\n\n if (\n this.isViewerEmbedded &&\n AppOptions.get(\"externalLinkTarget\") === LinkTarget.NONE\n ) {\n // Prevent external links from \"replacing\" the viewer,\n // when it's embedded in e.g. an