mirror of
https://github.com/PlayEdu/PlayEdu
synced 2025-10-27 07:01:37 +08:00
Compare commits
82 Commits
v1.0-beta.
...
v1.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1d5a9c648 | ||
|
|
11fbf34b65 | ||
|
|
1103a89e71 | ||
|
|
baf4d50b33 | ||
|
|
700da4c468 | ||
|
|
e8c08f9c09 | ||
|
|
99830cb707 | ||
|
|
3fa8a047d0 | ||
|
|
ef87c684c6 | ||
|
|
acb2ce83db | ||
|
|
f69f19bdb3 | ||
|
|
9fef487b13 | ||
|
|
b685a21717 | ||
|
|
a82e2992b4 | ||
|
|
ad6151ab39 | ||
|
|
9b621e4e62 | ||
|
|
46b0bb7555 | ||
|
|
657d418e7a | ||
|
|
8cf5bc0a6e | ||
|
|
06da295d58 | ||
|
|
61eb5be2ee | ||
|
|
e1519f49cb | ||
|
|
6952f8679d | ||
|
|
4fd23b0417 | ||
|
|
4897401d32 | ||
|
|
d5e410cb1f | ||
|
|
069c3e4cc9 | ||
|
|
76dceaa44d | ||
|
|
4387471d76 | ||
|
|
5a93eb9423 | ||
|
|
828f3e08b9 | ||
|
|
95e2652615 | ||
|
|
1d31045807 | ||
|
|
2e0801fb57 | ||
|
|
828f6446a5 | ||
|
|
b34320350d | ||
|
|
30806bfdcf | ||
|
|
54abd4ae6c | ||
|
|
acffce65ba | ||
|
|
e72d351d25 | ||
|
|
26074efea4 | ||
|
|
86cd51a0d6 | ||
|
|
bdd1b1bbb9 | ||
|
|
b7c4410028 | ||
|
|
db4c92e23e | ||
|
|
5c1346e22c | ||
|
|
8d18d5423b | ||
|
|
099642675b | ||
|
|
f3103559d5 | ||
|
|
935ee6a500 | ||
|
|
c6eef3477e | ||
|
|
67c3578609 | ||
|
|
c65013f266 | ||
|
|
ae0b3ab9e0 | ||
|
|
bc194e6be2 | ||
|
|
0aefff9aaf | ||
|
|
e28e2e30af | ||
|
|
d697ded1ec | ||
|
|
277332d410 | ||
|
|
ae13fa0201 | ||
|
|
b9623983c7 | ||
|
|
cd475f080e | ||
|
|
e0f807909f | ||
|
|
c88fc11c7e | ||
|
|
39519db020 | ||
|
|
46015593e9 | ||
|
|
3aa2ea9990 | ||
|
|
0da1c9d0d2 | ||
|
|
b58ee9dbc6 | ||
|
|
93752a9ca7 | ||
|
|
3eb7864582 | ||
|
|
295992e4d4 | ||
|
|
1edc205e9f | ||
|
|
f9c6a6ad74 | ||
|
|
d1d7c43a3a | ||
|
|
e554c01c7b | ||
|
|
a23155cb27 | ||
|
|
c987b34b9b | ||
|
|
4c085d4836 | ||
|
|
ce1cf5b475 | ||
|
|
da3a6eff37 | ||
|
|
192326bf7e |
36
.github/workflows/build.yml
vendored
Normal file
36
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
name: EstablishDockerImage
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
- 'feat/**'
|
||||
|
||||
env:
|
||||
IMAGE_FQDN: registry.cn-hangzhou.aliyuncs.com/playedu/api
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Login to GHCR
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: registry.cn-hangzhou.aliyuncs.com
|
||||
username: ${{ secrets.ALI_REGISTRY_EMAIL }}
|
||||
password: ${{ secrets.ALI_REGISTRY_PASS }}
|
||||
- name: Build
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.IMAGE_FQDN }}:1.4
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -33,4 +33,5 @@ build/
|
||||
.vscode/
|
||||
|
||||
/src/main/resources/application-dev.yml
|
||||
/playedu-api/src/main/resources/application-dev.yml
|
||||
/logs
|
||||
18
Dockerfile
18
Dockerfile
@@ -1,23 +1,25 @@
|
||||
FROM eclipse-temurin:17-alpine as builder
|
||||
|
||||
WORKDIR /app
|
||||
FROM eclipse-temurin:17 as builder
|
||||
|
||||
COPY . /app
|
||||
|
||||
RUN /app/docker-build.sh
|
||||
WORKDIR /app
|
||||
|
||||
FROM eclipse-temurin:17-alpine
|
||||
RUN /app/mvnw -Dmaven.test.skip=true clean package
|
||||
|
||||
FROM eclipse-temurin:17
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 使用东八区时间环境
|
||||
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||
RUN echo "Asia/Shanghai" > /etc/timezone
|
||||
|
||||
# 将指定目录下的jar包复制到docker容器的/目录下
|
||||
COPY --from=builder /app/target/playedu-api-*.jar /app/app.jar
|
||||
COPY --from=builder /app/playedu-api/target/playedu-api.jar /app/app.jar
|
||||
|
||||
RUN chmod +x /app/app.jar
|
||||
|
||||
# 声明服务运行在8080端口
|
||||
EXPOSE 9898
|
||||
|
||||
# 指定docker容器启动时运行jar包
|
||||
ENTRYPOINT ["java", "-jar", "app.jar"]
|
||||
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
|
||||
|
||||
@@ -33,4 +33,10 @@ PlayEdu 是由白书科技团队经营多年线上教育系统打造出的一款
|
||||
|
||||
### 使用协议
|
||||
|
||||
本开源项目中所有代码基于 Apache-2.0 许可协议。
|
||||
● 要求
|
||||
- 保留页脚处版权信息。
|
||||
- 保留源代码中的协议。
|
||||
- 如果修改了代码,则必须在文件中进行说明。
|
||||
|
||||
● 允许
|
||||
- 私用、商用、修改。
|
||||
|
||||
@@ -1,468 +0,0 @@
|
||||
# ************************************************************
|
||||
# Sequel Pro SQL dump
|
||||
# Version 4541
|
||||
#
|
||||
# http://www.sequelpro.com/
|
||||
# https://github.com/sequelpro/sequelpro
|
||||
#
|
||||
# Host: 127.0.0.1 (MySQL 5.6.51)
|
||||
# Database: playedu
|
||||
# Generation Time: 2023-04-06 03:00:20 +0000
|
||||
# ************************************************************
|
||||
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
/*!40101 SET NAMES utf8 */;
|
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
|
||||
# Dump of table admin_logs
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `admin_logs` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`admin_id` int(11) NOT NULL DEFAULT '0' COMMENT '管理员ID',
|
||||
`module` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '模块',
|
||||
`opt` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '操作指令',
|
||||
`remark` mediumtext COLLATE utf8mb4_unicode_ci COMMENT '备注',
|
||||
`ip` varchar(45) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT 'ip',
|
||||
`ip_area` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '地址',
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `a_m_o` (`admin_id`,`module`,`opt`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
|
||||
|
||||
# Dump of table admin_permissions
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `admin_permissions` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`type` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '类型[行为:action,数据:data]',
|
||||
`group_name` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '分组',
|
||||
`sort` int(11) NOT NULL COMMENT '升序',
|
||||
`name` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '权限名',
|
||||
`slug` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'slug',
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
|
||||
|
||||
# Dump of table admin_role_permission
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `admin_role_permission` (
|
||||
`role_id` int(11) unsigned NOT NULL DEFAULT '0',
|
||||
`perm_id` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
KEY `role_id` (`role_id`),
|
||||
KEY `perm_id` (`perm_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
|
||||
|
||||
# Dump of table admin_roles
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `admin_roles` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '角色名',
|
||||
`slug` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'slug',
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `slug` (`slug`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
INSERT INTO `admin_roles` (`name`, `slug`, `created_at`, `updated_at`)
|
||||
VALUES
|
||||
('超级管理角色', 'super-role', '2023-02-24 06:19:15', '2023-02-24 06:19:15');
|
||||
|
||||
|
||||
|
||||
# Dump of table admin_user_role
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `admin_user_role` (
|
||||
`admin_id` int(11) unsigned NOT NULL DEFAULT '0',
|
||||
`role_id` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
KEY `admin_id` (`admin_id`),
|
||||
KEY `role_id` (`role_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
INSERT INTO `admin_user_role` (`admin_id`, `role_id`)
|
||||
VALUES
|
||||
(1, 1);
|
||||
|
||||
|
||||
|
||||
# Dump of table admin_users
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `admin_users` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '姓名',
|
||||
`email` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '邮箱',
|
||||
`password` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '密码',
|
||||
`salt` varchar(10) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT 'Salt',
|
||||
`login_ip` varchar(15) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '登录IP',
|
||||
`login_at` timestamp NULL DEFAULT NULL COMMENT '登录时间',
|
||||
`is_ban_login` tinyint(4) NOT NULL DEFAULT '0' COMMENT '1禁止登录,0否',
|
||||
`login_times` int(11) NOT NULL DEFAULT '0' COMMENT '登录次数',
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `administrators_email_unique` (`email`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
INSERT INTO `admin_users` (`name`, `email`, `password`, `salt`, `login_ip`, `login_at`, `is_ban_login`, `login_times`, `created_at`, `updated_at`)
|
||||
VALUES
|
||||
('超级管理员', 'admin@playedu.xyz', 'd771587aa711961304fa8c1a5273f491', 'VROkTh', '', '2023-04-06 16:51:17', 0, 0, '2023-02-19 18:10:12', '2023-04-06 16:51:17');
|
||||
|
||||
|
||||
|
||||
# Dump of table app_config
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `app_config` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`group_name` varchar(24) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '分组',
|
||||
`name` varchar(24) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名称',
|
||||
`sort` int(11) NOT NULL DEFAULT '0' COMMENT '升序',
|
||||
`field_type` varchar(24) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '字段类型',
|
||||
`key_name` varchar(188) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '键',
|
||||
`key_value` longtext COLLATE utf8mb4_unicode_ci COMMENT '值',
|
||||
`option_value` text COLLATE utf8mb4_unicode_ci COMMENT '可选值',
|
||||
`is_private` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否私密信息',
|
||||
`help` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '帮助信息',
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`is_hidden` tinyint(4) NOT NULL DEFAULT '0' COMMENT '1显示,0否',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `app_config_key_unique` (`key_name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
|
||||
|
||||
# Dump of table course_chapters
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `course_chapters` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`course_id` int(11) NOT NULL DEFAULT '0' COMMENT '课程ID',
|
||||
`name` varchar(64) NOT NULL DEFAULT '' COMMENT '章节名',
|
||||
`sort` int(11) NOT NULL DEFAULT '0' COMMENT '升序',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
|
||||
|
||||
# Dump of table course_department
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `course_department` (
|
||||
`course_id` int(11) NOT NULL DEFAULT '0',
|
||||
`dep_id` int(11) NOT NULL DEFAULT '0',
|
||||
KEY `course_id` (`course_id`),
|
||||
KEY `dep_id` (`dep_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
|
||||
|
||||
# Dump of table course_hour
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `course_hour` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`course_id` int(11) NOT NULL DEFAULT '0' COMMENT '课程ID',
|
||||
`chapter_id` int(11) NOT NULL DEFAULT '0' COMMENT '章节ID',
|
||||
`sort` int(11) NOT NULL DEFAULT '0' COMMENT '升序',
|
||||
`title` varchar(255) NOT NULL DEFAULT '' COMMENT '课时名',
|
||||
`type` varchar(20) NOT NULL DEFAULT '' COMMENT '课时类型',
|
||||
`rid` int(11) NOT NULL DEFAULT '0' COMMENT '资源id',
|
||||
`duration` int(11) NOT NULL COMMENT '时长[s]',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `course_id` (`course_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
|
||||
|
||||
# Dump of table courses
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `courses` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`title` varchar(255) NOT NULL DEFAULT '' COMMENT '课程标题',
|
||||
`thumb` varchar(255) NOT NULL DEFAULT '' COMMENT '课程封面',
|
||||
`charge` int(11) NOT NULL DEFAULT '0' COMMENT '课程价格(分)',
|
||||
`short_desc` varchar(255) NOT NULL DEFAULT '' COMMENT '简介',
|
||||
`class_hour` int(11) NOT NULL DEFAULT '0' COMMENT '课时数',
|
||||
`is_show` tinyint(4) NOT NULL DEFAULT '0' COMMENT '显示[1:是,0:否]',
|
||||
`is_required` tinyint(4) NOT NULL DEFAULT '0' COMMENT '1:必修,0:选修',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
|
||||
`deleted_at` timestamp NULL DEFAULT NULL COMMENT '删除时间',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
|
||||
|
||||
# Dump of table departments
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `departments` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(64) NOT NULL DEFAULT '' COMMENT '部门名',
|
||||
`parent_id` int(11) NOT NULL COMMENT '父id',
|
||||
`parent_chain` varchar(255) NOT NULL DEFAULT '' COMMENT '父链',
|
||||
`sort` int(11) NOT NULL DEFAULT '0' COMMENT '升序',
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
|
||||
|
||||
# Dump of table resource_categories
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `resource_categories` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`parent_id` int(11) NOT NULL DEFAULT '0',
|
||||
`parent_chain` varchar(2550) NOT NULL DEFAULT '',
|
||||
`name` varchar(64) NOT NULL DEFAULT '' COMMENT '分类名',
|
||||
`sort` int(11) NOT NULL COMMENT '升序',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
|
||||
|
||||
# Dump of table resource_category
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `resource_category` (
|
||||
`cid` int(11) NOT NULL DEFAULT '0',
|
||||
`rid` int(11) NOT NULL,
|
||||
KEY `cid` (`cid`),
|
||||
KEY `rid` (`rid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
|
||||
|
||||
# Dump of table resource_course_category
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `resource_course_category` (
|
||||
`course_id` int(11) NOT NULL DEFAULT '0',
|
||||
`category_id` int(11) NOT NULL DEFAULT '0',
|
||||
KEY `course_id` (`course_id`),
|
||||
KEY `category_id` (`category_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
|
||||
|
||||
# Dump of table resource_videos
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `resource_videos` (
|
||||
`rid` int(11) unsigned NOT NULL,
|
||||
`poster` varchar(255) NOT NULL DEFAULT '' COMMENT '封面',
|
||||
`duration` int(10) unsigned NOT NULL COMMENT '视频时长[s]',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
UNIQUE KEY `rid` (`rid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
|
||||
|
||||
# Dump of table resources
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `resources` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`admin_id` int(11) NOT NULL DEFAULT '0',
|
||||
`type` varchar(10) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '类型',
|
||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '资源名',
|
||||
`extension` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '文件类型',
|
||||
`size` bigint(20) DEFAULT '0' COMMENT '大小[字节]',
|
||||
`disk` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '存储磁盘',
|
||||
`file_id` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '文件id',
|
||||
`path` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '相对地址',
|
||||
`url` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT 'URL地址',
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`parent_id` int(11) NOT NULL DEFAULT '0' COMMENT '所属素材',
|
||||
`is_hidden` tinyint(4) NOT NULL DEFAULT '0' COMMENT '隐藏[0:否,1:是]',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `type` (`type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
|
||||
|
||||
# Dump of table user_course_hour_records
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `user_course_hour_records` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(11) NOT NULL DEFAULT '0',
|
||||
`course_id` int(11) NOT NULL DEFAULT '0',
|
||||
`hour_id` int(11) NOT NULL DEFAULT '0',
|
||||
`total_duration` int(11) NOT NULL DEFAULT '0' COMMENT '总时长',
|
||||
`finished_duration` int(11) NOT NULL DEFAULT '0' COMMENT '已完成时长',
|
||||
`real_duration` int(11) NOT NULL DEFAULT '0' COMMENT '实际观看时长',
|
||||
`is_finished` tinyint(4) DEFAULT NULL COMMENT '是否看完[1:是,0:否]',
|
||||
`finished_at` timestamp NULL DEFAULT NULL COMMENT '看完时间',
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `u_h_c_id` (`user_id`,`hour_id`,`course_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
|
||||
|
||||
# Dump of table user_course_records
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `user_course_records` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(11) NOT NULL DEFAULT '0',
|
||||
`course_id` int(11) NOT NULL DEFAULT '0',
|
||||
`hour_count` int(11) NOT NULL DEFAULT '0' COMMENT '课时数量',
|
||||
`finished_count` int(11) NOT NULL DEFAULT '0' COMMENT '已完成课时数',
|
||||
`progress` int(11) NOT NULL DEFAULT '0' COMMENT '进度',
|
||||
`is_finished` tinyint(4) NOT NULL DEFAULT '0' COMMENT '看完[1:是,0:否]',
|
||||
`finished_at` timestamp NULL DEFAULT NULL COMMENT '看完时间',
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
|
||||
|
||||
# Dump of table user_department
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `user_department` (
|
||||
`user_id` int(11) unsigned NOT NULL DEFAULT '0',
|
||||
`dep_id` int(11) unsigned NOT NULL DEFAULT '0',
|
||||
KEY `user_id` (`user_id`),
|
||||
KEY `dep_id` (`dep_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
|
||||
|
||||
# Dump of table user_learn_duration_records
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `user_learn_duration_records` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(11) NOT NULL DEFAULT '0',
|
||||
`created_date` date NOT NULL,
|
||||
`duration` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '已学习时长[微秒]',
|
||||
`start_at` timestamp NULL DEFAULT NULL COMMENT '开始时间',
|
||||
`end_at` timestamp NULL DEFAULT NULL COMMENT '结束时间',
|
||||
`course_id` int(11) NOT NULL DEFAULT '0',
|
||||
`hour_id` int(11) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `u_d` (`user_id`,`created_date`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
|
||||
|
||||
# Dump of table user_learn_duration_stats
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `user_learn_duration_stats` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(11) NOT NULL DEFAULT '0',
|
||||
`duration` bigint(20) NOT NULL DEFAULT '0',
|
||||
`created_date` date NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `u_d` (`user_id`,`created_date`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
|
||||
|
||||
# Dump of table user_login_records
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `user_login_records` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(11) NOT NULL,
|
||||
`jti` varchar(64) NOT NULL DEFAULT '' COMMENT 'JTI',
|
||||
`ip` varchar(15) NOT NULL DEFAULT '' COMMENT '登录ip',
|
||||
`ip_area` varchar(64) NOT NULL DEFAULT '' COMMENT 'Ip解析区域',
|
||||
`browser` varchar(64) NOT NULL DEFAULT '' COMMENT '浏览器',
|
||||
`browser_version` varchar(64) NOT NULL DEFAULT '' COMMENT '浏览器版本',
|
||||
`os` varchar(128) NOT NULL DEFAULT '' COMMENT '操作系统',
|
||||
`expired` bigint(20) NOT NULL DEFAULT '0' COMMENT '过期时间',
|
||||
`is_logout` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否注销',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `jti` (`jti`),
|
||||
KEY `user_id` (`user_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
|
||||
|
||||
# Dump of table user_upload_image_logs
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `user_upload_image_logs` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(11) NOT NULL DEFAULT '0',
|
||||
`typed` varchar(32) NOT NULL DEFAULT '' COMMENT '图片类型',
|
||||
`scene` varchar(24) NOT NULL DEFAULT '' COMMENT '上传场景',
|
||||
`driver` varchar(32) NOT NULL DEFAULT '' COMMENT '驱动',
|
||||
`path` varchar(255) NOT NULL DEFAULT '' COMMENT '相对路径',
|
||||
`url` varchar(255) NOT NULL DEFAULT '' COMMENT '访问地址',
|
||||
`size` bigint(20) NOT NULL COMMENT '大小,单位:字节',
|
||||
`name` varchar(255) NOT NULL DEFAULT '' COMMENT '文件名',
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
|
||||
|
||||
# Dump of table users
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `users` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`email` varchar(32) NOT NULL DEFAULT '' COMMENT '邮件',
|
||||
`name` varchar(24) NOT NULL DEFAULT '' COMMENT '真实姓名',
|
||||
`avatar` varchar(255) NOT NULL DEFAULT '' COMMENT '头像',
|
||||
`password` varchar(128) NOT NULL DEFAULT '' COMMENT '密码',
|
||||
`salt` varchar(12) NOT NULL DEFAULT '' COMMENT 'salt',
|
||||
`id_card` varchar(64) NOT NULL DEFAULT '' COMMENT '身份证号',
|
||||
`credit1` int(11) NOT NULL DEFAULT '0' COMMENT '学分',
|
||||
`create_ip` varchar(15) NOT NULL DEFAULT '' COMMENT '注册Ip',
|
||||
`create_city` varchar(32) NOT NULL DEFAULT '' COMMENT '注册城市',
|
||||
`is_active` tinyint(4) NOT NULL DEFAULT '0' COMMENT '激活[1:是,0:否]',
|
||||
`is_lock` tinyint(4) NOT NULL DEFAULT '0' COMMENT '锁定[1:是,0:否]',
|
||||
`is_verify` tinyint(4) NOT NULL DEFAULT '0' COMMENT '实名认证[1:是,0:否]',
|
||||
`verify_at` timestamp NULL DEFAULT NULL COMMENT '实名认证时间',
|
||||
`is_set_password` tinyint(4) NOT NULL DEFAULT '0' COMMENT '设置密码[1:是,0:否]',
|
||||
`login_at` timestamp NULL DEFAULT NULL COMMENT '登录时间',
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `email` (`email`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
|
||||
|
||||
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
@@ -1,13 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo '设置M2_HOME...'
|
||||
|
||||
cp -r docker/.m2 /root
|
||||
|
||||
ls /root/.m2
|
||||
|
||||
echo '开始打包...'
|
||||
|
||||
export MAVEN_OPTS=-Dmaven.test.skip=true
|
||||
|
||||
/app/mvnw clean package
|
||||
@@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
|
||||
<mirrors>
|
||||
<mirror>
|
||||
<id>Ali</id>
|
||||
<name>Ali Maven</name>
|
||||
<mirrorOf>*</mirrorOf>
|
||||
<url>https://maven.aliyun.com/nexus/content/groups/public/</url>
|
||||
</mirror>
|
||||
</mirrors>
|
||||
</settings>
|
||||
58
playedu-api/pom.xml
Normal file
58
playedu-api/pom.xml
Normal file
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>xyz.playedu</groupId>
|
||||
<artifactId>playedu</artifactId>
|
||||
<version>1.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>playedu-api</artifactId>
|
||||
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>xyz.playedu</groupId>
|
||||
<artifactId>playedu-common</artifactId>
|
||||
<version>1.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>xyz.playedu</groupId>
|
||||
<artifactId>playedu-system</artifactId>
|
||||
<version>1.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>xyz.playedu</groupId>
|
||||
<artifactId>playedu-course</artifactId>
|
||||
<version>1.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>xyz.playedu</groupId>
|
||||
<artifactId>playedu-resource</artifactId>
|
||||
<version>1.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>playedu-api</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>3.1.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -15,16 +15,22 @@
|
||||
*/
|
||||
package xyz.playedu.api;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import xyz.playedu.api.config.UniqueNameGenerator;
|
||||
import xyz.playedu.common.config.UniqueNameGeneratorConfig;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableAsync
|
||||
@ComponentScan(nameGenerator = UniqueNameGenerator.class)
|
||||
@EnableTransactionManagement
|
||||
@ComponentScan(
|
||||
basePackages = {"xyz.playedu"},
|
||||
nameGenerator = UniqueNameGeneratorConfig.class)
|
||||
@MapperScan("xyz.playedu.**.mapper")
|
||||
public class PlayeduApiApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
143
playedu-api/src/main/java/xyz/playedu/api/bus/LoginBus.java
Normal file
143
playedu-api/src/main/java/xyz/playedu/api/bus/LoginBus.java
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (C) 2023 杭州白书科技有限公司
|
||||
*
|
||||
* 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 xyz.playedu.api.bus;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import xyz.playedu.api.event.UserLoginEvent;
|
||||
import xyz.playedu.common.domain.LdapUser;
|
||||
import xyz.playedu.common.domain.User;
|
||||
import xyz.playedu.common.exception.ServiceException;
|
||||
import xyz.playedu.common.service.*;
|
||||
import xyz.playedu.common.util.HelperUtil;
|
||||
import xyz.playedu.common.util.IpUtil;
|
||||
import xyz.playedu.common.util.RequestUtil;
|
||||
import xyz.playedu.common.util.StringUtil;
|
||||
import xyz.playedu.common.util.ldap.LdapTransformUser;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class LoginBus {
|
||||
|
||||
@Autowired private FrontendAuthService authService;
|
||||
|
||||
@Autowired private DepartmentService departmentService;
|
||||
|
||||
@Autowired private LdapUserService ldapUserService;
|
||||
|
||||
@Autowired private UserService userService;
|
||||
|
||||
@Autowired private AppConfigService appConfigService;
|
||||
|
||||
@Autowired private ApplicationContext ctx;
|
||||
|
||||
public HashMap<String, Object> tokenByUser(User user) {
|
||||
String token = authService.loginUsingId(user.getId(), RequestUtil.url());
|
||||
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
data.put("token", token);
|
||||
|
||||
ctx.publishEvent(
|
||||
new UserLoginEvent(
|
||||
this,
|
||||
user.getId(),
|
||||
user.getEmail(),
|
||||
token,
|
||||
IpUtil.getIpAddress(),
|
||||
RequestUtil.ua()));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public HashMap<String, Object> tokenByLdapTransformUser(LdapTransformUser ldapTransformUser)
|
||||
throws ServiceException {
|
||||
// LDAP用户的名字
|
||||
String ldapUserName = ldapTransformUser.getCn();
|
||||
|
||||
// 将LDAP用户所属的部门同步到本地
|
||||
Integer depId = departmentService.createWithChainList(ldapTransformUser.getOu());
|
||||
Integer[] depIds = depId == 0 ? null : new Integer[] {depId};
|
||||
|
||||
// LDAP用户在本地的缓存记录
|
||||
LdapUser ldapUser = ldapUserService.findByUUID(ldapTransformUser.getId());
|
||||
User user;
|
||||
|
||||
// 计算将LDAP用户关联到本地users表的email字段值
|
||||
String localUserEmail = ldapTransformUser.getUid();
|
||||
if (StringUtil.isNotEmpty(ldapTransformUser.getEmail())) {
|
||||
localUserEmail = ldapTransformUser.getEmail();
|
||||
}
|
||||
|
||||
if (ldapUser == null) {
|
||||
// 检测localUserEmail是否存在
|
||||
if (userService.find(localUserEmail) != null) {
|
||||
throw new ServiceException(String.format("已有其它账号在使用:%s", localUserEmail));
|
||||
}
|
||||
// LDAP用户数据缓存到本地
|
||||
ldapUser = ldapUserService.store(ldapTransformUser);
|
||||
// 创建本地user
|
||||
user =
|
||||
userService.createWithDepIds(
|
||||
localUserEmail,
|
||||
ldapUserName,
|
||||
appConfigService.defaultAvatar(),
|
||||
HelperUtil.randomString(20),
|
||||
"",
|
||||
depIds);
|
||||
// 将LDAP缓存数据与本地user关联
|
||||
ldapUserService.updateUserId(ldapUser.getId(), user.getId());
|
||||
} else {
|
||||
user = userService.find(ldapUser.getUserId());
|
||||
// 账号修改[账号有可能是email也有可能是uid]
|
||||
if (!localUserEmail.equals(user.getEmail())) {
|
||||
// 检测localUserEmail是否存在
|
||||
if (userService.find(localUserEmail) != null) {
|
||||
throw new ServiceException(String.format("已有其它账号在使用:%s", localUserEmail));
|
||||
}
|
||||
userService.updateEmail(user.getId(), localUserEmail);
|
||||
}
|
||||
// ldap-email的变化
|
||||
if (!ldapUser.getEmail().equals(ldapTransformUser.getEmail())) {
|
||||
ldapUserService.updateEmail(ldapUser.getId(), ldapTransformUser.getEmail());
|
||||
}
|
||||
// ldap-uid的变化
|
||||
if (!ldapUser.getUid().equals(ldapTransformUser.getUid())) {
|
||||
ldapUserService.updateUid(ldapUser.getId(), ldapTransformUser.getUid());
|
||||
}
|
||||
// 名字同步修改
|
||||
if (!ldapUserName.equals(ldapUser.getCn())) {
|
||||
userService.updateName(user.getId(), ldapUserName);
|
||||
ldapUserService.updateCN(ldapUser.getId(), ldapUserName);
|
||||
}
|
||||
// 部门修改同步
|
||||
String newOU = String.join(",", ldapTransformUser.getOu());
|
||||
if (!newOU.equals(ldapUser.getOu())) {
|
||||
userService.updateDepId(user.getId(), depIds);
|
||||
ldapUserService.updateOU(ldapUser.getId(), newOU);
|
||||
}
|
||||
}
|
||||
|
||||
return tokenByUser(user);
|
||||
}
|
||||
}
|
||||
50
playedu-api/src/main/java/xyz/playedu/api/cache/LoginLimitCache.java
vendored
Normal file
50
playedu-api/src/main/java/xyz/playedu/api/cache/LoginLimitCache.java
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2023 杭州白书科技有限公司
|
||||
*
|
||||
* 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 xyz.playedu.api.cache;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import xyz.playedu.common.config.PlayEduConfig;
|
||||
import xyz.playedu.common.exception.ServiceException;
|
||||
import xyz.playedu.common.service.RateLimiterService;
|
||||
import xyz.playedu.common.util.RedisUtil;
|
||||
|
||||
@Component
|
||||
public class LoginLimitCache {
|
||||
|
||||
@Autowired private RateLimiterService rateLimiterService;
|
||||
|
||||
@Autowired private PlayEduConfig playEduConfig;
|
||||
|
||||
public void check(String email) throws ServiceException {
|
||||
String limitKey = cacheKey(email);
|
||||
Long reqCount = rateLimiterService.current(limitKey, 600L);
|
||||
if (reqCount >= 10 && !playEduConfig.getTesting()) {
|
||||
Long exp = RedisUtil.ttlWithoutPrefix(limitKey);
|
||||
String msg = String.format("您的账号已被锁定,请%s后重试", exp > 60 ? exp / 60 + "分钟" : exp + "秒");
|
||||
throw new ServiceException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy(String email) {
|
||||
RedisUtil.del(cacheKey(email));
|
||||
}
|
||||
|
||||
private String cacheKey(String email) {
|
||||
return "login-limit:" + email;
|
||||
}
|
||||
}
|
||||
@@ -13,25 +13,30 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package xyz.playedu.api.bus;
|
||||
package xyz.playedu.api.cache;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import xyz.playedu.api.config.PlayEduConfig;
|
||||
import xyz.playedu.api.constant.SystemConstant;
|
||||
import xyz.playedu.common.util.RedisDistributedLock;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
*
|
||||
* @create 2023/2/19 12:06
|
||||
*/
|
||||
@Component
|
||||
public class AppBus {
|
||||
public class LoginLockCache {
|
||||
|
||||
@Autowired private PlayEduConfig playEduConfig;
|
||||
@Autowired private RedisDistributedLock redisDistributedLock;
|
||||
|
||||
public boolean isDev() {
|
||||
return !playEduConfig.getEnv().equals(SystemConstant.ENV_PROD);
|
||||
public boolean apply(String username) {
|
||||
String key = cacheKey(username);
|
||||
return redisDistributedLock.tryLock(key, 10L, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public void release(String username) {
|
||||
redisDistributedLock.releaseLock(cacheKey(username));
|
||||
}
|
||||
|
||||
private String cacheKey(String username) {
|
||||
return "login-lock:" + username;
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ package xyz.playedu.api.controller;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.data.redis.RedisConnectionFailureException;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.validation.ObjectError;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
@@ -26,10 +27,10 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
|
||||
|
||||
import xyz.playedu.api.exception.LimitException;
|
||||
import xyz.playedu.api.exception.NotFoundException;
|
||||
import xyz.playedu.api.exception.ServiceException;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.common.exception.LimitException;
|
||||
import xyz.playedu.common.exception.NotFoundException;
|
||||
import xyz.playedu.common.exception.ServiceException;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -37,20 +38,26 @@ import java.util.List;
|
||||
@Slf4j
|
||||
public class ExceptionController {
|
||||
|
||||
// @ExceptionHandler(Exception.class)
|
||||
// public JsonResponse exceptionHandler(Exception e) {
|
||||
// log.error(e.getMessage());
|
||||
// return JsonResponse.error("系统错误", 500);
|
||||
// }
|
||||
@ExceptionHandler(Exception.class)
|
||||
public JsonResponse exceptionHandler(Exception e) {
|
||||
log.error(e.getMessage());
|
||||
return JsonResponse.error("系统错误", 500);
|
||||
}
|
||||
|
||||
@ExceptionHandler(ServiceException.class)
|
||||
public JsonResponse serviceExceptionHandler(ServiceException e) {
|
||||
return JsonResponse.error(e.getMessage(), 1);
|
||||
}
|
||||
|
||||
@ExceptionHandler(RedisConnectionFailureException.class)
|
||||
public JsonResponse serviceExceptionHandler(RedisConnectionFailureException e) {
|
||||
return JsonResponse.error("redis服务连接失败", 500);
|
||||
}
|
||||
|
||||
@ExceptionHandler(HttpMessageNotReadableException.class)
|
||||
public JsonResponse serviceExceptionHandler(HttpMessageNotReadableException e) {
|
||||
return JsonResponse.error("参数为空", 406);
|
||||
log.error("error", e);
|
||||
return JsonResponse.error("前端提交参数解析失败", 406);
|
||||
}
|
||||
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2023 杭州白书科技有限公司
|
||||
*
|
||||
* 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 xyz.playedu.api.controller.backend;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import xyz.playedu.common.annotation.BackendPermission;
|
||||
import xyz.playedu.common.annotation.Log;
|
||||
import xyz.playedu.common.bus.BackendBus;
|
||||
import xyz.playedu.common.constant.BPermissionConstant;
|
||||
import xyz.playedu.common.constant.BusinessTypeConstant;
|
||||
import xyz.playedu.common.context.BCtx;
|
||||
import xyz.playedu.common.domain.AdminLog;
|
||||
import xyz.playedu.common.exception.ServiceException;
|
||||
import xyz.playedu.common.service.AdminLogService;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.types.paginate.AdminLogPaginateFiler;
|
||||
import xyz.playedu.common.types.paginate.PaginationResult;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@RestController
|
||||
@Slf4j
|
||||
@RequestMapping("/backend/v1/admin/log")
|
||||
public class AdminLogController {
|
||||
|
||||
@Autowired private AdminLogService adminLogService;
|
||||
|
||||
@Autowired private BackendBus backendBus;
|
||||
|
||||
@BackendPermission(slug = BPermissionConstant.ADMIN_LOG)
|
||||
@GetMapping("/index")
|
||||
@Log(title = "管理员日志-列表", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse index(@RequestParam HashMap<String, Object> params) {
|
||||
Integer page = MapUtils.getInteger(params, "page", 1);
|
||||
Integer size = MapUtils.getInteger(params, "size", 10);
|
||||
String sortField = MapUtils.getString(params, "sort_field");
|
||||
String sortAlgo = MapUtils.getString(params, "sort_algo");
|
||||
|
||||
Integer adminId = MapUtils.getInteger(params, "admin_id");
|
||||
String adminName = MapUtils.getString(params, "admin_name");
|
||||
String module = MapUtils.getString(params, "module");
|
||||
String title = MapUtils.getString(params, "title");
|
||||
Integer opt = MapUtils.getInteger(params, "opt");
|
||||
String startTime = MapUtils.getString(params, "start_time");
|
||||
String endTime = MapUtils.getString(params, "end_time");
|
||||
|
||||
AdminLogPaginateFiler filter = new AdminLogPaginateFiler();
|
||||
if (backendBus.isSuperAdmin()) {
|
||||
filter.setAdminId(adminId);
|
||||
} else {
|
||||
filter.setAdminId(BCtx.getId());
|
||||
}
|
||||
filter.setAdminName(adminName);
|
||||
filter.setModule(module);
|
||||
filter.setTitle(title);
|
||||
filter.setOpt(opt);
|
||||
filter.setStartTime(startTime);
|
||||
filter.setEndTime(endTime);
|
||||
filter.setSortField(sortField);
|
||||
filter.setSortAlgo(sortAlgo);
|
||||
|
||||
PaginationResult<AdminLog> result = adminLogService.paginate(page, size, filter);
|
||||
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
data.put("data", result.getData());
|
||||
data.put("total", result.getTotal());
|
||||
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermission(slug = BPermissionConstant.ADMIN_LOG)
|
||||
@GetMapping("/detail/{id}")
|
||||
public JsonResponse detail(@PathVariable(name = "id") Integer id) {
|
||||
Integer adminId = 0;
|
||||
if (!backendBus.isSuperAdmin()) {
|
||||
adminId = BCtx.getId();
|
||||
}
|
||||
|
||||
AdminLog log = adminLogService.find(id, adminId);
|
||||
if (log == null) {
|
||||
throw new ServiceException("日志不存在");
|
||||
}
|
||||
return JsonResponse.data(log);
|
||||
}
|
||||
}
|
||||
@@ -21,16 +21,18 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import xyz.playedu.api.constant.BPermissionConstant;
|
||||
import xyz.playedu.api.constant.BackendConstant;
|
||||
import xyz.playedu.api.domain.AdminPermission;
|
||||
import xyz.playedu.api.domain.AdminRole;
|
||||
import xyz.playedu.api.exception.NotFoundException;
|
||||
import xyz.playedu.api.middleware.BackendPermissionMiddleware;
|
||||
import xyz.playedu.api.request.backend.AdminRoleRequest;
|
||||
import xyz.playedu.api.service.AdminPermissionService;
|
||||
import xyz.playedu.api.service.AdminRoleService;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.common.annotation.BackendPermission;
|
||||
import xyz.playedu.common.annotation.Log;
|
||||
import xyz.playedu.common.constant.BPermissionConstant;
|
||||
import xyz.playedu.common.constant.BackendConstant;
|
||||
import xyz.playedu.common.constant.BusinessTypeConstant;
|
||||
import xyz.playedu.common.domain.AdminPermission;
|
||||
import xyz.playedu.common.domain.AdminRole;
|
||||
import xyz.playedu.common.exception.NotFoundException;
|
||||
import xyz.playedu.common.service.AdminPermissionService;
|
||||
import xyz.playedu.common.service.AdminRoleService;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -38,11 +40,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
*
|
||||
* @create 2023/2/21 15:56
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/backend/v1/admin-role")
|
||||
@Slf4j
|
||||
@@ -53,13 +50,15 @@ public class AdminRoleController {
|
||||
@Autowired private AdminPermissionService permissionService;
|
||||
|
||||
@GetMapping("/index")
|
||||
@Log(title = "管理员角色-列表", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse index() {
|
||||
List<AdminRole> data = roleService.list();
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.ADMIN_ROLE)
|
||||
@BackendPermission(slug = BPermissionConstant.ADMIN_ROLE)
|
||||
@GetMapping("/create")
|
||||
@Log(title = "管理员角色-新建", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse create() {
|
||||
List<AdminPermission> permissions = permissionService.listOrderBySortAsc();
|
||||
|
||||
@@ -71,15 +70,17 @@ public class AdminRoleController {
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.ADMIN_ROLE)
|
||||
@BackendPermission(slug = BPermissionConstant.ADMIN_ROLE)
|
||||
@PostMapping("/create")
|
||||
@Log(title = "管理员角色-新建", businessType = BusinessTypeConstant.INSERT)
|
||||
public JsonResponse store(@RequestBody @Validated AdminRoleRequest request) {
|
||||
roleService.createWithPermissionIds(request.getName(), request.getPermissionIds());
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.ADMIN_ROLE)
|
||||
@BackendPermission(slug = BPermissionConstant.ADMIN_ROLE)
|
||||
@GetMapping("/{id}")
|
||||
@Log(title = "管理员角色-编辑", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse edit(@PathVariable(name = "id") Integer id) throws NotFoundException {
|
||||
AdminRole role = roleService.findOrFail(id);
|
||||
|
||||
@@ -111,8 +112,9 @@ public class AdminRoleController {
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.ADMIN_ROLE)
|
||||
@BackendPermission(slug = BPermissionConstant.ADMIN_ROLE)
|
||||
@PutMapping("/{id}")
|
||||
@Log(title = "管理员角色-编辑", businessType = BusinessTypeConstant.UPDATE)
|
||||
public JsonResponse update(
|
||||
@PathVariable(name = "id") Integer id, @RequestBody @Validated AdminRoleRequest request)
|
||||
throws NotFoundException {
|
||||
@@ -126,8 +128,9 @@ public class AdminRoleController {
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.ADMIN_ROLE)
|
||||
@BackendPermission(slug = BPermissionConstant.ADMIN_ROLE)
|
||||
@DeleteMapping("/{id}")
|
||||
@Log(title = "管理员角色-删除", businessType = BusinessTypeConstant.DELETE)
|
||||
public JsonResponse destroy(@PathVariable(name = "id") Integer id) throws NotFoundException {
|
||||
AdminRole role = roleService.findOrFail(id);
|
||||
|
||||
@@ -22,18 +22,20 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import xyz.playedu.api.constant.BPermissionConstant;
|
||||
import xyz.playedu.api.domain.AdminRole;
|
||||
import xyz.playedu.api.domain.AdminUser;
|
||||
import xyz.playedu.api.exception.NotFoundException;
|
||||
import xyz.playedu.api.exception.ServiceException;
|
||||
import xyz.playedu.api.middleware.BackendPermissionMiddleware;
|
||||
import xyz.playedu.api.request.backend.AdminUserRequest;
|
||||
import xyz.playedu.api.service.AdminRoleService;
|
||||
import xyz.playedu.api.service.AdminUserService;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.api.types.paginate.AdminUserPaginateFilter;
|
||||
import xyz.playedu.api.types.paginate.PaginationResult;
|
||||
import xyz.playedu.common.annotation.BackendPermission;
|
||||
import xyz.playedu.common.annotation.Log;
|
||||
import xyz.playedu.common.constant.BPermissionConstant;
|
||||
import xyz.playedu.common.constant.BusinessTypeConstant;
|
||||
import xyz.playedu.common.domain.AdminRole;
|
||||
import xyz.playedu.common.domain.AdminUser;
|
||||
import xyz.playedu.common.exception.NotFoundException;
|
||||
import xyz.playedu.common.exception.ServiceException;
|
||||
import xyz.playedu.common.service.AdminRoleService;
|
||||
import xyz.playedu.common.service.AdminUserService;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.types.paginate.AdminUserPaginateFilter;
|
||||
import xyz.playedu.common.types.paginate.PaginationResult;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -49,8 +51,9 @@ public class AdminUserController {
|
||||
|
||||
@Autowired private AdminRoleService roleService;
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.ADMIN_USER_INDEX)
|
||||
@BackendPermission(slug = BPermissionConstant.ADMIN_USER_INDEX)
|
||||
@GetMapping("/index")
|
||||
@Log(title = "管理员-列表", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse Index(@RequestParam HashMap<String, Object> params) {
|
||||
Integer page = MapUtils.getInteger(params, "page", 1);
|
||||
Integer size = MapUtils.getInteger(params, "size", 10);
|
||||
@@ -81,8 +84,9 @@ public class AdminUserController {
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.ADMIN_USER_CUD)
|
||||
@BackendPermission(slug = BPermissionConstant.ADMIN_USER_CUD)
|
||||
@GetMapping("/create")
|
||||
@Log(title = "管理员-新建", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse create() {
|
||||
List<AdminRole> roles = roleService.list();
|
||||
|
||||
@@ -92,11 +96,12 @@ public class AdminUserController {
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.ADMIN_USER_CUD)
|
||||
@BackendPermission(slug = BPermissionConstant.ADMIN_USER_CUD)
|
||||
@PostMapping("/create")
|
||||
@Log(title = "管理员-新建", businessType = BusinessTypeConstant.INSERT)
|
||||
public JsonResponse store(@RequestBody @Validated AdminUserRequest req)
|
||||
throws ServiceException {
|
||||
if (req.getPassword() == null || req.getPassword().length() == 0) {
|
||||
if (req.getPassword().length() == 0) {
|
||||
return JsonResponse.error("请输入密码");
|
||||
}
|
||||
|
||||
@@ -110,8 +115,9 @@ public class AdminUserController {
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.ADMIN_USER_CUD)
|
||||
@BackendPermission(slug = BPermissionConstant.ADMIN_USER_CUD)
|
||||
@GetMapping("/{id}")
|
||||
@Log(title = "管理员-编辑", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse edit(@PathVariable Integer id) throws NotFoundException {
|
||||
AdminUser adminUser = adminUserService.findOrFail(id);
|
||||
List<Integer> roleIds = adminUserService.getRoleIdsByUserId(adminUser.getId());
|
||||
@@ -123,8 +129,9 @@ public class AdminUserController {
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.ADMIN_USER_CUD)
|
||||
@BackendPermission(slug = BPermissionConstant.ADMIN_USER_CUD)
|
||||
@PutMapping("/{id}")
|
||||
@Log(title = "管理员-编辑", businessType = BusinessTypeConstant.UPDATE)
|
||||
public JsonResponse update(
|
||||
@PathVariable Integer id, @RequestBody @Validated AdminUserRequest req)
|
||||
throws NotFoundException, ServiceException {
|
||||
@@ -139,8 +146,9 @@ public class AdminUserController {
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.ADMIN_USER_CUD)
|
||||
@BackendPermission(slug = BPermissionConstant.ADMIN_USER_CUD)
|
||||
@DeleteMapping("/{id}")
|
||||
@Log(title = "管理员-删除", businessType = BusinessTypeConstant.DELETE)
|
||||
public JsonResponse destroy(@PathVariable Integer id) {
|
||||
adminUserService.removeWithRoleIds(id);
|
||||
return JsonResponse.success();
|
||||
@@ -18,36 +18,36 @@ package xyz.playedu.api.controller.backend;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import xyz.playedu.api.constant.BPermissionConstant;
|
||||
import xyz.playedu.api.constant.SystemConstant;
|
||||
import xyz.playedu.api.domain.AppConfig;
|
||||
import xyz.playedu.api.middleware.BackendPermissionMiddleware;
|
||||
import xyz.playedu.api.request.backend.AppConfigRequest;
|
||||
import xyz.playedu.api.service.AppConfigService;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.common.annotation.BackendPermission;
|
||||
import xyz.playedu.common.annotation.Log;
|
||||
import xyz.playedu.common.constant.BPermissionConstant;
|
||||
import xyz.playedu.common.constant.BusinessTypeConstant;
|
||||
import xyz.playedu.common.constant.ConfigConstant;
|
||||
import xyz.playedu.common.constant.SystemConstant;
|
||||
import xyz.playedu.common.domain.AppConfig;
|
||||
import xyz.playedu.common.service.AppConfigService;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.util.StringUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
*
|
||||
* @create 2023/3/9 11:14
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/backend/v1/app-config")
|
||||
public class AppConfigController {
|
||||
|
||||
@Autowired private AppConfigService configService;
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.SYSTEM_CONFIG)
|
||||
@BackendPermission(slug = BPermissionConstant.SYSTEM_CONFIG)
|
||||
@GetMapping("")
|
||||
@Log(title = "系统配置-读取", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse index() {
|
||||
List<AppConfig> configs = configService.allShow();
|
||||
List<AppConfig> data = new ArrayList<>();
|
||||
for (AppConfig item : configs) {
|
||||
if (item.getIsPrivate() == 1) {
|
||||
if (item.getIsPrivate() == 1 && StringUtil.isNotEmpty(item.getKeyValue())) {
|
||||
item.setKeyValue(SystemConstant.CONFIG_MASK);
|
||||
}
|
||||
data.add(item);
|
||||
@@ -55,17 +55,28 @@ public class AppConfigController {
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.SYSTEM_CONFIG)
|
||||
@BackendPermission(slug = BPermissionConstant.SYSTEM_CONFIG)
|
||||
@PutMapping("")
|
||||
@Log(title = "系统配置-保存", businessType = BusinessTypeConstant.UPDATE)
|
||||
public JsonResponse save(@RequestBody AppConfigRequest req) {
|
||||
HashMap<String, String> data = new HashMap<>();
|
||||
req.getData()
|
||||
.forEach(
|
||||
(key, value) -> {
|
||||
// 过滤掉未变动的private配置
|
||||
if (SystemConstant.CONFIG_MASK.equals(value)) {
|
||||
return;
|
||||
}
|
||||
data.put(key, value);
|
||||
String saveValue = value;
|
||||
|
||||
// LDAP的url配置自动加ldap://处理
|
||||
if (ConfigConstant.LDAP_URL.equals(key)
|
||||
&& StringUtil.isNotEmpty(value)
|
||||
&& !StringUtil.startsWithIgnoreCase(value, "ldap://")) {
|
||||
saveValue = "ldap://" + saveValue;
|
||||
}
|
||||
|
||||
data.put(key, saveValue);
|
||||
});
|
||||
configService.saveFromMap(data);
|
||||
return JsonResponse.data(null);
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (C) 2023 杭州白书科技有限公司
|
||||
*
|
||||
* 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 xyz.playedu.api.controller.backend;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import xyz.playedu.api.request.backend.CourseAttachmentMultiRequest;
|
||||
import xyz.playedu.api.request.backend.CourseAttachmentRequest;
|
||||
import xyz.playedu.api.request.backend.CourseAttachmentSortRequest;
|
||||
import xyz.playedu.common.annotation.BackendPermission;
|
||||
import xyz.playedu.common.annotation.Log;
|
||||
import xyz.playedu.common.constant.BPermissionConstant;
|
||||
import xyz.playedu.common.constant.BackendConstant;
|
||||
import xyz.playedu.common.constant.BusinessTypeConstant;
|
||||
import xyz.playedu.common.exception.NotFoundException;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.course.domain.CourseAttachment;
|
||||
import xyz.playedu.course.service.CourseAttachmentService;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@Slf4j
|
||||
@RequestMapping("/backend/v1/course/{courseId}/attachment")
|
||||
public class CourseAttachmentController {
|
||||
|
||||
@Autowired private CourseAttachmentService attachmentService;
|
||||
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE)
|
||||
@PostMapping("/create")
|
||||
@Log(title = "线上课-附件-新建", businessType = BusinessTypeConstant.INSERT)
|
||||
public JsonResponse store(
|
||||
@PathVariable(name = "courseId") Integer courseId,
|
||||
@RequestBody @Validated CourseAttachmentRequest req)
|
||||
throws NotFoundException {
|
||||
// 附件类型校验
|
||||
String type = req.getType();
|
||||
if (!BackendConstant.RESOURCE_TYPE_ATTACHMENT.contains(type)) {
|
||||
return JsonResponse.error("附件类型不支持");
|
||||
}
|
||||
|
||||
// 课时重复添加校验
|
||||
List<Integer> existsRids = attachmentService.getRidsByCourseId(courseId);
|
||||
if (existsRids != null) {
|
||||
if (existsRids.contains(req.getRid())) {
|
||||
return JsonResponse.error("附件已存在");
|
||||
}
|
||||
}
|
||||
|
||||
CourseAttachment courseAttachment =
|
||||
attachmentService.create(
|
||||
courseId, req.getSort(), req.getTitle(), type, req.getRid());
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE)
|
||||
@PostMapping("/create-batch")
|
||||
@Transactional
|
||||
@Log(title = "线上课-附件-批量新建", businessType = BusinessTypeConstant.INSERT)
|
||||
public JsonResponse storeMulti(
|
||||
@PathVariable(name = "courseId") Integer courseId,
|
||||
@RequestBody @Validated CourseAttachmentMultiRequest req) {
|
||||
if (req.getAttachments().size() == 0) {
|
||||
return JsonResponse.error("参数为空");
|
||||
}
|
||||
|
||||
List<Integer> existsRids = attachmentService.getRidsByCourseId(courseId);
|
||||
|
||||
List<CourseAttachment> attachments = new ArrayList<>();
|
||||
Date now = new Date();
|
||||
|
||||
for (CourseAttachmentMultiRequest.AttachmentItem item : req.getAttachments()) {
|
||||
if (existsRids.contains(item.getRid())) {
|
||||
return JsonResponse.error("附件《" + item.getTitle() + "》已存在");
|
||||
}
|
||||
|
||||
attachments.add(
|
||||
new CourseAttachment() {
|
||||
{
|
||||
setCourseId(courseId);
|
||||
setSort(item.getSort());
|
||||
setType(item.getType());
|
||||
setRid(item.getRid());
|
||||
setTitle(item.getTitle());
|
||||
setCreatedAt(now);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
attachmentService.saveBatch(attachments);
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE)
|
||||
@GetMapping("/{id}")
|
||||
@Log(title = "线上课-附件-编辑", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse edit(
|
||||
@PathVariable(name = "courseId") Integer courseId,
|
||||
@PathVariable(name = "id") Integer id)
|
||||
throws NotFoundException {
|
||||
CourseAttachment courseAttachment = attachmentService.findOrFail(id, courseId);
|
||||
return JsonResponse.data(courseAttachment);
|
||||
}
|
||||
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE)
|
||||
@PutMapping("/{id}")
|
||||
@Log(title = "线上课-附件-编辑", businessType = BusinessTypeConstant.UPDATE)
|
||||
public JsonResponse update(
|
||||
@PathVariable(name = "courseId") Integer courseId,
|
||||
@PathVariable(name = "id") Integer id,
|
||||
@RequestBody @Validated CourseAttachmentRequest req)
|
||||
throws NotFoundException {
|
||||
CourseAttachment courseAttachment = attachmentService.findOrFail(id, courseId);
|
||||
attachmentService.update(courseAttachment, req.getSort(), req.getTitle());
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE)
|
||||
@DeleteMapping("/{id}")
|
||||
@Log(title = "线上课-附件-删除", businessType = BusinessTypeConstant.DELETE)
|
||||
public JsonResponse destroy(
|
||||
@PathVariable(name = "courseId") Integer courseId,
|
||||
@PathVariable(name = "id") Integer id)
|
||||
throws NotFoundException {
|
||||
CourseAttachment courseAttachment = attachmentService.findOrFail(id, courseId);
|
||||
attachmentService.removeById(courseAttachment.getId());
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@PutMapping("/update/sort")
|
||||
@Log(title = "线上课-附件-排序调整", businessType = BusinessTypeConstant.UPDATE)
|
||||
public JsonResponse updateSort(
|
||||
@PathVariable(name = "courseId") Integer courseId,
|
||||
@RequestBody @Validated CourseAttachmentSortRequest req) {
|
||||
attachmentService.updateSort(req.getIds(), courseId);
|
||||
return JsonResponse.success();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2023 杭州白书科技有限公司
|
||||
*
|
||||
* 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 xyz.playedu.api.controller.backend;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import xyz.playedu.common.annotation.Log;
|
||||
import xyz.playedu.common.constant.BusinessTypeConstant;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.types.paginate.CourseAttachmentDownloadLogPaginateFiler;
|
||||
import xyz.playedu.common.types.paginate.PaginationResult;
|
||||
import xyz.playedu.course.domain.CourseAttachmentDownloadLog;
|
||||
import xyz.playedu.course.service.CourseAttachmentDownloadLogService;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@Slf4j
|
||||
@RequestMapping("/backend/v1/course/attachment/download/log")
|
||||
public class CourseAttachmentDownloadLogController {
|
||||
|
||||
@Autowired private CourseAttachmentDownloadLogService courseAttachmentDownloadLogService;
|
||||
|
||||
@GetMapping("/index")
|
||||
@Log(title = "学员下载课件记录-列表", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse index(@RequestParam HashMap<String, Object> params) {
|
||||
Integer page = MapUtils.getInteger(params, "page", 1);
|
||||
Integer size = MapUtils.getInteger(params, "size", 10);
|
||||
String sortField = MapUtils.getString(params, "sort_field");
|
||||
String sortAlgo = MapUtils.getString(params, "sort_algo");
|
||||
|
||||
Integer userId = MapUtils.getInteger(params, "user_id");
|
||||
Integer courseId = MapUtils.getInteger(params, "course_id");
|
||||
String title = MapUtils.getString(params, "title");
|
||||
Integer courserAttachmentId = MapUtils.getInteger(params, "courser_attachment_id");
|
||||
Integer rid = MapUtils.getInteger(params, "rid");
|
||||
|
||||
CourseAttachmentDownloadLogPaginateFiler filter =
|
||||
new CourseAttachmentDownloadLogPaginateFiler();
|
||||
filter.setUserId(userId);
|
||||
filter.setCourseId(courseId);
|
||||
filter.setTitle(title);
|
||||
filter.setCourserAttachmentId(courserAttachmentId);
|
||||
filter.setRid(rid);
|
||||
filter.setSortField(sortField);
|
||||
filter.setSortAlgo(sortAlgo);
|
||||
|
||||
PaginationResult<CourseAttachmentDownloadLog> result =
|
||||
courseAttachmentDownloadLogService.paginate(page, size, filter);
|
||||
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
data.put("data", result.getData());
|
||||
data.put("total", result.getTotal());
|
||||
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
}
|
||||
@@ -20,23 +20,20 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import xyz.playedu.api.BCtx;
|
||||
import xyz.playedu.api.constant.BPermissionConstant;
|
||||
import xyz.playedu.api.domain.CourseChapter;
|
||||
import xyz.playedu.api.event.CourseChapterDestroyEvent;
|
||||
import xyz.playedu.api.exception.NotFoundException;
|
||||
import xyz.playedu.api.middleware.BackendPermissionMiddleware;
|
||||
import xyz.playedu.api.request.backend.CourseChapterRequest;
|
||||
import xyz.playedu.api.request.backend.CourseChapterSortRequest;
|
||||
import xyz.playedu.api.service.CourseChapterService;
|
||||
import xyz.playedu.api.service.CourseHourService;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.common.annotation.BackendPermission;
|
||||
import xyz.playedu.common.annotation.Log;
|
||||
import xyz.playedu.common.constant.BPermissionConstant;
|
||||
import xyz.playedu.common.constant.BusinessTypeConstant;
|
||||
import xyz.playedu.common.context.BCtx;
|
||||
import xyz.playedu.common.exception.NotFoundException;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.course.domain.CourseChapter;
|
||||
import xyz.playedu.course.service.CourseChapterService;
|
||||
import xyz.playedu.course.service.CourseHourService;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
*
|
||||
* @create 2023/2/26 17:28
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/backend/v1/course/{courseId}/chapter")
|
||||
public class CourseChapterController {
|
||||
@@ -47,8 +44,9 @@ public class CourseChapterController {
|
||||
|
||||
@Autowired private ApplicationContext ctx;
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.COURSE)
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE)
|
||||
@PostMapping("/create")
|
||||
@Log(title = "线上课-章节-新建", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse store(
|
||||
@PathVariable(name = "courseId") Integer courseId,
|
||||
@RequestBody @Validated CourseChapterRequest req) {
|
||||
@@ -56,8 +54,9 @@ public class CourseChapterController {
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.COURSE)
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE)
|
||||
@GetMapping("/{id}")
|
||||
@Log(title = "线上课-章节-编辑", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse edit(
|
||||
@PathVariable(name = "courseId") Integer courseId,
|
||||
@PathVariable(name = "id") Integer id)
|
||||
@@ -66,8 +65,9 @@ public class CourseChapterController {
|
||||
return JsonResponse.data(chapter);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.COURSE)
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE)
|
||||
@PutMapping("/{id}")
|
||||
@Log(title = "线上课-章节-编辑", businessType = BusinessTypeConstant.UPDATE)
|
||||
public JsonResponse update(
|
||||
@PathVariable(name = "courseId") Integer courseId,
|
||||
@PathVariable(name = "id") Integer id,
|
||||
@@ -78,8 +78,9 @@ public class CourseChapterController {
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.COURSE)
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE)
|
||||
@DeleteMapping("/{id}")
|
||||
@Log(title = "线上课-章节-删除", businessType = BusinessTypeConstant.DELETE)
|
||||
public JsonResponse destroy(
|
||||
@PathVariable(name = "courseId") Integer courseId,
|
||||
@PathVariable(name = "id") Integer id)
|
||||
@@ -96,6 +97,7 @@ public class CourseChapterController {
|
||||
}
|
||||
|
||||
@PutMapping("/update/sort")
|
||||
@Log(title = "线上课-章节-更新排序", businessType = BusinessTypeConstant.UPDATE)
|
||||
public JsonResponse updateSort(
|
||||
@PathVariable(name = "courseId") Integer courseId,
|
||||
@RequestBody @Validated CourseChapterSortRequest req) {
|
||||
@@ -24,27 +24,34 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import xyz.playedu.api.BCtx;
|
||||
import xyz.playedu.api.constant.BPermissionConstant;
|
||||
import xyz.playedu.api.domain.*;
|
||||
import xyz.playedu.api.event.CourseDestroyEvent;
|
||||
import xyz.playedu.api.exception.NotFoundException;
|
||||
import xyz.playedu.api.middleware.BackendPermissionMiddleware;
|
||||
import xyz.playedu.api.request.backend.CourseRequest;
|
||||
import xyz.playedu.api.service.*;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.api.types.paginate.CoursePaginateFiler;
|
||||
import xyz.playedu.api.types.paginate.PaginationResult;
|
||||
import xyz.playedu.common.annotation.BackendPermission;
|
||||
import xyz.playedu.common.annotation.Log;
|
||||
import xyz.playedu.common.constant.BPermissionConstant;
|
||||
import xyz.playedu.common.constant.BusinessTypeConstant;
|
||||
import xyz.playedu.common.context.BCtx;
|
||||
import xyz.playedu.common.exception.NotFoundException;
|
||||
import xyz.playedu.common.service.*;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.types.paginate.CoursePaginateFiler;
|
||||
import xyz.playedu.common.types.paginate.PaginationResult;
|
||||
import xyz.playedu.course.domain.Course;
|
||||
import xyz.playedu.course.domain.CourseAttachment;
|
||||
import xyz.playedu.course.domain.CourseChapter;
|
||||
import xyz.playedu.course.domain.CourseHour;
|
||||
import xyz.playedu.course.service.CourseAttachmentService;
|
||||
import xyz.playedu.course.service.CourseChapterService;
|
||||
import xyz.playedu.course.service.CourseHourService;
|
||||
import xyz.playedu.course.service.CourseService;
|
||||
import xyz.playedu.resource.domain.Resource;
|
||||
import xyz.playedu.resource.service.ResourceService;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
*
|
||||
* @create 2023/2/24 14:16
|
||||
*/
|
||||
@RestController
|
||||
@Slf4j
|
||||
@RequestMapping("/backend/v1/course")
|
||||
@@ -52,17 +59,23 @@ public class CourseController {
|
||||
|
||||
@Autowired private CourseService courseService;
|
||||
|
||||
@Autowired private ResourceCategoryService categoryService;
|
||||
@Autowired private CategoryService categoryService;
|
||||
|
||||
@Autowired private CourseChapterService chapterService;
|
||||
|
||||
@Autowired private CourseHourService hourService;
|
||||
|
||||
@Autowired private CourseAttachmentService attachmentService;
|
||||
|
||||
@Autowired private ResourceService resourceService;
|
||||
|
||||
@Autowired private DepartmentService departmentService;
|
||||
|
||||
@Autowired private ApplicationContext ctx;
|
||||
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE)
|
||||
@GetMapping("/index")
|
||||
@Log(title = "线上课-列表", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse index(@RequestParam HashMap<String, Object> params) {
|
||||
Integer page = MapUtils.getInteger(params, "page", 1);
|
||||
Integer size = MapUtils.getInteger(params, "size", 10);
|
||||
@@ -97,7 +110,7 @@ public class CourseController {
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.COURSE)
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE)
|
||||
@GetMapping("/create")
|
||||
public JsonResponse create() {
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
@@ -105,11 +118,12 @@ public class CourseController {
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.COURSE)
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE)
|
||||
@PostMapping("/create")
|
||||
@Transactional
|
||||
@Log(title = "线上课-新建", businessType = BusinessTypeConstant.INSERT)
|
||||
public JsonResponse store(@RequestBody @Validated CourseRequest req) throws ParseException {
|
||||
if (req.getShortDesc() != null && req.getShortDesc().length() > 200) {
|
||||
if (req.getShortDesc().length() > 200) {
|
||||
return JsonResponse.error("课程简短介绍不能超过200字");
|
||||
}
|
||||
Course course =
|
||||
@@ -125,7 +139,7 @@ public class CourseController {
|
||||
Date now = new Date();
|
||||
int classHourCount = 0;
|
||||
|
||||
if (req.getHours().size() > 0) { // 无章节课时配置
|
||||
if (!req.getHours().isEmpty()) { // 无章节课时配置
|
||||
List<CourseHour> insertHours = new ArrayList<>();
|
||||
final Integer[] chapterSort = {0};
|
||||
for (CourseRequest.HourItem hourItem : req.getHours()) {
|
||||
@@ -143,12 +157,12 @@ public class CourseController {
|
||||
}
|
||||
});
|
||||
}
|
||||
if (insertHours.size() > 0) {
|
||||
if (!insertHours.isEmpty()) {
|
||||
hourService.saveBatch(insertHours);
|
||||
classHourCount = insertHours.size();
|
||||
}
|
||||
} else {
|
||||
if (req.getChapters() == null || req.getChapters().size() == 0) {
|
||||
if (req.getChapters().isEmpty()) {
|
||||
return JsonResponse.error("请配置课时");
|
||||
}
|
||||
|
||||
@@ -186,7 +200,7 @@ public class CourseController {
|
||||
});
|
||||
}
|
||||
}
|
||||
if (insertHours.size() > 0) {
|
||||
if (!insertHours.isEmpty()) {
|
||||
hourService.saveBatch(insertHours);
|
||||
classHourCount = insertHours.size();
|
||||
}
|
||||
@@ -196,17 +210,57 @@ public class CourseController {
|
||||
courseService.updateClassHour(course.getId(), classHourCount);
|
||||
}
|
||||
|
||||
// 课程附件
|
||||
if (null != req.getAttachments() && !req.getAttachments().isEmpty()) {
|
||||
List<CourseAttachment> insertAttachments = new ArrayList<>();
|
||||
final Integer[] sort = {0};
|
||||
for (CourseRequest.AttachmentItem attachmentItem : req.getAttachments()) {
|
||||
insertAttachments.add(
|
||||
new CourseAttachment() {
|
||||
{
|
||||
setCourseId(course.getId());
|
||||
setSort(sort[0]++);
|
||||
setTitle(attachmentItem.getName());
|
||||
setType(attachmentItem.getType());
|
||||
setRid(attachmentItem.getRid());
|
||||
setCreatedAt(now);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!insertAttachments.isEmpty()) {
|
||||
attachmentService.saveBatch(insertAttachments);
|
||||
}
|
||||
}
|
||||
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.COURSE)
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE)
|
||||
@GetMapping("/{id}")
|
||||
@Log(title = "线上课-编辑", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse edit(@PathVariable(name = "id") Integer id) throws NotFoundException {
|
||||
Course course = courseService.findOrFail(id);
|
||||
List<Integer> depIds = courseService.getDepIdsByCourseId(course.getId());
|
||||
List<Integer> categoryIds = courseService.getCategoryIdsByCourseId(course.getId());
|
||||
List<CourseChapter> chapters = chapterService.getChaptersByCourseId(course.getId());
|
||||
List<CourseHour> hours = hourService.getHoursByCourseId(course.getId());
|
||||
List<CourseAttachment> attachments =
|
||||
attachmentService.getAttachmentsByCourseId(course.getId());
|
||||
if (null != attachments && !attachments.isEmpty()) {
|
||||
Map<Integer, Resource> resourceMap =
|
||||
resourceService
|
||||
.chunks(attachments.stream().map(CourseAttachment::getRid).toList())
|
||||
.stream()
|
||||
.collect(Collectors.toMap(Resource::getId, Function.identity()));
|
||||
attachments.forEach(
|
||||
courseAttachment -> {
|
||||
Resource resource = resourceMap.get(courseAttachment.getRid());
|
||||
if (null != resource) {
|
||||
courseAttachment.setUrl(resource.getUrl());
|
||||
courseAttachment.setExt(resource.getExtension());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
data.put("course", course);
|
||||
@@ -214,13 +268,14 @@ public class CourseController {
|
||||
data.put("category_ids", categoryIds); // 已关联的分类
|
||||
data.put("chapters", chapters);
|
||||
data.put("hours", hours.stream().collect(Collectors.groupingBy(CourseHour::getChapterId)));
|
||||
|
||||
data.put("attachments", attachments);
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.COURSE)
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE)
|
||||
@PutMapping("/{id}")
|
||||
@Transactional
|
||||
@Log(title = "线上课-编辑", businessType = BusinessTypeConstant.UPDATE)
|
||||
public JsonResponse update(
|
||||
@PathVariable(name = "id") Integer id, @RequestBody @Validated CourseRequest req)
|
||||
throws NotFoundException {
|
||||
@@ -232,13 +287,15 @@ public class CourseController {
|
||||
req.getShortDesc(),
|
||||
req.getIsRequired(),
|
||||
req.getIsShow(),
|
||||
req.getPublishedAt(),
|
||||
req.getCategoryIds(),
|
||||
req.getDepIds());
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.COURSE)
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE)
|
||||
@DeleteMapping("/{id}")
|
||||
@Log(title = "线上课-删除", businessType = BusinessTypeConstant.DELETE)
|
||||
public JsonResponse destroy(@PathVariable(name = "id") Integer id) {
|
||||
courseService.removeById(id);
|
||||
ctx.publishEvent(new CourseDestroyEvent(this, BCtx.getId(), id));
|
||||
@@ -23,22 +23,24 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import xyz.playedu.api.BCtx;
|
||||
import xyz.playedu.api.constant.BPermissionConstant;
|
||||
import xyz.playedu.api.constant.BackendConstant;
|
||||
import xyz.playedu.api.domain.CourseChapter;
|
||||
import xyz.playedu.api.domain.CourseHour;
|
||||
import xyz.playedu.api.event.CourseHourCreatedEvent;
|
||||
import xyz.playedu.api.event.CourseHourDestroyEvent;
|
||||
import xyz.playedu.api.exception.NotFoundException;
|
||||
import xyz.playedu.api.middleware.BackendPermissionMiddleware;
|
||||
import xyz.playedu.api.request.backend.CourseHourMultiRequest;
|
||||
import xyz.playedu.api.request.backend.CourseHourRequest;
|
||||
import xyz.playedu.api.request.backend.CourseHourSortRequest;
|
||||
import xyz.playedu.api.service.CourseChapterService;
|
||||
import xyz.playedu.api.service.CourseHourService;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.api.types.SelectOption;
|
||||
import xyz.playedu.common.annotation.BackendPermission;
|
||||
import xyz.playedu.common.annotation.Log;
|
||||
import xyz.playedu.common.constant.BPermissionConstant;
|
||||
import xyz.playedu.common.constant.BackendConstant;
|
||||
import xyz.playedu.common.constant.BusinessTypeConstant;
|
||||
import xyz.playedu.common.context.BCtx;
|
||||
import xyz.playedu.common.exception.NotFoundException;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.types.SelectOption;
|
||||
import xyz.playedu.course.domain.CourseChapter;
|
||||
import xyz.playedu.course.domain.CourseHour;
|
||||
import xyz.playedu.course.service.CourseChapterService;
|
||||
import xyz.playedu.course.service.CourseHourService;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -58,8 +60,9 @@ public class CourseHourController {
|
||||
|
||||
@Autowired private ApplicationContext ctx;
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.COURSE)
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE)
|
||||
@GetMapping("/create")
|
||||
@Log(title = "线上课-课时-新建", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse create(@PathVariable(name = "courseId") Integer courseId) {
|
||||
// 课时类型
|
||||
List<SelectOption<String>> typeItems = new ArrayList<>();
|
||||
@@ -81,8 +84,9 @@ public class CourseHourController {
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.COURSE)
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE)
|
||||
@PostMapping("/create")
|
||||
@Log(title = "线上课-课时-新建", businessType = BusinessTypeConstant.INSERT)
|
||||
public JsonResponse store(
|
||||
@PathVariable(name = "courseId") Integer courseId,
|
||||
@RequestBody @Validated CourseHourRequest req)
|
||||
@@ -124,9 +128,10 @@ public class CourseHourController {
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.COURSE)
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE)
|
||||
@PostMapping("/create-batch")
|
||||
@Transactional
|
||||
@Log(title = "线上课-课时-批量导入", businessType = BusinessTypeConstant.INSERT)
|
||||
public JsonResponse storeMulti(
|
||||
@PathVariable(name = "courseId") Integer courseId,
|
||||
@RequestBody @Validated CourseHourMultiRequest req) {
|
||||
@@ -175,8 +180,9 @@ public class CourseHourController {
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.COURSE)
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE)
|
||||
@GetMapping("/{id}")
|
||||
@Log(title = "线上课-课时-编辑", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse edit(
|
||||
@PathVariable(name = "courseId") Integer courseId,
|
||||
@PathVariable(name = "id") Integer id)
|
||||
@@ -185,8 +191,9 @@ public class CourseHourController {
|
||||
return JsonResponse.data(courseHour);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.COURSE)
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE)
|
||||
@PutMapping("/{id}")
|
||||
@Log(title = "线上课-课时-编辑", businessType = BusinessTypeConstant.UPDATE)
|
||||
public JsonResponse update(
|
||||
@PathVariable(name = "courseId") Integer courseId,
|
||||
@PathVariable(name = "id") Integer id,
|
||||
@@ -201,8 +208,9 @@ public class CourseHourController {
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.COURSE)
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE)
|
||||
@DeleteMapping("/{id}")
|
||||
@Log(title = "线上课-课时-删除", businessType = BusinessTypeConstant.DELETE)
|
||||
public JsonResponse destroy(
|
||||
@PathVariable(name = "courseId") Integer courseId,
|
||||
@PathVariable(name = "id") Integer id)
|
||||
@@ -220,6 +228,7 @@ public class CourseHourController {
|
||||
}
|
||||
|
||||
@PutMapping("/update/sort")
|
||||
@Log(title = "线上课-课时-更新排序", businessType = BusinessTypeConstant.UPDATE)
|
||||
public JsonResponse updateSort(
|
||||
@PathVariable(name = "courseId") Integer courseId,
|
||||
@RequestBody @Validated CourseHourSortRequest req) {
|
||||
@@ -24,17 +24,22 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import xyz.playedu.api.constant.BPermissionConstant;
|
||||
import xyz.playedu.api.domain.User;
|
||||
import xyz.playedu.api.domain.UserCourseRecord;
|
||||
import xyz.playedu.api.event.UserCourseRecordDestroyEvent;
|
||||
import xyz.playedu.api.middleware.BackendPermissionMiddleware;
|
||||
import xyz.playedu.api.request.backend.CourseUserDestroyRequest;
|
||||
import xyz.playedu.api.service.*;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.api.types.mapper.UserCourseHourRecordUserFirstCreatedAtMapper;
|
||||
import xyz.playedu.api.types.paginate.PaginationResult;
|
||||
import xyz.playedu.api.types.paginate.UserPaginateFilter;
|
||||
import xyz.playedu.common.annotation.BackendPermission;
|
||||
import xyz.playedu.common.annotation.Log;
|
||||
import xyz.playedu.common.constant.BPermissionConstant;
|
||||
import xyz.playedu.common.constant.BusinessTypeConstant;
|
||||
import xyz.playedu.common.domain.User;
|
||||
import xyz.playedu.common.service.*;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.types.mapper.UserCourseHourRecordUserFirstCreatedAtMapper;
|
||||
import xyz.playedu.common.types.paginate.PaginationResult;
|
||||
import xyz.playedu.common.types.paginate.UserPaginateFilter;
|
||||
import xyz.playedu.course.domain.UserCourseRecord;
|
||||
import xyz.playedu.course.service.CourseService;
|
||||
import xyz.playedu.course.service.UserCourseHourRecordService;
|
||||
import xyz.playedu.course.service.UserCourseRecordService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -63,9 +68,10 @@ public class CourseUserController {
|
||||
|
||||
@Autowired private ApplicationContext ctx;
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.COURSE_USER)
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE_USER)
|
||||
@GetMapping("/index")
|
||||
@SneakyThrows
|
||||
@Log(title = "线上课-学习记录-列表", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse index(
|
||||
@PathVariable(name = "courseId") Integer courseId,
|
||||
@RequestParam HashMap<String, Object> params) {
|
||||
@@ -138,8 +144,9 @@ public class CourseUserController {
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.COURSE_USER_DESTROY)
|
||||
@BackendPermission(slug = BPermissionConstant.COURSE_USER_DESTROY)
|
||||
@PostMapping("/destroy")
|
||||
@Log(title = "线上课-学习记录-删除", businessType = BusinessTypeConstant.DELETE)
|
||||
public JsonResponse destroy(
|
||||
@PathVariable(name = "courseId") Integer courseId,
|
||||
@RequestBody @Validated CourseUserDestroyRequest req) {
|
||||
@@ -20,12 +20,17 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import xyz.playedu.api.constant.BackendConstant;
|
||||
import xyz.playedu.api.constant.SystemConstant;
|
||||
import xyz.playedu.api.domain.User;
|
||||
import xyz.playedu.api.domain.UserLearnDurationStats;
|
||||
import xyz.playedu.api.service.*;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.common.annotation.Log;
|
||||
import xyz.playedu.common.constant.BackendConstant;
|
||||
import xyz.playedu.common.constant.BusinessTypeConstant;
|
||||
import xyz.playedu.common.constant.SystemConstant;
|
||||
import xyz.playedu.common.domain.User;
|
||||
import xyz.playedu.common.service.*;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.course.domain.UserLearnDurationStats;
|
||||
import xyz.playedu.course.service.CourseService;
|
||||
import xyz.playedu.course.service.UserLearnDurationStatsService;
|
||||
import xyz.playedu.resource.service.ResourceService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -44,7 +49,7 @@ public class DashboardController {
|
||||
|
||||
@Autowired private AdminUserService adminUserService;
|
||||
|
||||
@Autowired private ResourceCategoryService resourceCategoryService;
|
||||
@Autowired private CategoryService categoryService;
|
||||
|
||||
@Autowired private UserService userService;
|
||||
|
||||
@@ -57,6 +62,7 @@ public class DashboardController {
|
||||
@Autowired private UserLearnDurationStatsService userLearnDurationStatsService;
|
||||
|
||||
@GetMapping("/index")
|
||||
@Log(title = "主面板", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse index() {
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
data.put("version", SystemConstant.VERSION);
|
||||
@@ -68,7 +74,7 @@ public class DashboardController {
|
||||
data.put("course_total", courseService.total()); // 线上课数量
|
||||
|
||||
data.put("department_total", departmentService.total());
|
||||
data.put("resource_category_total", resourceCategoryService.total());
|
||||
data.put("resource_category_total", categoryService.total());
|
||||
data.put("admin_user_total", adminUserService.total());
|
||||
|
||||
data.put(
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package xyz.playedu.api.controller.backend;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
@@ -23,32 +24,35 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import xyz.playedu.api.BCtx;
|
||||
import xyz.playedu.api.constant.BPermissionConstant;
|
||||
import xyz.playedu.api.domain.Course;
|
||||
import xyz.playedu.api.domain.Department;
|
||||
import xyz.playedu.api.domain.User;
|
||||
import xyz.playedu.api.domain.UserCourseRecord;
|
||||
import xyz.playedu.api.event.DepartmentDestroyEvent;
|
||||
import xyz.playedu.api.exception.NotFoundException;
|
||||
import xyz.playedu.api.middleware.BackendPermissionMiddleware;
|
||||
import xyz.playedu.api.request.backend.*;
|
||||
import xyz.playedu.api.service.CourseService;
|
||||
import xyz.playedu.api.service.DepartmentService;
|
||||
import xyz.playedu.api.service.UserCourseRecordService;
|
||||
import xyz.playedu.api.service.UserService;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.api.types.paginate.PaginationResult;
|
||||
import xyz.playedu.api.types.paginate.UserPaginateFilter;
|
||||
import xyz.playedu.api.request.backend.DepartmentParentRequest;
|
||||
import xyz.playedu.api.request.backend.DepartmentRequest;
|
||||
import xyz.playedu.api.request.backend.DepartmentSortRequest;
|
||||
import xyz.playedu.common.annotation.BackendPermission;
|
||||
import xyz.playedu.common.annotation.Log;
|
||||
import xyz.playedu.common.constant.BPermissionConstant;
|
||||
import xyz.playedu.common.constant.BusinessTypeConstant;
|
||||
import xyz.playedu.common.context.BCtx;
|
||||
import xyz.playedu.common.domain.Department;
|
||||
import xyz.playedu.common.domain.User;
|
||||
import xyz.playedu.common.exception.NotFoundException;
|
||||
import xyz.playedu.common.service.AppConfigService;
|
||||
import xyz.playedu.common.service.DepartmentService;
|
||||
import xyz.playedu.common.service.UserService;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.types.LdapConfig;
|
||||
import xyz.playedu.common.types.paginate.PaginationResult;
|
||||
import xyz.playedu.common.types.paginate.UserPaginateFilter;
|
||||
import xyz.playedu.common.util.ldap.LdapUtil;
|
||||
import xyz.playedu.course.domain.Course;
|
||||
import xyz.playedu.course.domain.UserCourseRecord;
|
||||
import xyz.playedu.course.service.CourseDepartmentService;
|
||||
import xyz.playedu.course.service.CourseService;
|
||||
import xyz.playedu.course.service.UserCourseRecordService;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
*
|
||||
* @create 2023/2/19 10:33
|
||||
*/
|
||||
@RestController
|
||||
@Slf4j
|
||||
@RequestMapping("/backend/v1/department")
|
||||
@@ -56,6 +60,8 @@ public class DepartmentController {
|
||||
|
||||
@Autowired private DepartmentService departmentService;
|
||||
|
||||
@Autowired private CourseDepartmentService courseDepartmentService;
|
||||
|
||||
@Autowired private UserService userService;
|
||||
|
||||
@Autowired private CourseService courseService;
|
||||
@@ -64,7 +70,10 @@ public class DepartmentController {
|
||||
|
||||
@Autowired private ApplicationContext ctx;
|
||||
|
||||
@Autowired private AppConfigService appConfigService;
|
||||
|
||||
@GetMapping("/index")
|
||||
@Log(title = "部门-列表", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse index() {
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
data.put("departments", departmentService.groupByParent());
|
||||
@@ -74,48 +83,63 @@ public class DepartmentController {
|
||||
}
|
||||
|
||||
@GetMapping("/departments")
|
||||
@Log(title = "部门-全部部门", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse index(
|
||||
@RequestParam(name = "parent_id", defaultValue = "0") Integer parentId) {
|
||||
List<Department> departments = departmentService.listByParentId(parentId);
|
||||
return JsonResponse.data(departments);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.DEPARTMENT_CUD)
|
||||
@BackendPermission(slug = BPermissionConstant.DEPARTMENT_CUD)
|
||||
@GetMapping("/create")
|
||||
@Log(title = "部门-新建", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse create() {
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
data.put("departments", departmentService.groupByParent());
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.DEPARTMENT_CUD)
|
||||
@BackendPermission(slug = BPermissionConstant.DEPARTMENT_CUD)
|
||||
@PostMapping("/create")
|
||||
@Log(title = "部门-新建", businessType = BusinessTypeConstant.INSERT)
|
||||
public JsonResponse store(@RequestBody @Validated DepartmentRequest req)
|
||||
throws NotFoundException {
|
||||
if (appConfigService.enabledLdapLogin()) {
|
||||
return JsonResponse.error("已启用LDAP服务,禁止添加部门");
|
||||
}
|
||||
departmentService.create(req.getName(), req.getParentId(), req.getSort());
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.DEPARTMENT_CUD)
|
||||
@BackendPermission(slug = BPermissionConstant.DEPARTMENT_CUD)
|
||||
@GetMapping("/{id}")
|
||||
@Log(title = "部门-编辑", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse edit(@PathVariable Integer id) throws NotFoundException {
|
||||
Department department = departmentService.findOrFail(id);
|
||||
return JsonResponse.data(department);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.DEPARTMENT_CUD)
|
||||
@BackendPermission(slug = BPermissionConstant.DEPARTMENT_CUD)
|
||||
@PutMapping("/{id}")
|
||||
@Log(title = "部门-编辑", businessType = BusinessTypeConstant.UPDATE)
|
||||
public JsonResponse update(@PathVariable Integer id, @RequestBody DepartmentRequest req)
|
||||
throws NotFoundException {
|
||||
if (appConfigService.enabledLdapLogin()) {
|
||||
return JsonResponse.error("已启用LDAP服务,禁止添加部门");
|
||||
}
|
||||
Department department = departmentService.findOrFail(id);
|
||||
departmentService.update(department, req.getName(), req.getParentId(), req.getSort());
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.DEPARTMENT_CUD)
|
||||
@BackendPermission(slug = BPermissionConstant.DEPARTMENT_CUD)
|
||||
@GetMapping("/{id}/destroy")
|
||||
@Log(title = "部门-批量删除", businessType = BusinessTypeConstant.DELETE)
|
||||
public JsonResponse preDestroy(@PathVariable Integer id) {
|
||||
List<Integer> courseIds = departmentService.getCourseIdsByDepId(id);
|
||||
if (appConfigService.enabledLdapLogin()) {
|
||||
return JsonResponse.error("已启用LDAP服务,禁止添加部门");
|
||||
}
|
||||
List<Integer> courseIds = courseDepartmentService.getCourseIdsByDepId(id);
|
||||
List<Integer> userIds = departmentService.getUserIdsByDepId(id);
|
||||
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
@@ -123,7 +147,7 @@ public class DepartmentController {
|
||||
data.put("users", new ArrayList<>());
|
||||
data.put("children", departmentService.listByParentId(id));
|
||||
|
||||
if (courseIds != null && courseIds.size() > 0) {
|
||||
if (courseIds != null && !courseIds.isEmpty()) {
|
||||
data.put(
|
||||
"courses",
|
||||
courseService.chunks(
|
||||
@@ -135,7 +159,7 @@ public class DepartmentController {
|
||||
}
|
||||
}));
|
||||
}
|
||||
if (userIds != null && userIds.size() > 0) {
|
||||
if (userIds != null && !userIds.isEmpty()) {
|
||||
data.put(
|
||||
"users",
|
||||
userService.chunks(
|
||||
@@ -152,32 +176,42 @@ public class DepartmentController {
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.DEPARTMENT_CUD)
|
||||
@BackendPermission(slug = BPermissionConstant.DEPARTMENT_CUD)
|
||||
@DeleteMapping("/{id}")
|
||||
@Log(title = "部门-删除", businessType = BusinessTypeConstant.DELETE)
|
||||
public JsonResponse destroy(@PathVariable Integer id) throws NotFoundException {
|
||||
if (appConfigService.enabledLdapLogin()) {
|
||||
return JsonResponse.error("已启用LDAP服务,禁止添加部门");
|
||||
}
|
||||
Department department = departmentService.findOrFail(id);
|
||||
departmentService.destroy(department.getId());
|
||||
ctx.publishEvent(new DepartmentDestroyEvent(this, BCtx.getId(), department.getId()));
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.DEPARTMENT_CUD)
|
||||
@BackendPermission(slug = BPermissionConstant.DEPARTMENT_CUD)
|
||||
@PutMapping("/update/sort")
|
||||
@Log(title = "部门-更新排序", businessType = BusinessTypeConstant.UPDATE)
|
||||
public JsonResponse resort(@RequestBody @Validated DepartmentSortRequest req) {
|
||||
departmentService.resetSort(req.getIds());
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.DEPARTMENT_CUD)
|
||||
@BackendPermission(slug = BPermissionConstant.DEPARTMENT_CUD)
|
||||
@PutMapping("/update/parent")
|
||||
@Log(title = "部门-更新父级", businessType = BusinessTypeConstant.UPDATE)
|
||||
public JsonResponse updateParent(@RequestBody @Validated DepartmentParentRequest req)
|
||||
throws NotFoundException {
|
||||
if (appConfigService.enabledLdapLogin()) {
|
||||
return JsonResponse.error("已启用LDAP服务,禁止添加部门");
|
||||
}
|
||||
departmentService.changeParent(req.getId(), req.getParentId(), req.getIds());
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.DEPARTMENT_USER_LEARN)
|
||||
@BackendPermission(slug = BPermissionConstant.DEPARTMENT_USER_LEARN)
|
||||
@GetMapping("/{id}/users")
|
||||
@Log(title = "部门-学员", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse users(
|
||||
@PathVariable(name = "id") Integer id, @RequestParam HashMap<String, Object> params) {
|
||||
Integer page = MapUtils.getInteger(params, "page", 1);
|
||||
@@ -213,7 +247,7 @@ public class DepartmentController {
|
||||
PaginationResult<User> users = userService.paginate(page, size, filter);
|
||||
|
||||
List<Course> courses;
|
||||
if (courseIdsStr != null && courseIdsStr.trim().length() > 0) {
|
||||
if (courseIdsStr != null && !courseIdsStr.trim().isEmpty()) {
|
||||
// 指定了需要显示的线上课
|
||||
courses =
|
||||
courseService.chunks(
|
||||
@@ -275,4 +309,63 @@ public class DepartmentController {
|
||||
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermission(slug = BPermissionConstant.DEPARTMENT_CUD)
|
||||
@PostMapping("/ldap-sync")
|
||||
@Log(title = "部门-LDAP同步", businessType = BusinessTypeConstant.INSERT)
|
||||
@SneakyThrows
|
||||
public JsonResponse ldapSync() {
|
||||
LdapConfig ldapConfig = appConfigService.ldapConfig();
|
||||
|
||||
List<String> ouList =
|
||||
LdapUtil.departments(
|
||||
ldapConfig.getUrl(),
|
||||
ldapConfig.getAdminUser(),
|
||||
ldapConfig.getAdminPass(),
|
||||
ldapConfig.getBaseDN());
|
||||
|
||||
if (ouList == null || ouList.isEmpty()) {
|
||||
return JsonResponse.error("部门为空");
|
||||
}
|
||||
|
||||
HashMap<String, Integer> depIdKeyByName = new HashMap<>();
|
||||
Integer sort = 0;
|
||||
|
||||
for (String department : ouList) {
|
||||
String[] tmp = department.toLowerCase().split(",");
|
||||
String prevName = "";
|
||||
for (String s : tmp) {
|
||||
// 控制部门排序
|
||||
sort++;
|
||||
// 当前的子部门名
|
||||
String tmpName = s.replace("ou=", "");
|
||||
// 父部门id
|
||||
Integer parentId = 0;
|
||||
// 部门的链名=>父部门1,父部门2,子部门
|
||||
String fullName = tmpName;
|
||||
if (!prevName.isEmpty()) {
|
||||
fullName = prevName + "," + tmpName;
|
||||
parentId = depIdKeyByName.get(prevName);
|
||||
}
|
||||
|
||||
// 检查是否已经创建
|
||||
Integer depId = depIdKeyByName.get(tmpName);
|
||||
if (depId == null) {
|
||||
// 检查是否已经创建
|
||||
Department tmpDep = departmentService.findByName(tmpName, parentId);
|
||||
if (tmpDep == null) {
|
||||
// 创建部门
|
||||
Integer tmpDepId = departmentService.create(tmpName, parentId, sort);
|
||||
depIdKeyByName.put(fullName, tmpDepId);
|
||||
} else {
|
||||
depIdKeyByName.put(fullName, tmpDep.getId());
|
||||
}
|
||||
}
|
||||
|
||||
prevName = fullName;
|
||||
}
|
||||
}
|
||||
|
||||
return JsonResponse.success();
|
||||
}
|
||||
}
|
||||
@@ -20,21 +20,25 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import xyz.playedu.api.BCtx;
|
||||
import xyz.playedu.api.bus.BackendBus;
|
||||
import xyz.playedu.api.constant.BPermissionConstant;
|
||||
import xyz.playedu.api.domain.AdminUser;
|
||||
import xyz.playedu.api.event.AdminUserLoginEvent;
|
||||
import xyz.playedu.api.middleware.BackendPermissionMiddleware;
|
||||
import xyz.playedu.api.middleware.ImageCaptchaCheckMiddleware;
|
||||
import xyz.playedu.api.request.backend.LoginRequest;
|
||||
import xyz.playedu.api.request.backend.PasswordChangeRequest;
|
||||
import xyz.playedu.api.service.AdminUserService;
|
||||
import xyz.playedu.api.service.BackendAuthService;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.api.util.HelperUtil;
|
||||
import xyz.playedu.api.util.IpUtil;
|
||||
import xyz.playedu.api.util.RequestUtil;
|
||||
import xyz.playedu.common.annotation.BackendPermission;
|
||||
import xyz.playedu.common.annotation.Log;
|
||||
import xyz.playedu.common.bus.BackendBus;
|
||||
import xyz.playedu.common.config.PlayEduConfig;
|
||||
import xyz.playedu.common.constant.BPermissionConstant;
|
||||
import xyz.playedu.common.constant.BusinessTypeConstant;
|
||||
import xyz.playedu.common.context.BCtx;
|
||||
import xyz.playedu.common.domain.AdminUser;
|
||||
import xyz.playedu.common.service.AdminUserService;
|
||||
import xyz.playedu.common.service.BackendAuthService;
|
||||
import xyz.playedu.common.service.RateLimiterService;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.util.HelperUtil;
|
||||
import xyz.playedu.common.util.IpUtil;
|
||||
import xyz.playedu.common.util.RedisUtil;
|
||||
import xyz.playedu.common.util.RequestUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -50,20 +54,36 @@ public class LoginController {
|
||||
|
||||
@Autowired private ApplicationContext ctx;
|
||||
|
||||
@Autowired private RateLimiterService rateLimiterService;
|
||||
|
||||
@Autowired private PlayEduConfig playEduConfig;
|
||||
|
||||
@PostMapping("/login")
|
||||
@ImageCaptchaCheckMiddleware
|
||||
@Log(title = "管理员-登录", businessType = BusinessTypeConstant.LOGIN)
|
||||
public JsonResponse login(@RequestBody @Validated LoginRequest loginRequest) {
|
||||
AdminUser adminUser = adminUserService.findByEmail(loginRequest.email);
|
||||
if (adminUser == null) {
|
||||
return JsonResponse.error("邮箱或密码错误");
|
||||
}
|
||||
|
||||
String limitKey = "admin-login-limit:" + loginRequest.getEmail();
|
||||
Long reqCount = rateLimiterService.current(limitKey, 3600L);
|
||||
if (reqCount > 5 && !playEduConfig.getTesting()) {
|
||||
Long exp = RedisUtil.ttlWithoutPrefix(limitKey);
|
||||
return JsonResponse.error(
|
||||
String.format("您的账号已被锁定,请%s后重试", exp > 60 ? exp / 60 + "分钟" : exp + "秒"));
|
||||
}
|
||||
|
||||
String password =
|
||||
HelperUtil.MD5(loginRequest.getPassword() + adminUser.getSalt()).toLowerCase();
|
||||
if (!adminUser.getPassword().equals(password)) {
|
||||
return JsonResponse.error("邮箱或密码错误");
|
||||
}
|
||||
|
||||
RedisUtil.del(limitKey);
|
||||
|
||||
if (adminUser.getIsBanLogin().equals(1)) {
|
||||
return JsonResponse.error("当前用户已禁止登录");
|
||||
return JsonResponse.error("当前管理员已禁止登录");
|
||||
}
|
||||
|
||||
String token = authService.loginUsingId(adminUser.getId(), RequestUtil.url());
|
||||
@@ -83,12 +103,14 @@ public class LoginController {
|
||||
}
|
||||
|
||||
@PostMapping("/logout")
|
||||
@Log(title = "管理员-登出", businessType = BusinessTypeConstant.LOGOUT)
|
||||
public JsonResponse logout() {
|
||||
authService.logout();
|
||||
return JsonResponse.success("success");
|
||||
}
|
||||
|
||||
@GetMapping("/detail")
|
||||
@Log(title = "管理员-详情", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse detail() {
|
||||
AdminUser user = BCtx.getAdminUser();
|
||||
HashMap<String, Boolean> permissions = backendBus.adminUserPermissions(user.getId());
|
||||
@@ -100,8 +122,9 @@ public class LoginController {
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.PASSWORD_CHANGE)
|
||||
@BackendPermission(slug = BPermissionConstant.PASSWORD_CHANGE)
|
||||
@PutMapping("/password")
|
||||
@Log(title = "管理员-密码修改", businessType = BusinessTypeConstant.UPDATE)
|
||||
public JsonResponse changePassword(@RequestBody @Validated PasswordChangeRequest req) {
|
||||
AdminUser user = BCtx.getAdminUser();
|
||||
String password = HelperUtil.MD5(req.getOldPassword() + user.getSalt());
|
||||
@@ -20,21 +20,25 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import xyz.playedu.api.BCtx;
|
||||
import xyz.playedu.api.constant.BPermissionConstant;
|
||||
import xyz.playedu.api.constant.BackendConstant;
|
||||
import xyz.playedu.api.domain.Resource;
|
||||
import xyz.playedu.api.domain.ResourceCategory;
|
||||
import xyz.playedu.api.event.ResourceCategoryDestroyEvent;
|
||||
import xyz.playedu.api.exception.NotFoundException;
|
||||
import xyz.playedu.api.middleware.BackendPermissionMiddleware;
|
||||
import xyz.playedu.api.request.backend.ResourceCategoryParentRequest;
|
||||
import xyz.playedu.api.request.backend.ResourceCategoryRequest;
|
||||
import xyz.playedu.api.request.backend.ResourceCategorySortRequest;
|
||||
import xyz.playedu.api.service.CourseService;
|
||||
import xyz.playedu.api.service.ResourceCategoryService;
|
||||
import xyz.playedu.api.service.ResourceService;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.common.annotation.BackendPermission;
|
||||
import xyz.playedu.common.annotation.Log;
|
||||
import xyz.playedu.common.constant.BPermissionConstant;
|
||||
import xyz.playedu.common.constant.BackendConstant;
|
||||
import xyz.playedu.common.constant.BusinessTypeConstant;
|
||||
import xyz.playedu.common.context.BCtx;
|
||||
import xyz.playedu.common.domain.Category;
|
||||
import xyz.playedu.common.exception.NotFoundException;
|
||||
import xyz.playedu.common.service.CategoryService;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.course.service.CourseCategoryService;
|
||||
import xyz.playedu.course.service.CourseService;
|
||||
import xyz.playedu.resource.domain.Resource;
|
||||
import xyz.playedu.resource.service.ResourceCategoryService;
|
||||
import xyz.playedu.resource.service.ResourceService;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -48,15 +52,20 @@ import java.util.stream.Collectors;
|
||||
@RequestMapping("/backend/v1/resource-category")
|
||||
public class ResourceCategoryController {
|
||||
|
||||
@Autowired private ResourceCategoryService categoryService;
|
||||
@Autowired private CategoryService categoryService;
|
||||
|
||||
@Autowired private CourseService courseService;
|
||||
|
||||
@Autowired private ResourceService resourceService;
|
||||
|
||||
@Autowired private ResourceCategoryService resourceCategoryService;
|
||||
|
||||
@Autowired private CourseCategoryService courseCategoryService;
|
||||
|
||||
@Autowired private ApplicationContext ctx;
|
||||
|
||||
@GetMapping("/index")
|
||||
@Log(title = "资源-分类-列表", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse index() {
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
data.put("categories", categoryService.groupByParent());
|
||||
@@ -64,48 +73,54 @@ public class ResourceCategoryController {
|
||||
}
|
||||
|
||||
@GetMapping("/categories")
|
||||
@Log(title = "资源-分类-全部分类", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse index(
|
||||
@RequestParam(name = "parent_id", defaultValue = "0") Integer parentId) {
|
||||
List<ResourceCategory> categories = categoryService.listByParentId(parentId);
|
||||
List<Category> categories = categoryService.listByParentId(parentId);
|
||||
return JsonResponse.data(categories);
|
||||
}
|
||||
|
||||
@GetMapping("/create")
|
||||
@Log(title = "资源-分类-新建", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse create() {
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
data.put("categories", categoryService.groupByParent());
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.RESOURCE_CATEGORY)
|
||||
@BackendPermission(slug = BPermissionConstant.RESOURCE_CATEGORY)
|
||||
@PostMapping("/create")
|
||||
@Log(title = "资源-分类-新建", businessType = BusinessTypeConstant.INSERT)
|
||||
public JsonResponse store(@RequestBody @Validated ResourceCategoryRequest req)
|
||||
throws NotFoundException {
|
||||
categoryService.create(req.getName(), req.getParentId(), req.getSort());
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.RESOURCE_CATEGORY)
|
||||
@BackendPermission(slug = BPermissionConstant.RESOURCE_CATEGORY)
|
||||
@GetMapping("/{id}")
|
||||
@Log(title = "资源-分类-编辑", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse edit(@PathVariable Integer id) throws NotFoundException {
|
||||
ResourceCategory category = categoryService.findOrFail(id);
|
||||
Category category = categoryService.findOrFail(id);
|
||||
return JsonResponse.data(category);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.RESOURCE_CATEGORY)
|
||||
@BackendPermission(slug = BPermissionConstant.RESOURCE_CATEGORY)
|
||||
@PutMapping("/{id}")
|
||||
@Log(title = "资源-分类-编辑", businessType = BusinessTypeConstant.UPDATE)
|
||||
public JsonResponse update(@PathVariable Integer id, @RequestBody ResourceCategoryRequest req)
|
||||
throws NotFoundException {
|
||||
ResourceCategory category = categoryService.findOrFail(id);
|
||||
Category category = categoryService.findOrFail(id);
|
||||
categoryService.update(category, req.getName(), req.getParentId(), req.getSort());
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.RESOURCE_CATEGORY)
|
||||
@BackendPermission(slug = BPermissionConstant.RESOURCE_CATEGORY)
|
||||
@GetMapping("/{id}/destroy")
|
||||
@Log(title = "资源-分类-批量删除", businessType = BusinessTypeConstant.DELETE)
|
||||
public JsonResponse preDestroy(@PathVariable Integer id) {
|
||||
List<Integer> courseIds = categoryService.getCourseIdsById(id);
|
||||
List<Integer> rids = categoryService.getRidsById(id);
|
||||
List<Integer> courseIds = courseCategoryService.getCourseIdsByCategoryId(id);
|
||||
List<Integer> rids = resourceCategoryService.getRidsByCategoryId(id);
|
||||
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
data.put("children", categoryService.listByParentId(id));
|
||||
@@ -149,22 +164,27 @@ public class ResourceCategoryController {
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.RESOURCE_CATEGORY)
|
||||
@BackendPermission(slug = BPermissionConstant.RESOURCE_CATEGORY)
|
||||
@DeleteMapping("/{id}")
|
||||
@Log(title = "资源-分类-删除", businessType = BusinessTypeConstant.DELETE)
|
||||
public JsonResponse destroy(@PathVariable Integer id) throws NotFoundException {
|
||||
ResourceCategory category = categoryService.findOrFail(id);
|
||||
Category category = categoryService.findOrFail(id);
|
||||
categoryService.deleteById(category.getId());
|
||||
ctx.publishEvent(new ResourceCategoryDestroyEvent(this, BCtx.getId(), category.getId()));
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermission(slug = BPermissionConstant.RESOURCE_CATEGORY)
|
||||
@PutMapping("/update/sort")
|
||||
@Log(title = "资源-分类-更新排序", businessType = BusinessTypeConstant.UPDATE)
|
||||
public JsonResponse resort(@RequestBody @Validated ResourceCategorySortRequest req) {
|
||||
categoryService.resetSort(req.getIds());
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermission(slug = BPermissionConstant.RESOURCE_CATEGORY)
|
||||
@PutMapping("/update/parent")
|
||||
@Log(title = "资源-分类-更新父级", businessType = BusinessTypeConstant.UPDATE)
|
||||
public JsonResponse updateParent(@RequestBody @Validated ResourceCategoryParentRequest req)
|
||||
throws NotFoundException {
|
||||
categoryService.changeParent(req.getId(), req.getParentId(), req.getIds());
|
||||
@@ -23,23 +23,25 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import xyz.playedu.api.BCtx;
|
||||
import xyz.playedu.api.bus.BackendBus;
|
||||
import xyz.playedu.api.constant.BackendConstant;
|
||||
import xyz.playedu.api.domain.AdminUser;
|
||||
import xyz.playedu.api.domain.Resource;
|
||||
import xyz.playedu.api.domain.ResourceVideo;
|
||||
import xyz.playedu.api.exception.NotFoundException;
|
||||
import xyz.playedu.api.exception.ServiceException;
|
||||
import xyz.playedu.api.request.backend.ResourceDestroyMultiRequest;
|
||||
import xyz.playedu.api.request.backend.ResourceUpdateRequest;
|
||||
import xyz.playedu.api.service.AdminUserService;
|
||||
import xyz.playedu.api.service.MinioService;
|
||||
import xyz.playedu.api.service.ResourceService;
|
||||
import xyz.playedu.api.service.ResourceVideoService;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.api.types.paginate.PaginationResult;
|
||||
import xyz.playedu.api.types.paginate.ResourcePaginateFilter;
|
||||
import xyz.playedu.common.annotation.Log;
|
||||
import xyz.playedu.common.bus.BackendBus;
|
||||
import xyz.playedu.common.constant.BackendConstant;
|
||||
import xyz.playedu.common.constant.BusinessTypeConstant;
|
||||
import xyz.playedu.common.context.BCtx;
|
||||
import xyz.playedu.common.domain.AdminUser;
|
||||
import xyz.playedu.common.exception.NotFoundException;
|
||||
import xyz.playedu.common.exception.ServiceException;
|
||||
import xyz.playedu.common.service.AdminUserService;
|
||||
import xyz.playedu.common.service.MinioService;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.types.paginate.PaginationResult;
|
||||
import xyz.playedu.common.types.paginate.ResourcePaginateFilter;
|
||||
import xyz.playedu.resource.domain.Resource;
|
||||
import xyz.playedu.resource.domain.ResourceVideo;
|
||||
import xyz.playedu.resource.service.ResourceService;
|
||||
import xyz.playedu.resource.service.ResourceVideoService;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -59,6 +61,7 @@ public class ResourceController {
|
||||
@Autowired private BackendBus backendBus;
|
||||
|
||||
@GetMapping("/index")
|
||||
@Log(title = "资源-列表", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse index(@RequestParam HashMap<String, Object> params) {
|
||||
Integer page = MapUtils.getInteger(params, "page", 1);
|
||||
Integer size = MapUtils.getInteger(params, "size", 10);
|
||||
@@ -68,7 +71,7 @@ public class ResourceController {
|
||||
String type = MapUtils.getString(params, "type");
|
||||
String categoryIds = MapUtils.getString(params, "category_ids");
|
||||
|
||||
if (type == null || type.trim().length() == 0) {
|
||||
if (type == null || type.trim().isEmpty()) {
|
||||
return JsonResponse.error("请选择资源类型");
|
||||
}
|
||||
|
||||
@@ -100,7 +103,7 @@ public class ResourceController {
|
||||
|
||||
// 操作人
|
||||
data.put("admin_users", new HashMap<>());
|
||||
if (result.getData().size() > 0) {
|
||||
if (!result.getData().isEmpty()) {
|
||||
Map<Integer, String> adminUsers =
|
||||
adminUserService
|
||||
.chunks(result.getData().stream().map(Resource::getAdminId).toList())
|
||||
@@ -109,12 +112,18 @@ public class ResourceController {
|
||||
data.put("admin_users", adminUsers);
|
||||
}
|
||||
|
||||
if (!type.equals(BackendConstant.RESOURCE_TYPE_VIDEO)
|
||||
&& !type.equals(BackendConstant.RESOURCE_TYPE_IMAGE)) {
|
||||
filter.setType(BackendConstant.RESOURCE_TYPE_ATTACHMENT);
|
||||
data.put("existing_types", resourceService.paginateType(filter));
|
||||
}
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
@Transactional
|
||||
@SneakyThrows
|
||||
@Log(title = "资源-删除", businessType = BusinessTypeConstant.DELETE)
|
||||
public JsonResponse destroy(@PathVariable(name = "id") Integer id) throws NotFoundException {
|
||||
Resource resource = resourceService.findOrFail(id);
|
||||
|
||||
@@ -137,13 +146,14 @@ public class ResourceController {
|
||||
|
||||
@PostMapping("/destroy-multi")
|
||||
@SneakyThrows
|
||||
@Log(title = "资源-批量列表", businessType = BusinessTypeConstant.DELETE)
|
||||
public JsonResponse multiDestroy(@RequestBody ResourceDestroyMultiRequest req) {
|
||||
if (req.getIds() == null || req.getIds().size() == 0) {
|
||||
if (req.getIds() == null || req.getIds().isEmpty()) {
|
||||
return JsonResponse.error("请选择需要删除的资源");
|
||||
}
|
||||
|
||||
List<Resource> resources = resourceService.chunks(req.getIds());
|
||||
if (resources == null || resources.size() == 0) {
|
||||
if (resources == null || resources.isEmpty()) {
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@@ -169,6 +179,7 @@ public class ResourceController {
|
||||
|
||||
@GetMapping("/{id}")
|
||||
@SneakyThrows
|
||||
@Log(title = "资源-编辑", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse edit(@PathVariable(name = "id") Integer id) {
|
||||
Resource resource = resourceService.findOrFail(id);
|
||||
|
||||
@@ -186,6 +197,7 @@ public class ResourceController {
|
||||
|
||||
@PutMapping("/{id}")
|
||||
@SneakyThrows
|
||||
@Log(title = "资源-编辑", businessType = BusinessTypeConstant.UPDATE)
|
||||
public JsonResponse update(
|
||||
@RequestBody @Validated ResourceUpdateRequest req,
|
||||
@PathVariable(name = "id") Integer id) {
|
||||
@@ -22,14 +22,15 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import xyz.playedu.api.BCtx;
|
||||
import xyz.playedu.api.constant.CConfig;
|
||||
import xyz.playedu.api.service.ImageCaptchaService;
|
||||
import xyz.playedu.api.types.ImageCaptchaResult;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.api.util.RequestUtil;
|
||||
import xyz.playedu.common.annotation.Log;
|
||||
import xyz.playedu.common.constant.BusinessTypeConstant;
|
||||
import xyz.playedu.common.constant.ConfigConstant;
|
||||
import xyz.playedu.common.context.BCtx;
|
||||
import xyz.playedu.common.service.CategoryService;
|
||||
import xyz.playedu.common.service.DepartmentService;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.util.RequestUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -40,25 +41,17 @@ import java.util.Map;
|
||||
@Slf4j
|
||||
public class SystemController {
|
||||
|
||||
@Autowired private ImageCaptchaService imageCaptchaService;
|
||||
@Autowired private DepartmentService departmentService;
|
||||
|
||||
@GetMapping("/image-captcha")
|
||||
public JsonResponse imageCaptcha() throws IOException {
|
||||
ImageCaptchaResult imageCaptchaResult = imageCaptchaService.generate();
|
||||
|
||||
HashMap<String, String> data = new HashMap<>();
|
||||
data.put("key", imageCaptchaResult.getKey());
|
||||
data.put("image", imageCaptchaResult.getImage());
|
||||
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
@Autowired private CategoryService categoryService;
|
||||
|
||||
@GetMapping("/config")
|
||||
@Log(title = "其它-系统配置", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse config() {
|
||||
Map<String, String> configData = BCtx.getConfig();
|
||||
|
||||
String apiUrl = configData.get(CConfig.SYSTEM_API_URL);
|
||||
if (apiUrl == null || apiUrl.trim().length() == 0) {
|
||||
String apiUrl = configData.get(ConfigConstant.SYSTEM_API_URL);
|
||||
if (apiUrl == null || apiUrl.trim().isEmpty()) {
|
||||
apiUrl = RequestUtil.uriWithProtocol();
|
||||
} else {
|
||||
if (apiUrl.endsWith("/")) {
|
||||
@@ -68,18 +61,18 @@ public class SystemController {
|
||||
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
|
||||
data.put(CConfig.SYSTEM_NAME, configData.get(CConfig.SYSTEM_NAME));
|
||||
data.put(CConfig.SYSTEM_LOGO, configData.get(CConfig.SYSTEM_LOGO));
|
||||
data.put(CConfig.SYSTEM_API_URL, apiUrl);
|
||||
data.put(CConfig.SYSTEM_PC_URL, configData.get(CConfig.SYSTEM_PC_URL));
|
||||
data.put(CConfig.SYSTEM_H5_URL, configData.get(CConfig.SYSTEM_H5_URL));
|
||||
data.put(ConfigConstant.SYSTEM_NAME, configData.get(ConfigConstant.SYSTEM_NAME));
|
||||
data.put(ConfigConstant.SYSTEM_LOGO, configData.get(ConfigConstant.SYSTEM_LOGO));
|
||||
data.put(ConfigConstant.SYSTEM_API_URL, apiUrl);
|
||||
data.put(ConfigConstant.SYSTEM_PC_URL, configData.get(ConfigConstant.SYSTEM_PC_URL));
|
||||
data.put(ConfigConstant.SYSTEM_H5_URL, configData.get(ConfigConstant.SYSTEM_H5_URL));
|
||||
|
||||
// 学员的默认头像
|
||||
String memberDefaultAvatar = configData.get(CConfig.MEMBER_DEFAULT_AVATAR);
|
||||
if (memberDefaultAvatar == null || memberDefaultAvatar.trim().length() == 0) {
|
||||
data.put(CConfig.MEMBER_DEFAULT_AVATAR, apiUrl + "/images/default_avatar.png");
|
||||
String memberDefaultAvatar = configData.get(ConfigConstant.MEMBER_DEFAULT_AVATAR);
|
||||
if (memberDefaultAvatar == null || memberDefaultAvatar.trim().isEmpty()) {
|
||||
data.put(ConfigConstant.MEMBER_DEFAULT_AVATAR, apiUrl + "/images/default_avatar.png");
|
||||
} else {
|
||||
data.put(CConfig.MEMBER_DEFAULT_AVATAR, memberDefaultAvatar);
|
||||
data.put(ConfigConstant.MEMBER_DEFAULT_AVATAR, memberDefaultAvatar);
|
||||
}
|
||||
|
||||
// 内置的三个线上课封面
|
||||
@@ -89,6 +82,15 @@ public class SystemController {
|
||||
defaultCourseThumbs.add(apiUrl + "/images/courses/thumb3.png");
|
||||
data.put("default.course_thumbs", defaultCourseThumbs);
|
||||
|
||||
// LDAP登录
|
||||
data.put("ldap-enabled", "1".equals(configData.get(ConfigConstant.LDAP_ENABLED)));
|
||||
|
||||
// 全部部门
|
||||
data.put("departments", departmentService.groupByParent());
|
||||
|
||||
// 全部资源分类
|
||||
data.put("resource_categories", categoryService.groupByParent());
|
||||
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
}
|
||||
@@ -23,16 +23,20 @@ import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import xyz.playedu.api.BCtx;
|
||||
import xyz.playedu.api.constant.BackendConstant;
|
||||
import xyz.playedu.api.domain.Resource;
|
||||
import xyz.playedu.api.exception.ServiceException;
|
||||
import xyz.playedu.api.request.backend.UploadVideoMergeRequest;
|
||||
import xyz.playedu.api.service.MinioService;
|
||||
import xyz.playedu.api.service.ResourceService;
|
||||
import xyz.playedu.api.service.UploadService;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.api.util.HelperUtil;
|
||||
import xyz.playedu.api.request.backend.UploadFileMergeRequest;
|
||||
import xyz.playedu.common.annotation.BackendPermission;
|
||||
import xyz.playedu.common.annotation.Log;
|
||||
import xyz.playedu.common.constant.BPermissionConstant;
|
||||
import xyz.playedu.common.constant.BackendConstant;
|
||||
import xyz.playedu.common.constant.BusinessTypeConstant;
|
||||
import xyz.playedu.common.context.BCtx;
|
||||
import xyz.playedu.common.exception.ServiceException;
|
||||
import xyz.playedu.common.service.MinioService;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.util.HelperUtil;
|
||||
import xyz.playedu.resource.domain.Resource;
|
||||
import xyz.playedu.resource.service.ResourceService;
|
||||
import xyz.playedu.resource.service.UploadService;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -46,7 +50,9 @@ public class UploadController {
|
||||
|
||||
@Autowired private ResourceService resourceService;
|
||||
|
||||
@BackendPermission(slug = BPermissionConstant.UPLOAD)
|
||||
@PostMapping("/minio")
|
||||
@Log(title = "上传-MinIO", businessType = BusinessTypeConstant.UPLOAD)
|
||||
public JsonResponse uploadMinio(
|
||||
@RequestParam HashMap<String, Object> params, MultipartFile file)
|
||||
throws ServiceException {
|
||||
@@ -55,10 +61,12 @@ public class UploadController {
|
||||
return JsonResponse.data(res);
|
||||
}
|
||||
|
||||
@BackendPermission(slug = BPermissionConstant.UPLOAD)
|
||||
@GetMapping("/minio/upload-id")
|
||||
@Log(title = "上传-MinIO-uploadId", businessType = BusinessTypeConstant.UPLOAD)
|
||||
public JsonResponse minioUploadId(@RequestParam HashMap<String, Object> params) {
|
||||
String extension = MapUtils.getString(params, "extension");
|
||||
if (extension == null || extension.trim().length() == 0) {
|
||||
if (extension == null || extension.trim().isEmpty()) {
|
||||
return JsonResponse.error("extension参数为空");
|
||||
}
|
||||
String type = BackendConstant.RESOURCE_EXT_2_TYPE.get(extension.toLowerCase());
|
||||
@@ -78,7 +86,9 @@ public class UploadController {
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermission(slug = BPermissionConstant.UPLOAD)
|
||||
@GetMapping("/minio/pre-sign-url")
|
||||
@Log(title = "上传-MinIO-签名URL", businessType = BusinessTypeConstant.UPLOAD)
|
||||
public JsonResponse minioPreSignUrl(@RequestParam HashMap<String, Object> params) {
|
||||
String uploadId = MapUtils.getString(params, "upload_id");
|
||||
Integer partNumber = MapUtils.getInteger(params, "part_number");
|
||||
@@ -92,8 +102,10 @@ public class UploadController {
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@PostMapping("/minio/merge-video")
|
||||
public JsonResponse minioMergeVideo(@RequestBody @Validated UploadVideoMergeRequest req)
|
||||
@BackendPermission(slug = BPermissionConstant.UPLOAD)
|
||||
@PostMapping("/minio/merge-file")
|
||||
@Log(title = "上传-MinIO-文件合并", businessType = BusinessTypeConstant.UPLOAD)
|
||||
public JsonResponse minioMergeFile(@RequestBody @Validated UploadFileMergeRequest req)
|
||||
throws ServiceException {
|
||||
String type = BackendConstant.RESOURCE_EXT_2_TYPE.get(req.getExtension());
|
||||
if (type == null) {
|
||||
@@ -102,10 +114,10 @@ public class UploadController {
|
||||
String extension = req.getExtension();
|
||||
String originalFilename = req.getOriginalFilename().replaceAll("(?i)." + extension, "");
|
||||
|
||||
// 合并视频文件
|
||||
// 合并资源文件
|
||||
String url = minioService.merge(req.getFilename(), req.getUploadId());
|
||||
|
||||
// 视频素材保存
|
||||
// 资源素材保存
|
||||
Resource videoResource =
|
||||
resourceService.create(
|
||||
BCtx.getId(),
|
||||
@@ -118,14 +130,18 @@ public class UploadController {
|
||||
"",
|
||||
req.getFilename(),
|
||||
url);
|
||||
// 视频封面素材保存
|
||||
Resource posterResource =
|
||||
uploadService.storeBase64Image(BCtx.getId(), req.getPoster(), null);
|
||||
// 视频的封面素材改为[隐藏 && 属于视频的子素材]
|
||||
resourceService.changeParentId(posterResource.getId(), videoResource.getId());
|
||||
// 视频信息
|
||||
resourceService.storeResourceVideo(
|
||||
videoResource.getId(), req.getDuration(), posterResource.getUrl());
|
||||
|
||||
// 视频资源特殊处理--视频封面资源
|
||||
if (BackendConstant.RESOURCE_TYPE_VIDEO.equals(type)) {
|
||||
// 视频封面素材保存
|
||||
Resource posterResource =
|
||||
uploadService.storeBase64Image(BCtx.getId(), req.getPoster(), null);
|
||||
// 视频的封面素材改为[隐藏 && 属于视频的子素材]
|
||||
resourceService.changeParentId(posterResource.getId(), videoResource.getId());
|
||||
// 视频信息
|
||||
resourceService.storeResourceVideo(
|
||||
videoResource.getId(), req.getDuration(), posterResource.getUrl());
|
||||
}
|
||||
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
data.put("url", url);
|
||||
@@ -133,14 +149,16 @@ public class UploadController {
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermission(slug = BPermissionConstant.UPLOAD)
|
||||
@GetMapping("/minio/merge")
|
||||
@Log(title = "上传-MinIO-文件合并", businessType = BusinessTypeConstant.UPLOAD)
|
||||
public JsonResponse minioMerge(@RequestParam HashMap<String, Object> params) {
|
||||
String filename = MapUtils.getString(params, "filename");
|
||||
String uploadId = MapUtils.getString(params, "upload_id");
|
||||
if (filename == null || filename.trim().length() == 0) {
|
||||
if (filename == null || filename.trim().isEmpty()) {
|
||||
return JsonResponse.error("filename必填");
|
||||
}
|
||||
if (uploadId == null || uploadId.trim().length() == 0) {
|
||||
if (uploadId == null || uploadId.trim().isEmpty()) {
|
||||
return JsonResponse.error("uploadId必填");
|
||||
}
|
||||
|
||||
@@ -28,27 +28,31 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import xyz.playedu.api.BCtx;
|
||||
import xyz.playedu.api.constant.BPermissionConstant;
|
||||
import xyz.playedu.api.constant.CConfig;
|
||||
import xyz.playedu.api.constant.SystemConstant;
|
||||
import xyz.playedu.api.domain.*;
|
||||
import xyz.playedu.api.event.UserCourseHourRecordDestroyEvent;
|
||||
import xyz.playedu.api.event.UserCourseRecordDestroyEvent;
|
||||
import xyz.playedu.api.event.UserDestroyEvent;
|
||||
import xyz.playedu.api.exception.NotFoundException;
|
||||
import xyz.playedu.api.middleware.BackendPermissionMiddleware;
|
||||
import xyz.playedu.api.request.backend.UserImportRequest;
|
||||
import xyz.playedu.api.request.backend.UserRequest;
|
||||
import xyz.playedu.api.service.*;
|
||||
import xyz.playedu.api.service.internal.UserDepartmentService;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.api.types.mapper.UserCourseHourRecordCourseCountMapper;
|
||||
import xyz.playedu.api.types.paginate.PaginationResult;
|
||||
import xyz.playedu.api.types.paginate.UserCourseHourRecordPaginateFilter;
|
||||
import xyz.playedu.api.types.paginate.UserCourseRecordPaginateFilter;
|
||||
import xyz.playedu.api.types.paginate.UserPaginateFilter;
|
||||
import xyz.playedu.api.util.HelperUtil;
|
||||
import xyz.playedu.common.annotation.BackendPermission;
|
||||
import xyz.playedu.common.annotation.Log;
|
||||
import xyz.playedu.common.constant.BPermissionConstant;
|
||||
import xyz.playedu.common.constant.BusinessTypeConstant;
|
||||
import xyz.playedu.common.constant.ConfigConstant;
|
||||
import xyz.playedu.common.constant.SystemConstant;
|
||||
import xyz.playedu.common.context.BCtx;
|
||||
import xyz.playedu.common.domain.*;
|
||||
import xyz.playedu.common.exception.NotFoundException;
|
||||
import xyz.playedu.common.service.*;
|
||||
import xyz.playedu.common.service.UserDepartmentService;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.types.mapper.UserCourseHourRecordCourseCountMapper;
|
||||
import xyz.playedu.common.types.paginate.PaginationResult;
|
||||
import xyz.playedu.common.types.paginate.UserCourseHourRecordPaginateFilter;
|
||||
import xyz.playedu.common.types.paginate.UserCourseRecordPaginateFilter;
|
||||
import xyz.playedu.common.types.paginate.UserPaginateFilter;
|
||||
import xyz.playedu.common.util.HelperUtil;
|
||||
import xyz.playedu.course.domain.*;
|
||||
import xyz.playedu.course.service.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -83,8 +87,9 @@ public class UserController {
|
||||
|
||||
@Autowired private ApplicationContext ctx;
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.USER_INDEX)
|
||||
@BackendPermission(slug = BPermissionConstant.USER_INDEX)
|
||||
@GetMapping("/index")
|
||||
@Log(title = "学员-列表", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse index(@RequestParam HashMap<String, Object> params) {
|
||||
Integer page = MapUtils.getInteger(params, "page", 1);
|
||||
Integer size = MapUtils.getInteger(params, "size", 10);
|
||||
@@ -101,7 +106,7 @@ public class UserController {
|
||||
String createdAt = MapUtils.getString(params, "created_at");
|
||||
String depIdsStr = MapUtils.getString(params, "dep_ids");
|
||||
List<Integer> depIds = null;
|
||||
if (depIdsStr != null && depIdsStr.trim().length() > 0) {
|
||||
if (depIdsStr != null && !depIdsStr.trim().isEmpty()) {
|
||||
if ("0".equals(depIdsStr)) {
|
||||
depIds = new ArrayList<>();
|
||||
} else {
|
||||
@@ -126,7 +131,7 @@ public class UserController {
|
||||
}
|
||||
};
|
||||
|
||||
if (createdAt != null && createdAt.trim().length() > 0) {
|
||||
if (createdAt != null && !createdAt.trim().isEmpty()) {
|
||||
filter.setCreatedAt(createdAt.split(","));
|
||||
}
|
||||
|
||||
@@ -140,25 +145,28 @@ public class UserController {
|
||||
userService.getDepIdsGroup(result.getData().stream().map(User::getId).toList()));
|
||||
data.put("departments", departmentService.id2name());
|
||||
data.put("pure_total", userService.total());
|
||||
data.put("dep_user_count", departmentService.getDepartmentsUserCount());
|
||||
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.USER_STORE)
|
||||
@BackendPermission(slug = BPermissionConstant.USER_STORE)
|
||||
@GetMapping("/create")
|
||||
@Log(title = "学员-新建", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse create() {
|
||||
return JsonResponse.data(null);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.USER_STORE)
|
||||
@BackendPermission(slug = BPermissionConstant.USER_STORE)
|
||||
@PostMapping("/create")
|
||||
@Log(title = "学员-新建", businessType = BusinessTypeConstant.INSERT)
|
||||
public JsonResponse store(@RequestBody @Validated UserRequest req) {
|
||||
String email = req.getEmail();
|
||||
if (userService.emailIsExists(email)) {
|
||||
return JsonResponse.error("邮箱已存在");
|
||||
}
|
||||
String password = req.getPassword();
|
||||
if (password.length() == 0) {
|
||||
if (password.isEmpty()) {
|
||||
return JsonResponse.error("请输入密码");
|
||||
}
|
||||
userService.createWithDepIds(
|
||||
@@ -171,8 +179,9 @@ public class UserController {
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.USER_UPDATE)
|
||||
@BackendPermission(slug = BPermissionConstant.USER_UPDATE)
|
||||
@GetMapping("/{id}")
|
||||
@Log(title = "学员-编辑", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse edit(@PathVariable(name = "id") Integer id) throws NotFoundException {
|
||||
User user = userService.findOrFail(id);
|
||||
|
||||
@@ -185,9 +194,10 @@ public class UserController {
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.USER_UPDATE)
|
||||
@BackendPermission(slug = BPermissionConstant.USER_UPDATE)
|
||||
@PutMapping("/{id}")
|
||||
@Transactional
|
||||
@Log(title = "学员-编辑", businessType = BusinessTypeConstant.UPDATE)
|
||||
public JsonResponse update(
|
||||
@PathVariable(name = "id") Integer id, @RequestBody @Validated UserRequest req)
|
||||
throws NotFoundException {
|
||||
@@ -209,8 +219,9 @@ public class UserController {
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.USER_DESTROY)
|
||||
@BackendPermission(slug = BPermissionConstant.USER_DESTROY)
|
||||
@DeleteMapping("/{id}")
|
||||
@Log(title = "学员-删除", businessType = BusinessTypeConstant.DELETE)
|
||||
public JsonResponse destroy(@PathVariable(name = "id") Integer id) throws NotFoundException {
|
||||
User user = userService.findOrFail(id);
|
||||
userService.removeById(user.getId());
|
||||
@@ -220,9 +231,10 @@ public class UserController {
|
||||
|
||||
@PostMapping("/store-batch")
|
||||
@Transactional
|
||||
@Log(title = "学员-批量导入", businessType = BusinessTypeConstant.INSERT)
|
||||
public JsonResponse batchStore(@RequestBody @Validated UserImportRequest req) {
|
||||
List<UserImportRequest.UserItem> users = req.getUsers();
|
||||
if (users.size() == 0) {
|
||||
if (users.isEmpty()) {
|
||||
return JsonResponse.error("数据为空");
|
||||
}
|
||||
if (users.size() > 1000) {
|
||||
@@ -233,7 +245,7 @@ public class UserController {
|
||||
Integer startLine = req.getStartLine();
|
||||
|
||||
// 默认的学员头像
|
||||
String defaultAvatar = BCtx.getConfig().get(CConfig.MEMBER_DEFAULT_AVATAR);
|
||||
String defaultAvatar = BCtx.getConfig().get(ConfigConstant.MEMBER_DEFAULT_AVATAR);
|
||||
|
||||
List<String[]> errorLines = new ArrayList<>();
|
||||
errorLines.add(new String[] {"错误行", "错误信息"}); // 错误表-表头
|
||||
@@ -246,7 +258,7 @@ public class UserController {
|
||||
HashMap<String, Integer> depChainNameMap = new HashMap<>();
|
||||
for (Department tmpDepItem : departments) {
|
||||
// 一级部门
|
||||
if (tmpDepItem.getParentChain() == null || tmpDepItem.getParentChain().length() == 0) {
|
||||
if (tmpDepItem.getParentChain() == null || tmpDepItem.getParentChain().isEmpty()) {
|
||||
depChainNameMap.put(tmpDepItem.getName(), tmpDepItem.getId());
|
||||
continue;
|
||||
}
|
||||
@@ -275,7 +287,7 @@ public class UserController {
|
||||
for (UserImportRequest.UserItem userItem : users) {
|
||||
i++; // 索引值
|
||||
|
||||
if (userItem.getEmail() == null || userItem.getEmail().trim().length() == 0) {
|
||||
if (userItem.getEmail() == null || userItem.getEmail().trim().isEmpty()) {
|
||||
errorLines.add(new String[] {"第" + (i + startLine) + "行", "未输入邮箱账号"});
|
||||
} else {
|
||||
// 邮箱重复判断
|
||||
@@ -292,7 +304,7 @@ public class UserController {
|
||||
}
|
||||
|
||||
// 部门数据检测
|
||||
if (userItem.getDeps() == null || userItem.getDeps().trim().length() == 0) {
|
||||
if (userItem.getDeps() == null || userItem.getDeps().trim().isEmpty()) {
|
||||
errorLines.add(new String[] {"第" + (i + startLine) + "行", "未选择部门"});
|
||||
} else {
|
||||
String[] tmpDepList = userItem.getDeps().trim().split("\\|");
|
||||
@@ -315,13 +327,13 @@ public class UserController {
|
||||
|
||||
// 姓名为空检测
|
||||
String tmpName = userItem.getName();
|
||||
if (tmpName == null || tmpName.trim().length() == 0) {
|
||||
if (tmpName == null || tmpName.trim().isEmpty()) {
|
||||
errorLines.add(new String[] {"第" + (i + startLine) + "行", "昵称为空"});
|
||||
}
|
||||
|
||||
// 密码为空检测
|
||||
String tmpPassword = userItem.getPassword();
|
||||
if (tmpPassword == null || tmpPassword.trim().length() == 0) {
|
||||
if (tmpPassword == null || tmpPassword.trim().isEmpty()) {
|
||||
errorLines.add(new String[] {"第" + (i + startLine) + "行", "密码为空"});
|
||||
}
|
||||
|
||||
@@ -348,7 +360,7 @@ public class UserController {
|
||||
|
||||
// 邮箱是否注册检测
|
||||
List<String> existsEmails = userService.existsEmailsByEmails(emails);
|
||||
if (existsEmails.size() > 0) {
|
||||
if (!existsEmails.isEmpty()) {
|
||||
for (String tmpEmail : existsEmails) {
|
||||
errorLines.add(new String[] {"第" + emailRepeat.get(tmpEmail) + "行", "邮箱已注册"});
|
||||
}
|
||||
@@ -381,9 +393,10 @@ public class UserController {
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.USER_LEARN)
|
||||
@BackendPermission(slug = BPermissionConstant.USER_LEARN)
|
||||
@GetMapping("/{id}/learn-hours")
|
||||
@SneakyThrows
|
||||
@Log(title = "学员-已学习课时列表", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse learnHours(
|
||||
@PathVariable(name = "id") Integer id, @RequestParam HashMap<String, Object> params) {
|
||||
Integer page = MapUtils.getInteger(params, "page", 1);
|
||||
@@ -417,8 +430,9 @@ public class UserController {
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.USER_LEARN)
|
||||
@BackendPermission(slug = BPermissionConstant.USER_LEARN)
|
||||
@GetMapping("/{id}/learn-courses")
|
||||
@Log(title = "学员-已学习课程列表", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse latestLearnCourses(
|
||||
@PathVariable(name = "id") Integer id, @RequestParam HashMap<String, Object> params) {
|
||||
Integer page = MapUtils.getInteger(params, "page", 1);
|
||||
@@ -452,8 +466,9 @@ public class UserController {
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.USER_LEARN)
|
||||
@BackendPermission(slug = BPermissionConstant.USER_LEARN)
|
||||
@GetMapping("/{id}/all-courses")
|
||||
@Log(title = "学员-课程", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse allCourses(@PathVariable(name = "id") Integer id) {
|
||||
// 读取学员关联的部门
|
||||
List<Integer> depIds = userService.getDepIdsByUserId(id);
|
||||
@@ -461,7 +476,7 @@ public class UserController {
|
||||
HashMap<Integer, List<Course>> depCourses = new HashMap<>();
|
||||
List<Integer> courseIds = new ArrayList<>();
|
||||
|
||||
if (depIds != null && depIds.size() > 0) {
|
||||
if (depIds != null && !depIds.isEmpty()) {
|
||||
departments = departmentService.chunk(depIds);
|
||||
depIds.forEach(
|
||||
(depId) -> {
|
||||
@@ -474,7 +489,7 @@ public class UserController {
|
||||
});
|
||||
depCourses.put(depId, tmpCourses);
|
||||
|
||||
if (tmpCourses != null && tmpCourses.size() > 0) {
|
||||
if (tmpCourses != null && !tmpCourses.isEmpty()) {
|
||||
courseIds.addAll(tmpCourses.stream().map(Course::getId).toList());
|
||||
}
|
||||
});
|
||||
@@ -482,13 +497,13 @@ public class UserController {
|
||||
|
||||
// 未关联部门课程
|
||||
List<Course> openCourses = courseService.getOpenCoursesAndShow(1000);
|
||||
if (openCourses != null && openCourses.size() > 0) {
|
||||
if (openCourses != null && !openCourses.isEmpty()) {
|
||||
courseIds.addAll(openCourses.stream().map(Course::getId).toList());
|
||||
}
|
||||
|
||||
// 读取学员的线上课学习记录
|
||||
List<UserCourseRecord> userCourseRecords = new ArrayList<>();
|
||||
if (courseIds.size() > 0) {
|
||||
if (!courseIds.isEmpty()) {
|
||||
userCourseRecords = userCourseRecordService.chunk(id, courseIds);
|
||||
}
|
||||
|
||||
@@ -513,9 +528,10 @@ public class UserController {
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.USER_LEARN)
|
||||
@BackendPermission(slug = BPermissionConstant.USER_LEARN)
|
||||
@GetMapping("/{id}/learn-course/{courseId}")
|
||||
@SneakyThrows
|
||||
@Log(title = "学员-单个课程的学习记录", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse learnCourseDetail(
|
||||
@PathVariable(name = "id") Integer id,
|
||||
@PathVariable(name = "courseId") Integer courseId) {
|
||||
@@ -534,9 +550,10 @@ public class UserController {
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.USER_LEARN)
|
||||
@BackendPermission(slug = BPermissionConstant.USER_LEARN)
|
||||
@GetMapping("/{id}/learn-stats")
|
||||
@SneakyThrows
|
||||
@Log(title = "学员-学习统计", businessType = BusinessTypeConstant.GET)
|
||||
public JsonResponse learn(@PathVariable(name = "id") Integer id) {
|
||||
// 最近一个月的每天学习时长
|
||||
String todayStr = DateTime.now().toDateStr();
|
||||
@@ -581,9 +598,10 @@ public class UserController {
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.USER_LEARN_DESTROY)
|
||||
@BackendPermission(slug = BPermissionConstant.USER_LEARN_DESTROY)
|
||||
@DeleteMapping("/{id}/learn-course/{courseId}")
|
||||
@SneakyThrows
|
||||
@Log(title = "学员-线上课学习记录删除", businessType = BusinessTypeConstant.DELETE)
|
||||
public JsonResponse destroyUserCourse(
|
||||
@PathVariable(name = "id") Integer id,
|
||||
@PathVariable(name = "courseId") Integer courseId) {
|
||||
@@ -592,9 +610,10 @@ public class UserController {
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
@BackendPermissionMiddleware(slug = BPermissionConstant.USER_LEARN_DESTROY)
|
||||
@BackendPermission(slug = BPermissionConstant.USER_LEARN_DESTROY)
|
||||
@DeleteMapping("/{id}/learn-course/{courseId}/hour/{hourId}")
|
||||
@SneakyThrows
|
||||
@Log(title = "学员-线上课课时学习记录删除", businessType = BusinessTypeConstant.DELETE)
|
||||
public JsonResponse destroyUserHour(
|
||||
@PathVariable(name = "id") Integer id,
|
||||
@PathVariable(name = "courseId") Integer courseId,
|
||||
@@ -20,9 +20,9 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import xyz.playedu.api.domain.ResourceCategory;
|
||||
import xyz.playedu.api.service.ResourceCategoryService;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.common.domain.Category;
|
||||
import xyz.playedu.common.service.CategoryService;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -32,15 +32,15 @@ import java.util.stream.Collectors;
|
||||
@RequestMapping("/api/v1/category")
|
||||
public class CategoryController {
|
||||
|
||||
@Autowired private ResourceCategoryService resourceCategoryService;
|
||||
@Autowired private CategoryService categoryService;
|
||||
|
||||
@GetMapping("/all")
|
||||
public JsonResponse all() {
|
||||
List<ResourceCategory> categories = resourceCategoryService.all();
|
||||
List<Category> categories = categoryService.all();
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
data.put(
|
||||
"categories",
|
||||
categories.stream().collect(Collectors.groupingBy(ResourceCategory::getParentId)));
|
||||
categories.stream().collect(Collectors.groupingBy(Category::getParentId)));
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2023 杭州白书科技有限公司
|
||||
*
|
||||
* 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 xyz.playedu.api.controller.frontend;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import xyz.playedu.common.context.FCtx;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.util.IpUtil;
|
||||
import xyz.playedu.course.domain.*;
|
||||
import xyz.playedu.course.service.*;
|
||||
import xyz.playedu.resource.domain.Resource;
|
||||
import xyz.playedu.resource.service.ResourceService;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
*
|
||||
* @create 2023/3/13 16:25
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/course")
|
||||
public class CourseController {
|
||||
|
||||
@Autowired private CourseService courseService;
|
||||
|
||||
@Autowired private CourseChapterService chapterService;
|
||||
|
||||
@Autowired private CourseHourService hourService;
|
||||
|
||||
@Autowired private CourseAttachmentService attachmentService;
|
||||
|
||||
@Autowired private ResourceService resourceService;
|
||||
|
||||
@Autowired private UserCourseRecordService userCourseRecordService;
|
||||
|
||||
@Autowired private UserCourseHourRecordService userCourseHourRecordService;
|
||||
|
||||
@Autowired private CourseAttachmentDownloadLogService courseAttachmentDownloadLogService;
|
||||
|
||||
@GetMapping("/{id}")
|
||||
@SneakyThrows
|
||||
public JsonResponse detail(@PathVariable(name = "id") Integer id) {
|
||||
Course course = courseService.findOrFail(id);
|
||||
|
||||
List<CourseHour> courseHours = hourService.getHoursByCourseId(course.getId());
|
||||
|
||||
List<CourseAttachment> attachments =
|
||||
attachmentService.getAttachmentsByCourseId(course.getId());
|
||||
if (null != attachments && !attachments.isEmpty()) {
|
||||
Map<Integer, Resource> resourceMap =
|
||||
resourceService
|
||||
.chunks(attachments.stream().map(CourseAttachment::getRid).toList())
|
||||
.stream()
|
||||
.collect(Collectors.toMap(Resource::getId, Function.identity()));
|
||||
attachments.forEach(
|
||||
courseAttachment -> {
|
||||
Resource resource = resourceMap.get(courseAttachment.getRid());
|
||||
if (null != resource) {
|
||||
courseAttachment.setExt(resource.getExtension());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
data.put("course", course);
|
||||
data.put("chapters", chapterService.getChaptersByCourseId(course.getId()));
|
||||
data.put(
|
||||
"hours",
|
||||
courseHours.stream().collect(Collectors.groupingBy(CourseHour::getChapterId)));
|
||||
data.put("learn_record", userCourseRecordService.find(FCtx.getId(), course.getId()));
|
||||
data.put(
|
||||
"learn_hour_records",
|
||||
userCourseHourRecordService.getRecords(FCtx.getId(), course.getId()).stream()
|
||||
.collect(Collectors.toMap(UserCourseHourRecord::getHourId, e -> e)));
|
||||
data.put("attachments", attachments);
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@GetMapping("/{courseId}/attach/{id}/download")
|
||||
@SneakyThrows
|
||||
public JsonResponse attachmentDownload(
|
||||
@PathVariable(name = "courseId") Integer courseId,
|
||||
@PathVariable(name = "id") Integer id) {
|
||||
CourseAttachment attachment = attachmentService.findOrFail(id, courseId);
|
||||
Resource resource = resourceService.findOrFail(attachment.getRid());
|
||||
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
data.put("download_url", resource.getUrl());
|
||||
|
||||
courseAttachmentDownloadLogService.save(
|
||||
new CourseAttachmentDownloadLog() {
|
||||
{
|
||||
setUserId(FCtx.getId());
|
||||
setCourseId(attachment.getCourseId());
|
||||
setCourserAttachmentId(attachment.getId());
|
||||
setRid(resource.getId());
|
||||
setTitle(attachment.getTitle());
|
||||
setIp(IpUtil.getIpAddress());
|
||||
setCreatedAt(new Date());
|
||||
}
|
||||
});
|
||||
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
}
|
||||
@@ -19,14 +19,14 @@ import org.apache.commons.collections4.MapUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import xyz.playedu.api.domain.Course;
|
||||
import xyz.playedu.api.domain.Department;
|
||||
import xyz.playedu.api.exception.NotFoundException;
|
||||
import xyz.playedu.api.service.CourseService;
|
||||
import xyz.playedu.api.service.DepartmentService;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.api.types.paginate.CoursePaginateFiler;
|
||||
import xyz.playedu.api.types.paginate.PaginationResult;
|
||||
import xyz.playedu.common.domain.Department;
|
||||
import xyz.playedu.common.exception.NotFoundException;
|
||||
import xyz.playedu.common.service.DepartmentService;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.types.paginate.CoursePaginateFiler;
|
||||
import xyz.playedu.common.types.paginate.PaginationResult;
|
||||
import xyz.playedu.course.domain.Course;
|
||||
import xyz.playedu.course.service.CourseService;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -18,21 +18,27 @@ package xyz.playedu.api.controller.frontend;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import xyz.playedu.api.FCtx;
|
||||
import xyz.playedu.api.bus.UserBus;
|
||||
import xyz.playedu.api.caches.CourseCache;
|
||||
import xyz.playedu.api.caches.UserCanSeeCourseCache;
|
||||
import xyz.playedu.api.domain.*;
|
||||
import xyz.playedu.api.event.UserCourseHourFinishedEvent;
|
||||
import xyz.playedu.api.event.UserLearnCourseUpdateEvent;
|
||||
import xyz.playedu.api.request.frontend.CourseHourRecordRequest;
|
||||
import xyz.playedu.api.service.CourseHourService;
|
||||
import xyz.playedu.api.service.CourseService;
|
||||
import xyz.playedu.api.service.ResourceService;
|
||||
import xyz.playedu.api.service.UserCourseHourRecordService;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.api.util.RedisDistributedLock;
|
||||
import xyz.playedu.common.context.FCtx;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.util.RedisDistributedLock;
|
||||
import xyz.playedu.course.caches.CourseCache;
|
||||
import xyz.playedu.course.caches.UserCanSeeCourseCache;
|
||||
import xyz.playedu.course.caches.UserLastLearnTimeCache;
|
||||
import xyz.playedu.course.domain.Course;
|
||||
import xyz.playedu.course.domain.CourseHour;
|
||||
import xyz.playedu.course.domain.UserCourseHourRecord;
|
||||
import xyz.playedu.course.service.CourseHourService;
|
||||
import xyz.playedu.course.service.CourseService;
|
||||
import xyz.playedu.course.service.UserCourseHourRecordService;
|
||||
import xyz.playedu.resource.domain.Resource;
|
||||
import xyz.playedu.resource.service.ResourceService;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -54,14 +60,16 @@ public class HourController {
|
||||
|
||||
@Autowired private UserCourseHourRecordService userCourseHourRecordService;
|
||||
|
||||
@Autowired private UserBus userBus;
|
||||
|
||||
// ------- CACHE ----------
|
||||
@Autowired private UserCanSeeCourseCache userCanSeeCourseCache;
|
||||
@Autowired private CourseCache courseCache;
|
||||
|
||||
@Autowired private RedisDistributedLock redisDistributedLock;
|
||||
|
||||
@Autowired private UserLastLearnTimeCache userLastLearnTimeCache;
|
||||
|
||||
@Autowired private ApplicationContext ctx;
|
||||
|
||||
@GetMapping("/{id}")
|
||||
@SneakyThrows
|
||||
public JsonResponse detail(
|
||||
@@ -124,11 +132,23 @@ public class HourController {
|
||||
return JsonResponse.error("请稍后再试");
|
||||
}
|
||||
|
||||
userCourseHourRecordService.storeOrUpdate(
|
||||
FCtx.getId(), course.getId(), hour.getId(), duration, hour.getDuration());
|
||||
|
||||
// 此处未考虑上面代码执行失败释放锁
|
||||
redisDistributedLock.releaseLock(lockKey);
|
||||
try {
|
||||
boolean isFinished =
|
||||
userCourseHourRecordService.storeOrUpdate(
|
||||
FCtx.getId(),
|
||||
course.getId(),
|
||||
hour.getId(),
|
||||
duration,
|
||||
hour.getDuration());
|
||||
if (isFinished) {
|
||||
ctx.publishEvent(
|
||||
new UserCourseHourFinishedEvent(
|
||||
this, FCtx.getId(), courseId, hour.getId()));
|
||||
}
|
||||
} finally {
|
||||
// 此处未考虑上面代码执行失败释放锁
|
||||
redisDistributedLock.releaseLock(lockKey);
|
||||
}
|
||||
|
||||
return JsonResponse.success();
|
||||
}
|
||||
@@ -149,10 +169,25 @@ public class HourController {
|
||||
return JsonResponse.error("请稍后再试");
|
||||
}
|
||||
|
||||
userBus.userLearnDurationRecord(FCtx.getUser(), course, hour);
|
||||
try {
|
||||
Long curTime = System.currentTimeMillis();
|
||||
|
||||
// 此处未考虑上面代码执行失败释放锁
|
||||
redisDistributedLock.releaseLock(lockKey);
|
||||
// 最近一次学习时间
|
||||
Long lastTime = userLastLearnTimeCache.get(FCtx.getId());
|
||||
// 最大周期为10s+0.5s的网络延迟
|
||||
if (lastTime == null || curTime - lastTime > 10500) {
|
||||
lastTime = curTime - 10000;
|
||||
}
|
||||
|
||||
userLastLearnTimeCache.put(FCtx.getId(), curTime);
|
||||
|
||||
ctx.publishEvent(
|
||||
new UserLearnCourseUpdateEvent(
|
||||
this, FCtx.getId(), course.getId(), hour.getId(), lastTime, curTime));
|
||||
} finally {
|
||||
// 此处未考虑上面代码执行失败释放锁
|
||||
redisDistributedLock.releaseLock(lockKey);
|
||||
}
|
||||
|
||||
return JsonResponse.success();
|
||||
}
|
||||
@@ -18,17 +18,10 @@ package xyz.playedu.api.controller.frontend;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
*
|
||||
* @create 2023/3/24 17:42
|
||||
*/
|
||||
@RestController
|
||||
public class IndexController {
|
||||
@GetMapping("/")
|
||||
public JsonResponse index() {
|
||||
return JsonResponse.success();
|
||||
public String index() {
|
||||
return "系统正在运行中...";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (C) 2023 杭州白书科技有限公司
|
||||
*
|
||||
* 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 xyz.playedu.api.controller.frontend;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
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;
|
||||
|
||||
import xyz.playedu.api.bus.LoginBus;
|
||||
import xyz.playedu.api.cache.LoginLimitCache;
|
||||
import xyz.playedu.api.cache.LoginLockCache;
|
||||
import xyz.playedu.api.event.UserLogoutEvent;
|
||||
import xyz.playedu.api.request.frontend.LoginLdapRequest;
|
||||
import xyz.playedu.api.request.frontend.LoginPasswordRequest;
|
||||
import xyz.playedu.common.constant.ConfigConstant;
|
||||
import xyz.playedu.common.context.FCtx;
|
||||
import xyz.playedu.common.domain.User;
|
||||
import xyz.playedu.common.exception.LimitException;
|
||||
import xyz.playedu.common.exception.ServiceException;
|
||||
import xyz.playedu.common.service.*;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.util.*;
|
||||
import xyz.playedu.common.util.ldap.LdapTransformUser;
|
||||
import xyz.playedu.common.util.ldap.LdapUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/auth/login")
|
||||
@Slf4j
|
||||
public class LoginController {
|
||||
|
||||
@Autowired private UserService userService;
|
||||
|
||||
@Autowired private FrontendAuthService authService;
|
||||
|
||||
@Autowired private ApplicationContext ctx;
|
||||
|
||||
@Autowired private AppConfigService appConfigService;
|
||||
|
||||
@Autowired private LoginBus loginBus;
|
||||
|
||||
@Autowired private LoginLimitCache loginLimitCache;
|
||||
|
||||
@Autowired private LoginLockCache loginLockCache;
|
||||
|
||||
@PostMapping("/password")
|
||||
@SneakyThrows
|
||||
public JsonResponse password(@RequestBody @Validated LoginPasswordRequest req)
|
||||
throws LimitException {
|
||||
if (appConfigService.enabledLdapLogin()) {
|
||||
return JsonResponse.error("请使用LDAP登录");
|
||||
}
|
||||
|
||||
String email = req.getEmail();
|
||||
|
||||
User user = userService.find(email);
|
||||
if (user == null) {
|
||||
return JsonResponse.error("邮箱或密码错误");
|
||||
}
|
||||
|
||||
loginLimitCache.check(email);
|
||||
|
||||
if (!HelperUtil.MD5(req.getPassword() + user.getSalt()).equals(user.getPassword())) {
|
||||
return JsonResponse.error("邮箱或密码错误");
|
||||
}
|
||||
|
||||
if (user.getIsLock() == 1) {
|
||||
return JsonResponse.error("当前学员已锁定无法登录");
|
||||
}
|
||||
|
||||
loginLimitCache.destroy(email);
|
||||
|
||||
return JsonResponse.data(loginBus.tokenByUser(user));
|
||||
}
|
||||
|
||||
@PostMapping("/ldap")
|
||||
@SneakyThrows
|
||||
public JsonResponse ldap(@RequestBody @Validated LoginLdapRequest req) {
|
||||
String username = req.getUsername();
|
||||
|
||||
// 系统配置
|
||||
Map<String, String> config = appConfigService.keyValues();
|
||||
String url = config.get(ConfigConstant.LDAP_URL);
|
||||
String adminUser = config.get(ConfigConstant.LDAP_ADMIN_USER);
|
||||
String adminPass = config.get(ConfigConstant.LDAP_ADMIN_PASS);
|
||||
String baseDN = config.get(ConfigConstant.LDAP_BASE_DN);
|
||||
if (url.isEmpty() || adminUser.isEmpty() || adminPass.isEmpty() || baseDN.isEmpty()) {
|
||||
return JsonResponse.error("LDAP服务未配置");
|
||||
}
|
||||
|
||||
String mail = null;
|
||||
String uid = null;
|
||||
if (StringUtil.contains(username, "@")) {
|
||||
mail = username;
|
||||
} else {
|
||||
uid = username;
|
||||
}
|
||||
|
||||
// 限流控制
|
||||
loginLimitCache.check(username);
|
||||
|
||||
// 锁控制-防止并发登录重复写入数据
|
||||
if (!loginLockCache.apply(username)) {
|
||||
return JsonResponse.error("请稍候再试");
|
||||
}
|
||||
|
||||
try {
|
||||
LdapTransformUser ldapTransformUser =
|
||||
LdapUtil.loginByMailOrUid(
|
||||
url, adminUser, adminPass, baseDN, mail, uid, req.getPassword());
|
||||
if (ldapTransformUser == null) {
|
||||
return JsonResponse.error("登录失败.请检查账号和密码");
|
||||
}
|
||||
|
||||
HashMap<String, Object> data = loginBus.tokenByLdapTransformUser(ldapTransformUser);
|
||||
|
||||
// 删除限流控制
|
||||
loginLimitCache.destroy(username);
|
||||
|
||||
return JsonResponse.data(data);
|
||||
} catch (ServiceException e) {
|
||||
return JsonResponse.error(e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("LDAP登录失败", e);
|
||||
return JsonResponse.error("系统错误");
|
||||
} finally {
|
||||
loginLockCache.release(username);
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/logout")
|
||||
public JsonResponse logout() {
|
||||
authService.logout();
|
||||
ctx.publishEvent(new UserLogoutEvent(this, FCtx.getId(), FCtx.getJwtJti()));
|
||||
return JsonResponse.success();
|
||||
}
|
||||
}
|
||||
@@ -20,40 +20,30 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import xyz.playedu.api.constant.CConfig;
|
||||
import xyz.playedu.api.service.AppConfigService;
|
||||
import xyz.playedu.api.service.ImageCaptchaService;
|
||||
import xyz.playedu.api.types.ImageCaptchaResult;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.common.constant.ConfigConstant;
|
||||
import xyz.playedu.common.service.AppConfigService;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
*
|
||||
* @create 2023/3/13 11:26
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/system")
|
||||
public class SystemController {
|
||||
|
||||
@Autowired private AppConfigService appConfigService;
|
||||
|
||||
@Autowired private ImageCaptchaService imageCaptchaService;
|
||||
|
||||
@GetMapping("/config")
|
||||
public JsonResponse config() {
|
||||
Map<String, String> configs = appConfigService.keyValues();
|
||||
|
||||
HashMap<String, String> data = new HashMap<>();
|
||||
|
||||
data.put("system-name", configs.get(CConfig.SYSTEM_NAME));
|
||||
data.put("system-logo", configs.get(CConfig.SYSTEM_LOGO));
|
||||
data.put("system-api-url", configs.get(CConfig.SYSTEM_API_URL));
|
||||
data.put("system-pc-url", configs.get(CConfig.SYSTEM_PC_URL));
|
||||
data.put("system-h5-url", configs.get(CConfig.SYSTEM_H5_URL));
|
||||
data.put("system-name", configs.get(ConfigConstant.SYSTEM_NAME));
|
||||
data.put("system-logo", configs.get(ConfigConstant.SYSTEM_LOGO));
|
||||
data.put("system-api-url", configs.get(ConfigConstant.SYSTEM_API_URL));
|
||||
data.put("system-pc-url", configs.get(ConfigConstant.SYSTEM_PC_URL));
|
||||
data.put("system-h5-url", configs.get(ConfigConstant.SYSTEM_H5_URL));
|
||||
data.put("system-pc-index-footer-msg", configs.get("system.pc_index_footer_msg"));
|
||||
|
||||
data.put("player-poster", configs.get("player.poster"));
|
||||
@@ -63,16 +53,7 @@ public class SystemController {
|
||||
data.put("player-bullet-secret-opacity", configs.get("player.bullet_secret_opacity"));
|
||||
data.put("player-disabled-drag", configs.get("player.disabled_drag"));
|
||||
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
|
||||
@GetMapping("/image-captcha")
|
||||
public JsonResponse imageCaptcha() throws IOException {
|
||||
ImageCaptchaResult imageCaptchaResult = imageCaptchaService.generate();
|
||||
|
||||
HashMap<String, String> data = new HashMap<>();
|
||||
data.put("key", imageCaptchaResult.getKey());
|
||||
data.put("image", imageCaptchaResult.getImage());
|
||||
data.put("ldap-enabled", configs.get(ConfigConstant.LDAP_ENABLED));
|
||||
|
||||
return JsonResponse.data(data);
|
||||
}
|
||||
@@ -23,25 +23,25 @@ import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import xyz.playedu.api.FCtx;
|
||||
import xyz.playedu.api.constant.FrontendConstant;
|
||||
import xyz.playedu.api.domain.*;
|
||||
import xyz.playedu.api.exception.ServiceException;
|
||||
import xyz.playedu.api.request.frontend.ChangePasswordRequest;
|
||||
import xyz.playedu.api.service.*;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.api.types.mapper.UserCourseHourRecordCourseCountMapper;
|
||||
import xyz.playedu.api.types.response.UserLatestLearn;
|
||||
import xyz.playedu.api.util.PrivacyUtil;
|
||||
import xyz.playedu.common.constant.FrontendConstant;
|
||||
import xyz.playedu.common.context.FCtx;
|
||||
import xyz.playedu.common.domain.Department;
|
||||
import xyz.playedu.common.domain.User;
|
||||
import xyz.playedu.common.domain.UserUploadImageLog;
|
||||
import xyz.playedu.common.exception.ServiceException;
|
||||
import xyz.playedu.common.service.DepartmentService;
|
||||
import xyz.playedu.common.service.UserService;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.types.mapper.UserCourseHourRecordCourseCountMapper;
|
||||
import xyz.playedu.common.util.PrivacyUtil;
|
||||
import xyz.playedu.course.domain.*;
|
||||
import xyz.playedu.course.service.*;
|
||||
import xyz.playedu.resource.service.UploadService;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
*
|
||||
* @create 2023/3/13 09:21
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/user")
|
||||
@Slf4j
|
||||
@@ -68,7 +68,7 @@ public class UserController {
|
||||
User user = FCtx.getUser();
|
||||
List<Department> departments = new ArrayList<>();
|
||||
List<Integer> depIds = userService.getDepIdsByUserId(user.getId());
|
||||
if (depIds != null && depIds.size() > 0) {
|
||||
if (depIds != null && !depIds.isEmpty()) {
|
||||
departments = departmentService.listByIds(depIds);
|
||||
}
|
||||
|
||||
@@ -134,17 +134,21 @@ public class UserController {
|
||||
// 全部部门课
|
||||
List<Course> openCourses = courseService.getOpenCoursesAndShow(500, categoryId);
|
||||
// 汇总到一个list中
|
||||
if (depCourses != null && depCourses.size() > 0) {
|
||||
if (depCourses != null && !depCourses.isEmpty()) {
|
||||
courses.addAll(depCourses);
|
||||
}
|
||||
if (openCourses != null && openCourses.size() > 0) {
|
||||
if (openCourses != null && !openCourses.isEmpty()) {
|
||||
courses.addAll(openCourses);
|
||||
}
|
||||
// 对结果进行排序->按照课程id倒序
|
||||
if (courses.size() > 0) {
|
||||
if (!courses.isEmpty()) {
|
||||
courses =
|
||||
courses.stream()
|
||||
.sorted(Comparator.comparing(Course::getId).reversed())
|
||||
.sorted(
|
||||
Comparator.comparing(
|
||||
Course::getPublishedAt,
|
||||
Comparator.nullsFirst(Date::compareTo))
|
||||
.reversed())
|
||||
.toList();
|
||||
}
|
||||
|
||||
@@ -154,7 +158,7 @@ public class UserController {
|
||||
|
||||
// -------- 读取学习进度 ----------
|
||||
Map<Integer, UserCourseRecord> learnCourseRecords = new HashMap<>();
|
||||
if (courses.size() > 0) {
|
||||
if (!courses.isEmpty()) {
|
||||
learnCourseRecords =
|
||||
userCourseRecordService.chunk(FCtx.getId(), courseIds).stream()
|
||||
.collect(Collectors.toMap(UserCourseRecord::getCourseId, e -> e));
|
||||
@@ -174,7 +178,7 @@ public class UserController {
|
||||
Long learnDuration = userLearnDurationStatsService.userDuration(FCtx.getId()); // 学习总时长
|
||||
|
||||
// -------- 学习数据统计 ----------
|
||||
if (courses.size() > 0) {
|
||||
if (!courses.isEmpty()) {
|
||||
for (Course courseItem : courses) {
|
||||
if (courseItem.getIsRequired() == 1) {
|
||||
requiredHourCount += courseItem.getClassHour();
|
||||
@@ -233,7 +237,7 @@ public class UserController {
|
||||
// 读取当前学员最近100条学习的线上课
|
||||
List<UserCourseHourRecord> userCourseHourRecords =
|
||||
userCourseHourRecordService.getLatestCourseIds(FCtx.getId(), 100);
|
||||
if (userCourseHourRecords == null || userCourseHourRecords.size() == 0) {
|
||||
if (userCourseHourRecords == null || userCourseHourRecords.isEmpty()) {
|
||||
return JsonResponse.data(new ArrayList<>());
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package xyz.playedu.api.middleware;
|
||||
package xyz.playedu.api.interceptor;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
@@ -21,32 +21,31 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import xyz.playedu.api.BCtx;
|
||||
import xyz.playedu.api.bus.AppBus;
|
||||
import xyz.playedu.api.bus.BackendBus;
|
||||
import xyz.playedu.api.domain.AdminUser;
|
||||
import xyz.playedu.api.service.AdminUserService;
|
||||
import xyz.playedu.api.service.AppConfigService;
|
||||
import xyz.playedu.api.service.BackendAuthService;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.api.util.HelperUtil;
|
||||
import xyz.playedu.common.bus.BackendBus;
|
||||
import xyz.playedu.common.context.BCtx;
|
||||
import xyz.playedu.common.domain.AdminUser;
|
||||
import xyz.playedu.common.service.AdminUserService;
|
||||
import xyz.playedu.common.service.AppConfigService;
|
||||
import xyz.playedu.common.service.BackendAuthService;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.util.HelperUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class AdminMiddleware implements HandlerInterceptor {
|
||||
@Order(20)
|
||||
public class AdminInterceptor implements HandlerInterceptor {
|
||||
|
||||
@Autowired private BackendAuthService authService;
|
||||
|
||||
@Autowired private AdminUserService adminUserService;
|
||||
|
||||
@Autowired private AppBus appBus;
|
||||
|
||||
@Autowired private BackendBus backendBus;
|
||||
|
||||
@Autowired private AppConfigService configService;
|
||||
@@ -55,10 +54,6 @@ public class AdminMiddleware implements HandlerInterceptor {
|
||||
public boolean preHandle(
|
||||
HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||
throws Exception {
|
||||
if ("OPTIONS".equals(request.getMethod())) {
|
||||
return HandlerInterceptor.super.preHandle(request, response, handler);
|
||||
}
|
||||
|
||||
// 读取全局配置
|
||||
Map<String, String> systemConfig = configService.keyValues();
|
||||
BCtx.setConfig(systemConfig);
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2023 杭州白书科技有限公司
|
||||
*
|
||||
* 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 xyz.playedu.api.interceptor;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import xyz.playedu.common.config.PlayEduConfig;
|
||||
import xyz.playedu.common.constant.BackendConstant;
|
||||
import xyz.playedu.common.service.RateLimiterService;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.util.HelperUtil;
|
||||
import xyz.playedu.common.util.IpUtil;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
@Order(10)
|
||||
public class ApiInterceptor implements HandlerInterceptor {
|
||||
|
||||
@Autowired private RateLimiterService rateLimiterService;
|
||||
|
||||
@Autowired private PlayEduConfig playEduConfig;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(
|
||||
HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||
throws Exception {
|
||||
response.setHeader("Access-Control-Allow-Origin", "*");
|
||||
response.setHeader("Access-Control-Allow-Headers", "*");
|
||||
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
|
||||
response.setHeader("Access-Control-Max-Age", "86400");
|
||||
|
||||
if ("OPTIONS".equals(request.getMethod())) {
|
||||
response.setStatus(204);
|
||||
// 返回false意味着整个请求执行到这里结束,不会继续乡下执行了
|
||||
return false;
|
||||
}
|
||||
|
||||
// 当前api的请求路径
|
||||
String path = request.getRequestURI();
|
||||
// 白名单过滤 || OPTIONS请求
|
||||
if (BackendConstant.API_LIMIT_WHITELIST.contains(path)) {
|
||||
return HandlerInterceptor.super.preHandle(request, response, handler);
|
||||
}
|
||||
|
||||
// 限流判断
|
||||
String reqCountKey = "api-limiter:" + IpUtil.getIpAddress();
|
||||
Long reqCount = rateLimiterService.current(reqCountKey, playEduConfig.getLimiterDuration());
|
||||
long limitCount = playEduConfig.getLimiterLimit();
|
||||
long limitRemaining = limitCount - reqCount;
|
||||
response.setHeader("X-RateLimit-Limit", String.valueOf(limitCount));
|
||||
response.setHeader("X-RateLimit-Remaining", String.valueOf(limitRemaining));
|
||||
if (limitRemaining <= 0) {
|
||||
response.setStatus(429);
|
||||
response.setContentType("application/json;charset=utf-8");
|
||||
response.getWriter().print(HelperUtil.toJsonStr(JsonResponse.error("太多请求")));
|
||||
return false;
|
||||
}
|
||||
|
||||
return HandlerInterceptor.super.preHandle(request, response, handler);
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package xyz.playedu.api.middleware;
|
||||
package xyz.playedu.api.interceptor;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
@@ -21,22 +21,24 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import xyz.playedu.api.FCtx;
|
||||
import xyz.playedu.api.constant.FrontendConstant;
|
||||
import xyz.playedu.api.domain.User;
|
||||
import xyz.playedu.api.service.FrontendAuthService;
|
||||
import xyz.playedu.api.service.UserService;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.api.util.HelperUtil;
|
||||
import xyz.playedu.common.constant.FrontendConstant;
|
||||
import xyz.playedu.common.context.FCtx;
|
||||
import xyz.playedu.common.domain.User;
|
||||
import xyz.playedu.common.service.FrontendAuthService;
|
||||
import xyz.playedu.common.service.UserService;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.util.HelperUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class FrontMiddleware implements HandlerInterceptor {
|
||||
@Order(20)
|
||||
public class FrontInterceptor implements HandlerInterceptor {
|
||||
|
||||
@Autowired private FrontendAuthService authService;
|
||||
|
||||
@@ -46,10 +48,6 @@ public class FrontMiddleware implements HandlerInterceptor {
|
||||
public boolean preHandle(
|
||||
HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||
throws Exception {
|
||||
if ("OPTIONS".equals(request.getMethod())) {
|
||||
return HandlerInterceptor.super.preHandle(request, response, handler);
|
||||
}
|
||||
|
||||
if (FrontendConstant.UN_AUTH_URI_WHITELIST.contains(request.getRequestURI())) {
|
||||
return HandlerInterceptor.super.preHandle(request, response, handler);
|
||||
}
|
||||
@@ -13,42 +13,29 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package xyz.playedu.api.config;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
package xyz.playedu.api.interceptor;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import xyz.playedu.api.middleware.AdminMiddleware;
|
||||
import xyz.playedu.api.middleware.FrontMiddleware;
|
||||
|
||||
@Configuration
|
||||
@Slf4j
|
||||
public class WebMvcConfig implements WebMvcConfigurer {
|
||||
|
||||
@Resource private AdminMiddleware adminMiddleware;
|
||||
@Autowired private AdminInterceptor adminInterceptor;
|
||||
|
||||
@Autowired private FrontMiddleware frontMiddleware;
|
||||
@Autowired private FrontInterceptor frontInterceptor;
|
||||
|
||||
@Autowired private ApiInterceptor apiInterceptor;
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(adminMiddleware).addPathPatterns("/backend/**");
|
||||
registry.addInterceptor(frontMiddleware).addPathPatterns("/api/v1/**");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**")
|
||||
.allowCredentials(false)
|
||||
.allowedOrigins("*")
|
||||
.allowedHeaders("*")
|
||||
.allowedMethods("GET", "PUT", "POST", "DELETE")
|
||||
.exposedHeaders("*");
|
||||
registry.addInterceptor(apiInterceptor).addPathPatterns("/**");
|
||||
registry.addInterceptor(adminInterceptor).addPathPatterns("/backend/**");
|
||||
registry.addInterceptor(frontInterceptor).addPathPatterns("/api/v1/**");
|
||||
}
|
||||
}
|
||||
@@ -19,18 +19,11 @@ import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import xyz.playedu.api.constant.BackendLogConstant;
|
||||
import xyz.playedu.api.domain.AdminLog;
|
||||
import xyz.playedu.api.domain.AdminUser;
|
||||
import xyz.playedu.api.event.AdminUserLoginEvent;
|
||||
import xyz.playedu.api.service.AdminLogService;
|
||||
import xyz.playedu.api.service.AdminUserService;
|
||||
import xyz.playedu.api.util.IpUtil;
|
||||
|
||||
import java.util.Date;
|
||||
import xyz.playedu.common.domain.AdminUser;
|
||||
import xyz.playedu.common.service.AdminUserService;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
@@ -38,8 +31,6 @@ public class AdminUserLoginListener {
|
||||
|
||||
@Autowired private AdminUserService adminUserService;
|
||||
|
||||
@Autowired private AdminLogService adminLogService;
|
||||
|
||||
@EventListener
|
||||
public void updateLoginInfo(AdminUserLoginEvent event) {
|
||||
AdminUser adminUser = new AdminUser();
|
||||
@@ -51,20 +42,4 @@ public class AdminUserLoginListener {
|
||||
|
||||
adminUserService.updateById(adminUser);
|
||||
}
|
||||
|
||||
@Async
|
||||
@EventListener
|
||||
public void log(AdminUserLoginEvent event) {
|
||||
String area = IpUtil.getRealAddressByIP(event.getIp());
|
||||
|
||||
AdminLog adminLog = new AdminLog();
|
||||
adminLog.setAdminId(event.getAdminId());
|
||||
adminLog.setModule(BackendLogConstant.MODULE_LOGIN);
|
||||
adminLog.setOpt(BackendLogConstant.OPT_LOGIN);
|
||||
adminLog.setIp(event.getIp());
|
||||
adminLog.setIpArea(area);
|
||||
adminLog.setCreatedAt(new Date());
|
||||
|
||||
adminLogService.save(adminLog);
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import xyz.playedu.api.event.CourseCategoryDestroyEvent;
|
||||
import xyz.playedu.api.service.CourseService;
|
||||
import xyz.playedu.course.service.CourseService;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
@@ -20,7 +20,7 @@ import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import xyz.playedu.api.event.CourseChapterDestroyEvent;
|
||||
import xyz.playedu.api.service.CourseHourService;
|
||||
import xyz.playedu.course.service.CourseHourService;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
@@ -20,10 +20,11 @@ import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import xyz.playedu.api.event.CourseDestroyEvent;
|
||||
import xyz.playedu.api.service.CourseDepartmentService;
|
||||
import xyz.playedu.api.service.UserCourseHourRecordService;
|
||||
import xyz.playedu.api.service.UserCourseRecordService;
|
||||
import xyz.playedu.api.service.internal.ResourceCourseCategoryService;
|
||||
import xyz.playedu.course.service.CourseAttachmentService;
|
||||
import xyz.playedu.course.service.CourseCategoryService;
|
||||
import xyz.playedu.course.service.CourseDepartmentService;
|
||||
import xyz.playedu.course.service.UserCourseHourRecordService;
|
||||
import xyz.playedu.course.service.UserCourseRecordService;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
@@ -35,12 +36,14 @@ public class CourseDestroyListener {
|
||||
|
||||
@Autowired private CourseDepartmentService courseDepartmentService;
|
||||
|
||||
@Autowired private ResourceCourseCategoryService courseCategoryService;
|
||||
@Autowired private CourseCategoryService courseCategoryService;
|
||||
|
||||
@Autowired private UserCourseRecordService userCourseRecordService;
|
||||
|
||||
@Autowired private UserCourseHourRecordService userCourseHourRecordService;
|
||||
|
||||
@Autowired private CourseAttachmentService courseAttachmentService;
|
||||
|
||||
@EventListener
|
||||
public void departmentRelateRemove(CourseDestroyEvent event) {
|
||||
courseDepartmentService.removeByCourseId(event.getCourseId());
|
||||
@@ -51,6 +54,11 @@ public class CourseDestroyListener {
|
||||
courseCategoryService.removeByCourseId(event.getCourseId());
|
||||
}
|
||||
|
||||
@EventListener
|
||||
public void attachmentRelateRemove(CourseDestroyEvent event) {
|
||||
courseAttachmentService.remove(event.getCourseId());
|
||||
}
|
||||
|
||||
@EventListener
|
||||
public void removeUserRecords(CourseDestroyEvent event) {
|
||||
userCourseRecordService.removeByCourseId(event.getCourseId());
|
||||
@@ -20,8 +20,8 @@ import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import xyz.playedu.api.event.CourseHourCreatedEvent;
|
||||
import xyz.playedu.api.service.CourseHourService;
|
||||
import xyz.playedu.api.service.CourseService;
|
||||
import xyz.playedu.course.service.CourseHourService;
|
||||
import xyz.playedu.course.service.CourseService;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
@@ -20,8 +20,8 @@ import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import xyz.playedu.api.event.CourseHourDestroyEvent;
|
||||
import xyz.playedu.api.service.CourseHourService;
|
||||
import xyz.playedu.api.service.CourseService;
|
||||
import xyz.playedu.course.service.CourseHourService;
|
||||
import xyz.playedu.course.service.CourseService;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
@@ -20,7 +20,7 @@ import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import xyz.playedu.api.event.DepartmentDestroyEvent;
|
||||
import xyz.playedu.api.service.DepartmentService;
|
||||
import xyz.playedu.common.service.DepartmentService;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
@@ -20,9 +20,9 @@ import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import xyz.playedu.api.event.UserCourseHourFinishedEvent;
|
||||
import xyz.playedu.api.service.CourseHourService;
|
||||
import xyz.playedu.api.service.UserCourseHourRecordService;
|
||||
import xyz.playedu.api.service.UserCourseRecordService;
|
||||
import xyz.playedu.course.service.CourseHourService;
|
||||
import xyz.playedu.course.service.UserCourseHourRecordService;
|
||||
import xyz.playedu.course.service.UserCourseRecordService;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
@@ -22,7 +22,7 @@ import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import xyz.playedu.api.event.UserCourseHourRecordDestroyEvent;
|
||||
import xyz.playedu.api.service.UserCourseRecordService;
|
||||
import xyz.playedu.course.service.UserCourseRecordService;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
@@ -20,7 +20,7 @@ import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import xyz.playedu.api.event.UserCourseRecordDestroyEvent;
|
||||
import xyz.playedu.api.service.UserCourseHourRecordService;
|
||||
import xyz.playedu.course.service.UserCourseHourRecordService;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
@@ -22,7 +22,12 @@ import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import xyz.playedu.api.event.UserDestroyEvent;
|
||||
import xyz.playedu.api.service.*;
|
||||
import xyz.playedu.common.service.UserLoginRecordService;
|
||||
import xyz.playedu.common.service.UserService;
|
||||
import xyz.playedu.course.service.UserCourseHourRecordService;
|
||||
import xyz.playedu.course.service.UserCourseRecordService;
|
||||
import xyz.playedu.course.service.UserLearnDurationRecordService;
|
||||
import xyz.playedu.course.service.UserLearnDurationStatsService;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
@@ -22,8 +22,8 @@ import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import xyz.playedu.api.event.UserLearnCourseUpdateEvent;
|
||||
import xyz.playedu.api.service.UserLearnDurationRecordService;
|
||||
import xyz.playedu.api.service.UserLearnDurationStatsService;
|
||||
import xyz.playedu.course.service.UserLearnDurationRecordService;
|
||||
import xyz.playedu.course.service.UserLearnDurationStatsService;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
@@ -23,9 +23,9 @@ import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import xyz.playedu.api.event.UserLoginEvent;
|
||||
import xyz.playedu.api.service.FrontendAuthService;
|
||||
import xyz.playedu.api.service.UserLoginRecordService;
|
||||
import xyz.playedu.api.util.IpUtil;
|
||||
import xyz.playedu.common.service.FrontendAuthService;
|
||||
import xyz.playedu.common.service.UserLoginRecordService;
|
||||
import xyz.playedu.common.util.IpUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import xyz.playedu.api.event.UserLogoutEvent;
|
||||
import xyz.playedu.api.service.UserLoginRecordService;
|
||||
import xyz.playedu.common.service.UserLoginRecordService;
|
||||
|
||||
/**
|
||||
* @Author 杭州白书科技有限公司
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2023 杭州白书科技有限公司
|
||||
*
|
||||
* 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 xyz.playedu.api.request.backend;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class CourseAttachmentMultiRequest {
|
||||
@Data
|
||||
public static class AttachmentItem {
|
||||
private String title;
|
||||
private Integer sort;
|
||||
private String type;
|
||||
private Integer rid;
|
||||
}
|
||||
|
||||
@NotNull(message = "attachments参数不存在")
|
||||
private List<AttachmentItem> attachments;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2023 杭州白书科技有限公司
|
||||
*
|
||||
* 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 xyz.playedu.api.request.backend;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class CourseAttachmentRequest {
|
||||
|
||||
@NotBlank(message = "请输入附件名称")
|
||||
private String title;
|
||||
|
||||
@NotNull(message = "sort参数不存在")
|
||||
private Integer sort;
|
||||
|
||||
@NotBlank(message = "请选择附件类型")
|
||||
private String type;
|
||||
|
||||
@NotNull(message = "rid参数不存在")
|
||||
private Integer rid;
|
||||
}
|
||||
@@ -13,15 +13,13 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package xyz.playedu.api.service;
|
||||
package xyz.playedu.api.request.backend;
|
||||
|
||||
import xyz.playedu.api.types.ImageCaptchaResult;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public interface ImageCaptchaService {
|
||||
|
||||
ImageCaptchaResult generate() throws IOException;
|
||||
|
||||
boolean verify(String key, String code);
|
||||
@Data
|
||||
public class CourseAttachmentSortRequest {
|
||||
private List<Integer> ids;
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -58,6 +59,9 @@ public class CourseRequest {
|
||||
@JsonProperty("category_ids")
|
||||
private Integer[] categoryIds;
|
||||
|
||||
@JsonProperty("published_at")
|
||||
private Date publishedAt;
|
||||
|
||||
@Data
|
||||
public static class HourItem {
|
||||
private String name;
|
||||
@@ -72,6 +76,13 @@ public class CourseRequest {
|
||||
private List<HourItem> hours;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class AttachmentItem {
|
||||
private String name;
|
||||
private String type;
|
||||
private Integer rid;
|
||||
}
|
||||
|
||||
// 格式
|
||||
// [
|
||||
// {
|
||||
@@ -100,4 +111,14 @@ public class CourseRequest {
|
||||
// ]
|
||||
@NotNull(message = "hours参数不存在")
|
||||
private List<HourItem> hours;
|
||||
|
||||
// 格式
|
||||
// [
|
||||
// {
|
||||
// 'name' => '附件名',
|
||||
// 'type' => '附件类型',
|
||||
// 'rid' => '资源id',
|
||||
// }...
|
||||
// ]
|
||||
private List<AttachmentItem> attachments;
|
||||
}
|
||||
@@ -15,19 +15,15 @@
|
||||
*/
|
||||
package xyz.playedu.api.request.backend;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import xyz.playedu.api.request.backend.types.ImageCaptchaRequestInterface;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class LoginRequest implements Serializable, ImageCaptchaRequestInterface {
|
||||
public class LoginRequest implements Serializable {
|
||||
|
||||
@Serial private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -36,12 +32,4 @@ public class LoginRequest implements Serializable, ImageCaptchaRequestInterface
|
||||
|
||||
@NotNull(message = "请输入密码")
|
||||
public String password;
|
||||
|
||||
@NotNull(message = "请输入图形验证码")
|
||||
@JsonProperty("captcha_value")
|
||||
public String captchaValue;
|
||||
|
||||
@NotNull(message = "captchaKey参数为空")
|
||||
@JsonProperty("captcha_key")
|
||||
public String captchaKey;
|
||||
}
|
||||
@@ -28,7 +28,7 @@ import lombok.Data;
|
||||
* @create 2023/3/8 14:49
|
||||
*/
|
||||
@Data
|
||||
public class UploadVideoMergeRequest {
|
||||
public class UploadFileMergeRequest {
|
||||
|
||||
@NotBlank(message = "请输入课程标题")
|
||||
private String filename;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user