Skip to content

Commit 3624944

Browse files
committed
Merge branch 'next' into internal
2 parents 743683a + cb60600 commit 3624944

File tree

9 files changed

+129
-71
lines changed

9 files changed

+129
-71
lines changed

app/assets/stylesheets/less/_common.less

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,4 +305,9 @@ input.white:-ms-input-placeholder { color:#fff; opacity:0.8; }
305305
line-height: 36px;
306306
}
307307

308-
.dimgray { color:dimgray; }
308+
.dimgray { color:dimgray; }
309+
310+
.vertical-align {
311+
display: flex;
312+
align-items: center;
313+
}

app/controllers/ProjectApp.java

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import models.enumeration.*;
1919
import org.apache.commons.collections.CollectionUtils;
2020
import org.apache.commons.lang.exception.ExceptionUtils;
21-
import org.apache.commons.lang3.BooleanUtils;
2221
import org.apache.commons.lang3.StringUtils;
2322
import org.apache.commons.mail.HtmlEmail;
2423
import com.fasterxml.jackson.databind.node.ObjectNode;
@@ -49,7 +48,6 @@
4948
import views.html.project.transfer;
5049
import views.html.project.change_vcs;
5150

52-
import javax.annotation.Nonnull;
5351
import javax.servlet.ServletException;
5452
import java.io.IOException;
5553
import java.security.NoSuchAlgorithmException;
@@ -1291,22 +1289,27 @@ public static Result newWebhook(String ownerId, String projectName) {
12911289
return notFound(ErrorViews.NotFound.render("error.notfound"));
12921290
}
12931291

1294-
Form<Webhook> addWebhookForm = form(Webhook.class).bindFromRequest();
1295-
if (addWebhookForm == null) {
1292+
Form<Webhook> addNewWebhookForm = form(Webhook.class).bindFromRequest();
1293+
if (addNewWebhookForm == null) {
12961294
Logger.warn("Failed creating webhook: got null form from newWebhook request");
1297-
return badRequest();
1298-
} else if (addWebhookForm.hasErrors()) {
1299-
return badRequest(ErrorViews.BadRequest.render());
1295+
return badRequest("Failed creating webhook: got null form from newWebhook request");
1296+
} else if (addNewWebhookForm.hasErrors()) {
1297+
return badRequest(ErrorViews.BadRequest.render(addNewWebhookForm.errorsAsJson().toString()));
13001298
}
13011299

1302-
Webhook webhook = addWebhookForm.get();
1303-
1304-
Webhook.create(project.id, webhook.payloadUrl.trim(), webhook.secret,
1305-
BooleanUtils.toBooleanDefaultIfNull(webhook.gitPushOnly, false));
1300+
createWebhook(project, addNewWebhookForm);
13061301

13071302
return redirect(routes.ProjectApp.webhooks(project.owner, project.name));
13081303
}
13091304

1305+
private static void createWebhook(Project project, Form<Webhook> forms) {
1306+
Webhook webhook = forms.get();
1307+
webhook.project = project;
1308+
if(webhook.gitPushOnly == null) webhook.gitPushOnly = false;
1309+
webhook.createdAt = new Date();
1310+
webhook.save();
1311+
}
1312+
13101313
@Transactional
13111314
@IsAllowed(Operation.UPDATE)
13121315
public static Result deleteWebhook(String ownerId, String projectName, Long id) {

app/models/Webhook.java

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,10 @@
11
/**
2-
* Yobi, Project Hosting SW
3-
*
4-
* Copyright 2015 NAVER Corp.
5-
* http://yobi.io
6-
*
7-
* @author Jihwan Chun
8-
*
9-
* Licensed under the Apache License, Version 2.0 (the "License");
10-
* you may not use this file except in compliance with the License.
11-
* You may obtain a copy of the License at
12-
*
13-
* http://www.apache.org/licenses/LICENSE-2.0
14-
*
15-
* Unless required by applicable law or agreed to in writing, software
16-
* distributed under the License is distributed on an "AS IS" BASIS,
17-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18-
* See the License for the specific language governing permissions and
19-
* limitations under the License.
20-
*/
2+
* Yona, 21st Century Project Hosting SW
3+
* <p>
4+
* Copyright Yona & Yobi Authors & NAVER Corp. & NAVER LABS Corp.
5+
* https://yona.io
6+
**/
7+
218
package models;
229

2310
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -26,6 +13,7 @@
2613
import models.enumeration.EventType;
2714
import models.enumeration.PullRequestReviewAction;
2815
import models.enumeration.ResourceType;
16+
import models.enumeration.WebhookType;
2917
import models.resource.GlobalResource;
3018
import models.resource.Resource;
3119
import models.resource.ResourceConvertible;
@@ -86,10 +74,12 @@ public class Webhook extends Model implements ResourceConvertible {
8674
public String secret;
8775

8876
/**
89-
* Type of webhook (true = git only push, false = all cases)
77+
* Condition of sending webhook (true: git only push, false: all cases)
9078
*/
9179
public Boolean gitPushOnly;
9280

81+
public WebhookType webhookType = WebhookType.SIMPLE;
82+
9383
/**
9484
* Payload URL of webhook.
9585
*/
@@ -260,11 +250,18 @@ private String buildRequestBody(EventType eventType, User sender, PullRequest ev
260250
}
261251
requestMessage += " <" + utils.Config.getScheme() + "://" + utils.Config.getHostport("localhost:9000") + RouteUtil.getUrl(eventPullRequest) + "|#" + eventPullRequest.number + ": " + eventPullRequest.title + ">";
262252

253+
if (this.webhookType == WebhookType.DETAIL_SLACK) {
254+
return buildJsonWithPullReqtuestDetails(eventPullRequest, detailFields, attachments, requestMessage);
255+
} else {
256+
return buildTextPropertyOnlyJSON(requestMessage);
257+
}
258+
}
259+
260+
private String buildJsonWithPullReqtuestDetails(PullRequest eventPullRequest, ArrayNode detailFields, ArrayNode attachments, String requestMessage) {
263261
detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), "pullRequest.sender"), eventPullRequest.contributor.name, false));
264262
detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), "pullRequest.from"), eventPullRequest.fromBranch, true));
265-
detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), "pullRequest.to"), eventPullRequest.toBranch,true));
263+
detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), "pullRequest.to"), eventPullRequest.toBranch, true));
266264
attachments.add(buildAttachmentJSON(eventPullRequest.body, detailFields));
267-
268265
return Json.stringify(buildRequestJSON(requestMessage, attachments));
269266
}
270267

@@ -285,12 +282,11 @@ private String buildRequestBody(EventType eventType, User sender, PullRequest ev
285282
}
286283
requestMessage += " <" + utils.Config.getScheme() + "://" + utils.Config.getHostport("localhost:9000") + RouteUtil.getUrl(eventPullRequest) + "|#" + eventPullRequest.number + ": " + eventPullRequest.title + ">";
287284

288-
detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), "pullRequest.sender"), eventPullRequest.contributor.name, false));
289-
detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), "pullRequest.from"), eventPullRequest.fromBranch, true));
290-
detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), "pullRequest.to"), eventPullRequest.toBranch, true));
291-
attachments.add(buildAttachmentJSON(eventPullRequest.body, detailFields));
292-
293-
return Json.stringify(buildRequestJSON(requestMessage, attachments));
285+
if (this.webhookType == WebhookType.SIMPLE) {
286+
return buildTextPropertyOnlyJSON(requestMessage);
287+
} else {
288+
return buildJsonWithPullReqtuestDetails(eventPullRequest, detailFields, attachments, requestMessage);
289+
}
294290
}
295291

296292
private String buildRequestBody(EventType eventType, User sender, Issue eventIssue) {
@@ -324,11 +320,18 @@ private String buildRequestBody(EventType eventType, User sender, Issue eventIss
324320

325321
requestMessage += " <" + utils.Config.getScheme() + "://" + utils.Config.getHostport("localhost:9000") + RouteUtil.getUrl(eventIssue) + "|#" + eventIssue.number + ": " + eventIssue.title + ">";
326322

323+
if (this.webhookType == WebhookType.SIMPLE) {
324+
return buildTextPropertyOnlyJSON(requestMessage);
325+
} else {
326+
return buildJsonWithIssueEventDetails(eventIssue, detailFields, attachments, requestMessage);
327+
}
328+
}
329+
330+
private String buildJsonWithIssueEventDetails(Issue eventIssue, ArrayNode detailFields, ArrayNode attachments, String requestMessage) {
327331
detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), "notification.type.milestone.changed"), eventIssue.milestoneId().toString(), true));
328332
detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), ""), eventIssue.assigneeName(), true));
329333
detailFields.add(buildTitleValueJSON(Messages.get(Lang.defaultLang(), "issue.state"), eventIssue.state.toString(), true));
330334
attachments.add(buildAttachmentJSON(eventIssue.body, detailFields));
331-
332335
return Json.stringify(buildRequestJSON(requestMessage, attachments));
333336
}
334337

@@ -354,9 +357,12 @@ private String buildRequestBody(EventType eventType, User sender, Comment eventC
354357
break;
355358
}
356359

357-
attachments.add(buildAttachmentJSON(eventComment.contents, null));
358-
359-
return Json.stringify(buildRequestJSON(requestMessage, attachments));
360+
if (this.webhookType == WebhookType.SIMPLE) {
361+
return buildTextPropertyOnlyJSON(requestMessage);
362+
} else {
363+
attachments.add(buildAttachmentJSON(eventComment.contents, null));
364+
return Json.stringify(buildRequestJSON(requestMessage, attachments));
365+
}
360366
}
361367

362368
private ObjectNode buildJSONFromCommit(Project project, RevCommit commit) {
@@ -409,6 +415,12 @@ private ObjectNode buildRequestJSON(String requestMessage, ArrayNode attachments
409415
return requestBody;
410416
}
411417

418+
private String buildTextPropertyOnlyJSON(String requestMessage) {
419+
ObjectNode requestBody = Json.newObject();
420+
requestBody.put("text", requestMessage);
421+
return Json.stringify(requestBody);
422+
}
423+
412424
private ObjectNode buildSenderJSON(User sender) {
413425
ObjectNode senderJSON = Json.newObject();
414426
senderJSON.put("login", sender.loginId);
@@ -457,6 +469,7 @@ public String toString() {
457469
", payloadUrl='" + payloadUrl + '\'' +
458470
", secret='" + secret + '\'' +
459471
", gitPushOnly=" + gitPushOnly +
472+
", webhookType=" + webhookType +
460473
", createdAt=" + createdAt +
461474
'}';
462475
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/**
2+
* Yona, 21st Century Project Hosting SW
3+
* <p>
4+
* Copyright Yona & Yobi Authors & NAVER Corp. & NAVER LABS Corp.
5+
* https://yona.io
6+
**/
7+
package models.enumeration;
8+
9+
public enum WebhookType {
10+
SIMPLE(0), DETAIL_SLACK(1);
11+
12+
private int type;
13+
14+
WebhookType(int type) {
15+
this.type = type;
16+
}
17+
}

app/views/project/partial_webhooks_list.scala.html

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -30,41 +30,51 @@
3030
</div>
3131
} else {
3232
<div class="row-fluid list-head">
33-
<div class="span8 payload-url">
33+
<div class="span5 payload-url">
3434
<strong>@Messages("project.webhook.payloadUrl")</strong>
3535
</div>
36-
<div class="span4 secret">
37-
<strong>@Messages("project.webhook.secret") / Working only when Git push</strong>
36+
<div class="span2 secret text-center">
37+
<strong>@Messages("project.webhook.secret")</strong>
3838
</div>
39+
<div class="span2 secret text-center">
40+
<strong>Type of message</strong>
41+
</div>
42+
<div class="span2 secret text-center">
43+
<strong>Just the push event</strong>
44+
</div>
45+
<div class="span1 secret text-center"></div>
46+
3947
</div>
4048

4149
@webhooks.map { webhook =>
42-
<div class="row-fluid list-item" data-webhook-id="@webhook.id">
43-
<div class="span8">
50+
<div class="row-fluid list-item vertical-align" data-webhook-id="@webhook.id">
51+
<div class="span5">
4452
<h6 class="mr20 truncate">
4553
@webhook.payloadUrl
4654
</h6>
4755
</div>
48-
<div class="span4">
49-
<table class="table nm">
50-
<tr>
51-
<td>
52-
<span class="webhook-secret truncate">
53-
@webhook.secret
54-
</span>
55-
</td>
56-
<td>
57-
<span class="webhook-secret truncate">
58-
<input type="checkbox" @if(webhook.gitPushOnly){checked} onclick="return false;" />
59-
</span>
60-
</td>
61-
<td class="actions">
62-
<button type="button" class="ybtn ybtn-danger ybtn-small" data-request-method="delete" data-request-uri="@routes.ProjectApp.deleteWebhook(project.owner, project.name, webhook.id)">
63-
@Messages("button.delete")
64-
</button>
65-
</td>
66-
</tr>
67-
</table>
56+
<div class="span2 text-center">
57+
<h6>
58+
@if(webhook.secret.isEmpty) {
59+
NONE
60+
} else {
61+
@webhook.secret
62+
}
63+
</h6>
64+
</div>
65+
<div class="span2 text-center">
66+
<h6>
67+
@webhook.webhookType
68+
</h6>
69+
</div>
70+
<div class="span2 text-center">
71+
<input type="checkbox" @if(webhook.gitPushOnly){checked} onclick="return false;" />
72+
73+
</div>
74+
<div class="span1 text-center">
75+
<button type="button" class="ybtn ybtn-danger ybtn-small" data-request-method="delete" data-request-uri="@routes.ProjectApp.deleteWebhook(project.owner, project.name, webhook.id)">
76+
@Messages("button.delete")
77+
</button>
6878
</div>
6979
</div>
7080
}

app/views/project/webhooks.scala.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
<div>
2323
<input type="text" name="payloadUrl" class="input-webhook-payload" maxlength="2000" autocomplete="off" placeholder="@Messages("project.webhook.payloadUrl")">
2424
<input type="text" name="secret" class="input-webhook-secret" maxlength="250" autocomplete="off" placeholder="@Messages("project.webhook.secret")">
25+
<select class="form-control" title="add details or not" name="webhookType">
26+
<option value="SIMPLE">SIMPLE Version (no details)</option>
27+
<option value="DETAIL_SLACK">DETAIL Version (for slack) </option>
28+
</select>
2529
<label for="gitPushOnly">@Messages("project.webhook.gitPushOnly")</label>
2630
<input type="checkbox" id="gitPushOnly" name="gitPushOnly" class="form-check-input">
2731
</div>

conf/evolutions/default/24.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# --- !Ups
2+
ALTER TABLE webhook ADD COLUMN webhook_type tinyint(1) default 1;
3+
CREATE INDEX ix_webhook_webhook_type ON webhook (webhook_type);
4+
5+
# --- !Downs
6+
ALTER TABLE webhook DROP COLUMN webhook_type;

conf/messages

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,7 @@ project.webhook.payloadUrl.empty = Paylaod URL is required field.
717717
project.webhook.payloadUrl.tooLong = Given payload URL is too long. (Maximum 2000 Characters)
718718
project.webhook.secret = Authorization Token
719719
project.webhook.secret.tooLong = Given secret token is too long. (Maximum 250 Characters)
720-
project.webhook.gitPushOnly = Git push hook
720+
project.webhook.gitPushOnly = When to Git push only
721721
project.you.are.not.watching = You are not watching {0} project.
722722
project.you.are.watching = You are watching {0} project.
723723
project.you.may.want.to.be.a.member = You can send a sign-up request for {0} project.

conf/messages.ko-KR

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,7 @@ project.webhook.new = 새 웹후크 생성
716716
project.webhook.payloadUrl = 전송할 주소
717717
project.webhook.payloadUrl.empty = Paylaod URL 은 필수 필드입니다.
718718
project.webhook.payloadUrl.tooLong = Payload URL 이 너무 깁니다 (최대 2000글자)웹후크 추가
719-
project.webhook.gitPushOnly = Git push hook
719+
project.webhook.gitPushOnly = Git push 시에만 동작을 원하면 체크
720720
project.webhook.secret = Authorization Token
721721
project.webhook.secret.tooLong = 보안 토큰이 너무 깁니다. (최대 250 글자)
722722
project.you.are.not.watching = {0} 프로젝트를 지켜보고 있지 않습니다.

0 commit comments

Comments
 (0)