Forráskód Böngészése

feat:迁移老用户系统

370774330@qq.com 5 éve
szülő
commit
c7ae8c7b4a
23 módosított fájl, 871 hozzáadás és 403 törlés
  1. 21 45
      api/src/main/java/seecoder/devcloud/api/ApplicationProperties.java
  2. 5 0
      common/pom.xml
  3. 13 0
      common/src/main/java/seecoder/devcloud/common/serializer/CustomLocalDateTimeDeserializer.java
  4. 13 0
      common/src/main/java/seecoder/devcloud/common/serializer/CustomLocalDateTimeSerializer.java
  5. 32 0
      common/src/main/java/seecoder/devcloud/common/serializer/TimestampLocalDateDeserializer.java
  6. 29 0
      common/src/main/java/seecoder/devcloud/common/serializer/TimestampLocalDateTimeSerializer.java
  7. 41 0
      common/src/main/java/seecoder/devcloud/common/validate/FieldCompare.java
  8. 39 0
      common/src/main/java/seecoder/devcloud/common/validate/FieldEquals.java
  9. 38 0
      common/src/main/java/seecoder/devcloud/common/validate/validator/FieldCompareValidator.java
  10. 30 0
      common/src/main/java/seecoder/devcloud/common/validate/validator/FieldEqualsValidator.java
  11. 33 0
      web/src/main/java/seecoder/devcloud/web/dao/user/UserDAO.java
  12. 24 0
      web/src/main/java/seecoder/devcloud/web/dto/user/UserDTO.java
  13. 23 0
      web/src/main/java/seecoder/devcloud/web/enums/UserIdentity.java
  14. 45 0
      web/src/main/java/seecoder/devcloud/web/po/user/User.java
  15. 235 232
      web/src/main/java/seecoder/devcloud/web/service/impl/user/UserServiceImpl.java
  16. 39 37
      web/src/main/java/seecoder/devcloud/web/service/user/UserService.java
  17. 18 0
      web/src/main/java/seecoder/devcloud/web/vo/user/ChangePasswordVO.java
  18. 24 0
      web/src/main/java/seecoder/devcloud/web/vo/user/GroupDTO.java
  19. 36 0
      web/src/main/java/seecoder/devcloud/web/vo/user/GroupVO.java
  20. 44 0
      web/src/main/java/seecoder/devcloud/web/vo/user/RegisterVO.java
  21. 37 0
      web/src/main/java/seecoder/devcloud/web/vo/user/UserSerializer.java
  22. 40 0
      web/src/main/java/seecoder/devcloud/web/vo/user/UserVO.java
  23. 12 89
      web/src/main/resources/application-wph.yml

+ 21 - 45
api/src/main/java/seecoder/devcloud/api/ApplicationProperties.java

@@ -20,9 +20,7 @@ import java.util.Map;
 @ConfigurationProperties("seecoder")
 @Validated
 public class ApplicationProperties {
-	@Pattern(regexp = "^[a-zA-Z0-9]+$")
-	@NotEmpty
-	private String secret;
+
 	@Valid
 	private Gitlab gitlab = new Gitlab();
 	@Valid
@@ -31,34 +29,44 @@ public class ApplicationProperties {
 	private Docker docker = new Docker();
 	@Valid
 	private Mail mail = new Mail();
-//	@Valid
-//	private Storage storage = new Storage();
 	@Valid
 	private K8s k8s = new K8s();
 	@Valid
 	private Registry registry = new Registry();
-//	@Valid
-//	private Auth auth = new Auth();
+
 
 	@Data
 	public static class Gitlab {
+
 		@URL
 		@NotEmpty
 		private String host;
-		private String gitProxy;
+
+		//private String gitProxy;
+		/**
+		 * 回调地址
+		 */
 		@URL
 		@NotEmpty
 		private String webHookProxy;
-		@NotEmpty
-		private String username = "root";
+
+
+//		@NotEmpty
+//		private String username = "root";
         @NotNull
         private Integer userId = 1;
+
+		/**
+		 * 采用的Personal/project access tokens的认证方式
+		 * 这里使用管理员的token
+		 * https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html
+		 */
 		@NotEmpty
 		private String token;
 
-		public String getGitProxy() {
-			return StringUtils.defaultString(gitProxy, host);
-		}
+//		public String getGitProxy() {
+//			return StringUtils.defaultString(gitProxy, host);
+//		}
 	}
 
 	@Data
@@ -70,8 +78,6 @@ public class ApplicationProperties {
 		private String username = "root";
 		@NotEmpty
 		private String token;
-		@NotEmpty
-		private String baseImage = "172.19.51.9:18082/build-base";
 	}
 
 	@Data
@@ -91,11 +97,6 @@ public class ApplicationProperties {
 		private String personal = "MOOCODER";
 	}
 
-//	@Data
-//	public static class Storage {
-//		private String type = "local";
-//		private Map<String, String> properties = new HashMap<>();
-//	}
 
 	@Data
 	public static class K8s{
@@ -104,18 +105,6 @@ public class ApplicationProperties {
 		private String apiServer;
 		@NotEmpty
 		private String token;
-//		@NotEmpty
-//		private String ingressHost;
-//		@NotEmpty
-//		private String publicNamespace;
-//		@NotEmpty
-//		private String publicMysqlUrl;
-//		@NotEmpty
-//		private String publicMysqlPod;
-//		@NotEmpty
-//		private String publicMysqlUsername;
-//
-//		private String publicMysqlPassword;
 
 		private Boolean validateSSL = false;
 
@@ -143,17 +132,4 @@ public class ApplicationProperties {
 		private String cleanUpTask = "4da7e1e1-2b28-46b5-a080-9d834cc96019";
 	}
 
-//	@Data
-//	public static class Auth {
-//		@NotEmpty
-//		private String signingKey;
-//		@NotEmpty
-//		private String iss = "p.seecoder.cn";
-//		@NotEmpty
-//		private String aud = "seec-seec";
-//		@NotEmpty
-//		private String portal = "http://p.seecoder.cn";
-//		@NotEmpty
-//		private String redirectUri;
-//	}
 }

+ 5 - 0
common/pom.xml

@@ -29,6 +29,11 @@
             <scope>compile</scope>
         </dependency>
 
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>

+ 13 - 0
common/src/main/java/seecoder/devcloud/common/serializer/CustomLocalDateTimeDeserializer.java

@@ -0,0 +1,13 @@
+package seecoder.devcloud.common.serializer;
+
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
+
+import java.time.format.DateTimeFormatter;
+
+public class CustomLocalDateTimeDeserializer extends LocalDateTimeDeserializer {
+	private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm");
+
+	public CustomLocalDateTimeDeserializer() {
+		super(FORMATTER);
+	}
+}

+ 13 - 0
common/src/main/java/seecoder/devcloud/common/serializer/CustomLocalDateTimeSerializer.java

@@ -0,0 +1,13 @@
+package seecoder.devcloud.common.serializer;
+
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
+
+import java.time.format.DateTimeFormatter;
+
+public class CustomLocalDateTimeSerializer extends LocalDateTimeSerializer {
+	private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm");
+
+	public CustomLocalDateTimeSerializer() {
+		super(FORMATTER);
+	}
+}

+ 32 - 0
common/src/main/java/seecoder/devcloud/common/serializer/TimestampLocalDateDeserializer.java

@@ -0,0 +1,32 @@
+package seecoder.devcloud.common.serializer;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+
+import java.io.IOException;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+
+public class TimestampLocalDateDeserializer extends JsonDeserializer<LocalDateTime> {
+	@Override
+	public LocalDateTime deserialize(JsonParser p, DeserializationContext context) throws IOException {
+		Long epochSecond = null;
+		if (p.hasToken(JsonToken.VALUE_NUMBER_INT)) {
+			epochSecond = p.getLongValue();
+		} else if (p.hasToken(JsonToken.VALUE_STRING)) {
+			String value = p.getText().trim();
+			try {
+				epochSecond = Long.valueOf(value);
+			} catch (NumberFormatException e) {
+				epochSecond = null;
+			}
+		}
+		if (epochSecond != null) {
+			return LocalDateTime.ofInstant(Instant.ofEpochSecond(epochSecond), ZoneId.systemDefault());
+		}
+		return null;
+	}
+}

+ 29 - 0
common/src/main/java/seecoder/devcloud/common/serializer/TimestampLocalDateTimeSerializer.java

@@ -0,0 +1,29 @@
+package seecoder.devcloud.common.serializer;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
+
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+
+public class TimestampLocalDateTimeSerializer extends LocalDateTimeSerializer {
+	@Override
+	protected LocalDateTimeSerializer withFormat(Boolean useTimestamp, DateTimeFormatter f, JsonFormat.Shape shape) {
+		return this;
+	}
+
+	@Override
+	public void serialize(LocalDateTime value, JsonGenerator g, SerializerProvider provider) throws IOException {
+		g.writeNumber(value.atZone(ZoneId.systemDefault()).toEpochSecond());
+	}
+
+	@Override
+	public void serializeWithType(LocalDateTime value, JsonGenerator g, SerializerProvider provider, TypeSerializer typeSer) throws IOException {
+		serialize(value, g, provider);
+	}
+}

+ 41 - 0
common/src/main/java/seecoder/devcloud/common/validate/FieldCompare.java

@@ -0,0 +1,41 @@
+package seecoder.devcloud.common.validate;
+
+import com.moekr.moocoder.util.validate.FieldCompare.List;
+import com.moekr.moocoder.util.validate.validator.FieldCompareValidator;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Target({TYPE, ANNOTATION_TYPE})
+@Retention(RUNTIME)
+@Repeatable(List.class)
+@Constraint(validatedBy = FieldCompareValidator.class)
+@Documented
+public @interface FieldCompare {
+	String message() default "{com.moekr.moocoder.util.validate.FieldCompare}";
+
+	Class<?>[] groups() default {};
+
+	Class<? extends Payload>[] payload() default {};
+
+	String lessField();
+
+	String greaterField();
+
+	boolean allowEqual() default false;
+
+	@Target({TYPE, ANNOTATION_TYPE})
+	@Retention(RUNTIME)
+	@Documented
+	@interface List {
+		FieldCompare[] value();
+	}
+}

+ 39 - 0
common/src/main/java/seecoder/devcloud/common/validate/FieldEquals.java

@@ -0,0 +1,39 @@
+package seecoder.devcloud.common.validate;
+
+import seecoder.devcloud.common.validate.validator.FieldEqualsValidator;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Target({TYPE, ANNOTATION_TYPE})
+@Retention(RUNTIME)
+@Repeatable(FieldEquals.List.class)
+@Constraint(validatedBy = FieldEqualsValidator.class)
+@Documented
+public @interface FieldEquals {
+	String message() default "{com.moekr.moocoder.util.validate.FieldEquals}";
+
+	Class<?>[] groups() default {};
+
+	Class<? extends Payload>[] payload() default {};
+
+	String firstField();
+
+	String secondField();
+
+	@Target({TYPE, ANNOTATION_TYPE})
+	@Retention(RUNTIME)
+	@Documented
+	@interface List {
+		FieldEquals[] value();
+	}
+
+}

+ 38 - 0
common/src/main/java/seecoder/devcloud/common/validate/validator/FieldCompareValidator.java

@@ -0,0 +1,38 @@
+package seecoder.devcloud.common.validate.validator;
+
+import org.springframework.beans.BeanUtils;
+import seecoder.devcloud.common.validate.FieldCompare;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+public class FieldCompareValidator implements ConstraintValidator<FieldCompare, Object> {
+	private String lessField;
+	private String greaterField;
+	private boolean allowEqual;
+
+
+	@Override
+	public void initialize(FieldCompare constraintAnnotation) {
+		this.lessField = constraintAnnotation.lessField();
+		this.greaterField = constraintAnnotation.greaterField();
+		this.allowEqual = constraintAnnotation.allowEqual();
+	}
+
+	@Override
+	@SuppressWarnings("unchecked")
+	public boolean isValid(Object value, ConstraintValidatorContext context) {
+		try {
+			Comparable lessObject = (Comparable) BeanUtils.getPropertyDescriptor(value.getClass(), lessField).getReadMethod().invoke(value);
+			Comparable greaterObject = (Comparable) BeanUtils.getPropertyDescriptor(value.getClass(), greaterField).getReadMethod().invoke(value);
+			int result = lessObject.compareTo(greaterObject);
+			if (allowEqual && result == 0) {
+				return true;
+			} else {
+				return result < 0;
+			}
+		} catch (Exception e) {
+			return false;
+		}
+	}
+}

+ 30 - 0
common/src/main/java/seecoder/devcloud/common/validate/validator/FieldEqualsValidator.java

@@ -0,0 +1,30 @@
+package seecoder.devcloud.common.validate.validator;
+
+import org.springframework.beans.BeanUtils;
+import seecoder.devcloud.common.validate.FieldEquals;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+import java.util.Objects;
+
+public class FieldEqualsValidator implements ConstraintValidator<FieldEquals, Object> {
+	private String firstField;
+	private String secondField;
+
+	@Override
+	public void initialize(FieldEquals constraintAnnotation) {
+		this.firstField = constraintAnnotation.firstField();
+		this.secondField = constraintAnnotation.secondField();
+	}
+
+	@Override
+	public boolean isValid(Object value, ConstraintValidatorContext context) {
+		try {
+			Object firstObject = BeanUtils.getPropertyDescriptor(value.getClass(), firstField).getReadMethod().invoke(value);
+			Object secondObject = BeanUtils.getPropertyDescriptor(value.getClass(), secondField).getReadMethod().invoke(value);
+			return Objects.equals(firstObject, secondObject);
+		} catch (Exception e) {
+			return false;
+		}
+	}
+}

+ 33 - 0
web/src/main/java/seecoder/devcloud/web/dao/user/UserDAO.java

@@ -0,0 +1,33 @@
+package seecoder.devcloud.web.dao.user;
+
+
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import seecoder.devcloud.web.enums.UserIdentity;
+import seecoder.devcloud.web.po.user.User;
+
+import java.util.List;
+
+
+
+public interface UserDAO {
+	User findById(int id);
+
+	User findByUsername(String username);
+
+	User findByEmail(String email);
+
+	Page<User> findAllByUsernameLike(String search, Pageable pageable);
+
+	Integer countByRole(UserIdentity role);
+
+	User findUserByUsername(String username);
+
+	User findUserById(Integer id);
+
+	User findByPid(Integer pid);
+
+	User findByPhone(String phone);
+
+	List<User> findByRole(UserIdentity userIdentity);
+}

+ 24 - 0
web/src/main/java/seecoder/devcloud/web/dto/user/UserDTO.java

@@ -0,0 +1,24 @@
+package seecoder.devcloud.web.dto.user;
+
+import com.moekr.moocoder.util.enums.UserIdentity;
+import lombok.Data;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+
+@Data
+public class UserDTO {
+	@Pattern(regexp = "[0-9a-zA-Z_]{4,16}", message = "用户名只能包含大小写字母、数字和下划线,且必须为4-16位!", groups = PostMapping.class)
+	@NotNull(message = "请填写用户名!", groups = PostMapping.class)
+	private String username;
+	@Email(message = "邮箱格式不正确!", groups = {PostMapping.class, PutMapping.class})
+	@NotNull(message = "请填写邮箱!", groups = {PostMapping.class, PutMapping.class})
+	private String email;
+//	@NotNull(message = "请选择用户角色!", groups = PostMapping.class)
+	private UserIdentity role;
+	//string | null
+	private String nickname;
+}

+ 23 - 0
web/src/main/java/seecoder/devcloud/web/enums/UserIdentity.java

@@ -0,0 +1,23 @@
+package seecoder.devcloud.web.enums;
+
+public enum UserIdentity {
+	/**
+	 * 学生角色
+	 */
+	STUDENT("学生"),
+	/**
+	 * 教师角色
+	 */
+	TEACHER("教师");
+
+	private final String name;
+
+	UserIdentity(String name) {
+		this.name = name;
+	}
+
+	@Override
+	public String toString() {
+		return name;
+	}
+}

+ 45 - 0
web/src/main/java/seecoder/devcloud/web/po/user/User.java

@@ -0,0 +1,45 @@
+package seecoder.devcloud.web.po.user;
+
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.hibernate.annotations.LazyCollection;
+import org.hibernate.annotations.LazyCollectionOption;
+import org.springframework.data.annotation.CreatedDate;
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
+import seecoder.devcloud.web.enums.UserIdentity;
+
+import javax.persistence.*;
+import java.time.LocalDateTime;
+import java.util.HashSet;
+import java.util.Set;
+
+@Data
+public class User {
+
+	private Integer id;
+
+	private String username;
+
+	private String nickname="";
+
+	private String bio="";
+
+	private Integer pid;
+
+	private String password;
+
+	private String phone;
+
+	private String email;
+
+	private Integer namespace;
+
+	private String token;
+
+	private UserIdentity role;
+
+	private LocalDateTime createdAt;
+
+}

+ 235 - 232
web/src/main/java/seecoder/devcloud/web/service/impl/user/UserServiceImpl.java

@@ -1,232 +1,235 @@
-//package seecoder.devcloud.web.service.impl.user;
-//
-//
-//import org.apache.commons.codec.digest.DigestUtils;
-//import org.gitlab4j.api.GitLabApiException;
-//import org.springframework.beans.BeanUtils;
-//import org.springframework.beans.factory.annotation.Autowired;
-//import org.springframework.data.domain.Page;
-//import org.springframework.data.domain.PageRequest;
-//import org.springframework.data.domain.Pageable;
-//import org.springframework.data.domain.Sort;
-//import org.springframework.stereotype.Service;
-//import org.springframework.transaction.annotation.Transactional;
-//import org.springframework.util.Assert;
-//import seecoder.devcloud.api.gitlab.GitlabApi;
-//import seecoder.devcloud.api.gitlab.model.GitlabUser;
-//import seecoder.devcloud.api.jenkins.JenkinsApi;
-//import seecoder.devcloud.common.exceptions.Asserts;
-//import seecoder.devcloud.common.exceptions.ServiceException;
-//import seecoder.devcloud.common.util.ToolKit;
-//import seecoder.devcloud.web.service.user.MailService;
-//
-//@Service
-//public class UserServiceImpl implements UserService {
-//	private static final Sort PAGE_SORT = Sort.by(Sort.Direction.ASC, "id");
-//
-//	private final UserDAO userDAO;
-//	private final MailService mailService;
-//	private final GitlabApi gitlabApi;
-//	private final JenkinsApi jenkinsApi;
-//
-//	@Autowired
-//	public UserServiceImpl(UserDAO userDAO, MailService mailService, GitlabApi gitlabApi, JenkinsApi jenkinsApi) {
-//		this.userDAO = userDAO;
-//		this.mailService = mailService;
-//		this.gitlabApi = gitlabApi;
-//		this.jenkinsApi = jenkinsApi;
-//	}
-//
-//	@Override
-//	@Transactional
-//	public UserVO create(UserDTO userDTO) throws ServiceException {
-//		return register(userDTO.getUsername(), userDTO.getEmail(), null,userDTO.getNickname(), userDTO.getRole());
-//	}
-//
-//	@Override
-//	@Transactional
-//	public User register(String username, String name, String email, String password, String phone, UserIdentity role, Integer pid) throws ServiceException {
-//		User user = userDAO.findByUsername(username);
-//		Asserts.isNull(user, "用户名已被使用!");
-//		user = userDAO.findByEmail(email);
-//		Asserts.isNull(user, "邮箱已被使用!");
-//		String realPassword = password == null ? ToolKit.randomPassword() : password;
-//		GitlabUser gitlabUser;
-//		try {
-//			gitlabUser = gitlabApi.createUser(username, email, realPassword);
-//		} catch (GitLabApiException e) {
-//			throw new ServiceException("创建GitLab用户时发生异常[" + e.getMessage() + "]");
-//		}
-//		user = new User();
-//		BeanUtils.copyProperties(gitlabUser, user);
-//		if(name!=null){
-//			user.setNickname(name);
-//		}
-//
-//		user.setUsername(username);
-//		user.setEmail(email);
-//		user.setPassword(DigestUtils.sha256Hex(realPassword));
-//		user.setPid(pid);
-//		user.setPhone(phone);
-//		user.setRole(role);
-//		user = userDAO.save(user);
-//		if (password == null) {
-//			mailService.send("尊敬的" + username + "您好, 您的初始密码为" + realPassword + ", 请及时修改", "注册成功 | SEECODER", email);
-//		}
-//		return user;
-//	}
-//
-//	@Override
-//	public Page<UserVO> retrievePage(int page, int limit, String search) {
-//		Pageable pageable = PageRequest.of(page, limit, PAGE_SORT);
-//		Page<User> pageResult;
-//		if (search == null || search.isEmpty()) {
-//			pageResult = userDAO.findAll(pageable);
-//		} else {
-//			pageResult = userDAO.findAllByUsernameLike("%" + search + "%", pageable);
-//		}
-//		return pageResult.map(UserVO::new);
-//	}
-//
-//	@Override
-//	public UserVO retrieve(int userId) throws ServiceException {
-//		User user = userDAO.findById(userId);
-//		Asserts.notNull(user, "所选用户不存在");
-//		return new UserVO(user);
-//	}
-//
-//	@Override
-//	@Transactional
-//	public void delete(int userId) throws ServiceException {
-//		User user = userDAO.findById(userId);
-//		Assert.notNull(user, "找不到要删除的用户");
-//		Assert.isTrue(user.getRole() == UserIdentity.STUDENT, "目标用户只能是学生");
-//		try {
-//			gitlabApi.deleteUser(userId);
-//		} catch (Exception e) {
-//			throw new ServiceException("删除GitLab用户时发生异常[" + e.getMessage() + "]");
-//		}
-//		for (Result result : user.getResultSet()) {
-//			if (!result.isDeleted()) {
-//				try {
-//					jenkinsApi.deleteJob(result.getId());
-//				} catch (Exception e) {
-//					throw new ServiceException("删除Jenkins项目时发生异常[" + e.getMessage() + "]");
-//				}
-//			}
-//		}
-//		userDAO.delete(user);
-//	}
-//
-//	@Override
-//	@Transactional
-//	public UserSerializer register(RegisterForm form) throws ServiceException {
-//		return new UserSerializer(register(form.getUsername(), form.getEmail(), form.getPassword(),form.getNickname(), UserIdentity.STUDENT));
-//	}
-//	@Override
-//	@Transactional
-//	public UserSerializer registerTeacher(RegisterForm form) throws ServiceException {
-//		return new UserSerializer(register(form.getUsername(), form.getEmail(), form.getPassword(),form.getNickname(), UserIdentity.TEACHER));
-//	}
-//	private UserVO register(String username, String email, String password, String nickname,UserIdentity role) throws ServiceException {
-//		User user = userDAO.findByUsername(username);
-//		Asserts.isNull(user, "用户名已被使用!");
-//		user = userDAO.findByEmail(email);
-//		Asserts.isNull(user, "邮箱已被使用!");
-//		String realPassword = password == null ? ToolKit.randomPassword() : password;
-//		GitlabUser gitlabUser;
-//		try {
-//			gitlabUser = gitlabApi.createUser(username, email, realPassword);
-//		} catch (GitLabApiException e) {
-//			throw new ServiceException("创建GitLab用户时发生异常[" + e.getMessage() + "]");
-//		}
-//		user = new User();
-//		BeanUtils.copyProperties(gitlabUser, user);
-//		if(nickname!=null){
-//			user.setNickname(nickname);
-//		}
-//
-//		user.setUsername(username);
-//		user.setEmail(email);
-//		user.setPassword(DigestUtils.sha256Hex(realPassword));
-//		user.setRole(role);
-//		final UserVO userVO = new UserVO(userDAO.save(user));
-//		if (password == null) {
-//			mailService.send("尊敬的" + username + "您好, 您的初始密码为" + realPassword + ", 请及时修改", "注册成功 | SEECODER", email);
-//		}
-//		return userVO;
-//	}
-//
-//
-//	@Override
-//	public UserSerializer getUserById(Integer userid) {
-//		return new UserSerializer(userDAO.getOne(userid));
-//	}
-//
-//	@Override
-//	public UserSerializer changeUserInfo(Integer userid,String nickName, String bio) throws ServiceException {
-//		User one = userDAO.findById(userid).orElse(null);
-//		if (one == null) {
-//			throw new ServiceException("用户不存在");
-//		}
-//		if(nickName!=null){
-//			one.setNickname(nickName);
-//		}
-//		if(bio!=null){
-//			one.setBio(bio);
-//		}
-//		return new UserSerializer(userDAO.save(one));
-//	}
-//
-//	@Override
-//	public UserSerializer changeUserPassword(Integer userid,String oldPassword, String newPassword) throws ServiceException {
-//		User one = userDAO.findById(userid).orElse(null);
-//		if (one == null) {
-//			throw new ServiceException("用户不存在");
-//		}
-//		if(!one.getPassword().equals(DigestUtils.sha256Hex(oldPassword))){
-//			throw new ServiceException("原密码错误");
-//		}else{
-//			one.setPassword(DigestUtils.sha256Hex(newPassword));
-//		}
-//		try {
-//			gitlabApi.changePassword(userid, newPassword);
-//		} catch (GitLabApiException e) {
-//			throw new ServiceException("修改GitLab用户密码时发生异常[" + e.getMessage() + "]");
-//		}
-//		mailService.send( "您的新密码为"+newPassword,"密码变更提醒 | SEECODER",one.getEmail());
-//		return new UserSerializer(userDAO.save(one));
-//	}
-//
-//	@Override
-//	public void changePassword(int userId, ChangePasswordForm form) throws ServiceException {
-//		User user = userDAO.findById(userId);
-//		if (!user.getPassword().equals(DigestUtils.sha256Hex(form.getOrigin()))) {
-//			throw new InvalidRequestException("原密码验证失败,如忘记密码请联系管理员重置");
-//		}
-//		changePassword(user, form.getPassword(), false);
-//	}
-//
-//	@Override
-//	public void resetPassword(int userId) throws ServiceException {
-//		User user = userDAO.findById(userId);
-//		Asserts.notNull(user, "所选用户不存在");
-//		String password = ToolKit.randomPassword();
-//		changePassword(user, password, true);
-//	}
-//
-//
-//
-//	private void changePassword(User user, String password, boolean reset) throws ServiceException {
-//		try {
-//			gitlabApi.changePassword(user.getId(), password);
-//		} catch (GitLabApiException e) {
-//			throw new ServiceException("修改GitLab用户密码时发生异常[" + e.getMessage() + "]");
-//		}
-//		user.setPassword(DigestUtils.sha256Hex(password));
-//		user = userDAO.save(user);
-//		if (reset) {
-//			mailService.send( "您的新密码为"+password,"密码变更提醒 | SEECODER",user.getEmail());
-//		}
-//	}
-//}
+package seecoder.devcloud.web.service.impl.user;
+
+
+import org.apache.commons.codec.digest.DigestUtils;
+import org.gitlab4j.api.GitLabApiException;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.Assert;
+import seecoder.devcloud.api.gitlab.GitlabApi;
+import seecoder.devcloud.api.gitlab.model.GitlabUser;
+import seecoder.devcloud.api.jenkins.JenkinsApi;
+import seecoder.devcloud.common.exceptions.Asserts;
+import seecoder.devcloud.common.exceptions.InvalidRequestException;
+import seecoder.devcloud.common.exceptions.ServiceException;
+import seecoder.devcloud.common.util.ToolKit;
+import seecoder.devcloud.web.dao.user.UserDAO;
+import seecoder.devcloud.web.vo.user.ChangePasswordVO;
+import seecoder.devcloud.web.vo.user.RegisterVO;
+
+import seecoder.devcloud.web.dto.user.UserDTO;
+import seecoder.devcloud.web.enums.UserIdentity;
+import seecoder.devcloud.web.po.user.User;
+import seecoder.devcloud.web.vo.user.UserSerializer;
+import seecoder.devcloud.web.service.user.MailService;
+import seecoder.devcloud.web.service.user.UserService;
+import seecoder.devcloud.web.vo.user.UserVO;
+
+@Service
+public class UserServiceImpl implements UserService {
+	private static final Sort PAGE_SORT = Sort.by(Sort.Direction.ASC, "id");
+
+	private final UserDAO userDAO;
+	private final MailService mailService;
+	private final GitlabApi gitlabApi;
+	private final JenkinsApi jenkinsApi;
+
+	@Autowired
+	public UserServiceImpl(UserDAO userDAO, MailService mailService, GitlabApi gitlabApi, JenkinsApi jenkinsApi) {
+		this.userDAO = userDAO;
+		this.mailService = mailService;
+		this.gitlabApi = gitlabApi;
+		this.jenkinsApi = jenkinsApi;
+	}
+
+	@Override
+	@Transactional
+	public UserVO create(UserDTO userDTO) throws ServiceException {
+		return register(userDTO.getUsername(), userDTO.getEmail(), null,userDTO.getNickname(), userDTO.getRole());
+	}
+
+	@Override
+	@Transactional
+	public User register(String username, String name, String email, String password, String phone, UserIdentity role, Integer pid) throws ServiceException {
+		User user = userDAO.findByUsername(username);
+		Asserts.isNull(user, "用户名已被使用!");
+		user = userDAO.findByEmail(email);
+		Asserts.isNull(user, "邮箱已被使用!");
+		String realPassword = password == null ? ToolKit.randomPassword() : password;
+		GitlabUser gitlabUser;
+		try {
+			gitlabUser = gitlabApi.createUser(username, email, realPassword);
+		} catch (GitLabApiException e) {
+			throw new ServiceException("创建GitLab用户时发生异常[" + e.getMessage() + "]");
+		}
+		user = new User();
+		BeanUtils.copyProperties(gitlabUser, user);
+		if(name!=null){
+			user.setNickname(name);
+		}
+
+		user.setUsername(username);
+		user.setEmail(email);
+		user.setPassword(DigestUtils.sha256Hex(realPassword));
+		user.setPid(pid);
+		user.setPhone(phone);
+		user.setRole(role);
+		user = userDAO.save(user);
+		if (password == null) {
+			mailService.send("尊敬的" + username + "您好, 您的初始密码为" + realPassword + ", 请及时修改", "注册成功 | SEECODER", email);
+		}
+		return user;
+	}
+
+	@Override
+	public Page<UserVO> retrievePage(int page, int limit, String search) {
+		Pageable pageable = PageRequest.of(page, limit, PAGE_SORT);
+		Page<User> pageResult;
+		if (search == null || search.isEmpty()) {
+			pageResult = userDAO.findAll(pageable);
+		} else {
+			pageResult = userDAO.findAllByUsernameLike("%" + search + "%", pageable);
+		}
+		return pageResult.map(UserVO::new);
+	}
+
+	@Override
+	public UserVO retrieve(int userId) throws ServiceException {
+		User user = userDAO.findById(userId);
+		Asserts.notNull(user, "所选用户不存在");
+		return new UserVO(user);
+	}
+
+	@Override
+	@Transactional
+	public void delete(int userId) throws ServiceException {
+		User user = userDAO.findById(userId);
+		Assert.notNull(user, "找不到要删除的用户");
+		Assert.isTrue(user.getRole() == UserIdentity.STUDENT, "目标用户只能是学生");
+		try {
+			gitlabApi.deleteUser(userId);
+		} catch (Exception e) {
+			throw new ServiceException("删除GitLab用户时发生异常[" + e.getMessage() + "]");
+		}
+		//todo 删除用户需要连带删除什么
+		userDAO.delete(user);
+	}
+
+	@Override
+	@Transactional
+	public UserSerializer register(RegisterVO form) throws ServiceException {
+		return new UserSerializer(register(form.getUsername(), form.getEmail(), form.getPassword(),form.getNickname(), UserIdentity.STUDENT));
+	}
+	@Override
+	@Transactional
+	public UserSerializer registerTeacher(RegisterVO form) throws ServiceException {
+		return new UserSerializer(register(form.getUsername(), form.getEmail(), form.getPassword(),form.getNickname(), UserIdentity.TEACHER));
+	}
+	private UserVO register(String username, String email, String password, String nickname,UserIdentity role) throws ServiceException {
+		User user = userDAO.findByUsername(username);
+		Asserts.isNull(user, "用户名已被使用!");
+		user = userDAO.findByEmail(email);
+		Asserts.isNull(user, "邮箱已被使用!");
+		String realPassword = password == null ? ToolKit.randomPassword() : password;
+		GitlabUser gitlabUser;
+		try {
+			gitlabUser = gitlabApi.createUser(username, email, realPassword);
+		} catch (GitLabApiException e) {
+			throw new ServiceException("创建GitLab用户时发生异常[" + e.getMessage() + "]");
+		}
+		user = new User();
+		BeanUtils.copyProperties(gitlabUser, user);
+		if(nickname!=null){
+			user.setNickname(nickname);
+		}
+
+		user.setUsername(username);
+		user.setEmail(email);
+		user.setPassword(DigestUtils.sha256Hex(realPassword));
+		user.setRole(role);
+		final UserVO userVO = new UserVO(userDAO.save(user));
+		if (password == null) {
+			mailService.send("尊敬的" + username + "您好, 您的初始密码为" + realPassword + ", 请及时修改", "注册成功 | SEECODER", email);
+		}
+		return userVO;
+	}
+
+
+	@Override
+	public UserSerializer getUserById(Integer userid) {
+		return new UserSerializer(userDAO.getOne(userid));
+	}
+
+	@Override
+	public UserSerializer changeUserInfo(Integer userid,String nickName, String bio) throws ServiceException {
+		User one = userDAO.findById(userid).orElse(null);
+		if (one == null) {
+			throw new ServiceException("用户不存在");
+		}
+		if(nickName!=null){
+			one.setNickname(nickName);
+		}
+		if(bio!=null){
+			one.setBio(bio);
+		}
+		return new UserSerializer(userDAO.save(one));
+	}
+
+	@Override
+	public UserSerializer changeUserPassword(Integer userid,String oldPassword, String newPassword) throws ServiceException {
+		User one = userDAO.findById(userid).orElse(null);
+		if (one == null) {
+			throw new ServiceException("用户不存在");
+		}
+		if(!one.getPassword().equals(DigestUtils.sha256Hex(oldPassword))){
+			throw new ServiceException("原密码错误");
+		}else{
+			one.setPassword(DigestUtils.sha256Hex(newPassword));
+		}
+		try {
+			gitlabApi.changePassword(userid, newPassword);
+		} catch (GitLabApiException e) {
+			throw new ServiceException("修改GitLab用户密码时发生异常[" + e.getMessage() + "]");
+		}
+		mailService.send( "您的新密码为"+newPassword,"密码变更提醒 | SEECODER",one.getEmail());
+		return new UserSerializer(userDAO.save(one));
+	}
+
+	@Override
+	public void changePassword(int userId, ChangePasswordVO form) throws ServiceException {
+		User user = userDAO.findById(userId);
+		if (!user.getPassword().equals(DigestUtils.sha256Hex(form.getOrigin()))) {
+			throw new InvalidRequestException("原密码验证失败,如忘记密码请联系管理员重置");
+		}
+		changePassword(user, form.getPassword(), false);
+	}
+
+	@Override
+	public void resetPassword(int userId) throws ServiceException {
+		User user = userDAO.findById(userId);
+		Asserts.notNull(user, "所选用户不存在");
+		String password = ToolKit.randomPassword();
+		changePassword(user, password, true);
+	}
+
+
+
+	private void changePassword(User user, String password, boolean reset) throws ServiceException {
+		try {
+			gitlabApi.changePassword(user.getId(), password);
+		} catch (GitLabApiException e) {
+			throw new ServiceException("修改GitLab用户密码时发生异常[" + e.getMessage() + "]");
+		}
+		user.setPassword(DigestUtils.sha256Hex(password));
+		user = userDAO.save(user);
+		if (reset) {
+			mailService.send( "您的新密码为"+password,"密码变更提醒 | SEECODER",user.getEmail());
+		}
+	}
+}

+ 39 - 37
web/src/main/java/seecoder/devcloud/web/service/user/UserService.java

@@ -1,37 +1,39 @@
-//package seecoder.devcloud.web.service.user;
-//
-//import com.moekr.moocoder.data.entity.user.User;
-//import com.moekr.moocoder.logic.Serializer.UserSerializer;
-//import com.moekr.moocoder.logic.vo.user.UserVO;
-//import com.moekr.moocoder.util.enums.UserIdentity;
-//import com.moekr.moocoder.util.exceptions.ServiceException;
-//import com.moekr.moocoder.web.dto.form.ChangePasswordForm;
-//import com.moekr.moocoder.web.dto.form.RegisterForm;
-//import com.moekr.moocoder.web.dto.user.UserDTO;
-//import org.springframework.data.domain.Page;
-//
-//public interface UserService {
-//	UserVO create(UserDTO userDTO) throws ServiceException;
-//
-//	User register(String username, String name, String email, String password, String phone, UserIdentity role, Integer pid) throws ServiceException;
-//
-//	Page<UserVO> retrievePage(int page, int limit, String search) throws ServiceException;
-//
-//	UserVO retrieve(int userId) throws ServiceException;
-//
-//	void delete(int userId) throws ServiceException;
-//
-//	UserSerializer register(RegisterForm form) throws ServiceException;
-//
-//	UserSerializer registerTeacher(RegisterForm form) throws ServiceException;
-//
-//	void changePassword(int userId, ChangePasswordForm form) throws ServiceException;
-//
-//	void resetPassword(int userId) throws ServiceException;
-//
-//	UserSerializer getUserById(Integer userid);
-//
-//	UserSerializer changeUserInfo(Integer userid,String nickName, String bio) throws ServiceException;
-//
-//	UserSerializer changeUserPassword(Integer userid,String oldPassword, String newPassword) throws ServiceException;
-//}
+package seecoder.devcloud.web.service.user;
+
+
+import org.springframework.data.domain.Page;
+import seecoder.devcloud.common.exceptions.ServiceException;
+
+import seecoder.devcloud.web.vo.user.ChangePasswordVO;
+import seecoder.devcloud.web.vo.user.RegisterVO;
+import seecoder.devcloud.web.dto.user.UserDTO;
+import seecoder.devcloud.web.enums.UserIdentity;
+import seecoder.devcloud.web.po.user.User;
+import seecoder.devcloud.web.vo.user.UserSerializer;
+import seecoder.devcloud.web.vo.user.UserVO;
+
+public interface UserService {
+	UserVO create(UserDTO userDTO) throws ServiceException;
+
+	User register(String username, String name, String email, String password, String phone, UserIdentity role, Integer pid) throws ServiceException;
+
+	Page<UserVO> retrievePage(int page, int limit, String search) throws ServiceException;
+
+	UserVO retrieve(int userId) throws ServiceException;
+
+	void delete(int userId) throws ServiceException;
+
+	UserSerializer register(RegisterVO form) throws ServiceException;
+
+	UserSerializer registerTeacher(RegisterVO form) throws ServiceException;
+
+	void changePassword(int userId, ChangePasswordVO form) throws ServiceException;
+
+	void resetPassword(int userId) throws ServiceException;
+
+	UserSerializer getUserById(Integer userid);
+
+	UserSerializer changeUserInfo(Integer userid,String nickName, String bio) throws ServiceException;
+
+	UserSerializer changeUserPassword(Integer userid,String oldPassword, String newPassword) throws ServiceException;
+}

+ 18 - 0
web/src/main/java/seecoder/devcloud/web/vo/user/ChangePasswordVO.java

@@ -0,0 +1,18 @@
+package seecoder.devcloud.web.vo.user;
+
+import lombok.Data;
+import seecoder.devcloud.common.validate.FieldEquals;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+
+@Data
+@FieldEquals(firstField = "password", secondField = "confirm", message = "两次输入的密码不一致!")
+public class ChangePasswordVO {
+	@NotNull(message = "请填写原密码!")
+	private String origin;
+	@Pattern(regexp = "[0-9a-zA-Z_]{8,16}", message = "密码只能包含大小写字母、数字和下划线,且必须为8-16位!")
+	@NotNull(message = "请填写新密码!")
+	private String password;
+	private String confirm;
+}

+ 24 - 0
web/src/main/java/seecoder/devcloud/web/vo/user/GroupDTO.java

@@ -0,0 +1,24 @@
+package seecoder.devcloud.web.vo.user;
+
+import lombok.Data;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @ClassName GroupDTO
+ * @PackageName com.moekr.moocoder.web.dto
+ * @Author sheen
+ * @Date 2019/1/9
+ * @Version 1.0
+ * @Description //TODO
+ **/
+@Data
+public class GroupDTO {
+    private Integer id;
+    @NotNull(message = "小组名称不能为空!", groups = {PostMapping.class, PutMapping.class})
+    private String name;
+    @NotNull(message = "课程ID不能为空!", groups = {PostMapping.class, PutMapping.class})
+    private Integer courseId;
+}

+ 36 - 0
web/src/main/java/seecoder/devcloud/web/vo/user/GroupVO.java

@@ -0,0 +1,36 @@
+package seecoder.devcloud.web.vo.user;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @EnumName GroupVO
+ * @PackageName com.moekr.moocoder.logic.Serializer
+ * @Author sheen
+ * @Date 2019/1/9
+ * @Version 1.0
+ * @Description //TODO
+ **/
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class GroupVO {
+    private Integer id;
+    private String name;
+    private String code;
+    private List<UserSerializer> members;
+
+    public GroupVO(Group group) {
+        this.id=group.getId();
+        this.name=group.getName();
+        this.code=group.getShareLink();
+        this.members=group.getMembers().stream()
+                .map(UserSerializer::new)
+                .collect(Collectors.toList());
+    }
+
+}

+ 44 - 0
web/src/main/java/seecoder/devcloud/web/vo/user/RegisterVO.java

@@ -0,0 +1,44 @@
+package seecoder.devcloud.web.vo.user;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.web.bind.annotation.PostMapping;
+
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+
+@Data
+@NoArgsConstructor
+public class RegisterVO {
+	//@Email(message = "用户名也要填邮箱名称!")
+	@NotNull(groups = {PostMapping.class},message = "请填写用户名!")
+	private String username="default";
+	@Email(message = "邮箱格式不正确!")
+//	@NotNull(message = "请填写邮箱!")
+	@JsonIgnore
+	private String email;
+	@Pattern(groups = {PostMapping.class},regexp = "[0-9a-zA-Z_]{8,16}", message = "密码只能包含大小写字母、数字和下划线,且必须为8-16位!")
+	@NotNull(groups = {PostMapping.class},message = "请填写密码!")
+	private String password;
+	private String nickname="nickname";
+
+	public RegisterVO(@Email(message = "邮箱格式不正确!") @NotNull(message = "请填写邮箱!") String username, @Pattern(regexp = "[0-9a-zA-Z_]{8,16}", message = "密码只能包含大小写字母、数字和下划线,且必须为8-16位!") @NotNull(message = "请填写密码!") String password, String nickname) {
+		this.email = username;
+		this.username=buildUsername(username);
+		this.password = password;
+		this.nickname = nickname;
+	}
+	public void buildUsername(){
+		this.username=buildUsername(this.email);
+	}
+	public static String buildUsername(@Email(groups = {PostMapping.class},message = "邮箱格式不正确!") @NotNull(groups = {PostMapping.class},message = "请填写用户名!")String email){
+		return email.replace("@","_").replaceAll("\\.","_");
+	}
+
+	public void setUsername(String username) {
+		this.email = username;
+		this.username=buildUsername(username);
+	}
+}

+ 37 - 0
web/src/main/java/seecoder/devcloud/web/vo/user/UserSerializer.java

@@ -0,0 +1,37 @@
+package seecoder.devcloud.web.vo.user;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.beans.BeanUtils;
+import seecoder.devcloud.web.enums.UserIdentity;
+import seecoder.devcloud.web.po.user.User;
+import seecoder.devcloud.web.vo.user.UserVO;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class UserSerializer {
+    private Integer id;
+    private UserIdentity role;
+    @JsonIgnore
+    private String username;
+    private String nickname;
+    private String bio;
+    @JsonProperty("username")
+    private String email;
+    public UserSerializer(User user) {
+        this.id=user.getId();
+        this.role=user.getRole();
+        this.username=user.getUsername();
+        this.nickname=user.getNickname();
+        this.bio=user.getBio();
+        this.email=user.getEmail();
+
+    }
+    public UserSerializer(UserVO user) {
+        BeanUtils.copyProperties(user,this);
+    }
+}

+ 40 - 0
web/src/main/java/seecoder/devcloud/web/vo/user/UserVO.java

@@ -0,0 +1,40 @@
+package seecoder.devcloud.web.vo.user;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+
+import lombok.Data;
+import org.springframework.beans.BeanUtils;
+import seecoder.devcloud.common.serializer.TimestampLocalDateTimeSerializer;
+import seecoder.devcloud.web.enums.UserIdentity;
+import seecoder.devcloud.web.po.user.User;
+
+import java.time.LocalDateTime;
+
+@Data
+public class UserVO {
+	private Integer id;
+	private String username;
+	private String email;
+	private UserIdentity role;
+	//nickname : String - 昵称 | [a-zA-Z0-9]{4-16}
+	//bio : String - 用户自我描述 | {0-100}
+	private String nickname;
+	private String bio;
+	@JsonProperty("created_at")
+	@JsonSerialize(using = TimestampLocalDateTimeSerializer.class)
+	private LocalDateTime createdAt;
+
+	private UserVO() {
+		this.id = 0;
+		this.username = "管理员";
+		this.bio="bio : String - 用户自我描述 | {0-100}";
+	}
+
+	public UserVO(User user) {
+		BeanUtils.copyProperties(user, this);
+	}
+
+	public static final UserVO ADMIN = new UserVO();
+}

+ 12 - 89
web/src/main/resources/application-wph.yml

@@ -10,111 +10,34 @@ spring:
       naming:
         implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
         physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
-    database-platform: org.hibernate.dialect.MySQL57InnoDBDialect
-  security:
-    user:
-      name: root
-      password: NJU67software
-  mail:
-    host: smtp.163.com
-    username: seecoder@163.com
-    password: seec67NJU
-    properties:
-      mail:
-        smtp:
-          auth: true
-          socketFactory:
-            class: javax.net.ssl.SSLSocketFactory
-            port: 465
-          starttls:
-            enable: true
-            required: true
-  resources:
-    chain:
-      strategy:
-        content:
-          enabled: true
-          paths:
-            - /moocoder-frontend/**
-            - /js/**
-            - /css/**
-  servlet:
-    multipart:
-      max-file-size: 16MB
-      max-request-size: 16MB
-  redis:
-    host: http://192.168.68.76
-    port: 6379
-    password: NJU67redis
-    timeout: 1000
-    database: 0
-    lettuce:
-      pool:
-        min-idle: 5
-        max-active: 8
-        max-idle: 10
-        max-wait: 1ms
-
-      shutdown-timeout: 100ms
+    database-platform: org.hibernate.dialect.MySQL57InnoDBDialec
 
 
 server:
   port: 8080
-  tomcat:
-    remoteip:
-      remote-ip-header: X-Forwarded-For
-      protocol-header: X-Forwarded-Proto
-  servlet:
-    session:
-      persistent: true
-      store-dir: ${java.io.tmpdir}/moocoder-session
-      timeout: 1d
-  use-forward-headers: true
-management:
-  endpoints:
-    web:
-      base-path: /api/actuator
-  endpoint:
-    shutdown:
-      enabled: true
 
 seecoder:
-  secret: 1qaz2wsx
-  auth:
-    signingKey: SEEC-1919810-OIDC-114514
-    iss: p.seecoder.cn
-    aud: seec-seec
-    portal: http://p.seecoder.cn/api/interaction
-    redirectUri: http://seec.seecoder.cn/api/auth/receive
+  k8s:
+    api-server: https://192.168.99.105:8443
+    token: eyJhbGciOiJSUzI1NiIsImtpZCI6IjBmSXc4RlRjNUpBYVpGYWc4QzRDY1MzUWJad1JMdFhKcDI1cngzWGtiRlkifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZXZjbG91ZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJkZWZhdWx0LXRva2VuLXNicXY4Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImRlZmF1bHQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI5NmIxNzU1ZS0zZjE3LTQ1ZTctODFmYi01MTRhODA3NDRhMzQiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGV2Y2xvdWQ6ZGVmYXVsdCJ9.W0Y1lR6LBi1ZjylBx35YeqYuq2u2AqH-ayK4FD-LDfC26E89DanOwSv9XLrRMnnDBZFS_ZCRBumbnDeMiS5vw2x7-QnrDqj1M5u9FB2fIJsz2LyUkOhATZZmTzj_Uhewvvg09aDKh16ttj6ZX27m-KVk_6MP-VfiuvZnCVxDbqRkRjK-zsor4ty1CEATPyKK-tvugAwS0RFNHUL94DamfZAq_t1PSnH5ZtEHq0uEMZxY2c7j6u9d_aD9lphm_ZpCy_C8OCHfanM21CQPDHlcJTW_aiOO6bAp8qdc1egPO5uIamHl6Zm0N3RkcsRp4DGOHrltTV9y_cGZHXSWmRHfxw
+    debugging: true
   gitlab:
-    host: http://gitlab.seec.seecoder.cn
-    git-proxy: http://gitlab.seec.seecoder.cn
+    host: gitlab.192.168.99.105.nip.io
     webHookProxy: http://localhost:3000
-    username: root
-    token: x7Hwx-zq8LFkHznGku9a
+    token: wXDeETv2Kmt-JhiApJ9H
+
+
+
   jenkins:
     host: http://192.168.68.79:8082
     username: root
     token: 11d7b9e4c1acac481904c25813e2ec1f0a
-    baseImage: 172.19.51.9:18082/build-base
   docker:
     registry: 192.168.68.79:18082
   mail:
     from: seecoder@163.com
-  storage:
-    type: local
-    properties:
-      location: ./problem
-  k8s:
-    api-server: https://192.168.68.76:6443
-    token: eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi10b2tlbi1zdzlwOCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJhZG1pbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImY3MzQ2NzVlLWZmYmItMTFlOS1iYTdjLTIyNmUyZmY2ZTdlYyIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlLXN5c3RlbTphZG1pbiJ9.GvBP7iNM_WNJN7dPm8ZPszDJeykifhHwBYcF58c4W73iAet1ZcZPrmiurqn4mSHcavUHNR8FqPaafnS3OD4eq5dR-i7frdIBt7yiME7AIGA4pDKWNJ3NykhyfG75omCvtQ2Gp-UvFIdf_4peAilxbwDR2NtWpky4sJQOTukZIYzN9fCeYV8My85XDBl7ze20QBsEKfPxTGZkqmytX-4VmjKkQH9ob7YB90NR2ug5VK8CA16_2ZPjf8Fx4QsdTbkyZKdFo7zIrIID0fa2lpOc2TpCKWeYCl335-ULllpxds6kiVwkRXYP-5zkIOfpI_0SshK7kbBjd238OLM3KFDf6A
-    ingress-host: seecii.cn
-    public-namespace: dev
-    public-mysql-url: jdbc:mysql://seecii-mysql.dev.svc.cluster.local:3306
-    public-mysql-pod: seecii-mysql-579dc7c857-8m2fd
-    public-mysql-username: root
-    public-mysql-password: NJU67software
-    debugging: true
+
+
   registry:
     host: 192.168.68.79:18082
     username: admin