doortts doortts 2018-07-29
webhook: Add complementary codes
@6046f74b010c4192878d5d1bccc109308aa49127
app/controllers/ProjectApp.java
--- app/controllers/ProjectApp.java
+++ app/controllers/ProjectApp.java
@@ -18,7 +18,6 @@
 import models.enumeration.*;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang.exception.ExceptionUtils;
-import org.apache.commons.lang3.BooleanUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.mail.HtmlEmail;
 import com.fasterxml.jackson.databind.node.ObjectNode;
@@ -49,7 +48,6 @@
 import views.html.project.transfer;
 import views.html.project.change_vcs;
 
-import javax.annotation.Nonnull;
 import javax.servlet.ServletException;
 import java.io.IOException;
 import java.security.NoSuchAlgorithmException;
@@ -1291,22 +1289,27 @@
             return notFound(ErrorViews.NotFound.render("error.notfound"));
         }
 
-        Form<Webhook> addWebhookForm = form(Webhook.class).bindFromRequest();
-        if (addWebhookForm == null) {
+        Form<Webhook> addNewWebhookForm = form(Webhook.class).bindFromRequest();
+        if (addNewWebhookForm == null) {
             Logger.warn("Failed creating webhook: got null form from newWebhook request");
-            return badRequest();
-        } else if (addWebhookForm.hasErrors()) {
-            return badRequest(ErrorViews.BadRequest.render());
+            return badRequest("Failed creating webhook: got null form from newWebhook request");
+        } else if (addNewWebhookForm.hasErrors()) {
+            return badRequest(ErrorViews.BadRequest.render(addNewWebhookForm.errorsAsJson().toString()));
         }
 
-        Webhook webhook = addWebhookForm.get();
-
-        Webhook.create(project.id, webhook.payloadUrl.trim(), webhook.secret,
-                BooleanUtils.toBooleanDefaultIfNull(webhook.gitPushOnly, false), webhook.webhookType);
+        createWebhook(project, addNewWebhookForm);
 
         return redirect(routes.ProjectApp.webhooks(project.owner, project.name));
     }
 
+    private static void createWebhook(Project project, Form<Webhook> forms) {
+        Webhook webhook = forms.get();
+        webhook.project = project;
+        if(webhook.gitPushOnly == null) webhook.gitPushOnly = false;
+        webhook.createdAt = new Date();
+        webhook.save();
+    }
+
     @Transactional
     @IsAllowed(Operation.UPDATE)
     public static Result deleteWebhook(String ownerId, String projectName, Long id) {
app/models/Webhook.java
--- app/models/Webhook.java
+++ app/models/Webhook.java
@@ -1,23 +1,10 @@
 /**
- * Yobi, Project Hosting SW
- *
- * Copyright 2015 NAVER Corp.
- * http://yobi.io
- *
- * @author Jihwan Chun
- *
- * 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.
- */
+ * Yona, 21st Century Project Hosting SW
+ * <p>
+ * Copyright Yona & Yobi Authors & NAVER Corp. & NAVER LABS Corp.
+ * https://yona.io
+ **/
+
 package models;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -26,6 +13,7 @@
 import models.enumeration.EventType;
 import models.enumeration.PullRequestReviewAction;
 import models.enumeration.ResourceType;
+import models.enumeration.WebhookType;
 import models.resource.GlobalResource;
 import models.resource.Resource;
 import models.resource.ResourceConvertible;
@@ -90,10 +78,7 @@
      */
     public Boolean gitPushOnly;
 
-    /**
-     * Type of sending webhook (0: Simple Ver., 1: Slack Detail)
-     */
-    public Long webhookType;
+    public WebhookType webhookType = WebhookType.WITH_DETAILS;
 
     /**
      * Payload URL of webhook.
@@ -109,7 +94,7 @@
      * @param gitPushOnly type of webhook (true = git only push, false = all cases)
      * @param secret the secret token for server identity
      */
-    public Webhook(Long projectId, String payloadUrl, String secret, Boolean gitPushOnly, Long webhookType) {
+    public Webhook(Long projectId, String payloadUrl, String secret, Boolean gitPushOnly) {
         if (secret == null) {
             secret = "";
         }
@@ -117,7 +102,6 @@
         this.payloadUrl = payloadUrl;
         this.secret = secret;
         this.gitPushOnly = gitPushOnly;
-        this.webhookType = webhookType;
         this.createdAt = new Date();
     }
 
@@ -148,9 +132,9 @@
         return find.where().eq("project.id", projectId).findList();
     }
 
-    public static void create(Long projectId, String payloadUrl, String secret, Boolean gitPushOnly, Long webhookType) {
+    public static void create(Long projectId, String payloadUrl, String secret, Boolean gitPushOnly) {
         if (!payloadUrl.isEmpty()) {
-            Webhook webhook = new Webhook(projectId, payloadUrl, secret, gitPushOnly, webhookType);
+            Webhook webhook = new Webhook(projectId, payloadUrl, secret, gitPushOnly);
             webhook.save();
         }
         // TODO : Raise appropriate error when required field is empty
@@ -266,16 +250,19 @@
         }
         requestMessage += " <" + utils.Config.getScheme() + "://" + utils.Config.getHostport("localhost:9000") + RouteUtil.getUrl(eventPullRequest) + "|#" + eventPullRequest.number + ": " + eventPullRequest.title + ">";
 
-        if (this.webhookType == 1) {
-            detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), "pullRequest.sender"), eventPullRequest.contributor.name, false));
-            detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), "pullRequest.from"), eventPullRequest.fromBranch, true));
-            detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), "pullRequest.to"), eventPullRequest.toBranch, true));
-            attachments.add(buildAttachmentJSON(eventPullRequest.body, detailFields));
-            return Json.stringify(buildRequestJSON(requestMessage, attachments));
+        if (this.webhookType == WebhookType.WITH_DETAILS) {
+            return buildJsonWithPullReqtuestDetails(eventPullRequest, detailFields, attachments, requestMessage);
         } else {
-            return Json.stringify(buildRequestJSON(requestMessage));
+            return buildTextPropertyOnlyJSON(requestMessage);
         }
+    }
 
+    private String buildJsonWithPullReqtuestDetails(PullRequest eventPullRequest, ArrayNode detailFields, ArrayNode attachments, String requestMessage) {
+        detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), "pullRequest.sender"), eventPullRequest.contributor.name, false));
+        detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), "pullRequest.from"), eventPullRequest.fromBranch, true));
+        detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), "pullRequest.to"), eventPullRequest.toBranch, true));
+        attachments.add(buildAttachmentJSON(eventPullRequest.body, detailFields));
+        return Json.stringify(buildRequestJSON(requestMessage, attachments));
     }
 
     private String buildRequestBody(EventType eventType, User sender, PullRequest eventPullRequest, PullRequestReviewAction reviewAction) {
@@ -295,14 +282,10 @@
         }
         requestMessage += " <" + utils.Config.getScheme() + "://" + utils.Config.getHostport("localhost:9000") + RouteUtil.getUrl(eventPullRequest) + "|#" + eventPullRequest.number + ": " + eventPullRequest.title + ">";
 
-        if (this.webhookType == 1) {
-            detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), "pullRequest.sender"), eventPullRequest.contributor.name, false));
-            detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), "pullRequest.from"), eventPullRequest.fromBranch, true));
-            detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), "pullRequest.to"), eventPullRequest.toBranch, true));
-            attachments.add(buildAttachmentJSON(eventPullRequest.body, detailFields));
-            return Json.stringify(buildRequestJSON(requestMessage, attachments));
+        if (this.webhookType == WebhookType.SIMPLE) {
+            return buildTextPropertyOnlyJSON(requestMessage);
         } else {
-            return Json.stringify(buildRequestJSON(requestMessage));
+            return buildJsonWithPullReqtuestDetails(eventPullRequest, detailFields, attachments, requestMessage);
         }
     }
 
@@ -337,15 +320,19 @@
 
         requestMessage += " <" + utils.Config.getScheme() + "://" + utils.Config.getHostport("localhost:9000") + RouteUtil.getUrl(eventIssue) + "|#" + eventIssue.number + ": " + eventIssue.title + ">";
 
-        if (this.webhookType == 1) {
-            detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), "notification.type.milestone.changed"), eventIssue.milestoneId().toString(), true));
-            detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), ""), eventIssue.assigneeName(), true));
-            detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), "issue.state"), eventIssue.state.toString(), true));
-            attachments.add(buildAttachmentJSON(eventIssue.body, detailFields));
-            return Json.stringify(buildRequestJSON(requestMessage, attachments));
+        if (this.webhookType == WebhookType.SIMPLE) {
+            return buildTextPropertyOnlyJSON(requestMessage);
         } else {
-            return Json.stringify(buildRequestJSON(requestMessage));
+            return buildJsonWithIssueEventDetails(eventIssue, detailFields, attachments, requestMessage);
         }
+    }
+
+    private String buildJsonWithIssueEventDetails(Issue eventIssue, ArrayNode detailFields, ArrayNode attachments, String requestMessage) {
+        detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), "notification.type.milestone.changed"), eventIssue.milestoneId().toString(), true));
+        detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), ""), eventIssue.assigneeName(), true));
+        detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), "issue.state"), eventIssue.state.toString(), true));
+        attachments.add(buildAttachmentJSON(eventIssue.body, detailFields));
+        return Json.stringify(buildRequestJSON(requestMessage, attachments));
     }
 
     private String buildRequestBody(EventType eventType, User sender, Comment eventComment) {
@@ -370,11 +357,11 @@
                 break;
         }
 
-        if (this.webhookType == 1) {
+        if (this.webhookType == WebhookType.SIMPLE) {
+            return buildTextPropertyOnlyJSON(requestMessage);
+        } else {
             attachments.add(buildAttachmentJSON(eventComment.contents, null));
             return Json.stringify(buildRequestJSON(requestMessage, attachments));
-        } else {
-            return Json.stringify(buildRequestJSON(requestMessage));
         }
     }
 
@@ -428,10 +415,10 @@
         return requestBody;
     }
 
-    private ObjectNode buildRequestJSON(String requestMessage) {
+    private String buildTextPropertyOnlyJSON(String requestMessage) {
         ObjectNode requestBody = Json.newObject();
         requestBody.put("text", requestMessage);
-        return requestBody;
+        return Json.stringify(requestBody);
     }
 
     private ObjectNode buildSenderJSON(User sender) {
 
app/models/enumeration/WebhookType.java (added)
+++ app/models/enumeration/WebhookType.java
@@ -0,0 +1,17 @@
+/**
+ * Yona, 21st Century Project Hosting SW
+ * <p>
+ * Copyright Yona & Yobi Authors & NAVER Corp. & NAVER LABS Corp.
+ * https://yona.io
+ **/
+package models.enumeration;
+
+public enum WebhookType {
+    SIMPLE(0), WITH_DETAILS(1);
+
+    private int type;
+
+    WebhookType(int type) {
+        this.type = type;
+    }
+}
app/views/project/partial_webhooks_list.scala.html
--- app/views/project/partial_webhooks_list.scala.html
+++ app/views/project/partial_webhooks_list.scala.html
@@ -30,27 +30,36 @@
   </div>
 } else {
   <div class="row-fluid list-head">
-    <div class="span8 payload-url">
+    <div class="span6 payload-url">
       <strong>@Messages("project.webhook.payloadUrl")</strong>
     </div>
-    <div class="span4 secret">
-      <strong>@Messages("project.webhook.secret") / Working only when Git push</strong>
+    <div class="span6 secret">
+      <strong>@Messages("project.webhook.secret") | Include details or not | Working only when to push commit</strong>
     </div>
   </div>
 
   @webhooks.map { webhook =>
     <div class="row-fluid list-item" data-webhook-id="@webhook.id">
-      <div class="span8">
+      <div class="span6">
         <h6 class="mr20 truncate">
           @webhook.payloadUrl
         </h6>
       </div>
-      <div class="span4">
+      <div class="span6">
         <table class="table nm">
           <tr>
             <td>
               <span class="webhook-secret truncate">
-                  @webhook.secret
+              @if(webhook.secret.isEmpty) {
+                  NONE
+              } else {
+                @webhook.secret
+              }
+              </span>
+            </td>
+            <td>
+              <span class="webhook-secret truncate">
+              @webhook.webhookType
               </span>
             </td>
             <td>
app/views/project/webhooks.scala.html
--- app/views/project/webhooks.scala.html
+++ app/views/project/webhooks.scala.html
@@ -22,12 +22,12 @@
           <div>
             <input type="text" name="payloadUrl" class="input-webhook-payload" maxlength="2000" autocomplete="off" placeholder="@Messages("project.webhook.payloadUrl")">
             <input type="text" name="secret" class="input-webhook-secret" maxlength="250" autocomplete="off" placeholder="@Messages("project.webhook.secret")">
+            <select class="form-control" title="add details or not" name="webhookType">
+              <option value="SIMPLE">SIMPLE Version (no details)</option>
+              <option value="WITH_DETAILS">Normal (Slack/with details)</option>
+            </select>
             <label for="gitPushOnly">@Messages("project.webhook.gitPushOnly")</label>
             <input type="checkbox" id="gitPushOnly" name="gitPushOnly" class="form-check-input">
-            <select class="form-control" name="WebhookType">
-              <option value="0">SIMPLE Version</option>
-              <option value="1">Detail (Slack)</option>
-            </select>
           </div>
         </div>
         <button type="submit" class="ybtn ybtn-primary btn-submit">@Messages("project.webhook.add")</button>
 
conf/evolutions/default/24.sql (added)
+++ conf/evolutions/default/24.sql
@@ -0,0 +1,6 @@
+# --- !Ups
+ALTER TABLE webhook ADD COLUMN webhook_type tinyint(1) default 1;
+CREATE INDEX ix_webhook_webhook_type ON webhook (webhook_type);
+
+# --- !Downs
+ALTER TABLE webhook DROP COLUMN webhook_type;(파일 끝에 줄바꿈 문자 없음)
conf/messages
--- conf/messages
+++ conf/messages
@@ -717,7 +717,7 @@
 project.webhook.payloadUrl.tooLong = Given payload URL is too long. (Maximum 2000 Characters)
 project.webhook.secret = Authorization Token
 project.webhook.secret.tooLong = Given secret token is too long. (Maximum 250 Characters)
-project.webhook.gitPushOnly = Git push hook
+project.webhook.gitPushOnly = When to Git push only
 project.you.are.not.watching = You are not watching {0} project.
 project.you.are.watching = You are watching {0} project.
 project.you.may.want.to.be.a.member = You can send a sign-up request for {0} project.
conf/messages.ko-KR
--- conf/messages.ko-KR
+++ conf/messages.ko-KR
@@ -716,7 +716,7 @@
 project.webhook.payloadUrl = 전송할 주소
 project.webhook.payloadUrl.empty = Paylaod URL 은 필수 필드입니다.
 project.webhook.payloadUrl.tooLong = Payload URL 이 너무 깁니다 (최대 2000글자)웹후크 추가
-project.webhook.gitPushOnly = Git push hook
+project.webhook.gitPushOnly = Git push 시에만 동작을 원하면 체크
 project.webhook.secret = Authorization Token
 project.webhook.secret.tooLong = 보안 토큰이 너무 깁니다. (최대 250 글자)
 project.you.are.not.watching = {0} 프로젝트를 지켜보고 있지 않습니다.
Add a comment
List