From 6c2719311c6398aaaa886dfa151084a6ea814342 Mon Sep 17 00:00:00 2001 From: johnniang Date: Tue, 19 Mar 2019 14:26:13 +0800 Subject: [PATCH] Restructure InstallController --- .../java/cc/ryanc/halo/model/entity/User.java | 6 + .../ryanc/halo/model/params/InstallParam.java | 59 +++++++++ .../ryanc/halo/model/support/JsonResult.java | 1 - .../cc/ryanc/halo/service/OptionService.java | 8 ++ .../halo/service/impl/MailServiceImpl.java | 3 + .../halo/service/impl/OptionServiceImpl.java | 19 ++- .../controller/core/InstallController.java | 119 +++++++++++++++++- 7 files changed, 209 insertions(+), 6 deletions(-) create mode 100644 src/main/java/cc/ryanc/halo/model/params/InstallParam.java diff --git a/src/main/java/cc/ryanc/halo/model/entity/User.java b/src/main/java/cc/ryanc/halo/model/entity/User.java index e8cc7cbdf..7b9386eec 100644 --- a/src/main/java/cc/ryanc/halo/model/entity/User.java +++ b/src/main/java/cc/ryanc/halo/model/entity/User.java @@ -1,5 +1,6 @@ package cc.ryanc.halo.model.entity; +import cc.ryanc.halo.utils.DateUtils; import lombok.Data; import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.Where; @@ -87,4 +88,9 @@ public class User { */ @Column(name = "deleted", columnDefinition = "TINYINT default 0") private Boolean deleted; + + @PrePersist + public void prePersist() { + id = null; + } } diff --git a/src/main/java/cc/ryanc/halo/model/params/InstallParam.java b/src/main/java/cc/ryanc/halo/model/params/InstallParam.java new file mode 100644 index 000000000..d91465b86 --- /dev/null +++ b/src/main/java/cc/ryanc/halo/model/params/InstallParam.java @@ -0,0 +1,59 @@ +package cc.ryanc.halo.model.params; + +import lombok.Data; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; + +/** + * Install parameters. + * + * @author johnniang + * @date 3/19/19 + */ +@Data +public class InstallParam { + + /** + * Blog locale. + */ + @NotBlank(message = "Blog locale must not be blank") + private String locale; + + /** + * Blog title. + */ + @NotBlank(message = "Blog title must not be blank") + private String title; + + /** + * Blog url. + */ + @NotBlank(message = "Blog url must not be blank") + private String url; + + /** + * Username. + */ + @NotBlank(message = "Username must not be blank") + private String username; + + /** + * Nickname. + */ + @NotBlank(message = "Nickname must not be blank") + private String nickname; + + /** + * Email. + */ + @NotBlank(message = "Email must not be blank") + @Email(message = "It is not an email format") + private String email; + + /** + * Password. + */ + @NotBlank(message = "Password must not be blank") + private String password; +} diff --git a/src/main/java/cc/ryanc/halo/model/support/JsonResult.java b/src/main/java/cc/ryanc/halo/model/support/JsonResult.java index 1859dc8be..d6d52e940 100644 --- a/src/main/java/cc/ryanc/halo/model/support/JsonResult.java +++ b/src/main/java/cc/ryanc/halo/model/support/JsonResult.java @@ -4,7 +4,6 @@ import lombok.Data; import org.springframework.http.HttpStatus; import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; -import org.springframework.util.Assert; /** *
diff --git a/src/main/java/cc/ryanc/halo/service/OptionService.java b/src/main/java/cc/ryanc/halo/service/OptionService.java
index a6b0d1661..62bc25f3b 100755
--- a/src/main/java/cc/ryanc/halo/service/OptionService.java
+++ b/src/main/java/cc/ryanc/halo/service/OptionService.java
@@ -1,6 +1,7 @@
 package cc.ryanc.halo.service;
 
 import cc.ryanc.halo.model.entity.Option;
+import cc.ryanc.halo.model.enums.BlogProperties;
 import cc.ryanc.halo.service.base.CrudService;
 import org.springframework.lang.NonNull;
 
@@ -28,6 +29,13 @@ public interface OptionService extends CrudService {
      */
     void save(@NonNull Map options);
 
+    /**
+     * Saves blog properties.
+     *
+     * @param properties blog properties
+     */
+    void saveProperties(@NonNull Map properties);
+
     /**
      * Get all options
      *
diff --git a/src/main/java/cc/ryanc/halo/service/impl/MailServiceImpl.java b/src/main/java/cc/ryanc/halo/service/impl/MailServiceImpl.java
index 2268997e5..77c1e67b0 100644
--- a/src/main/java/cc/ryanc/halo/service/impl/MailServiceImpl.java
+++ b/src/main/java/cc/ryanc/halo/service/impl/MailServiceImpl.java
@@ -48,6 +48,7 @@ public class MailServiceImpl implements MailService {
                     .text(content)
                     .send();
         } catch (Exception e) {
+            // TODO Handle this exception.
             e.printStackTrace();
         }
     }
@@ -76,6 +77,7 @@ public class MailServiceImpl implements MailService {
                     .html(text.toString())
                     .send();
         } catch (Exception e) {
+            // TODO Handle this exception.
             e.printStackTrace();
         }
     }
@@ -107,6 +109,7 @@ public class MailServiceImpl implements MailService {
                     .attach(file, file.getName())
                     .send();
         } catch (Exception e) {
+            // TODO Handle this exception.
             e.printStackTrace();
         }
     }
diff --git a/src/main/java/cc/ryanc/halo/service/impl/OptionServiceImpl.java b/src/main/java/cc/ryanc/halo/service/impl/OptionServiceImpl.java
index a7176101a..dfab274b6 100644
--- a/src/main/java/cc/ryanc/halo/service/impl/OptionServiceImpl.java
+++ b/src/main/java/cc/ryanc/halo/service/impl/OptionServiceImpl.java
@@ -1,11 +1,11 @@
 package cc.ryanc.halo.service.impl;
 
 import cc.ryanc.halo.model.entity.Option;
+import cc.ryanc.halo.model.enums.BlogProperties;
 import cc.ryanc.halo.repository.OptionRepository;
 import cc.ryanc.halo.service.OptionService;
 import cc.ryanc.halo.service.base.AbstractCrudService;
 import cc.ryanc.halo.utils.ServiceUtils;
-import cn.hutool.core.util.StrUtil;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.util.Assert;
@@ -68,9 +68,22 @@ public class OptionServiceImpl extends AbstractCrudService impl
      */
     @Override
     public void save(Map options) {
-        if (!CollectionUtils.isEmpty(options)) {
-            options.forEach(this::save);
+        if (CollectionUtils.isEmpty(options)) {
+            return;
         }
+
+        // (Not recommended) Don't write "this::save" here
+        // Types of key and value are String
+        options.forEach((key, value) -> save(key, value));
+    }
+
+    @Override
+    public void saveProperties(Map properties) {
+        if (CollectionUtils.isEmpty(properties)) {
+            return;
+        }
+
+        properties.forEach((property, value) -> save(property.getValue(), value));
     }
 
     /**
diff --git a/src/main/java/cc/ryanc/halo/web/controller/core/InstallController.java b/src/main/java/cc/ryanc/halo/web/controller/core/InstallController.java
index 5975f2673..164ea7f81 100644
--- a/src/main/java/cc/ryanc/halo/web/controller/core/InstallController.java
+++ b/src/main/java/cc/ryanc/halo/web/controller/core/InstallController.java
@@ -1,9 +1,13 @@
 package cc.ryanc.halo.web.controller.core;
 
+import cc.ryanc.halo.exception.BadRequestException;
 import cc.ryanc.halo.model.entity.*;
+import cc.ryanc.halo.model.enums.AttachOrigin;
 import cc.ryanc.halo.model.enums.BlogProperties;
 import cc.ryanc.halo.model.enums.CommentStatus;
 import cc.ryanc.halo.model.enums.PostStatus;
+import cc.ryanc.halo.model.params.InstallParam;
+import cc.ryanc.halo.model.support.BaseResponse;
 import cc.ryanc.halo.model.support.JsonResult;
 import cc.ryanc.halo.service.*;
 import cc.ryanc.halo.utils.MarkdownUtils;
@@ -11,6 +15,7 @@ import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.RandomUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.crypto.SecureUtil;
+import cn.hutool.crypto.digest.BCrypt;
 import freemarker.template.Configuration;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Controller;
@@ -18,6 +23,7 @@ import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.validation.Valid;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -26,14 +32,18 @@ import java.util.Map;
 import static cc.ryanc.halo.model.support.HaloConst.OPTIONS;
 
 /**
+ * Installation controller.
+ *
  * @author : RYAN0UP
  * @date : 2019-03-17
  */
 @Slf4j
 @Controller
-@RequestMapping("/install")
+@RequestMapping("/installations")
 public class InstallController {
 
+    private final static String DEFAULT_THEME_NAME = "anatole";
+
     private final UserService userService;
 
     private final CategoryService categoryService;
@@ -79,11 +89,115 @@ public class InstallController {
                 model.addAttribute("isInstall", false);
             }
         } catch (Exception e) {
-            log.error(e.getMessage());
+            log.error("Error occurred", e);
         }
         return "common/install";
     }
 
+    @PostMapping
+    @ResponseBody
+    public BaseResponse installBlog(@Valid InstallParam installParam) {
+        // TODO Install blog.
+        // Check is installed
+        boolean isInstalled = Boolean.parseBoolean(OPTIONS.getOrDefault(BlogProperties.IS_INSTALL, "false"));
+
+        if (isInstalled) {
+            // TODO i18n
+            throw new BadRequestException("该博客已初始化,不能再次安装!");
+        }
+
+        // Initialize settings
+        initSettings(installParam);
+
+        // Create default user
+        User user = createDefaultUser(installParam);
+
+        // Create default category
+        Category category = createDefaultCategory();
+
+        // Create default post
+        Post post = createDefaultPost(category);
+
+        // Create default comment
+        Comment comment = createDefaultComment();
+
+        // Create default menu
+        createDefaultMenu();
+
+        // TODO Handle option cache
+
+        // TODO i18n
+        return BaseResponse.ok("Setup successfully!");
+    }
+
+    private void createDefaultMenu() {
+        Menu menuIndex = new Menu();
+        // TODO i18n
+        menuIndex.setName("首页");
+        menuIndex.setUrl("/");
+        menuIndex.setSort(1);
+        menuService.create(menuIndex);
+
+        Menu menuArchive = new Menu();
+        menuArchive.setName("归档");
+        menuArchive.setUrl("/archives");
+        menuArchive.setSort(2);
+        menuService.create(menuArchive);
+    }
+
+
+    private Comment createDefaultComment() {
+        // TODO Create default comment
+        return null;
+    }
+
+    private Post createDefaultPost(Category category) {
+        // TODO Create default post
+        return null;
+    }
+
+    private Category createDefaultCategory() {
+        Category category = new Category();
+
+        // TODO Multi level category
+        // TODO and i18n for the category name, description
+
+        category.setName("Initial Blog");
+        category.setSnakeName("initial_blog");
+        category.setDescription("Initial Blog for alphabet");
+        return categoryService.create(category);
+    }
+
+    private User createDefaultUser(InstallParam installParam) {
+        User user = new User();
+        user.setUsername(installParam.getUsername());
+        user.setNickname(installParam.getNickname());
+        user.setEmail(installParam.getEmail());
+        // Hash password with BCrypt
+        user.setPassword(BCrypt.hashpw(installParam.getPassword(), BCrypt.gensalt()));
+
+        return userService.create(user);
+    }
+
+    private void initSettings(InstallParam installParam) {
+        // Init properties
+        Map properties = new HashMap<>(11);
+        properties.put(BlogProperties.IS_INSTALL, Boolean.TRUE.toString());
+        properties.put(BlogProperties.BLOG_LOCALE, installParam.getLocale());
+        properties.put(BlogProperties.BLOG_TITLE, installParam.getTitle());
+        properties.put(BlogProperties.BLOG_URL, installParam.getUrl());
+        properties.put(BlogProperties.THEME, DEFAULT_THEME_NAME);
+        properties.put(BlogProperties.BLOG_START, DateUtil.format(DateUtil.date(), "yyyy-MM-dd"));
+        properties.put(BlogProperties.SMTP_EMAIL_ENABLE, Boolean.FALSE.toString());
+        properties.put(BlogProperties.NEW_COMMENT_NOTICE, Boolean.FALSE.toString());
+        properties.put(BlogProperties.COMMENT_PASS_NOTICE, Boolean.FALSE.toString());
+        properties.put(BlogProperties.COMMENT_REPLY_NOTICE, Boolean.FALSE.toString());
+        properties.put(BlogProperties.ATTACH_LOC, AttachOrigin.SERVER.getValue().toString());
+
+        // Create properties
+        optionService.saveProperties(properties);
+    }
+
     /**
      * Do install
      *
@@ -99,6 +213,7 @@ public class InstallController {
      */
     @PostMapping(value = "/do")
     @ResponseBody
+    @Deprecated
     public JsonResult doInstall(@RequestParam("blogLocale") String blogLocale,
                                 @RequestParam("blogTitle") String blogTitle,
                                 @RequestParam("blogUrl") String blogUrl,