Skip to content

Commit ca3998a

Browse files
committed
(refs #16)Implementing comment to gist
1 parent 02cc517 commit ca3998a

File tree

15 files changed

+389
-44
lines changed

15 files changed

+389
-44
lines changed
1.22 KB
Loading

src/main/scala/Plugin.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class Plugin extends gitbucket.core.plugin.Plugin {
5050
"images/menu-forks-active.png" -> fromClassPath("images/menu-forks-active.png"),
5151
"images/menu-forks.png" -> fromClassPath("images/menu-forks.png"),
5252
"images/code.png" -> fromClassPath("images/code.png"),
53+
"images/comment.png" -> fromClassPath("images/comment.png"),
5354
"images/snippet.png" -> fromClassPath("images/snippet.png")
5455
)
5556

src/main/scala/gitbucket/gist/controller/GistController.scala

Lines changed: 94 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
package gitbucket.gist.controller
22

33
import java.io.File
4+
import gitbucket.core.view.helpers
45
import jp.sf.amateras.scalatra.forms._
56

67
import gitbucket.core.controller.ControllerBase
78
import gitbucket.core.service.AccountService
9+
import gitbucket.core.service.RepositoryService.RepositoryInfo
810
import gitbucket.core.util._
911
import gitbucket.core.util.Directory._
1012
import gitbucket.core.util.ControlUtil._
1113
import gitbucket.core.util.Implicits._
1214
import gitbucket.core.view.helpers._
1315

1416
import gitbucket.gist.model._
15-
import gitbucket.gist.service.GistService
17+
import gitbucket.gist.service._
1618
import gitbucket.gist.util._
1719
import gitbucket.gist.util.GistUtils._
1820
import gitbucket.gist.util.Configurations._
@@ -21,12 +23,19 @@ import gitbucket.gist.html
2123
import org.apache.commons.io.FileUtils
2224
import org.eclipse.jgit.api.Git
2325
import org.eclipse.jgit.lib._
26+
import org.scalatra.Ok
2427

25-
class GistController extends GistControllerBase with GistService with AccountService
28+
class GistController extends GistControllerBase with GistService with GistCommentService with AccountService
2629
with GistEditorAuthenticator with UsersAuthenticator
2730

2831
trait GistControllerBase extends ControllerBase {
29-
self: GistService with AccountService with GistEditorAuthenticator with UsersAuthenticator =>
32+
self: GistService with GistCommentService with AccountService with GistEditorAuthenticator with UsersAuthenticator =>
33+
34+
case class CommentForm(content: String)
35+
36+
val commentForm = mapping(
37+
"content" -> trim(label("Comment", text(required)))
38+
)(CommentForm.apply)
3039

3140
get("/gist"){
3241
if(context.loginAccount.isDefined){
@@ -41,10 +50,12 @@ trait GistControllerBase extends ControllerBase {
4150
val count = countPublicGists()
4251

4352
val gists: Seq[(Gist, GistInfo)] = result.map { gist =>
44-
val files = getGistFiles(gist.userName, gist.repositoryName)
53+
val userName = gist.userName
54+
val repoName = gist.repositoryName
55+
val files = getGistFiles(userName, repoName)
4556
val (fileName, source) = files.head
4657

47-
(gist, GistInfo(fileName, source, files.length, getForkedCount(gist.userName, gist.repositoryName)))
58+
(gist, GistInfo(fileName, source, files.length, getForkedCount(userName, repoName), getCommentCount(userName, repoName)))
4859
}
4960

5061
html.list(None, gists, page, page * Limit < count)
@@ -318,6 +329,82 @@ trait GistControllerBase extends ControllerBase {
318329
} getOrElse NotFound
319330
}
320331

332+
post("/gist/:userName/:repoName/_preview"){
333+
val userName = params("userName")
334+
val repoName = params("repoName")
335+
336+
contentType = "text/html"
337+
helpers.markdown(params("content"),
338+
RepositoryInfo(
339+
owner = userName,
340+
name = repoName,
341+
httpUrl = "",
342+
repository = null,
343+
issueCount = 0,
344+
pullCount = 0,
345+
commitCount = 0,
346+
forkedCount = 0,
347+
branchList = Nil,
348+
tags = Nil,
349+
managers = Nil
350+
), false, false, false, false)
351+
}
352+
353+
post("/gist/:userName/:repoName/_comment", commentForm)(usersOnly { form =>
354+
val userName = params("userName")
355+
val repoName = params("repoName")
356+
val loginAccount = context.loginAccount.get
357+
358+
getGist(userName, repoName).map { gist =>
359+
registerGistComment(userName, repoName, form.content, loginAccount.userName)
360+
redirect(s"${context.path}/gist/${userName}/${repoName}")
361+
} getOrElse NotFound
362+
})
363+
364+
ajaxPost("/gist/:userName/:repoName/_comments/:commentId/_delete")(usersOnly {
365+
val userName = params("userName")
366+
val repoName = params("repoName")
367+
val commentId = params("commentId").toInt
368+
369+
// TODO Access check
370+
371+
Ok(deleteGistComment(userName, repoName, commentId))
372+
})
373+
374+
ajaxGet("/gist/:userName/:repoName/_comments/:commentId")(usersOnly {
375+
val userName = params("userName")
376+
val repoName = params("repoName")
377+
val commentId = params("commentId").toInt
378+
379+
// TODO Access check
380+
getGist(userName, repoName).flatMap { gist =>
381+
getGistComment(userName, repoName, commentId).map { comment =>
382+
params.get("dataType") collect {
383+
case t if t == "html" => gitbucket.gist.html.commentedit(
384+
comment.content, comment.commentId, comment.userName, comment.repositoryName)
385+
} getOrElse {
386+
contentType = formats("json")
387+
org.json4s.jackson.Serialization.write(
388+
Map("content" -> gitbucket.core.view.Markdown.toHtml(comment.content,
389+
gist.toRepositoryInfo, false, true, true, true) // TODO isEditableこれでいいのか?
390+
))
391+
}
392+
}
393+
} getOrElse NotFound
394+
})
395+
396+
ajaxPost("/gist/:userName/:repoName/_comments/:commentId/_update", commentForm)(usersOnly { form =>
397+
val userName = params("userName")
398+
val repoName = params("repoName")
399+
val commentId = params("commentId").toInt
400+
401+
// TODO Access check
402+
403+
updateGistComment(userName, repoName, commentId, form.content)
404+
redirect(s"/gist/${userName}/${repoName}/_comments/${commentId}")
405+
})
406+
407+
321408
private def _gist(userName: String, repoName: Option[String] = None, revision: String = "master") = {
322409
repoName match {
323410
case None => {
@@ -335,7 +422,7 @@ trait GistControllerBase extends ControllerBase {
335422
val repoName = gist.repositoryName
336423
val files = getGistFiles(userName, repoName, revision)
337424
val (fileName, source) = files.head
338-
(gist, GistInfo(fileName, source, files.length, getForkedCount(userName, repoName)))
425+
(gist, GistInfo(fileName, source, files.length, getForkedCount(userName, repoName), getCommentCount(userName, repoName)))
339426
}
340427

341428
val fullName = getAccountByUserName(userName).get.fullName
@@ -352,6 +439,7 @@ trait GistControllerBase extends ControllerBase {
352439
GistRepositoryURL(gist, baseUrl, context.settings),
353440
revision,
354441
getGistFiles(userName, repoName, revision),
442+
getGistComments(userName, repoName),
355443
isEditable(userName)
356444
)
357445
}

src/main/scala/gitbucket/gist/model/Gist.scala

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,23 @@ case class Gist(
3030
updatedDate: java.util.Date,
3131
originUserName: Option[String],
3232
originRepositoryName: Option[String]
33-
)
33+
){
34+
def toRepositoryInfo = {
35+
gitbucket.core.service.RepositoryService.RepositoryInfo(
36+
owner = userName,
37+
name = repositoryName,
38+
httpUrl = "",
39+
repository = null,
40+
issueCount = 0,
41+
pullCount = 0,
42+
commitCount = 0,
43+
forkedCount = 0,
44+
branchList = Nil,
45+
tags = Nil,
46+
managers = Nil
47+
)
48+
}
49+
}
3450

3551

3652

src/main/scala/gitbucket/gist/model/GistComment.scala

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@ trait GistCommentComponent { self: gitbucket.core.model.Profile =>
44
import profile.simple._
55
import self._
66

7-
lazy val GistComments = TableQuery[GistComments]
7+
lazy val GistComments = new TableQuery(tag => new GistComments(tag)){
8+
def autoInc = this returning this.map(_.commentId)
9+
}
810

911
class GistComments(tag: Tag) extends Table[GistComment](tag, "GIST_COMMENT") {
1012
val userName = column[String]("USER_NAME")
1113
val repositoryName = column[String]("REPOSITORY_NAME")
12-
val commentId = column[Int]("COMMENT_ID")
14+
val commentId = column[Int]("COMMENT_ID", O AutoInc)
1315
val commentedUserName = column[String]("COMMENTED_USER_NAME")
14-
val content = column[String]("DESCRIPTION")
16+
val content = column[String]("CONTENT")
1517
val registeredDate = column[java.util.Date]("REGISTERED_DATE")
1618
val updatedDate = column[java.util.Date]("UPDATED_DATE")
1719
def * = (userName, repositoryName, commentId, commentedUserName, content, registeredDate, updatedDate) <> (GistComment.tupled, GistComment.unapply)
@@ -21,7 +23,7 @@ trait GistCommentComponent { self: gitbucket.core.model.Profile =>
2123
case class GistComment(
2224
userName: String,
2325
repositoryName: String,
24-
commentId: Int,
26+
commentId: Int = 0,
2527
commentedUserName: String,
2628
content: String,
2729
registeredDate: java.util.Date,
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
package gitbucket.gist.model
22

3-
case class GistInfo(fileName: String, source: String, fileCount: Int, forkedCount: Int)
3+
case class GistInfo(fileName: String, source: String, fileCount: Int, forkedCount: Int, commentCount: Int)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package gitbucket.gist.service
2+
3+
import gitbucket.gist.model.GistComment
4+
import gitbucket.gist.model.Profile._
5+
import profile.simple._
6+
7+
trait GistCommentService {
8+
9+
def registerGistComment(userName: String, repositoryName: String, content: String, commentedUserName: String)
10+
(implicit s: Session): Int =
11+
GistComments.autoInc insert GistComment(
12+
userName = userName,
13+
repositoryName = repositoryName,
14+
commentedUserName = commentedUserName,
15+
content = content,
16+
registeredDate = currentDate,
17+
updatedDate = currentDate)
18+
19+
def getGistComments(userName: String, repositoryName: String)(implicit s: Session): Seq[GistComment] =
20+
GistComments.filter { t =>
21+
(t.userName === userName.bind) &&
22+
(t.repositoryName === repositoryName.bind)
23+
}.sortBy(_.registeredDate.desc).list
24+
25+
def getGistComment(userName: String, repositoryName: String, commentId: Int)(implicit s: Session): Option[GistComment] =
26+
GistComments.filter { t =>
27+
(t.userName === userName.bind) &&
28+
(t.repositoryName === repositoryName.bind) &&
29+
(t.commentId === commentId.bind)
30+
}.firstOption
31+
32+
def updateGistComment(userName: String, repositoryName: String, commentId: Int, content: String)(implicit s: Session): Int =
33+
GistComments.filter { t =>
34+
(t.userName === userName.bind) &&
35+
(t.repositoryName === repositoryName.bind) &&
36+
(t.commentId === commentId.bind)
37+
}.map { t =>
38+
(t.content, t.updatedDate)
39+
}.update(content, currentDate)
40+
41+
def deleteGistComment(userName: String, repositoryName: String, commentId: Int)(implicit s: Session): Int =
42+
GistComments.filter { t =>
43+
(t.userName === userName.bind) &&
44+
(t.repositoryName === repositoryName.bind) &&
45+
(t.commentId === commentId.bind)
46+
}.delete
47+
48+
def getCommentCount(userName: String, repositoryName: String)(implicit s: Session): Int =
49+
Query(GistComments.filter { t =>
50+
(t.userName === userName.bind) &&
51+
(t.repositoryName === repositoryName.bind)
52+
}.length).first
53+
54+
}

src/main/scala/gitbucket/gist/service/GistService.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ import profile.simple._
66

77
trait GistService {
88

9-
def getRecentGists(userName: String, offset: Int, limit: Int)(implicit s: Session): List[Gist] =
9+
def getRecentGists(userName: String, offset: Int, limit: Int)(implicit s: Session): Seq[Gist] =
1010
Gists.filter(_.userName === userName.bind).sortBy(_.registeredDate desc).drop(offset).take(limit).list
1111

12-
def getPublicGists(offset: Int, limit: Int)(implicit s: Session): List[Gist] =
12+
def getPublicGists(offset: Int, limit: Int)(implicit s: Session): Seq[Gist] =
1313
Gists.filter(_.isPrivate === false.bind).sortBy(_.registeredDate desc).drop(offset).take(limit).list
1414

1515
def countPublicGists()(implicit s: Session): Int =
1616
Query(Gists.filter(_.isPrivate === false.bind).length).first
1717

18-
def getUserGists(userName: String, loginUserName: Option[String], offset: Int, limit: Int)(implicit s: Session): List[Gist] =
18+
def getUserGists(userName: String, loginUserName: Option[String], offset: Int, limit: Int)(implicit s: Session): Seq[Gist] =
1919
(if(loginUserName.isDefined){
2020
Gists filter(t => (t.userName === userName.bind) && ((t.userName === loginUserName.bind) || (t.isPrivate === false.bind)))
2121
} else {
@@ -36,7 +36,7 @@ trait GistService {
3636
def getForkedCount(userName: String, repositoryName: String)(implicit s: Session): Int =
3737
Query(Gists.filter(t => (t.originUserName === userName.bind) && (t.originRepositoryName === repositoryName.bind)).length).first
3838

39-
def getForkedGists(userName: String, repositoryName: String)(implicit s: Session): List[Gist] =
39+
def getForkedGists(userName: String, repositoryName: String)(implicit s: Session): Seq[Gist] =
4040
Gists.filter(t => (t.originUserName === userName.bind) && (t.originRepositoryName === repositoryName.bind)).sortBy(_.userName).list
4141

4242
def registerGist(userName: String, repositoryName: String, isPrivate: Boolean, title: String, description: String,
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
@(content: String, commentId: Int, userName: String, repoName: String)(implicit context: gitbucket.core.controller.Context)
2+
@import context._
3+
<span id="error-edit-content-@commentId" class="error"></span>
4+
@gitbucket.core.helper.html.attached(userName, repoName){
5+
<textarea style="width: 635px; height: 100px;" id="edit-content-@commentId">@content</textarea>
6+
}
7+
<div>
8+
<input type="button" id="cancel-comment-@commentId" class="btn btn-small btn-danger" value="Cancel"/>
9+
<input type="button" id="update-comment-@commentId" class="btn btn-small pull-right" value="Update comment"/>
10+
</div>
11+
<script>
12+
$(function(){
13+
var callback = function(data){
14+
$('#update-comment-@commentId, #cancel-comment-@commentId').removeAttr('disabled');
15+
$('#commentContent-@commentId').empty().html(data.content);
16+
prettyPrint();
17+
};
18+
19+
$('#update-comment-@commentId').click(function(){
20+
$('#update-comment-@commentId, #cancel-comment-@commentId').attr('disabled', 'disabled');
21+
$.ajax({
22+
url: '@path/gist/@userName/@repoName/_comments/@commentId/_update',
23+
type: 'POST',
24+
data: {
25+
issueId : 0, // TODO
26+
content : $('#edit-content-@commentId').val()
27+
}
28+
}).done(
29+
callback
30+
).fail(function(req) {
31+
$('#update-comment-@commentId, #cancel-comment-@commentId').removeAttr('disabled');
32+
$('#error-edit-content-@commentId').text($.parseJSON(req.responseText).content);
33+
});
34+
});
35+
36+
$('#cancel-comment-@commentId').click(function(){
37+
$('#update-comment-@commentId, #cancel-comment-@commentId').attr('disabled', 'disabled');
38+
$.get('@path/gist/@userName/@repoName/_comments/@commentId', callback);
39+
return false;
40+
});
41+
});
42+
</script>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
@(gist: gitbucket.gist.model.Gist)(implicit context: gitbucket.core.controller.Context)
2+
@import context._
3+
@import gitbucket.core.view.helpers._
4+
@if(loginAccount.isDefined){
5+
<hr/><br/>
6+
<form method="POST" validate="true" action="@path/gist/@gist.userName/@gist.repositoryName/_comment">
7+
<div class="issue-avatar-image">@avatar(loginAccount.get.userName, 48)</div>
8+
<div class="box issue-comment-box">
9+
<div class="box-content">
10+
@gitbucket.gist.html.commentpreview(
11+
gist = gist,
12+
content = "",
13+
style = "width: 635px; height: 100px; max-height: 150px;",
14+
elastic = true
15+
)
16+
</div>
17+
</div>
18+
<div class="pull-right">
19+
<input type="submit" class="btn btn-success" value="Comment"/>
20+
</div>
21+
</form>
22+
}
23+
<script>
24+
$(function(){
25+
$('#action').click(function(){
26+
$('<input type="hidden">').attr('name', 'action').val($(this).val().toLowerCase()).appendTo('form');
27+
});
28+
});
29+
</script>

0 commit comments

Comments
 (0)