")
+ var text: String = node.getText
+ while (text.charAt(0) == '\n') {
+ printer.print("
")
+ text = text.substring(1)
+ }
+ printer.printEncoded(text)
+ printer.print("")
+ }
+}
+
+class GitBucketHtmlSerializer(
+ markdown: String,
+ repository: RepositoryService.RepositoryInfo,
+ enableWikiLink: Boolean,
+ enableRefsLink: Boolean,
+ enableTaskList: Boolean,
+ hasWritePermission: Boolean,
+ pages: List[String]
+ )(implicit val context: Context) extends ToHtmlSerializer(
+ new GitBucketLinkRender(context, repository, enableWikiLink, pages),
+ Map[String, VerbatimSerializer](VerbatimSerializer.DEFAULT -> new GitBucketVerbatimSerializer).asJava
+ ) with LinkConverter with RequestCache {
+
+ override protected def printImageTag(imageNode: SuperNode, url: String): Unit = {
+ printer.print("")
+ .print("${value.body.trim.split("\n").map(_.trim).mkString("\n")}")
+
+ /**
+ * Implicit conversion to add mkHtml() to Seq[Html].
+ */
+ implicit class RichHtmlSeq(seq: Seq[Html]) {
+ def mkHtml(separator: String) = Html(seq.mkString(separator))
+ def mkHtml(separator: scala.xml.Elem) = Html(seq.mkString(separator.toString))
+ }
+
+ def commitStateIcon(state: CommitState) = Html(state match {
+ case CommitState.PENDING => "●"
+ case CommitState.SUCCESS => "✔"
+ case CommitState.ERROR => "×"
+ case CommitState.FAILURE => "×"
+ })
+
+ def commitStateText(state: CommitState, commitId:String) = state match {
+ case CommitState.PENDING => "Waiting to hear about "+commitId.substring(0,8)
+ case CommitState.SUCCESS => "All is well"
+ case CommitState.ERROR => "Failed"
+ case CommitState.FAILURE => "Failed"
+ }
+}
diff --git a/src/main/scala/model/AccessToken.scala b/src/main/scala/model/AccessToken.scala
deleted file mode 100644
index 2695c2f..0000000
--- a/src/main/scala/model/AccessToken.scala
+++ /dev/null
@@ -1,20 +0,0 @@
-package model
-
-trait AccessTokenComponent { self: Profile =>
- import profile.simple._
- lazy val AccessTokens = TableQuery[AccessTokens]
-
- class AccessTokens(tag: Tag) extends Table[AccessToken](tag, "ACCESS_TOKEN") {
- val accessTokenId = column[Int]("ACCESS_TOKEN_ID", O AutoInc)
- val userName = column[String]("USER_NAME")
- val tokenHash = column[String]("TOKEN_HASH")
- val note = column[String]("NOTE")
- def * = (accessTokenId, userName, tokenHash, note) <> (AccessToken.tupled, AccessToken.unapply)
- }
-}
-case class AccessToken(
- accessTokenId: Int = 0,
- userName: String,
- tokenHash: String,
- note: String
-)
diff --git a/src/main/scala/model/Account.scala b/src/main/scala/model/Account.scala
deleted file mode 100644
index 012c559..0000000
--- a/src/main/scala/model/Account.scala
+++ /dev/null
@@ -1,39 +0,0 @@
-package model
-
-trait AccountComponent { self: Profile =>
- import profile.simple._
- import self._
-
- lazy val Accounts = TableQuery[Accounts]
-
- class Accounts(tag: Tag) extends Table[Account](tag, "ACCOUNT") {
- val userName = column[String]("USER_NAME", O PrimaryKey)
- val fullName = column[String]("FULL_NAME")
- val mailAddress = column[String]("MAIL_ADDRESS")
- val password = column[String]("PASSWORD")
- val isAdmin = column[Boolean]("ADMINISTRATOR")
- val url = column[String]("URL")
- val registeredDate = column[java.util.Date]("REGISTERED_DATE")
- val updatedDate = column[java.util.Date]("UPDATED_DATE")
- val lastLoginDate = column[java.util.Date]("LAST_LOGIN_DATE")
- val image = column[String]("IMAGE")
- val groupAccount = column[Boolean]("GROUP_ACCOUNT")
- val removed = column[Boolean]("REMOVED")
- def * = (userName, fullName, mailAddress, password, isAdmin, url.?, registeredDate, updatedDate, lastLoginDate.?, image.?, groupAccount, removed) <> (Account.tupled, Account.unapply)
- }
-}
-
-case class Account(
- userName: String,
- fullName: String,
- mailAddress: String,
- password: String,
- isAdmin: Boolean,
- url: Option[String],
- registeredDate: java.util.Date,
- updatedDate: java.util.Date,
- lastLoginDate: Option[java.util.Date],
- image: Option[String],
- isGroupAccount: Boolean,
- isRemoved: Boolean
-)
diff --git a/src/main/scala/model/Activity.scala b/src/main/scala/model/Activity.scala
deleted file mode 100644
index 8e3960e..0000000
--- a/src/main/scala/model/Activity.scala
+++ /dev/null
@@ -1,29 +0,0 @@
-package model
-
-trait ActivityComponent extends TemplateComponent { self: Profile =>
- import profile.simple._
- import self._
-
- lazy val Activities = TableQuery[Activities]
-
- class Activities(tag: Tag) extends Table[Activity](tag, "ACTIVITY") with BasicTemplate {
- val activityId = column[Int]("ACTIVITY_ID", O AutoInc)
- val activityUserName = column[String]("ACTIVITY_USER_NAME")
- val activityType = column[String]("ACTIVITY_TYPE")
- val message = column[String]("MESSAGE")
- val additionalInfo = column[String]("ADDITIONAL_INFO")
- val activityDate = column[java.util.Date]("ACTIVITY_DATE")
- def * = (userName, repositoryName, activityUserName, activityType, message, additionalInfo.?, activityDate, activityId) <> (Activity.tupled, Activity.unapply)
- }
-}
-
-case class Activity(
- userName: String,
- repositoryName: String,
- activityUserName: String,
- activityType: String,
- message: String,
- additionalInfo: Option[String],
- activityDate: java.util.Date,
- activityId: Int = 0
-)
diff --git a/src/main/scala/model/BasicTemplate.scala b/src/main/scala/model/BasicTemplate.scala
deleted file mode 100644
index 1d012c1..0000000
--- a/src/main/scala/model/BasicTemplate.scala
+++ /dev/null
@@ -1,57 +0,0 @@
-package model
-
-protected[model] trait TemplateComponent { self: Profile =>
- import profile.simple._
-
- trait BasicTemplate { self: Table[_] =>
- val userName = column[String]("USER_NAME")
- val repositoryName = column[String]("REPOSITORY_NAME")
-
- def byRepository(owner: String, repository: String) =
- (userName === owner.bind) && (repositoryName === repository.bind)
-
- def byRepository(userName: Column[String], repositoryName: Column[String]) =
- (this.userName === userName) && (this.repositoryName === repositoryName)
- }
-
- trait IssueTemplate extends BasicTemplate { self: Table[_] =>
- val issueId = column[Int]("ISSUE_ID")
-
- def byIssue(owner: String, repository: String, issueId: Int) =
- byRepository(owner, repository) && (this.issueId === issueId.bind)
-
- def byIssue(userName: Column[String], repositoryName: Column[String], issueId: Column[Int]) =
- byRepository(userName, repositoryName) && (this.issueId === issueId)
- }
-
- trait LabelTemplate extends BasicTemplate { self: Table[_] =>
- val labelId = column[Int]("LABEL_ID")
-
- def byLabel(owner: String, repository: String, labelId: Int) =
- byRepository(owner, repository) && (this.labelId === labelId.bind)
-
- def byLabel(userName: Column[String], repositoryName: Column[String], labelId: Column[Int]) =
- byRepository(userName, repositoryName) && (this.labelId === labelId)
- }
-
- trait MilestoneTemplate extends BasicTemplate { self: Table[_] =>
- val milestoneId = column[Int]("MILESTONE_ID")
-
- def byMilestone(owner: String, repository: String, milestoneId: Int) =
- byRepository(owner, repository) && (this.milestoneId === milestoneId.bind)
-
- def byMilestone(userName: Column[String], repositoryName: Column[String], milestoneId: Column[Int]) =
- byRepository(userName, repositoryName) && (this.milestoneId === milestoneId)
- }
-
- trait CommitTemplate extends BasicTemplate { self: Table[_] =>
- val commitId = column[String]("COMMIT_ID")
-
- def byCommit(owner: String, repository: String, commitId: String) =
- byRepository(owner, repository) && (this.commitId === commitId)
-
- def byCommit(owner: Column[String], repository: Column[String], commitId: Column[String]) =
- byRepository(userName, repositoryName) && (this.commitId === commitId)
- }
-
-}
diff --git a/src/main/scala/model/Collaborator.scala b/src/main/scala/model/Collaborator.scala
deleted file mode 100644
index 88311e1..0000000
--- a/src/main/scala/model/Collaborator.scala
+++ /dev/null
@@ -1,21 +0,0 @@
-package model
-
-trait CollaboratorComponent extends TemplateComponent { self: Profile =>
- import profile.simple._
-
- lazy val Collaborators = TableQuery[Collaborators]
-
- class Collaborators(tag: Tag) extends Table[Collaborator](tag, "COLLABORATOR") with BasicTemplate {
- val collaboratorName = column[String]("COLLABORATOR_NAME")
- def * = (userName, repositoryName, collaboratorName) <> (Collaborator.tupled, Collaborator.unapply)
-
- def byPrimaryKey(owner: String, repository: String, collaborator: String) =
- byRepository(owner, repository) && (collaboratorName === collaborator.bind)
- }
-}
-
-case class Collaborator(
- userName: String,
- repositoryName: String,
- collaboratorName: String
-)
diff --git a/src/main/scala/model/Comment.scala b/src/main/scala/model/Comment.scala
deleted file mode 100644
index 9569871..0000000
--- a/src/main/scala/model/Comment.scala
+++ /dev/null
@@ -1,78 +0,0 @@
-package model
-
-trait Comment {
- val commentedUserName: String
- val registeredDate: java.util.Date
-}
-
-trait IssueCommentComponent extends TemplateComponent { self: Profile =>
- import profile.simple._
- import self._
-
- lazy val IssueComments = new TableQuery(tag => new IssueComments(tag)){
- def autoInc = this returning this.map(_.commentId)
- }
-
- class IssueComments(tag: Tag) extends Table[IssueComment](tag, "ISSUE_COMMENT") with IssueTemplate {
- val commentId = column[Int]("COMMENT_ID", O AutoInc)
- val action = column[String]("ACTION")
- val commentedUserName = column[String]("COMMENTED_USER_NAME")
- val content = column[String]("CONTENT")
- val registeredDate = column[java.util.Date]("REGISTERED_DATE")
- val updatedDate = column[java.util.Date]("UPDATED_DATE")
- def * = (userName, repositoryName, issueId, commentId, action, commentedUserName, content, registeredDate, updatedDate) <> (IssueComment.tupled, IssueComment.unapply)
-
- def byPrimaryKey(commentId: Int) = this.commentId === commentId.bind
- }
-}
-
-case class IssueComment (
- userName: String,
- repositoryName: String,
- issueId: Int,
- commentId: Int = 0,
- action: String,
- commentedUserName: String,
- content: String,
- registeredDate: java.util.Date,
- updatedDate: java.util.Date
-) extends Comment
-
-trait CommitCommentComponent extends TemplateComponent { self: Profile =>
- import profile.simple._
- import self._
-
- lazy val CommitComments = new TableQuery(tag => new CommitComments(tag)){
- def autoInc = this returning this.map(_.commentId)
- }
-
- class CommitComments(tag: Tag) extends Table[CommitComment](tag, "COMMIT_COMMENT") with CommitTemplate {
- val commentId = column[Int]("COMMENT_ID", O AutoInc)
- val commentedUserName = column[String]("COMMENTED_USER_NAME")
- val content = column[String]("CONTENT")
- val fileName = column[Option[String]]("FILE_NAME")
- val oldLine = column[Option[Int]]("OLD_LINE_NUMBER")
- val newLine = column[Option[Int]]("NEW_LINE_NUMBER")
- val registeredDate = column[java.util.Date]("REGISTERED_DATE")
- val updatedDate = column[java.util.Date]("UPDATED_DATE")
- val pullRequest = column[Boolean]("PULL_REQUEST")
- def * = (userName, repositoryName, commitId, commentId, commentedUserName, content, fileName, oldLine, newLine, registeredDate, updatedDate, pullRequest) <> (CommitComment.tupled, CommitComment.unapply)
-
- def byPrimaryKey(commentId: Int) = this.commentId === commentId.bind
- }
-}
-
-case class CommitComment(
- userName: String,
- repositoryName: String,
- commitId: String,
- commentId: Int = 0,
- commentedUserName: String,
- content: String,
- fileName: Option[String],
- oldLine: Option[Int],
- newLine: Option[Int],
- registeredDate: java.util.Date,
- updatedDate: java.util.Date,
- pullRequest: Boolean
- ) extends Comment
diff --git a/src/main/scala/model/CommitStatus.scala b/src/main/scala/model/CommitStatus.scala
deleted file mode 100644
index 47a2343..0000000
--- a/src/main/scala/model/CommitStatus.scala
+++ /dev/null
@@ -1,71 +0,0 @@
-package model
-
-import scala.slick.lifted.MappedTo
-import scala.slick.jdbc._
-
-trait CommitStatusComponent extends TemplateComponent { self: Profile =>
- import profile.simple._
- import self._
-
- implicit val commitStateColumnType = MappedColumnType.base[CommitState, String](b => b.name , i => CommitState(i))
-
- lazy val CommitStatuses = TableQuery[CommitStatuses]
- class CommitStatuses(tag: Tag) extends Table[CommitStatus](tag, "COMMIT_STATUS") with CommitTemplate {
- val commitStatusId = column[Int]("COMMIT_STATUS_ID", O AutoInc)
- val context = column[String]("CONTEXT")
- val state = column[CommitState]("STATE")
- val targetUrl = column[Option[String]]("TARGET_URL")
- val description = column[Option[String]]("DESCRIPTION")
- val creator = column[String]("CREATOR")
- val registeredDate = column[java.util.Date]("REGISTERED_DATE")
- val updatedDate = column[java.util.Date]("UPDATED_DATE")
- def * = (commitStatusId, userName, repositoryName, commitId, context, state, targetUrl, description, creator, registeredDate, updatedDate) <> (CommitStatus.tupled, CommitStatus.unapply)
- def byPrimaryKey(id: Int) = commitStatusId === id.bind
- }
-}
-
-case class CommitStatus(
- commitStatusId: Int = 0,
- userName: String,
- repositoryName: String,
- commitId: String,
- context: String,
- state: CommitState,
- targetUrl: Option[String],
- description: Option[String],
- creator: String,
- registeredDate: java.util.Date,
- updatedDate: java.util.Date
-)
-sealed abstract class CommitState(val name: String)
-object CommitState {
- object ERROR extends CommitState("error")
- object FAILURE extends CommitState("failure")
- object PENDING extends CommitState("pending")
- object SUCCESS extends CommitState("success")
-
- val values: Vector[CommitState] = Vector(PENDING, SUCCESS, ERROR, FAILURE)
- private val map: Map[String, CommitState] = values.map(enum => enum.name -> enum).toMap
- def apply(name: String): CommitState = map(name)
- def valueOf(name: String): Option[CommitState] = map.get(name)
-
- /**
- * failure if any of the contexts report as error or failure
- * pending if there are no statuses or a context is pending
- * success if the latest status for all contexts is success
- */
- def combine(statuses: Set[CommitState]): CommitState = {
- if(statuses.isEmpty){
- PENDING
- }else if(statuses.contains(CommitState.ERROR) || statuses.contains(CommitState.FAILURE)){
- FAILURE
- }else if(statuses.contains(CommitState.PENDING)){
- PENDING
- }else{
- SUCCESS
- }
- }
-
- implicit val getResult: GetResult[CommitState] = GetResult(r => CommitState(r.<<))
- implicit val getResultOpt: GetResult[Option[CommitState]] = GetResult(r => r.<[String].map(CommitState(_)))
-}
diff --git a/src/main/scala/model/GroupMembers.scala b/src/main/scala/model/GroupMembers.scala
deleted file mode 100644
index f0161d3..0000000
--- a/src/main/scala/model/GroupMembers.scala
+++ /dev/null
@@ -1,20 +0,0 @@
-package model
-
-trait GroupMemberComponent { self: Profile =>
- import profile.simple._
-
- lazy val GroupMembers = TableQuery[GroupMembers]
-
- class GroupMembers(tag: Tag) extends Table[GroupMember](tag, "GROUP_MEMBER") {
- val groupName = column[String]("GROUP_NAME", O PrimaryKey)
- val userName = column[String]("USER_NAME", O PrimaryKey)
- val isManager = column[Boolean]("MANAGER")
- def * = (groupName, userName, isManager) <> (GroupMember.tupled, GroupMember.unapply)
- }
-}
-
-case class GroupMember(
- groupName: String,
- userName: String,
- isManager: Boolean
-)
diff --git a/src/main/scala/model/Issue.scala b/src/main/scala/model/Issue.scala
deleted file mode 100644
index 85c6014..0000000
--- a/src/main/scala/model/Issue.scala
+++ /dev/null
@@ -1,49 +0,0 @@
-package model
-
-trait IssueComponent extends TemplateComponent { self: Profile =>
- import profile.simple._
- import self._
-
- lazy val IssueId = TableQuery[IssueId]
- lazy val IssueOutline = TableQuery[IssueOutline]
- lazy val Issues = TableQuery[Issues]
-
- class IssueId(tag: Tag) extends Table[(String, String, Int)](tag, "ISSUE_ID") with IssueTemplate {
- def * = (userName, repositoryName, issueId)
- def byPrimaryKey(owner: String, repository: String) = byRepository(owner, repository)
- }
-
- class IssueOutline(tag: Tag) extends Table[(String, String, Int, Int)](tag, "ISSUE_OUTLINE_VIEW") with IssueTemplate {
- val commentCount = column[Int]("COMMENT_COUNT")
- def * = (userName, repositoryName, issueId, commentCount)
- }
-
- class Issues(tag: Tag) extends Table[Issue](tag, "ISSUE") with IssueTemplate with MilestoneTemplate {
- val openedUserName = column[String]("OPENED_USER_NAME")
- val assignedUserName = column[String]("ASSIGNED_USER_NAME")
- val title = column[String]("TITLE")
- val content = column[String]("CONTENT")
- val closed = column[Boolean]("CLOSED")
- val registeredDate = column[java.util.Date]("REGISTERED_DATE")
- val updatedDate = column[java.util.Date]("UPDATED_DATE")
- val pullRequest = column[Boolean]("PULL_REQUEST")
- def * = (userName, repositoryName, issueId, openedUserName, milestoneId.?, assignedUserName.?, title, content.?, closed, registeredDate, updatedDate, pullRequest) <> (Issue.tupled, Issue.unapply)
-
- def byPrimaryKey(owner: String, repository: String, issueId: Int) = byIssue(owner, repository, issueId)
- }
-}
-
-case class Issue(
- userName: String,
- repositoryName: String,
- issueId: Int,
- openedUserName: String,
- milestoneId: Option[Int],
- assignedUserName: Option[String],
- title: String,
- content: Option[String],
- closed: Boolean,
- registeredDate: java.util.Date,
- updatedDate: java.util.Date,
- isPullRequest: Boolean
-)
diff --git a/src/main/scala/model/IssueLabels.scala b/src/main/scala/model/IssueLabels.scala
deleted file mode 100644
index 5d42272..0000000
--- a/src/main/scala/model/IssueLabels.scala
+++ /dev/null
@@ -1,20 +0,0 @@
-package model
-
-trait IssueLabelComponent extends TemplateComponent { self: Profile =>
- import profile.simple._
-
- lazy val IssueLabels = TableQuery[IssueLabels]
-
- class IssueLabels(tag: Tag) extends Table[IssueLabel](tag, "ISSUE_LABEL") with IssueTemplate with LabelTemplate {
- def * = (userName, repositoryName, issueId, labelId) <> (IssueLabel.tupled, IssueLabel.unapply)
- def byPrimaryKey(owner: String, repository: String, issueId: Int, labelId: Int) =
- byIssue(owner, repository, issueId) && (this.labelId === labelId.bind)
- }
-}
-
-case class IssueLabel(
- userName: String,
- repositoryName: String,
- issueId: Int,
- labelId: Int
-)
diff --git a/src/main/scala/model/Labels.scala b/src/main/scala/model/Labels.scala
deleted file mode 100644
index 47c6a2b..0000000
--- a/src/main/scala/model/Labels.scala
+++ /dev/null
@@ -1,37 +0,0 @@
-package model
-
-trait LabelComponent extends TemplateComponent { self: Profile =>
- import profile.simple._
-
- lazy val Labels = TableQuery[Labels]
-
- class Labels(tag: Tag) extends Table[Label](tag, "LABEL") with LabelTemplate {
- override val labelId = column[Int]("LABEL_ID", O AutoInc)
- val labelName = column[String]("LABEL_NAME")
- val color = column[String]("COLOR")
- def * = (userName, repositoryName, labelId, labelName, color) <> (Label.tupled, Label.unapply)
-
- def byPrimaryKey(owner: String, repository: String, labelId: Int) = byLabel(owner, repository, labelId)
- def byPrimaryKey(userName: Column[String], repositoryName: Column[String], labelId: Column[Int]) = byLabel(userName, repositoryName, labelId)
- }
-}
-
-case class Label(
- userName: String,
- repositoryName: String,
- labelId: Int = 0,
- labelName: String,
- color: String){
-
- val fontColor = {
- val r = color.substring(0, 2)
- val g = color.substring(2, 4)
- val b = color.substring(4, 6)
-
- if(Integer.parseInt(r, 16) + Integer.parseInt(g, 16) + Integer.parseInt(b, 16) > 408){
- "000000"
- } else {
- "ffffff"
- }
- }
-}
diff --git a/src/main/scala/model/Milestone.scala b/src/main/scala/model/Milestone.scala
deleted file mode 100644
index c392219..0000000
--- a/src/main/scala/model/Milestone.scala
+++ /dev/null
@@ -1,30 +0,0 @@
-package model
-
-trait MilestoneComponent extends TemplateComponent { self: Profile =>
- import profile.simple._
- import self._
-
- lazy val Milestones = TableQuery[Milestones]
-
- class Milestones(tag: Tag) extends Table[Milestone](tag, "MILESTONE") with MilestoneTemplate {
- override val milestoneId = column[Int]("MILESTONE_ID", O AutoInc)
- val title = column[String]("TITLE")
- val description = column[String]("DESCRIPTION")
- val dueDate = column[java.util.Date]("DUE_DATE")
- val closedDate = column[java.util.Date]("CLOSED_DATE")
- def * = (userName, repositoryName, milestoneId, title, description.?, dueDate.?, closedDate.?) <> (Milestone.tupled, Milestone.unapply)
-
- def byPrimaryKey(owner: String, repository: String, milestoneId: Int) = byMilestone(owner, repository, milestoneId)
- def byPrimaryKey(userName: Column[String], repositoryName: Column[String], milestoneId: Column[Int]) = byMilestone(userName, repositoryName, milestoneId)
- }
-}
-
-case class Milestone(
- userName: String,
- repositoryName: String,
- milestoneId: Int = 0,
- title: String,
- description: Option[String],
- dueDate: Option[java.util.Date],
- closedDate: Option[java.util.Date]
-)
diff --git a/src/main/scala/model/Plugin.scala b/src/main/scala/model/Plugin.scala
deleted file mode 100644
index bc85ca0..0000000
--- a/src/main/scala/model/Plugin.scala
+++ /dev/null
@@ -1,19 +0,0 @@
-package model
-
-trait PluginComponent extends TemplateComponent { self: Profile =>
- import profile.simple._
- import self._
-
- lazy val Plugins = TableQuery[Plugins]
-
- class Plugins(tag: Tag) extends Table[Plugin](tag, "PLUGIN"){
- val pluginId = column[String]("PLUGIN_ID", O PrimaryKey)
- val version = column[String]("VERSION")
- def * = (pluginId, version) <> (Plugin.tupled, Plugin.unapply)
- }
-}
-
-case class Plugin(
- pluginId: String,
- version: String
-)
diff --git a/src/main/scala/model/Profile.scala b/src/main/scala/model/Profile.scala
deleted file mode 100644
index b88bb05..0000000
--- a/src/main/scala/model/Profile.scala
+++ /dev/null
@@ -1,45 +0,0 @@
-package model
-
-trait Profile {
- val profile: slick.driver.JdbcProfile
- import profile.simple._
-
- // java.util.Date Mapped Column Types
- implicit val dateColumnType = MappedColumnType.base[java.util.Date, java.sql.Timestamp](
- d => new java.sql.Timestamp(d.getTime),
- t => new java.util.Date(t.getTime)
- )
-
- implicit class RichColumn(c1: Column[Boolean]){
- def &&(c2: => Column[Boolean], guard: => Boolean): Column[Boolean] = if(guard) c1 && c2 else c1
- }
-
-}
-
-object Profile extends {
- val profile = slick.driver.H2Driver
-
-} with AccessTokenComponent
- with AccountComponent
- with ActivityComponent
- with CollaboratorComponent
- with CommitCommentComponent
- with CommitStatusComponent
- with GroupMemberComponent
- with IssueComponent
- with IssueCommentComponent
- with IssueLabelComponent
- with LabelComponent
- with MilestoneComponent
- with PullRequestComponent
- with RepositoryComponent
- with SshKeyComponent
- with WebHookComponent
- with PluginComponent with Profile {
-
- /**
- * Returns system date.
- */
- def currentDate = new java.util.Date()
-
-}
diff --git a/src/main/scala/model/PullRequest.scala b/src/main/scala/model/PullRequest.scala
deleted file mode 100644
index 3ba87ea..0000000
--- a/src/main/scala/model/PullRequest.scala
+++ /dev/null
@@ -1,32 +0,0 @@
-package model
-
-trait PullRequestComponent extends TemplateComponent { self: Profile =>
- import profile.simple._
-
- lazy val PullRequests = TableQuery[PullRequests]
-
- class PullRequests(tag: Tag) extends Table[PullRequest](tag, "PULL_REQUEST") with IssueTemplate {
- val branch = column[String]("BRANCH")
- val requestUserName = column[String]("REQUEST_USER_NAME")
- val requestRepositoryName = column[String]("REQUEST_REPOSITORY_NAME")
- val requestBranch = column[String]("REQUEST_BRANCH")
- val commitIdFrom = column[String]("COMMIT_ID_FROM")
- val commitIdTo = column[String]("COMMIT_ID_TO")
- def * = (userName, repositoryName, issueId, branch, requestUserName, requestRepositoryName, requestBranch, commitIdFrom, commitIdTo) <> (PullRequest.tupled, PullRequest.unapply)
-
- def byPrimaryKey(userName: String, repositoryName: String, issueId: Int) = byIssue(userName, repositoryName, issueId)
- def byPrimaryKey(userName: Column[String], repositoryName: Column[String], issueId: Column[Int]) = byIssue(userName, repositoryName, issueId)
- }
-}
-
-case class PullRequest(
- userName: String,
- repositoryName: String,
- issueId: Int,
- branch: String,
- requestUserName: String,
- requestRepositoryName: String,
- requestBranch: String,
- commitIdFrom: String,
- commitIdTo: String
-)
diff --git a/src/main/scala/model/Repository.scala b/src/main/scala/model/Repository.scala
deleted file mode 100644
index 5a888fc..0000000
--- a/src/main/scala/model/Repository.scala
+++ /dev/null
@@ -1,39 +0,0 @@
-package model
-
-trait RepositoryComponent extends TemplateComponent { self: Profile =>
- import profile.simple._
- import self._
-
- lazy val Repositories = TableQuery[Repositories]
-
- class Repositories(tag: Tag) extends Table[Repository](tag, "REPOSITORY") with BasicTemplate {
- val isPrivate = column[Boolean]("PRIVATE")
- val description = column[String]("DESCRIPTION")
- val defaultBranch = column[String]("DEFAULT_BRANCH")
- val registeredDate = column[java.util.Date]("REGISTERED_DATE")
- val updatedDate = column[java.util.Date]("UPDATED_DATE")
- val lastActivityDate = column[java.util.Date]("LAST_ACTIVITY_DATE")
- val originUserName = column[String]("ORIGIN_USER_NAME")
- val originRepositoryName = column[String]("ORIGIN_REPOSITORY_NAME")
- val parentUserName = column[String]("PARENT_USER_NAME")
- val parentRepositoryName = column[String]("PARENT_REPOSITORY_NAME")
- def * = (userName, repositoryName, isPrivate, description.?, defaultBranch, registeredDate, updatedDate, lastActivityDate, originUserName.?, originRepositoryName.?, parentUserName.?, parentRepositoryName.?) <> (Repository.tupled, Repository.unapply)
-
- def byPrimaryKey(owner: String, repository: String) = byRepository(owner, repository)
- }
-}
-
-case class Repository(
- userName: String,
- repositoryName: String,
- isPrivate: Boolean,
- description: Option[String],
- defaultBranch: String,
- registeredDate: java.util.Date,
- updatedDate: java.util.Date,
- lastActivityDate: java.util.Date,
- originUserName: Option[String],
- originRepositoryName: Option[String],
- parentUserName: Option[String],
- parentRepositoryName: Option[String]
-)
diff --git a/src/main/scala/model/SshKey.scala b/src/main/scala/model/SshKey.scala
deleted file mode 100644
index dcf3463..0000000
--- a/src/main/scala/model/SshKey.scala
+++ /dev/null
@@ -1,24 +0,0 @@
-package model
-
-trait SshKeyComponent { self: Profile =>
- import profile.simple._
-
- lazy val SshKeys = TableQuery[SshKeys]
-
- class SshKeys(tag: Tag) extends Table[SshKey](tag, "SSH_KEY") {
- val userName = column[String]("USER_NAME")
- val sshKeyId = column[Int]("SSH_KEY_ID", O AutoInc)
- val title = column[String]("TITLE")
- val publicKey = column[String]("PUBLIC_KEY")
- def * = (userName, sshKeyId, title, publicKey) <> (SshKey.tupled, SshKey.unapply)
-
- def byPrimaryKey(userName: String, sshKeyId: Int) = (this.userName === userName.bind) && (this.sshKeyId === sshKeyId.bind)
- }
-}
-
-case class SshKey(
- userName: String,
- sshKeyId: Int = 0,
- title: String,
- publicKey: String
-)
diff --git a/src/main/scala/model/WebHook.scala b/src/main/scala/model/WebHook.scala
deleted file mode 100644
index 4c13c87..0000000
--- a/src/main/scala/model/WebHook.scala
+++ /dev/null
@@ -1,20 +0,0 @@
-package model
-
-trait WebHookComponent extends TemplateComponent { self: Profile =>
- import profile.simple._
-
- lazy val WebHooks = TableQuery[WebHooks]
-
- class WebHooks(tag: Tag) extends Table[WebHook](tag, "WEB_HOOK") with BasicTemplate {
- val url = column[String]("URL")
- def * = (userName, repositoryName, url) <> (WebHook.tupled, WebHook.unapply)
-
- def byPrimaryKey(owner: String, repository: String, url: String) = byRepository(owner, repository) && (this.url === url.bind)
- }
-}
-
-case class WebHook(
- userName: String,
- repositoryName: String,
- url: String
-)
diff --git a/src/main/scala/model/package.scala b/src/main/scala/model/package.scala
deleted file mode 100644
index c65e72e..0000000
--- a/src/main/scala/model/package.scala
+++ /dev/null
@@ -1,3 +0,0 @@
-package object model {
- type Session = slick.jdbc.JdbcBackend#Session
-}
diff --git a/src/main/scala/plugin/Plugin.scala b/src/main/scala/plugin/Plugin.scala
deleted file mode 100644
index c176874..0000000
--- a/src/main/scala/plugin/Plugin.scala
+++ /dev/null
@@ -1,30 +0,0 @@
-package plugin
-
-import javax.servlet.ServletContext
-
-import util.Version
-
-/**
- * Trait for define plugin interface.
- * To provide plugin, put Plugin class which mixed in this trait into the package root.
- */
-trait Plugin {
-
- val pluginId: String
- val pluginName: String
- val description: String
- val versions: Seq[Version]
-
- /**
- * This method is invoked in initialization of plugin system.
- * Register plugin functionality to PluginRegistry.
- */
- def initialize(registry: PluginRegistry): Unit
-
- /**
- * This method is invoked in shutdown of plugin system.
- * If the plugin has any resources, release them in this method.
- */
- def shutdown(registry: PluginRegistry): Unit
-
-}
diff --git a/src/main/scala/plugin/PluginRegistory.scala b/src/main/scala/plugin/PluginRegistory.scala
deleted file mode 100644
index bb7c2cb..0000000
--- a/src/main/scala/plugin/PluginRegistory.scala
+++ /dev/null
@@ -1,145 +0,0 @@
-package plugin
-
-import java.io.{FilenameFilter, File}
-import java.net.URLClassLoader
-import javax.servlet.ServletContext
-import javax.servlet.http.{HttpServletRequest, HttpServletResponse}
-
-import org.slf4j.LoggerFactory
-import service.RepositoryService.RepositoryInfo
-import util.Directory._
-import util.JDBCUtil._
-import util.{Version, Versions}
-
-import scala.collection.mutable.ListBuffer
-import app.{ControllerBase, Context}
-
-class PluginRegistry {
-
- private val plugins = new ListBuffer[PluginInfo]
- private val javaScripts = new ListBuffer[(String, String)]
- private val controllers = new ListBuffer[(ControllerBase, String)]
-
- def addPlugin(pluginInfo: PluginInfo): Unit = {
- plugins += pluginInfo
- }
-
- def getPlugins(): List[PluginInfo] = plugins.toList
-
- def addController(controller: ControllerBase, path: String): Unit = {
- controllers += ((controller, path))
- }
-
- def getControllers(): List[(ControllerBase, String)] = controllers.toList
-
- def addJavaScript(path: String, script: String): Unit = {
- javaScripts += Tuple2(path, script)
- }
-
- //def getJavaScripts(): List[(String, String)] = javaScripts.toList
-
- def getJavaScript(currentPath: String): Option[String] = {
- javaScripts.find(x => currentPath.matches(x._1)).map(_._2)
- }
-
- private case class GlobalAction(
- method: String,
- path: String,
- function: (HttpServletRequest, HttpServletResponse, Context) => Any
- )
-
- private case class RepositoryAction(
- method: String,
- path: String,
- function: (HttpServletRequest, HttpServletResponse, Context, RepositoryInfo) => Any
- )
-
-}
-
-/**
- * Provides entry point to PluginRegistry.
- */
-object PluginRegistry {
-
- private val logger = LoggerFactory.getLogger(classOf[PluginRegistry])
-
- private val instance = new PluginRegistry()
-
- /**
- * Returns the PluginRegistry singleton instance.
- */
- def apply(): PluginRegistry = instance
-
- /**
- * Initializes all installed plugins.
- */
- def initialize(context: ServletContext, conn: java.sql.Connection): Unit = {
- val pluginDir = new File(PluginHome)
- if(pluginDir.exists && pluginDir.isDirectory){
- pluginDir.listFiles(new FilenameFilter {
- override def accept(dir: File, name: String): Boolean = name.endsWith(".jar")
- }).foreach { pluginJar =>
- val classLoader = new URLClassLoader(Array(pluginJar.toURI.toURL), Thread.currentThread.getContextClassLoader)
- try {
- val plugin = classLoader.loadClass("Plugin").newInstance().asInstanceOf[Plugin]
-
- // Migration
- val headVersion = plugin.versions.head
- val currentVersion = conn.find("SELECT * FROM PLUGIN WHERE PLUGIN_ID = ?", plugin.pluginId)(_.getString("VERSION")) match {
- case Some(x) => {
- val dim = x.split("\\.")
- Version(dim(0).toInt, dim(1).toInt)
- }
- case None => Version(0, 0)
- }
-
- Versions.update(conn, headVersion, currentVersion, plugin.versions, new URLClassLoader(Array(pluginJar.toURI.toURL))){ conn =>
- currentVersion.versionString match {
- case "0.0" =>
- conn.update("INSERT INTO PLUGIN (PLUGIN_ID, VERSION) VALUES (?, ?)", plugin.pluginId, headVersion.versionString)
- case _ =>
- conn.update("UPDATE PLUGIN SET VERSION = ? WHERE PLUGIN_ID = ?", headVersion.versionString, plugin.pluginId)
- }
- }
-
- // Initialize
- plugin.initialize(instance)
- instance.addPlugin(PluginInfo(
- pluginId = plugin.pluginId,
- pluginName = plugin.pluginName,
- version = plugin.versions.head.versionString,
- description = plugin.description,
- pluginClass = plugin
- ))
-
- } catch {
- case e: Exception => {
- logger.error(s"Error during plugin initialization", e)
- }
- }
- }
- }
- }
-
- def shutdown(context: ServletContext): Unit = {
- instance.getPlugins().foreach { pluginInfo =>
- try {
- pluginInfo.pluginClass.shutdown(instance)
- } catch {
- case e: Exception => {
- logger.error(s"Error during plugin shutdown", e)
- }
- }
- }
- }
-
-
-}
-
-case class PluginInfo(
- pluginId: String,
- pluginName: String,
- version: String,
- description: String,
- pluginClass: Plugin
-)
\ No newline at end of file
diff --git a/src/main/scala/plugin/Results.scala b/src/main/scala/plugin/Results.scala
deleted file mode 100644
index 18fdb7f..0000000
--- a/src/main/scala/plugin/Results.scala
+++ /dev/null
@@ -1,11 +0,0 @@
-package plugin
-
-import play.twirl.api.Html
-
-/**
- * Defines result case classes returned by plugin controller.
- */
-object Results {
- case class Redirect(path: String)
- case class Fragment(html: Html)
-}
diff --git a/src/main/scala/plugin/Sessions.scala b/src/main/scala/plugin/Sessions.scala
deleted file mode 100644
index 7398c9a..0000000
--- a/src/main/scala/plugin/Sessions.scala
+++ /dev/null
@@ -1,11 +0,0 @@
-package plugin
-
-import slick.jdbc.JdbcBackend.Session
-
-/**
- * Provides Slick Session to Plug-ins.
- */
-object Sessions {
- val sessions = new ThreadLocal[Session]
- implicit def session: Session = sessions.get()
-}
diff --git a/src/main/scala/service/AccesTokenService.scala b/src/main/scala/service/AccesTokenService.scala
deleted file mode 100644
index 4de5816..0000000
--- a/src/main/scala/service/AccesTokenService.scala
+++ /dev/null
@@ -1,52 +0,0 @@
-package service
-
-import model.Profile._
-import profile.simple._
-import model.{Account, AccessToken}
-import util.StringUtil
-import scala.util.Random
-
-trait AccessTokenService {
-
- def makeAccessTokenString: String = {
- val bytes = new Array[Byte](20)
- Random.nextBytes(bytes)
- bytes.map("%02x".format(_)).mkString
- }
-
- def tokenToHash(token: String): String = StringUtil.sha1(token)
-
- /**
- * @retuen (TokenId, Token)
- */
- def generateAccessToken(userName: String, note: String)(implicit s: Session): (Int, String) = {
- var token: String = null
- var hash: String = null
- do{
- token = makeAccessTokenString
- hash = tokenToHash(token)
- }while(AccessTokens.filter(_.tokenHash === hash.bind).exists.run)
- val newToken = AccessToken(
- userName = userName,
- note = note,
- tokenHash = hash)
- val tokenId = (AccessTokens returning AccessTokens.map(_.accessTokenId)) += newToken
- (tokenId, token)
- }
-
- def getAccountByAccessToken(token: String)(implicit s: Session): Option[Account] =
- Accounts
- .innerJoin(AccessTokens)
- .filter{ case (ac, t) => (ac.userName === t.userName) && (t.tokenHash === tokenToHash(token).bind) && (ac.removed === false.bind) }
- .map{ case (ac, t) => ac }
- .firstOption
-
- def getAccessTokens(userName: String)(implicit s: Session): List[AccessToken] =
- AccessTokens.filter(_.userName === userName.bind).sortBy(_.accessTokenId.desc).list
-
- def deleteAccessToken(userName: String, accessTokenId: Int)(implicit s: Session): Unit =
- AccessTokens filter (t => t.userName === userName.bind && t.accessTokenId === accessTokenId) delete
-
-}
-
-object AccessTokenService extends AccessTokenService
diff --git a/src/main/scala/service/AccountService.scala b/src/main/scala/service/AccountService.scala
deleted file mode 100644
index 88d95fa..0000000
--- a/src/main/scala/service/AccountService.scala
+++ /dev/null
@@ -1,188 +0,0 @@
-package service
-
-import model.Profile._
-import profile.simple._
-import model.{Account, GroupMember}
-// TODO [Slick 2.0]NOT import directly?
-import model.Profile.dateColumnType
-import service.SystemSettingsService.SystemSettings
-import util.StringUtil._
-import util.LDAPUtil
-import org.slf4j.LoggerFactory
-
-trait AccountService {
-
- private val logger = LoggerFactory.getLogger(classOf[AccountService])
-
- def authenticate(settings: SystemSettings, userName: String, password: String)(implicit s: Session): Option[Account] =
- if(settings.ldapAuthentication){
- ldapAuthentication(settings, userName, password)
- } else {
- defaultAuthentication(userName, password)
- }
-
- /**
- * Authenticate by internal database.
- */
- private def defaultAuthentication(userName: String, password: String)(implicit s: Session) = {
- getAccountByUserName(userName).collect {
- case account if(!account.isGroupAccount && account.password == sha1(password)) => Some(account)
- } getOrElse None
- }
-
- /**
- * Authenticate by LDAP.
- */
- private def ldapAuthentication(settings: SystemSettings, userName: String, password: String)
- (implicit s: Session): Option[Account] = {
- LDAPUtil.authenticate(settings.ldap.get, userName, password) match {
- case Right(ldapUserInfo) => {
- // Create or update account by LDAP information
- getAccountByUserName(ldapUserInfo.userName, true) match {
- case Some(x) if(!x.isRemoved) => {
- if(settings.ldap.get.mailAttribute.getOrElse("").isEmpty) {
- updateAccount(x.copy(fullName = ldapUserInfo.fullName))
- } else {
- updateAccount(x.copy(mailAddress = ldapUserInfo.mailAddress, fullName = ldapUserInfo.fullName))
- }
- getAccountByUserName(ldapUserInfo.userName)
- }
- case Some(x) if(x.isRemoved) => {
- logger.info("LDAP Authentication Failed: Account is already registered but disabled.")
- defaultAuthentication(userName, password)
- }
- case None => getAccountByMailAddress(ldapUserInfo.mailAddress, true) match {
- case Some(x) if(!x.isRemoved) => {
- updateAccount(x.copy(fullName = ldapUserInfo.fullName))
- getAccountByUserName(ldapUserInfo.userName)
- }
- case Some(x) if(x.isRemoved) => {
- logger.info("LDAP Authentication Failed: Account is already registered but disabled.")
- defaultAuthentication(userName, password)
- }
- case None => {
- createAccount(ldapUserInfo.userName, "", ldapUserInfo.fullName, ldapUserInfo.mailAddress, false, None)
- getAccountByUserName(ldapUserInfo.userName)
- }
- }
- }
- }
- case Left(errorMessage) => {
- logger.info(s"LDAP Authentication Failed: ${errorMessage}")
- defaultAuthentication(userName, password)
- }
- }
- }
-
- def getAccountByUserName(userName: String, includeRemoved: Boolean = false)(implicit s: Session): Option[Account] =
- Accounts filter(t => (t.userName === userName.bind) && (t.removed === false.bind, !includeRemoved)) firstOption
-
- def getAccountsByUserNames(userNames: Set[String], knowns:Set[Account], includeRemoved: Boolean = false)(implicit s: Session): Map[String, Account] = {
- val map = knowns.map(a => a.userName -> a).toMap
- val needs = userNames -- map.keySet
- if(needs.isEmpty){
- map
- }else{
- map ++ Accounts.filter(t => (t.userName inSetBind needs) && (t.removed === false.bind, !includeRemoved)).list.map(a => a.userName -> a).toMap
- }
- }
-
- def getAccountByMailAddress(mailAddress: String, includeRemoved: Boolean = false)(implicit s: Session): Option[Account] =
- Accounts filter(t => (t.mailAddress.toLowerCase === mailAddress.toLowerCase.bind) && (t.removed === false.bind, !includeRemoved)) firstOption
-
- def getAllUsers(includeRemoved: Boolean = true)(implicit s: Session): List[Account] =
- if(includeRemoved){
- Accounts sortBy(_.userName) list
- } else {
- Accounts filter (_.removed === false.bind) sortBy(_.userName) list
- }
-
- def createAccount(userName: String, password: String, fullName: String, mailAddress: String, isAdmin: Boolean, url: Option[String])
- (implicit s: Session): Unit =
- Accounts insert Account(
- userName = userName,
- password = password,
- fullName = fullName,
- mailAddress = mailAddress,
- isAdmin = isAdmin,
- url = url,
- registeredDate = currentDate,
- updatedDate = currentDate,
- lastLoginDate = None,
- image = None,
- isGroupAccount = false,
- isRemoved = false)
-
- def updateAccount(account: Account)(implicit s: Session): Unit =
- Accounts
- .filter { a => a.userName === account.userName.bind }
- .map { a => (a.password, a.fullName, a.mailAddress, a.isAdmin, a.url.?, a.registeredDate, a.updatedDate, a.lastLoginDate.?, a.removed) }
- .update (
- account.password,
- account.fullName,
- account.mailAddress,
- account.isAdmin,
- account.url,
- account.registeredDate,
- currentDate,
- account.lastLoginDate,
- account.isRemoved)
-
- def updateAvatarImage(userName: String, image: Option[String])(implicit s: Session): Unit =
- Accounts.filter(_.userName === userName.bind).map(_.image.?).update(image)
-
- def updateLastLoginDate(userName: String)(implicit s: Session): Unit =
- Accounts.filter(_.userName === userName.bind).map(_.lastLoginDate).update(currentDate)
-
- def createGroup(groupName: String, url: Option[String])(implicit s: Session): Unit =
- Accounts insert Account(
- userName = groupName,
- password = "",
- fullName = groupName,
- mailAddress = groupName + "@devnull",
- isAdmin = false,
- url = url,
- registeredDate = currentDate,
- updatedDate = currentDate,
- lastLoginDate = None,
- image = None,
- isGroupAccount = true,
- isRemoved = false)
-
- def updateGroup(groupName: String, url: Option[String], removed: Boolean)(implicit s: Session): Unit =
- Accounts.filter(_.userName === groupName.bind).map(t => t.url.? -> t.removed).update(url, removed)
-
- def updateGroupMembers(groupName: String, members: List[(String, Boolean)])(implicit s: Session): Unit = {
- GroupMembers.filter(_.groupName === groupName.bind).delete
- members.foreach { case (userName, isManager) =>
- GroupMembers insert GroupMember (groupName, userName, isManager)
- }
- }
-
- def getGroupMembers(groupName: String)(implicit s: Session): List[GroupMember] =
- GroupMembers
- .filter(_.groupName === groupName.bind)
- .sortBy(_.userName)
- .list
-
- def getGroupsByUserName(userName: String)(implicit s: Session): List[String] =
- GroupMembers
- .filter(_.userName === userName.bind)
- .sortBy(_.groupName)
- .map(_.groupName)
- .list
-
- def removeUserRelatedData(userName: String)(implicit s: Session): Unit = {
- GroupMembers.filter(_.userName === userName.bind).delete
- Collaborators.filter(_.collaboratorName === userName.bind).delete
- Repositories.filter(_.userName === userName.bind).delete
- }
-
- def getGroupNames(userName: String)(implicit s: Session): List[String] = {
- List(userName) ++
- Collaborators.filter(_.collaboratorName === userName.bind).sortBy(_.userName).map(_.userName).list
- }
-
-}
-
-object AccountService extends AccountService
diff --git a/src/main/scala/service/ActivityService.scala b/src/main/scala/service/ActivityService.scala
deleted file mode 100644
index b1e8202..0000000
--- a/src/main/scala/service/ActivityService.scala
+++ /dev/null
@@ -1,188 +0,0 @@
-package service
-
-import model.Profile._
-import profile.simple._
-import model.Activity
-
-trait ActivityService {
-
- def getActivitiesByUser(activityUserName: String, isPublic: Boolean)(implicit s: Session): List[Activity] =
- Activities
- .innerJoin(Repositories).on((t1, t2) => t1.byRepository(t2.userName, t2.repositoryName))
- .filter { case (t1, t2) =>
- if(isPublic){
- (t1.activityUserName === activityUserName.bind) && (t2.isPrivate === false.bind)
- } else {
- (t1.activityUserName === activityUserName.bind)
- }
- }
- .sortBy { case (t1, t2) => t1.activityId desc }
- .map { case (t1, t2) => t1 }
- .take(30)
- .list
-
- def getRecentActivities()(implicit s: Session): List[Activity] =
- Activities
- .innerJoin(Repositories).on((t1, t2) => t1.byRepository(t2.userName, t2.repositoryName))
- .filter { case (t1, t2) => t2.isPrivate === false.bind }
- .sortBy { case (t1, t2) => t1.activityId desc }
- .map { case (t1, t2) => t1 }
- .take(30)
- .list
-
- def getRecentActivitiesByOwners(owners : Set[String])(implicit s: Session): List[Activity] =
- Activities
- .innerJoin(Repositories).on((t1, t2) => t1.byRepository(t2.userName, t2.repositoryName))
- .filter { case (t1, t2) => (t2.isPrivate === false.bind) || (t2.userName inSetBind owners) }
- .sortBy { case (t1, t2) => t1.activityId desc }
- .map { case (t1, t2) => t1 }
- .take(30)
- .list
-
- def recordCreateRepositoryActivity(userName: String, repositoryName: String, activityUserName: String)
- (implicit s: Session): Unit =
- Activities insert Activity(userName, repositoryName, activityUserName,
- "create_repository",
- s"[user:${activityUserName}] created [repo:${userName}/${repositoryName}]",
- None,
- currentDate)
-
- def recordCreateIssueActivity(userName: String, repositoryName: String, activityUserName: String, issueId: Int, title: String)
- (implicit s: Session): Unit =
- Activities insert Activity(userName, repositoryName, activityUserName,
- "open_issue",
- s"[user:${activityUserName}] opened issue [issue:${userName}/${repositoryName}#${issueId}]",
- Some(title),
- currentDate)
-
- def recordCloseIssueActivity(userName: String, repositoryName: String, activityUserName: String, issueId: Int, title: String)
- (implicit s: Session): Unit =
- Activities insert Activity(userName, repositoryName, activityUserName,
- "close_issue",
- s"[user:${activityUserName}] closed issue [issue:${userName}/${repositoryName}#${issueId}]",
- Some(title),
- currentDate)
-
- def recordClosePullRequestActivity(userName: String, repositoryName: String, activityUserName: String, issueId: Int, title: String)
- (implicit s: Session): Unit =
- Activities insert Activity(userName, repositoryName, activityUserName,
- "close_issue",
- s"[user:${activityUserName}] closed pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
- Some(title),
- currentDate)
-
- def recordReopenIssueActivity(userName: String, repositoryName: String, activityUserName: String, issueId: Int, title: String)
- (implicit s: Session): Unit =
- Activities insert Activity(userName, repositoryName, activityUserName,
- "reopen_issue",
- s"[user:${activityUserName}] reopened issue [issue:${userName}/${repositoryName}#${issueId}]",
- Some(title),
- currentDate)
-
- def recordCommentIssueActivity(userName: String, repositoryName: String, activityUserName: String, issueId: Int, comment: String)
- (implicit s: Session): Unit =
- Activities insert Activity(userName, repositoryName, activityUserName,
- "comment_issue",
- s"[user:${activityUserName}] commented on issue [issue:${userName}/${repositoryName}#${issueId}]",
- Some(cut(comment, 200)),
- currentDate)
-
- def recordCommentPullRequestActivity(userName: String, repositoryName: String, activityUserName: String, issueId: Int, comment: String)
- (implicit s: Session): Unit =
- Activities insert Activity(userName, repositoryName, activityUserName,
- "comment_issue",
- s"[user:${activityUserName}] commented on pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
- Some(cut(comment, 200)),
- currentDate)
-
- def recordCommentCommitActivity(userName: String, repositoryName: String, activityUserName: String, commitId: String, comment: String)
- (implicit s: Session): Unit =
- Activities insert Activity(userName, repositoryName, activityUserName,
- "comment_commit",
- s"[user:${activityUserName}] commented on commit [commit:${userName}/${repositoryName}@${commitId}]",
- Some(cut(comment, 200)),
- currentDate
- )
-
- def recordCreateWikiPageActivity(userName: String, repositoryName: String, activityUserName: String, pageName: String)
- (implicit s: Session): Unit =
- Activities insert Activity(userName, repositoryName, activityUserName,
- "create_wiki",
- s"[user:${activityUserName}] created the [repo:${userName}/${repositoryName}] wiki",
- Some(pageName),
- currentDate)
-
- def recordEditWikiPageActivity(userName: String, repositoryName: String, activityUserName: String, pageName: String, commitId: String)
- (implicit s: Session): Unit =
- Activities insert Activity(userName, repositoryName, activityUserName,
- "edit_wiki",
- s"[user:${activityUserName}] edited the [repo:${userName}/${repositoryName}] wiki",
- Some(pageName + ":" + commitId),
- currentDate)
-
- def recordPushActivity(userName: String, repositoryName: String, activityUserName: String,
- branchName: String, commits: List[util.JGitUtil.CommitInfo])(implicit s: Session): Unit =
- Activities insert Activity(userName, repositoryName, activityUserName,
- "push",
- s"[user:${activityUserName}] pushed to [branch:${userName}/${repositoryName}#${branchName}] at [repo:${userName}/${repositoryName}]",
- Some(commits.map { commit => commit.id + ":" + commit.shortMessage }.mkString("\n")),
- currentDate)
-
- def recordCreateTagActivity(userName: String, repositoryName: String, activityUserName: String,
- tagName: String, commits: List[util.JGitUtil.CommitInfo])(implicit s: Session): Unit =
- Activities insert Activity(userName, repositoryName, activityUserName,
- "create_tag",
- s"[user:${activityUserName}] created tag [tag:${userName}/${repositoryName}#${tagName}] at [repo:${userName}/${repositoryName}]",
- None,
- currentDate)
-
- def recordDeleteTagActivity(userName: String, repositoryName: String, activityUserName: String,
- tagName: String, commits: List[util.JGitUtil.CommitInfo])(implicit s: Session): Unit =
- Activities insert Activity(userName, repositoryName, activityUserName,
- "delete_tag",
- s"[user:${activityUserName}] deleted tag ${tagName} at [repo:${userName}/${repositoryName}]",
- None,
- currentDate)
-
- def recordCreateBranchActivity(userName: String, repositoryName: String, activityUserName: String, branchName: String)
- (implicit s: Session): Unit =
- Activities insert Activity(userName, repositoryName, activityUserName,
- "create_branch",
- s"[user:${activityUserName}] created branch [branch:${userName}/${repositoryName}#${branchName}] at [repo:${userName}/${repositoryName}]",
- None,
- currentDate)
-
- def recordDeleteBranchActivity(userName: String, repositoryName: String, activityUserName: String, branchName: String)
- (implicit s: Session): Unit =
- Activities insert Activity(userName, repositoryName, activityUserName,
- "delete_branch",
- s"[user:${activityUserName}] deleted branch ${branchName} at [repo:${userName}/${repositoryName}]",
- None,
- currentDate)
-
- def recordForkActivity(userName: String, repositoryName: String, activityUserName: String, forkedUserName: String)(implicit s: Session): Unit =
- Activities insert Activity(userName, repositoryName, activityUserName,
- "fork",
- s"[user:${activityUserName}] forked [repo:${userName}/${repositoryName}] to [repo:${forkedUserName}/${repositoryName}]",
- None,
- currentDate)
-
- def recordPullRequestActivity(userName: String, repositoryName: String, activityUserName: String, issueId: Int, title: String)
- (implicit s: Session): Unit =
- Activities insert Activity(userName, repositoryName, activityUserName,
- "open_pullreq",
- s"[user:${activityUserName}] opened pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
- Some(title),
- currentDate)
-
- def recordMergeActivity(userName: String, repositoryName: String, activityUserName: String, issueId: Int, message: String)
- (implicit s: Session): Unit =
- Activities insert Activity(userName, repositoryName, activityUserName,
- "merge_pullreq",
- s"[user:${activityUserName}] merged pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
- Some(message),
- currentDate)
-
- private def cut(value: String, length: Int): String =
- if(value.length > length) value.substring(0, length) + "..." else value
-}
diff --git a/src/main/scala/service/CommitStatusService.scala b/src/main/scala/service/CommitStatusService.scala
deleted file mode 100644
index 8860f77..0000000
--- a/src/main/scala/service/CommitStatusService.scala
+++ /dev/null
@@ -1,50 +0,0 @@
-package service
-
-import model.Profile._
-import profile.simple._
-import model.{CommitState, CommitStatus, Account}
-import util.Implicits._
-import util.StringUtil._
-import service.RepositoryService.RepositoryInfo
-
-trait CommitStatusService {
- /** insert or update */
- def createCommitStatus(userName: String, repositoryName: String, sha:String, context:String, state:CommitState, targetUrl:Option[String], description:Option[String], now:java.util.Date, creator:Account)(implicit s: Session): Int =
- CommitStatuses.filter(t => t.byCommit(userName, repositoryName, sha) && t.context===context.bind )
- .map(_.commitStatusId).firstOption match {
- case Some(id:Int) => {
- CommitStatuses.filter(_.byPrimaryKey(id)).map{
- t => (t.state , t.targetUrl , t.updatedDate , t.creator, t.description)
- }.update( (state, targetUrl, now, creator.userName, description) )
- id
- }
- case None => (CommitStatuses returning CommitStatuses.map(_.commitStatusId)) += CommitStatus(
- userName = userName,
- repositoryName = repositoryName,
- commitId = sha,
- context = context,
- state = state,
- targetUrl = targetUrl,
- description = description,
- creator = creator.userName,
- registeredDate = now,
- updatedDate = now)
- }
-
- def getCommitStatus(userName: String, repositoryName: String, id: Int)(implicit s: Session) :Option[CommitStatus] =
- CommitStatuses.filter(t => t.byPrimaryKey(id) && t.byRepository(userName, repositoryName)).firstOption
-
- def getCommitStatus(userName: String, repositoryName: String, sha: String, context: String)(implicit s: Session) :Option[CommitStatus] =
- CommitStatuses.filter(t => t.byCommit(userName, repositoryName, sha) && t.context===context.bind ).firstOption
-
- def getCommitStatues(userName: String, repositoryName: String, sha: String)(implicit s: Session) :List[CommitStatus] =
- byCommitStatues(userName, repositoryName, sha).list
-
- def getCommitStatuesWithCreator(userName: String, repositoryName: String, sha: String)(implicit s: Session) :List[(CommitStatus, Account)] =
- byCommitStatues(userName, repositoryName, sha).innerJoin(Accounts)
- .filter{ case (t,a) => t.creator === a.userName }.list
-
- protected def byCommitStatues(userName: String, repositoryName: String, sha: String)(implicit s: Session) =
- CommitStatuses.filter(t => t.byCommit(userName, repositoryName, sha) ).sortBy(_.updatedDate desc)
-
-}
\ No newline at end of file
diff --git a/src/main/scala/service/CommitsService.scala b/src/main/scala/service/CommitsService.scala
deleted file mode 100644
index 6f70e3c..0000000
--- a/src/main/scala/service/CommitsService.scala
+++ /dev/null
@@ -1,52 +0,0 @@
-package service
-
-import scala.slick.jdbc.{StaticQuery => Q}
-import Q.interpolation
-
-import model.Profile._
-import profile.simple._
-import model.CommitComment
-import util.Implicits._
-import util.StringUtil._
-
-
-trait CommitsService {
-
- def getCommitComments(owner: String, repository: String, commitId: String, pullRequest: Boolean)(implicit s: Session) =
- CommitComments filter {
- t => t.byCommit(owner, repository, commitId) && (t.pullRequest === pullRequest || pullRequest)
- } list
-
- def getCommitComment(owner: String, repository: String, commentId: String)(implicit s: Session) =
- if (commentId forall (_.isDigit))
- CommitComments filter { t =>
- t.byPrimaryKey(commentId.toInt) && t.byRepository(owner, repository)
- } firstOption
- else
- None
-
- def createCommitComment(owner: String, repository: String, commitId: String, loginUser: String,
- content: String, fileName: Option[String], oldLine: Option[Int], newLine: Option[Int], pullRequest: Boolean)(implicit s: Session): Int =
- CommitComments.autoInc insert CommitComment(
- userName = owner,
- repositoryName = repository,
- commitId = commitId,
- commentedUserName = loginUser,
- content = content,
- fileName = fileName,
- oldLine = oldLine,
- newLine = newLine,
- registeredDate = currentDate,
- updatedDate = currentDate,
- pullRequest = pullRequest)
-
- def updateCommitComment(commentId: Int, content: String)(implicit s: Session) =
- CommitComments
- .filter (_.byPrimaryKey(commentId))
- .map { t =>
- t.content -> t.updatedDate
- }.update (content, currentDate)
-
- def deleteCommitComment(commentId: Int)(implicit s: Session) =
- CommitComments filter (_.byPrimaryKey(commentId)) delete
-}
diff --git a/src/main/scala/service/IssuesService.scala b/src/main/scala/service/IssuesService.scala
deleted file mode 100644
index 0edc884..0000000
--- a/src/main/scala/service/IssuesService.scala
+++ /dev/null
@@ -1,540 +0,0 @@
-package service
-
-import scala.slick.jdbc.{StaticQuery => Q}
-import Q.interpolation
-
-import model.Profile._
-import profile.simple._
-import model.{Issue, IssueComment, IssueLabel, Label}
-import util.Implicits._
-import util.StringUtil._
-
-trait IssuesService {
- import IssuesService._
-
- def getIssue(owner: String, repository: String, issueId: String)(implicit s: Session) =
- if (issueId forall (_.isDigit))
- Issues filter (_.byPrimaryKey(owner, repository, issueId.toInt)) firstOption
- else None
-
- def getComments(owner: String, repository: String, issueId: Int)(implicit s: Session) =
- IssueComments filter (_.byIssue(owner, repository, issueId)) list
-
- def getCommentsForApi(owner: String, repository: String, issueId: Int)(implicit s: Session) =
- IssueComments.filter(_.byIssue(owner, repository, issueId))
- .filter(_.action inSetBind Set("comment" , "close_comment", "reopen_comment"))
- .innerJoin(Accounts).on( (t1, t2) => t1.userName === t2.userName )
- .list
-
- def getComment(owner: String, repository: String, commentId: String)(implicit s: Session) =
- if (commentId forall (_.isDigit))
- IssueComments filter { t =>
- t.byPrimaryKey(commentId.toInt) && t.byRepository(owner, repository)
- } firstOption
- else None
-
- def getIssueLabels(owner: String, repository: String, issueId: Int)(implicit s: Session) =
- IssueLabels
- .innerJoin(Labels).on { (t1, t2) =>
- t1.byLabel(t2.userName, t2.repositoryName, t2.labelId)
- }
- .filter ( _._1.byIssue(owner, repository, issueId) )
- .map ( _._2 )
- .list
-
- def getIssueLabel(owner: String, repository: String, issueId: Int, labelId: Int)(implicit s: Session) =
- IssueLabels filter (_.byPrimaryKey(owner, repository, issueId, labelId)) firstOption
-
- /**
- * Returns the count of the search result against issues.
- *
- * @param condition the search condition
- * @param onlyPullRequest if true then counts only pull request, false then counts both of issue and pull request.
- * @param repos Tuple of the repository owner and the repository name
- * @return the count of the search result
- */
- def countIssue(condition: IssueSearchCondition, onlyPullRequest: Boolean,
- repos: (String, String)*)(implicit s: Session): Int =
- Query(searchIssueQuery(repos, condition, onlyPullRequest).length).first
-
- /**
- * Returns the Map which contains issue count for each labels.
- *
- * @param owner the repository owner
- * @param repository the repository name
- * @param condition the search condition
- * @return the Map which contains issue count for each labels (key is label name, value is issue count)
- */
- def countIssueGroupByLabels(owner: String, repository: String, condition: IssueSearchCondition,
- filterUser: Map[String, String])(implicit s: Session): Map[String, Int] = {
-
- searchIssueQuery(Seq(owner -> repository), condition.copy(labels = Set.empty), false)
- .innerJoin(IssueLabels).on { (t1, t2) =>
- t1.byIssue(t2.userName, t2.repositoryName, t2.issueId)
- }
- .innerJoin(Labels).on { case ((t1, t2), t3) =>
- t2.byLabel(t3.userName, t3.repositoryName, t3.labelId)
- }
- .groupBy { case ((t1, t2), t3) =>
- t3.labelName
- }
- .map { case (labelName, t) =>
- labelName -> t.length
- }
- .toMap
- }
-
- def getCommitStatues(issueList:Seq[(String, String, Int)])(implicit s: Session) :Map[(String, String, Int), CommitStatusInfo] ={
- if(issueList.isEmpty){
- Map.empty
- }else{
- import scala.slick.jdbc._
- val issueIdQuery = issueList.map(i => "(PR.USER_NAME=? AND PR.REPOSITORY_NAME=? AND PR.ISSUE_ID=?)").mkString(" OR ")
- implicit val qset = SetParameter[Seq[(String, String, Int)]] {
- case (seq, pp) =>
- for (a <- seq) {
- pp.setString(a._1)
- pp.setString(a._2)
- pp.setInt(a._3)
- }
- }
- import model.Profile.commitStateColumnType
- val query = Q.query[Seq[(String, String, Int)], (String, String, Int, Int, Int, Option[String], Option[model.CommitState], Option[String], Option[String])](s"""
- SELECT SUMM.USER_NAME, SUMM.REPOSITORY_NAME, SUMM.ISSUE_ID, CS_ALL, CS_SUCCESS
- , CSD.CONTEXT, CSD.STATE, CSD.TARGET_URL, CSD.DESCRIPTION
- FROM (SELECT
- PR.USER_NAME
- , PR.REPOSITORY_NAME
- , PR.ISSUE_ID
- , COUNT(CS.STATE) AS CS_ALL
- , SUM(CS.STATE='success') AS CS_SUCCESS
- , PR.COMMIT_ID_TO AS COMMIT_ID
- FROM PULL_REQUEST PR
- JOIN COMMIT_STATUS CS
- ON PR.USER_NAME=CS.USER_NAME
- AND PR.REPOSITORY_NAME=CS.REPOSITORY_NAME
- AND PR.COMMIT_ID_TO=CS.COMMIT_ID
- WHERE $issueIdQuery
- GROUP BY PR.USER_NAME, PR.REPOSITORY_NAME, PR.ISSUE_ID) as SUMM
- LEFT OUTER JOIN COMMIT_STATUS CSD
- ON SUMM.CS_ALL = 1 AND SUMM.COMMIT_ID = CSD.COMMIT_ID""");
- query(issueList).list.map{
- case(userName, repositoryName, issueId, count, successCount, context, state, targetUrl, description) =>
- (userName, repositoryName, issueId) -> CommitStatusInfo(count, successCount, context, state, targetUrl, description)
- }.toMap
- }
- }
-
- /**
- * Returns the search result against issues.
- *
- * @param condition the search condition
- * @param pullRequest if true then returns only pull requests, false then returns only issues.
- * @param offset the offset for pagination
- * @param limit the limit for pagination
- * @param repos Tuple of the repository owner and the repository name
- * @return the search result (list of tuples which contain issue, labels and comment count)
- */
- def searchIssue(condition: IssueSearchCondition, pullRequest: Boolean, offset: Int, limit: Int, repos: (String, String)*)
- (implicit s: Session): List[IssueInfo] = {
- // get issues and comment count and labels
- val result = searchIssueQueryBase(condition, pullRequest, offset, limit, repos)
- .leftJoin (IssueLabels) .on { case ((t1, t2), t3) => t1.byIssue(t3.userName, t3.repositoryName, t3.issueId) }
- .leftJoin (Labels) .on { case (((t1, t2), t3), t4) => t3.byLabel(t4.userName, t4.repositoryName, t4.labelId) }
- .leftJoin (Milestones) .on { case ((((t1, t2), t3), t4), t5) => t1.byMilestone(t5.userName, t5.repositoryName, t5.milestoneId) }
- .map { case ((((t1, t2), t3), t4), t5) =>
- (t1, t2.commentCount, t4.labelId.?, t4.labelName.?, t4.color.?, t5.title.?)
- }
- .list
- .splitWith { (c1, c2) =>
- c1._1.userName == c2._1.userName &&
- c1._1.repositoryName == c2._1.repositoryName &&
- c1._1.issueId == c2._1.issueId
- }
- val status = getCommitStatues(result.map(_.head._1).map(is => (is.userName, is.repositoryName, is.issueId)))
-
- result.map { issues => issues.head match {
- case (issue, commentCount, _, _, _, milestone) =>
- IssueInfo(issue,
- issues.flatMap { t => t._3.map (
- Label(issue.userName, issue.repositoryName, _, t._4.get, t._5.get)
- )} toList,
- milestone,
- commentCount,
- status.get(issue.userName, issue.repositoryName, issue.issueId))
- }} toList
- }
-
- /** for api
- * @return (issue, commentCount, pullRequest, headRepository, headOwner)
- */
- def searchPullRequestByApi(condition: IssueSearchCondition, offset: Int, limit: Int, repos: (String, String)*)
- (implicit s: Session): List[(Issue, model.Account, Int, model.PullRequest, model.Repository, model.Account)] = {
- // get issues and comment count and labels
- searchIssueQueryBase(condition, true, offset, limit, repos)
- .innerJoin(PullRequests).on { case ((t1, t2), t3) => t3.byPrimaryKey(t1.userName, t1.repositoryName, t1.issueId) }
- .innerJoin(Repositories).on { case (((t1, t2), t3), t4) => t4.byRepository(t1.userName, t1.repositoryName) }
- .innerJoin(Accounts).on { case ((((t1, t2), t3), t4), t5) => t5.userName === t1.userName }
- .innerJoin(Accounts).on { case (((((t1, t2), t3), t4), t5), t6) => t6.userName === t4.userName }
- .map { case (((((t1, t2), t3), t4), t5), t6) =>
- (t1, t5, t2.commentCount, t3, t4, t6)
- }
- .list
- }
-
- private def searchIssueQueryBase(condition: IssueSearchCondition, pullRequest: Boolean, offset: Int, limit: Int, repos: Seq[(String, String)])
- (implicit s: Session) =
- searchIssueQuery(repos, condition, pullRequest)
- .innerJoin(IssueOutline).on { (t1, t2) => t1.byIssue(t2.userName, t2.repositoryName, t2.issueId) }
- .sortBy { case (t1, t2) =>
- (condition.sort match {
- case "created" => t1.registeredDate
- case "comments" => t2.commentCount
- case "updated" => t1.updatedDate
- }) match {
- case sort => condition.direction match {
- case "asc" => sort asc
- case "desc" => sort desc
- }
- }
- }
- .drop(offset).take(limit)
-
-
- /**
- * Assembles query for conditional issue searching.
- */
- private def searchIssueQuery(repos: Seq[(String, String)], condition: IssueSearchCondition, pullRequest: Boolean)(implicit s: Session) =
- Issues filter { t1 =>
- repos
- .map { case (owner, repository) => t1.byRepository(owner, repository) }
- .foldLeft[Column[Boolean]](false) ( _ || _ ) &&
- (t1.closed === (condition.state == "closed").bind) &&
- //(t1.milestoneId === condition.milestoneId.get.get.bind, condition.milestoneId.flatten.isDefined) &&
- (t1.milestoneId.? isEmpty, condition.milestone == Some(None)) &&
- (t1.assignedUserName === condition.assigned.get.bind, condition.assigned.isDefined) &&
- (t1.openedUserName === condition.author.get.bind, condition.author.isDefined) &&
- (t1.pullRequest === pullRequest.bind) &&
- // Milestone filter
- (Milestones filter { t2 =>
- (t2.byPrimaryKey(t1.userName, t1.repositoryName, t1.milestoneId)) &&
- (t2.title === condition.milestone.get.get.bind)
- } exists, condition.milestone.flatten.isDefined) &&
- // Label filter
- (IssueLabels filter { t2 =>
- (t2.byIssue(t1.userName, t1.repositoryName, t1.issueId)) &&
- (t2.labelId in
- (Labels filter { t3 =>
- (t3.byRepository(t1.userName, t1.repositoryName)) &&
- (t3.labelName inSetBind condition.labels)
- } map(_.labelId)))
- } exists, condition.labels.nonEmpty) &&
- // Visibility filter
- (Repositories filter { t2 =>
- (t2.byRepository(t1.userName, t1.repositoryName)) &&
- (t2.isPrivate === (condition.visibility == Some("private")).bind)
- } exists, condition.visibility.nonEmpty) &&
- // Organization (group) filter
- (t1.userName inSetBind condition.groups, condition.groups.nonEmpty) &&
- // Mentioned filter
- ((t1.openedUserName === condition.mentioned.get.bind) || t1.assignedUserName === condition.mentioned.get.bind ||
- (IssueComments filter { t2 =>
- (t2.byIssue(t1.userName, t1.repositoryName, t1.issueId)) && (t2.commentedUserName === condition.mentioned.get.bind)
- } exists), condition.mentioned.isDefined)
- }
-
- def createIssue(owner: String, repository: String, loginUser: String, title: String, content: Option[String],
- assignedUserName: Option[String], milestoneId: Option[Int],
- isPullRequest: Boolean = false)(implicit s: Session) =
- // next id number
- sql"SELECT ISSUE_ID + 1 FROM ISSUE_ID WHERE USER_NAME = $owner AND REPOSITORY_NAME = $repository FOR UPDATE".as[Int]
- .firstOption.filter { id =>
- Issues insert Issue(
- owner,
- repository,
- id,
- loginUser,
- milestoneId,
- assignedUserName,
- title,
- content,
- false,
- currentDate,
- currentDate,
- isPullRequest)
-
- // increment issue id
- IssueId
- .filter (_.byPrimaryKey(owner, repository))
- .map (_.issueId)
- .update (id) > 0
- } get
-
- def registerIssueLabel(owner: String, repository: String, issueId: Int, labelId: Int)(implicit s: Session) =
- IssueLabels insert IssueLabel(owner, repository, issueId, labelId)
-
- def deleteIssueLabel(owner: String, repository: String, issueId: Int, labelId: Int)(implicit s: Session) =
- IssueLabels filter(_.byPrimaryKey(owner, repository, issueId, labelId)) delete
-
- def createComment(owner: String, repository: String, loginUser: String,
- issueId: Int, content: String, action: String)(implicit s: Session): Int =
- IssueComments.autoInc insert IssueComment(
- userName = owner,
- repositoryName = repository,
- issueId = issueId,
- action = action,
- commentedUserName = loginUser,
- content = content,
- registeredDate = currentDate,
- updatedDate = currentDate)
-
- def updateIssue(owner: String, repository: String, issueId: Int,
- title: String, content: Option[String])(implicit s: Session) =
- Issues
- .filter (_.byPrimaryKey(owner, repository, issueId))
- .map { t =>
- (t.title, t.content.?, t.updatedDate)
- }
- .update (title, content, currentDate)
-
- def updateAssignedUserName(owner: String, repository: String, issueId: Int,
- assignedUserName: Option[String])(implicit s: Session) =
- Issues.filter (_.byPrimaryKey(owner, repository, issueId)).map(_.assignedUserName?).update (assignedUserName)
-
- def updateMilestoneId(owner: String, repository: String, issueId: Int,
- milestoneId: Option[Int])(implicit s: Session) =
- Issues.filter (_.byPrimaryKey(owner, repository, issueId)).map(_.milestoneId?).update (milestoneId)
-
- def updateComment(commentId: Int, content: String)(implicit s: Session) =
- IssueComments
- .filter (_.byPrimaryKey(commentId))
- .map { t =>
- t.content -> t.updatedDate
- }
- .update (content, currentDate)
-
- def deleteComment(commentId: Int)(implicit s: Session) =
- IssueComments filter (_.byPrimaryKey(commentId)) delete
-
- def updateClosed(owner: String, repository: String, issueId: Int, closed: Boolean)(implicit s: Session) =
- Issues
- .filter (_.byPrimaryKey(owner, repository, issueId))
- .map { t =>
- t.closed -> t.updatedDate
- }
- .update (closed, currentDate)
-
- /**
- * Search issues by keyword.
- *
- * @param owner the repository owner
- * @param repository the repository name
- * @param query the keywords separated by whitespace.
- * @return issues with comment count and matched content of issue or comment
- */
- def searchIssuesByKeyword(owner: String, repository: String, query: String)
- (implicit s: Session): List[(Issue, Int, String)] = {
- import slick.driver.JdbcDriver.likeEncode
- val keywords = splitWords(query.toLowerCase)
-
- // Search Issue
- val issues = Issues
- .filter(_.byRepository(owner, repository))
- .innerJoin(IssueOutline).on { case (t1, t2) =>
- t1.byIssue(t2.userName, t2.repositoryName, t2.issueId)
- }
- .filter { case (t1, t2) =>
- keywords.map { keyword =>
- (t1.title.toLowerCase like (s"%${likeEncode(keyword)}%", '^')) ||
- (t1.content.toLowerCase like (s"%${likeEncode(keyword)}%", '^'))
- } .reduceLeft(_ && _)
- }
- .map { case (t1, t2) =>
- (t1, 0, t1.content.?, t2.commentCount)
- }
-
- // Search IssueComment
- val comments = IssueComments
- .filter(_.byRepository(owner, repository))
- .innerJoin(Issues).on { case (t1, t2) =>
- t1.byIssue(t2.userName, t2.repositoryName, t2.issueId)
- }
- .innerJoin(IssueOutline).on { case ((t1, t2), t3) =>
- t2.byIssue(t3.userName, t3.repositoryName, t3.issueId)
- }
- .filter { case ((t1, t2), t3) =>
- keywords.map { query =>
- t1.content.toLowerCase like (s"%${likeEncode(query)}%", '^')
- }.reduceLeft(_ && _)
- }
- .map { case ((t1, t2), t3) =>
- (t2, t1.commentId, t1.content.?, t3.commentCount)
- }
-
- issues.union(comments).sortBy { case (issue, commentId, _, _) =>
- issue.issueId -> commentId
- }.list.splitWith { case ((issue1, _, _, _), (issue2, _, _, _)) =>
- issue1.issueId == issue2.issueId
- }.map { _.head match {
- case (issue, _, content, commentCount) => (issue, commentCount, content.getOrElse(""))
- }
- }.toList
- }
-
- def closeIssuesFromMessage(message: String, userName: String, owner: String, repository: String)(implicit s: Session) = {
- extractCloseId(message).foreach { issueId =>
- for(issue <- getIssue(owner, repository, issueId) if !issue.closed){
- createComment(owner, repository, userName, issue.issueId, "Close", "close")
- updateClosed(owner, repository, issue.issueId, true)
- }
- }
- }
-}
-
-object IssuesService {
- import javax.servlet.http.HttpServletRequest
-
- val IssueLimit = 30
-
- case class IssueSearchCondition(
- labels: Set[String] = Set.empty,
- milestone: Option[Option[String]] = None,
- author: Option[String] = None,
- assigned: Option[String] = None,
- mentioned: Option[String] = None,
- state: String = "open",
- sort: String = "created",
- direction: String = "desc",
- visibility: Option[String] = None,
- groups: Set[String] = Set.empty){
-
- def isEmpty: Boolean = {
- labels.isEmpty && milestone.isEmpty && author.isEmpty && assigned.isEmpty &&
- state == "open" && sort == "created" && direction == "desc" && visibility.isEmpty
- }
-
- def nonEmpty: Boolean = !isEmpty
-
- def toFilterString: String = (
- List(
- Some(s"is:${state}"),
- author.map(author => s"author:${author}"),
- assigned.map(assignee => s"assignee:${assignee}"),
- mentioned.map(mentioned => s"mentions:${mentioned}")
- ).flatten ++
- labels.map(label => s"label:${label}") ++
- List(
- milestone.map { _ match {
- case Some(x) => s"milestone:${x}"
- case None => "no:milestone"
- }},
- (sort, direction) match {
- case ("created" , "desc") => None
- case ("created" , "asc" ) => Some("sort:created-asc")
- case ("comments", "desc") => Some("sort:comments-desc")
- case ("comments", "asc" ) => Some("sort:comments-asc")
- case ("updated" , "desc") => Some("sort:updated-desc")
- case ("updated" , "asc" ) => Some("sort:updated-asc")
- },
- visibility.map(visibility => s"visibility:${visibility}")
- ).flatten ++
- groups.map(group => s"group:${group}")
- ).mkString(" ")
-
- def toURL: String =
- "?" + List(
- if(labels.isEmpty) None else Some("labels=" + urlEncode(labels.mkString(","))),
- milestone.map { _ match {
- case Some(x) => "milestone=" + urlEncode(x)
- case None => "milestone=none"
- }},
- author .map(x => "author=" + urlEncode(x)),
- assigned .map(x => "assigned=" + urlEncode(x)),
- mentioned.map(x => "mentioned=" + urlEncode(x)),
- Some("state=" + urlEncode(state)),
- Some("sort=" + urlEncode(sort)),
- Some("direction=" + urlEncode(direction)),
- visibility.map(x => "visibility=" + urlEncode(x)),
- if(groups.isEmpty) None else Some("groups=" + urlEncode(groups.mkString(",")))
- ).flatten.mkString("&")
-
- }
-
- object IssueSearchCondition {
-
- private def param(request: HttpServletRequest, name: String, allow: Seq[String] = Nil): Option[String] = {
- val value = request.getParameter(name)
- if(value == null || value.isEmpty || (allow.nonEmpty && !allow.contains(value))) None else Some(value)
- }
-
- /**
- * Restores IssueSearchCondition instance from filter query.
- */
- def apply(filter: String, milestones: Map[String, Int]): IssueSearchCondition = {
- val conditions = filter.split("[ \t]+").map { x =>
- val dim = x.split(":")
- dim(0) -> dim(1)
- }.groupBy(_._1).map { case (key, values) =>
- key -> values.map(_._2).toSeq
- }
-
- val (sort, direction) = conditions.get("sort").flatMap(_.headOption).getOrElse("created-desc") match {
- case "created-asc" => ("created" , "asc" )
- case "comments-desc" => ("comments", "desc")
- case "comments-asc" => ("comments", "asc" )
- case "updated-desc" => ("comments", "desc")
- case "updated-asc" => ("comments", "asc" )
- case _ => ("created" , "desc")
- }
-
- IssueSearchCondition(
- conditions.get("label").map(_.toSet).getOrElse(Set.empty),
- conditions.get("milestone").flatMap(_.headOption) match {
- case None => None
- case Some("none") => Some(None)
- case Some(x) => Some(Some(x)) //milestones.get(x).map(x => Some(x))
- },
- conditions.get("author").flatMap(_.headOption),
- conditions.get("assignee").flatMap(_.headOption),
- conditions.get("mentions").flatMap(_.headOption),
- conditions.get("is").getOrElse(Seq.empty).find(x => x == "open" || x == "closed").getOrElse("open"),
- sort,
- direction,
- conditions.get("visibility").flatMap(_.headOption),
- conditions.get("group").map(_.toSet).getOrElse(Set.empty)
- )
- }
-
- /**
- * Restores IssueSearchCondition instance from request parameters.
- */
- def apply(request: HttpServletRequest): IssueSearchCondition =
- IssueSearchCondition(
- param(request, "labels").map(_.split(",").toSet).getOrElse(Set.empty),
- param(request, "milestone").map {
- case "none" => None
- case x => Some(x)
- },
- param(request, "author"),
- param(request, "assigned"),
- param(request, "mentioned"),
- param(request, "state", Seq("open", "closed")).getOrElse("open"),
- param(request, "sort", Seq("created", "comments", "updated")).getOrElse("created"),
- param(request, "direction", Seq("asc", "desc")).getOrElse("desc"),
- param(request, "visibility"),
- param(request, "groups").map(_.split(",").toSet).getOrElse(Set.empty)
- )
-
- def page(request: HttpServletRequest) = try {
- val i = param(request, "page").getOrElse("1").toInt
- if(i <= 0) 1 else i
- } catch {
- case e: NumberFormatException => 1
- }
- }
-
- case class CommitStatusInfo(count: Int, successCount: Int, context: Option[String], state: Option[model.CommitState], targetUrl: Option[String], description: Option[String])
-
- case class IssueInfo(issue: Issue, labels: List[Label], milestone: Option[String], commentCount: Int, status:Option[CommitStatusInfo])
-
-}
diff --git a/src/main/scala/service/LabelsService.scala b/src/main/scala/service/LabelsService.scala
deleted file mode 100644
index de1dcb8..0000000
--- a/src/main/scala/service/LabelsService.scala
+++ /dev/null
@@ -1,34 +0,0 @@
-package service
-
-import model.Profile._
-import profile.simple._
-import model.Label
-
-trait LabelsService {
-
- def getLabels(owner: String, repository: String)(implicit s: Session): List[Label] =
- Labels.filter(_.byRepository(owner, repository)).sortBy(_.labelName asc).list
-
- def getLabel(owner: String, repository: String, labelId: Int)(implicit s: Session): Option[Label] =
- Labels.filter(_.byPrimaryKey(owner, repository, labelId)).firstOption
-
- def createLabel(owner: String, repository: String, labelName: String, color: String)(implicit s: Session): Int =
- Labels returning Labels.map(_.labelId) += Label(
- userName = owner,
- repositoryName = repository,
- labelName = labelName,
- color = color
- )
-
- def updateLabel(owner: String, repository: String, labelId: Int, labelName: String, color: String)
- (implicit s: Session): Unit =
- Labels.filter(_.byPrimaryKey(owner, repository, labelId))
- .map(t => t.labelName -> t.color)
- .update(labelName, color)
-
- def deleteLabel(owner: String, repository: String, labelId: Int)(implicit s: Session): Unit = {
- IssueLabels.filter(_.byLabel(owner, repository, labelId)).delete
- Labels.filter(_.byPrimaryKey(owner, repository, labelId)).delete
- }
-
-}
diff --git a/src/main/scala/service/MergeService.scala b/src/main/scala/service/MergeService.scala
deleted file mode 100644
index b2168ac..0000000
--- a/src/main/scala/service/MergeService.scala
+++ /dev/null
@@ -1,168 +0,0 @@
-package service
-import util.LockUtil
-import util.Directory._
-import util.Implicits._
-import util.ControlUtil._
-import org.eclipse.jgit.merge.MergeStrategy
-import org.eclipse.jgit.api.Git
-import org.eclipse.jgit.transport.RefSpec
-import org.eclipse.jgit.errors.NoMergeBaseException
-import org.eclipse.jgit.lib.{ObjectId, CommitBuilder, PersonIdent}
-import model.Account
-import org.eclipse.jgit.revwalk.RevWalk
-trait MergeService {
- import MergeService._
- /**
- * Checks whether conflict will be caused in merging within pull request.
- * Returns true if conflict will be caused.
- */
- def checkConflict(userName: String, repositoryName: String, branch: String, issueId: Int): Boolean = {
- using(Git.open(getRepositoryDir(userName, repositoryName))) { git =>
- MergeCacheInfo(git, branch, issueId).checkConflict()
- }
- }
- /**
- * Checks whether conflict will be caused in merging within pull request.
- * only cache check.
- * Returns Some(true) if conflict will be caused.
- * Returns None if cache has not created yet.
- */
- def checkConflictCache(userName: String, repositoryName: String, branch: String, issueId: Int): Option[Boolean] = {
- using(Git.open(getRepositoryDir(userName, repositoryName))) { git =>
- MergeCacheInfo(git, branch, issueId).checkConflictCache()
- }
- }
- /** merge pull request */
- def mergePullRequest(git:Git, branch: String, issueId: Int, message:String, committer:PersonIdent): Unit = {
- MergeCacheInfo(git, branch, issueId).merge(message, committer)
- }
- /** fetch remote branch to my repository refs/pull/{issueId}/head */
- def fetchAsPullRequest(userName: String, repositoryName: String, requestUserName: String, requestRepositoryName: String, requestBranch:String, issueId:Int){
- using(Git.open(getRepositoryDir(userName, repositoryName))){ git =>
- git.fetch
- .setRemote(getRepositoryDir(requestUserName, requestRepositoryName).toURI.toString)
- .setRefSpecs(new RefSpec(s"refs/heads/${requestBranch}:refs/pull/${issueId}/head"))
- .call
- }
- }
- /**
- * Checks whether conflict will be caused in merging. Returns true if conflict will be caused.
- */
- def checkConflict(userName: String, repositoryName: String, branch: String,
- requestUserName: String, requestRepositoryName: String, requestBranch: String): Boolean = {
- using(Git.open(getRepositoryDir(requestUserName, requestRepositoryName))) { git =>
- val remoteRefName = s"refs/heads/${branch}"
- val tmpRefName = s"refs/merge-check/${userName}/${branch}"
- val refSpec = new RefSpec(s"${remoteRefName}:${tmpRefName}").setForceUpdate(true)
- try {
- // fetch objects from origin repository branch
- git.fetch
- .setRemote(getRepositoryDir(userName, repositoryName).toURI.toString)
- .setRefSpecs(refSpec)
- .call
- // merge conflict check
- val merger = MergeStrategy.RECURSIVE.newMerger(git.getRepository, true)
- val mergeBaseTip = git.getRepository.resolve(s"refs/heads/${requestBranch}")
- val mergeTip = git.getRepository.resolve(tmpRefName)
- try {
- !merger.merge(mergeBaseTip, mergeTip)
- } catch {
- case e: NoMergeBaseException => true
- }
- } finally {
- val refUpdate = git.getRepository.updateRef(refSpec.getDestination)
- refUpdate.setForceUpdate(true)
- refUpdate.delete()
- }
- }
- }
-}
-object MergeService{
- case class MergeCacheInfo(git:Git, branch:String, issueId:Int){
- val repository = git.getRepository
- val mergedBranchName = s"refs/pull/${issueId}/merge"
- val conflictedBranchName = s"refs/pull/${issueId}/conflict"
- lazy val mergeBaseTip = repository.resolve(s"refs/heads/${branch}")
- lazy val mergeTip = repository.resolve(s"refs/pull/${issueId}/head")
- def checkConflictCache(): Option[Boolean] = {
- Option(repository.resolve(mergedBranchName)).flatMap{ merged =>
- if(parseCommit( merged ).getParents().toSet == Set( mergeBaseTip, mergeTip )){
- // merged branch exists
- Some(false)
- }else{
- None
- }
- }.orElse(Option(repository.resolve(conflictedBranchName)).flatMap{ conflicted =>
- if(parseCommit( conflicted ).getParents().toSet == Set( mergeBaseTip, mergeTip )){
- // conflict branch exists
- Some(true)
- }else{
- None
- }
- })
- }
- def checkConflict():Boolean ={
- checkConflictCache.getOrElse(checkConflictForce)
- }
- def checkConflictForce():Boolean ={
- val merger = MergeStrategy.RECURSIVE.newMerger(repository, true)
- val conflicted = try {
- !merger.merge(mergeBaseTip, mergeTip)
- } catch {
- case e: NoMergeBaseException => true
- }
- val mergeTipCommit = using(new RevWalk( repository ))(_.parseCommit( mergeTip ))
- val committer = mergeTipCommit.getCommitterIdent;
- def updateBranch(treeId:ObjectId, message:String, branchName:String){
- // creates merge commit
- val mergeCommitId = createMergeCommit(treeId, committer, message)
- // update refs
- val refUpdate = repository.updateRef(branchName)
- refUpdate.setNewObjectId(mergeCommitId)
- refUpdate.setForceUpdate(true)
- refUpdate.setRefLogIdent(committer)
- refUpdate.update()
- }
- if(!conflicted){
- updateBranch(merger.getResultTreeId, s"Merge ${mergeTip.name} into ${mergeBaseTip.name}", mergedBranchName)
- git.branchDelete().setForce(true).setBranchNames(conflictedBranchName).call()
- }else{
- updateBranch(mergeTipCommit.getTree().getId(), s"can't merge ${mergeTip.name} into ${mergeBaseTip.name}", conflictedBranchName)
- git.branchDelete().setForce(true).setBranchNames(mergedBranchName).call()
- }
- conflicted
- }
- // update branch from cache
- def merge(message:String, committer:PersonIdent) = {
- if(checkConflict()){
- throw new RuntimeException("This pull request can't merge automatically.")
- }
- val mergeResultCommit = parseCommit( Option(repository.resolve(mergedBranchName)).getOrElse(throw new RuntimeException(s"not found branch ${mergedBranchName}")) )
- // creates merge commit
- val mergeCommitId = createMergeCommit(mergeResultCommit.getTree().getId(), committer, message)
- // update refs
- val refUpdate = repository.updateRef(s"refs/heads/${branch}")
- refUpdate.setNewObjectId(mergeCommitId)
- refUpdate.setForceUpdate(false)
- refUpdate.setRefLogIdent(committer)
- refUpdate.setRefLogMessage("merged", true)
- refUpdate.update()
- }
- // return treeId
- private def createMergeCommit(treeId:ObjectId, committer:PersonIdent, message:String) = {
- val mergeCommit = new CommitBuilder()
- mergeCommit.setTreeId(treeId)
- mergeCommit.setParentIds(Array[ObjectId](mergeBaseTip, mergeTip): _*)
- mergeCommit.setAuthor(committer)
- mergeCommit.setCommitter(committer)
- mergeCommit.setMessage(message)
- // insertObject and got mergeCommit Object Id
- val inserter = repository.newObjectInserter
- val mergeCommitId = inserter.insert(mergeCommit)
- inserter.flush()
- inserter.release()
- mergeCommitId
- }
- private def parseCommit(id:ObjectId) = using(new RevWalk( repository ))(_.parseCommit(id))
- }
-}
\ No newline at end of file
diff --git a/src/main/scala/service/MilestonesService.scala b/src/main/scala/service/MilestonesService.scala
deleted file mode 100644
index 476e0c4..0000000
--- a/src/main/scala/service/MilestonesService.scala
+++ /dev/null
@@ -1,57 +0,0 @@
-package service
-
-import model.Profile._
-import profile.simple._
-import model.Milestone
-// TODO [Slick 2.0]NOT import directly?
-import model.Profile.dateColumnType
-
-trait MilestonesService {
-
- def createMilestone(owner: String, repository: String, title: String, description: Option[String],
- dueDate: Option[java.util.Date])(implicit s: Session): Unit =
- Milestones insert Milestone(
- userName = owner,
- repositoryName = repository,
- title = title,
- description = description,
- dueDate = dueDate,
- closedDate = None
- )
-
- def updateMilestone(milestone: Milestone)(implicit s: Session): Unit =
- Milestones
- .filter (t => t.byPrimaryKey(milestone.userName, milestone.repositoryName, milestone.milestoneId))
- .map (t => (t.title, t.description.?, t.dueDate.?, t.closedDate.?))
- .update (milestone.title, milestone.description, milestone.dueDate, milestone.closedDate)
-
- def openMilestone(milestone: Milestone)(implicit s: Session): Unit =
- updateMilestone(milestone.copy(closedDate = None))
-
- def closeMilestone(milestone: Milestone)(implicit s: Session): Unit =
- updateMilestone(milestone.copy(closedDate = Some(currentDate)))
-
- def deleteMilestone(owner: String, repository: String, milestoneId: Int)(implicit s: Session): Unit = {
- Issues.filter(_.byMilestone(owner, repository, milestoneId)).map(_.milestoneId.?).update(None)
- Milestones.filter(_.byPrimaryKey(owner, repository, milestoneId)).delete
- }
-
- def getMilestone(owner: String, repository: String, milestoneId: Int)(implicit s: Session): Option[Milestone] =
- Milestones.filter(_.byPrimaryKey(owner, repository, milestoneId)).firstOption
-
- def getMilestonesWithIssueCount(owner: String, repository: String)(implicit s: Session): List[(Milestone, Int, Int)] = {
- val counts = Issues
- .filter { t => (t.byRepository(owner, repository)) && (t.milestoneId.? isDefined) }
- .groupBy { t => t.milestoneId -> t.closed }
- .map { case (t1, t2) => t1._1 -> t1._2 -> t2.length }
- .toMap
-
- getMilestones(owner, repository).map { milestone =>
- (milestone, counts.getOrElse((milestone.milestoneId, false), 0), counts.getOrElse((milestone.milestoneId, true), 0))
- }
- }
-
- def getMilestones(owner: String, repository: String)(implicit s: Session): List[Milestone] =
- Milestones.filter(_.byRepository(owner, repository)).sortBy(_.milestoneId asc).list
-
-}
diff --git a/src/main/scala/service/PluginService.scala b/src/main/scala/service/PluginService.scala
deleted file mode 100644
index d1bb9d8..0000000
--- a/src/main/scala/service/PluginService.scala
+++ /dev/null
@@ -1,24 +0,0 @@
-package service
-
-import model.Profile._
-import profile.simple._
-import model.Plugin
-
-trait PluginService {
-
- def getPlugins()(implicit s: Session): List[Plugin] =
- Plugins.sortBy(_.pluginId).list
-
- def registerPlugin(plugin: Plugin)(implicit s: Session): Unit =
- Plugins.insert(plugin)
-
- def updatePlugin(plugin: Plugin)(implicit s: Session): Unit =
- Plugins.filter(_.pluginId === plugin.pluginId.bind).map(_.version).update(plugin.version)
-
- def deletePlugin(pluginId: String)(implicit s: Session): Unit =
- Plugins.filter(_.pluginId === pluginId.bind).delete
-
- def getPlugin(pluginId: String)(implicit s: Session): Option[Plugin] =
- Plugins.filter(_.pluginId === pluginId.bind).firstOption
-
-}
diff --git a/src/main/scala/service/PullRequestService.scala b/src/main/scala/service/PullRequestService.scala
deleted file mode 100644
index 19c20d9..0000000
--- a/src/main/scala/service/PullRequestService.scala
+++ /dev/null
@@ -1,125 +0,0 @@
-package service
-
-import model.Profile._
-import profile.simple._
-import model.{PullRequest, Issue, WebHook, Account}
-import util.JGitUtil
-
-trait PullRequestService { self: IssuesService =>
- import PullRequestService._
-
- def getPullRequest(owner: String, repository: String, issueId: Int)
- (implicit s: Session): Option[(Issue, PullRequest)] =
- getIssue(owner, repository, issueId.toString).flatMap{ issue =>
- PullRequests.filter(_.byPrimaryKey(owner, repository, issueId)).firstOption.map{
- pullreq => (issue, pullreq)
- }
- }
-
- def updateCommitId(owner: String, repository: String, issueId: Int, commitIdTo: String, commitIdFrom: String)
- (implicit s: Session): Unit =
- PullRequests.filter(_.byPrimaryKey(owner, repository, issueId))
- .map(pr => pr.commitIdTo -> pr.commitIdFrom)
- .update((commitIdTo, commitIdFrom))
-
- def getPullRequestCountGroupByUser(closed: Boolean, owner: Option[String], repository: Option[String])
- (implicit s: Session): List[PullRequestCount] =
- PullRequests
- .innerJoin(Issues).on { (t1, t2) => t1.byPrimaryKey(t2.userName, t2.repositoryName, t2.issueId) }
- .filter { case (t1, t2) =>
- (t2.closed === closed.bind) &&
- (t1.userName === owner.get.bind, owner.isDefined) &&
- (t1.repositoryName === repository.get.bind, repository.isDefined)
- }
- .groupBy { case (t1, t2) => t2.openedUserName }
- .map { case (userName, t) => userName -> t.length }
- .sortBy(_._2 desc)
- .list
- .map { x => PullRequestCount(x._1, x._2) }
-
-// def getAllPullRequestCountGroupByUser(closed: Boolean, userName: String)(implicit s: Session): List[PullRequestCount] =
-// PullRequests
-// .innerJoin(Issues).on { (t1, t2) => t1.byPrimaryKey(t2.userName, t2.repositoryName, t2.issueId) }
-// .innerJoin(Repositories).on { case ((t1, t2), t3) => t2.byRepository(t3.userName, t3.repositoryName) }
-// .filter { case ((t1, t2), t3) =>
-// (t2.closed === closed.bind) &&
-// (
-// (t3.isPrivate === false.bind) ||
-// (t3.userName === userName.bind) ||
-// (Collaborators.filter { t4 => t4.byRepository(t3.userName, t3.repositoryName) && (t4.collaboratorName === userName.bind)} exists)
-// )
-// }
-// .groupBy { case ((t1, t2), t3) => t2.openedUserName }
-// .map { case (userName, t) => userName -> t.length }
-// .sortBy(_._2 desc)
-// .list
-// .map { x => PullRequestCount(x._1, x._2) }
-
- def createPullRequest(originUserName: String, originRepositoryName: String, issueId: Int,
- originBranch: String, requestUserName: String, requestRepositoryName: String, requestBranch: String,
- commitIdFrom: String, commitIdTo: String)(implicit s: Session): Unit =
- PullRequests insert PullRequest(
- originUserName,
- originRepositoryName,
- issueId,
- originBranch,
- requestUserName,
- requestRepositoryName,
- requestBranch,
- commitIdFrom,
- commitIdTo)
-
- def getPullRequestsByRequest(userName: String, repositoryName: String, branch: String, closed: Boolean)
- (implicit s: Session): List[PullRequest] =
- PullRequests
- .innerJoin(Issues).on { (t1, t2) => t1.byPrimaryKey(t2.userName, t2.repositoryName, t2.issueId) }
- .filter { case (t1, t2) =>
- (t1.requestUserName === userName.bind) &&
- (t1.requestRepositoryName === repositoryName.bind) &&
- (t1.requestBranch === branch.bind) &&
- (t2.closed === closed.bind)
- }
- .map { case (t1, t2) => t1 }
- .list
-
- /**
- * Fetch pull request contents into refs/pull/${issueId}/head and update pull request table.
- */
- def updatePullRequests(owner: String, repository: String, branch: String)(implicit s: Session): Unit =
- getPullRequestsByRequest(owner, repository, branch, false).foreach { pullreq =>
- if(Repositories.filter(_.byRepository(pullreq.userName, pullreq.repositoryName)).exists.run){
- val (commitIdTo, commitIdFrom) = JGitUtil.updatePullRequest(
- pullreq.userName, pullreq.repositoryName, pullreq.branch, pullreq.issueId,
- pullreq.requestUserName, pullreq.requestRepositoryName, pullreq.requestBranch)
- updateCommitId(pullreq.userName, pullreq.repositoryName, pullreq.issueId, commitIdTo, commitIdFrom)
- }
- }
-
- def getPullRequestByRequestCommit(userName: String, repositoryName: String, toBranch:String, fromBranch: String, commitId: String)
- (implicit s: Session): Option[(PullRequest, Issue)] = {
- if(toBranch == fromBranch){
- None
- } else {
- PullRequests
- .innerJoin(Issues).on { (t1, t2) => t1.byPrimaryKey(t2.userName, t2.repositoryName, t2.issueId) }
- .filter { case (t1, t2) =>
- (t1.userName === userName.bind) &&
- (t1.repositoryName === repositoryName.bind) &&
- (t1.branch === toBranch.bind) &&
- (t1.requestUserName === userName.bind) &&
- (t1.requestRepositoryName === repositoryName.bind) &&
- (t1.requestBranch === fromBranch.bind) &&
- (t1.commitIdTo === commitId.bind)
- }
- .firstOption
- }
- }
-}
-
-object PullRequestService {
-
- val PullRequestLimit = 25
-
- case class PullRequestCount(userName: String, count: Int)
-
-}
diff --git a/src/main/scala/service/RepositorySearchService.scala b/src/main/scala/service/RepositorySearchService.scala
deleted file mode 100644
index f727af1..0000000
--- a/src/main/scala/service/RepositorySearchService.scala
+++ /dev/null
@@ -1,128 +0,0 @@
-package service
-
-import util.{FileUtil, StringUtil, JGitUtil}
-import util.Directory._
-import util.ControlUtil._
-import org.eclipse.jgit.revwalk.RevWalk
-import org.eclipse.jgit.treewalk.TreeWalk
-import org.eclipse.jgit.lib.FileMode
-import org.eclipse.jgit.api.Git
-import model.Profile._
-import profile.simple._
-
-trait RepositorySearchService { self: IssuesService =>
- import RepositorySearchService._
-
- def countIssues(owner: String, repository: String, query: String)(implicit session: Session): Int =
- searchIssuesByKeyword(owner, repository, query).length
-
- def searchIssues(owner: String, repository: String, query: String)(implicit session: Session): List[IssueSearchResult] =
- searchIssuesByKeyword(owner, repository, query).map { case (issue, commentCount, content) =>
- IssueSearchResult(
- issue.issueId,
- issue.isPullRequest,
- issue.title,
- issue.openedUserName,
- issue.registeredDate,
- commentCount,
- getHighlightText(content, query)._1)
- }
-
- def countFiles(owner: String, repository: String, query: String): Int =
- using(Git.open(getRepositoryDir(owner, repository))){ git =>
- if(JGitUtil.isEmpty(git)) 0 else searchRepositoryFiles(git, query).length
- }
-
- def searchFiles(owner: String, repository: String, query: String): List[FileSearchResult] =
- using(Git.open(getRepositoryDir(owner, repository))){ git =>
- if(JGitUtil.isEmpty(git)){
- Nil
- } else {
- val files = searchRepositoryFiles(git, query)
- val commits = JGitUtil.getLatestCommitFromPaths(git, files.map(_._1), "HEAD")
- files.map { case (path, text) =>
- val (highlightText, lineNumber) = getHighlightText(text, query)
- FileSearchResult(
- path,
- commits(path).getCommitterIdent.getWhen,
- highlightText,
- lineNumber)
- }
- }
- }
-
- private def searchRepositoryFiles(git: Git, query: String): List[(String, String)] = {
- val revWalk = new RevWalk(git.getRepository)
- val objectId = git.getRepository.resolve("HEAD")
- val revCommit = revWalk.parseCommit(objectId)
- val treeWalk = new TreeWalk(git.getRepository)
- treeWalk.setRecursive(true)
- treeWalk.addTree(revCommit.getTree)
-
- val keywords = StringUtil.splitWords(query.toLowerCase)
- val list = new scala.collection.mutable.ListBuffer[(String, String)]
-
- while (treeWalk.next()) {
- val mode = treeWalk.getFileMode(0)
- if(mode == FileMode.REGULAR_FILE || mode == FileMode.EXECUTABLE_FILE){
- JGitUtil.getContentFromId(git, treeWalk.getObjectId(0), false).foreach { bytes =>
- if(FileUtil.isText(bytes)){
- val text = StringUtil.convertFromByteArray(bytes)
- val lowerText = text.toLowerCase
- val indices = keywords.map(lowerText.indexOf _)
- if(!indices.exists(_ < 0)){
- list.append((treeWalk.getPathString, text))
- }
- }
- }
- }
- }
- treeWalk.release
- revWalk.release
-
- list.toList
- }
-
-}
-
-object RepositorySearchService {
-
- val CodeLimit = 10
- val IssueLimit = 10
-
- def getHighlightText(content: String, query: String): (String, Int) = {
- val keywords = StringUtil.splitWords(query.toLowerCase)
- val lowerText = content.toLowerCase
- val indices = keywords.map(lowerText.indexOf _)
-
- if(!indices.exists(_ < 0)){
- val lineNumber = content.substring(0, indices.min).split("\n").size - 1
- val highlightText = StringUtil.escapeHtml(content.split("\n").drop(lineNumber).take(5).mkString("\n"))
- .replaceAll("(?i)(" + keywords.map("\\Q" + _ + "\\E").mkString("|") + ")",
- "$1")
- (highlightText, lineNumber + 1)
- } else {
- (content.split("\n").take(5).mkString("\n"), 1)
- }
- }
-
- case class SearchResult(
- files : List[(String, String)],
- issues: List[(model.Issue, Int, String)])
-
- case class IssueSearchResult(
- issueId: Int,
- isPullRequest: Boolean,
- title: String,
- openedUserName: String,
- registeredDate: java.util.Date,
- commentCount: Int,
- highlightText: String)
-
- case class FileSearchResult(
- path: String,
- lastModified: java.util.Date,
- highlightText: String,
- highlightLineNumber: Int)
-
-}
diff --git a/src/main/scala/service/RepositoryService.scala b/src/main/scala/service/RepositoryService.scala
deleted file mode 100644
index 34ece5b..0000000
--- a/src/main/scala/service/RepositoryService.scala
+++ /dev/null
@@ -1,400 +0,0 @@
-package service
-
-import model.Profile._
-import profile.simple._
-import model.{Repository, Account, Collaborator, Label}
-import util.JGitUtil
-
-trait RepositoryService { self: AccountService =>
- import RepositoryService._
-
- /**
- * Creates a new repository.
- *
- * @param repositoryName the repository name
- * @param userName the user name of the repository owner
- * @param description the repository description
- * @param isPrivate the repository type (private is true, otherwise false)
- * @param originRepositoryName specify for the forked repository. (default is None)
- * @param originUserName specify for the forked repository. (default is None)
- */
- def createRepository(repositoryName: String, userName: String, description: Option[String], isPrivate: Boolean,
- originRepositoryName: Option[String] = None, originUserName: Option[String] = None,
- parentRepositoryName: Option[String] = None, parentUserName: Option[String] = None)
- (implicit s: Session): Unit = {
- Repositories insert
- Repository(
- userName = userName,
- repositoryName = repositoryName,
- isPrivate = isPrivate,
- description = description,
- defaultBranch = "master",
- registeredDate = currentDate,
- updatedDate = currentDate,
- lastActivityDate = currentDate,
- originUserName = originUserName,
- originRepositoryName = originRepositoryName,
- parentUserName = parentUserName,
- parentRepositoryName = parentRepositoryName)
-
- IssueId insert (userName, repositoryName, 0)
- }
-
- def renameRepository(oldUserName: String, oldRepositoryName: String, newUserName: String, newRepositoryName: String)
- (implicit s: Session): Unit = {
- getAccountByUserName(newUserName).foreach { account =>
- (Repositories filter { t => t.byRepository(oldUserName, oldRepositoryName) } firstOption).map { repository =>
- Repositories insert repository.copy(userName = newUserName, repositoryName = newRepositoryName)
-
- val webHooks = WebHooks .filter(_.byRepository(oldUserName, oldRepositoryName)).list
- val milestones = Milestones .filter(_.byRepository(oldUserName, oldRepositoryName)).list
- val issueId = IssueId .filter(_.byRepository(oldUserName, oldRepositoryName)).list
- val issues = Issues .filter(_.byRepository(oldUserName, oldRepositoryName)).list
- val pullRequests = PullRequests .filter(_.byRepository(oldUserName, oldRepositoryName)).list
- val labels = Labels .filter(_.byRepository(oldUserName, oldRepositoryName)).list
- val issueComments = IssueComments .filter(_.byRepository(oldUserName, oldRepositoryName)).list
- val issueLabels = IssueLabels .filter(_.byRepository(oldUserName, oldRepositoryName)).list
- val commitComments = CommitComments.filter(_.byRepository(oldUserName, oldRepositoryName)).list
- val commitStatuses = CommitStatuses.filter(_.byRepository(oldUserName, oldRepositoryName)).list
- val collaborators = Collaborators .filter(_.byRepository(oldUserName, oldRepositoryName)).list
-
- Repositories.filter { t =>
- (t.originUserName === oldUserName.bind) && (t.originRepositoryName === oldRepositoryName.bind)
- }.map { t => t.originUserName -> t.originRepositoryName }.update(newUserName, newRepositoryName)
-
- Repositories.filter { t =>
- (t.parentUserName === oldUserName.bind) && (t.parentRepositoryName === oldRepositoryName.bind)
- }.map { t => t.originUserName -> t.originRepositoryName }.update(newUserName, newRepositoryName)
-
- PullRequests.filter { t =>
- t.requestRepositoryName === oldRepositoryName.bind
- }.map { t => t.requestUserName -> t.requestRepositoryName }.update(newUserName, newRepositoryName)
-
- // Updates activity fk before deleting repository because activity is sorted by activityId
- // and it can't be changed by deleting-and-inserting record.
- Activities.filter(_.byRepository(oldUserName, oldRepositoryName)).list.foreach { activity =>
- Activities.filter(_.activityId === activity.activityId.bind)
- .map(x => (x.userName, x.repositoryName)).update(newUserName, newRepositoryName)
- }
-
- deleteRepository(oldUserName, oldRepositoryName)
-
- WebHooks .insertAll(webHooks .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
- Milestones.insertAll(milestones .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
- IssueId .insertAll(issueId .map(_.copy(_1 = newUserName, _2 = newRepositoryName)) :_*)
-
- val newMilestones = Milestones.filter(_.byRepository(newUserName, newRepositoryName)).list
- Issues.insertAll(issues.map { x => x.copy(
- userName = newUserName,
- repositoryName = newRepositoryName,
- milestoneId = x.milestoneId.map { id =>
- newMilestones.find(_.title == milestones.find(_.milestoneId == id).get.title).get.milestoneId
- }
- )} :_*)
-
- PullRequests .insertAll(pullRequests .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
- IssueComments .insertAll(issueComments .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
- Labels .insertAll(labels .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
- CommitComments.insertAll(commitComments.map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
- CommitStatuses.insertAll(commitStatuses.map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
-
- // Convert labelId
- val oldLabelMap = labels.map(x => (x.labelId, x.labelName)).toMap
- val newLabelMap = Labels.filter(_.byRepository(newUserName, newRepositoryName)).map(x => (x.labelName, x.labelId)).list.toMap
- IssueLabels.insertAll(issueLabels.map(x => x.copy(
- labelId = newLabelMap(oldLabelMap(x.labelId)),
- userName = newUserName,
- repositoryName = newRepositoryName
- )) :_*)
-
- if(account.isGroupAccount){
- Collaborators.insertAll(getGroupMembers(newUserName).map(m => Collaborator(newUserName, newRepositoryName, m.userName)) :_*)
- } else {
- Collaborators.insertAll(collaborators.map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
- }
-
- // Update activity messages
- Activities.filter { t =>
- (t.message like s"%:${oldUserName}/${oldRepositoryName}]%") ||
- (t.message like s"%:${oldUserName}/${oldRepositoryName}#%") ||
- (t.message like s"%:${oldUserName}/${oldRepositoryName}@%")
- }.map { t => t.activityId -> t.message }.list.foreach { case (activityId, message) =>
- Activities.filter(_.activityId === activityId.bind).map(_.message).update(
- message
- .replace(s"[repo:${oldUserName}/${oldRepositoryName}]" ,s"[repo:${newUserName}/${newRepositoryName}]")
- .replace(s"[branch:${oldUserName}/${oldRepositoryName}#" ,s"[branch:${newUserName}/${newRepositoryName}#")
- .replace(s"[tag:${oldUserName}/${oldRepositoryName}#" ,s"[tag:${newUserName}/${newRepositoryName}#")
- .replace(s"[pullreq:${oldUserName}/${oldRepositoryName}#",s"[pullreq:${newUserName}/${newRepositoryName}#")
- .replace(s"[issue:${oldUserName}/${oldRepositoryName}#" ,s"[issue:${newUserName}/${newRepositoryName}#")
- .replace(s"[commit:${oldUserName}/${oldRepositoryName}@" ,s"[commit:${newUserName}/${newRepositoryName}@")
- )
- }
- }
- }
- }
-
- def deleteRepository(userName: String, repositoryName: String)(implicit s: Session): Unit = {
- Activities .filter(_.byRepository(userName, repositoryName)).delete
- Collaborators .filter(_.byRepository(userName, repositoryName)).delete
- CommitComments.filter(_.byRepository(userName, repositoryName)).delete
- IssueLabels .filter(_.byRepository(userName, repositoryName)).delete
- Labels .filter(_.byRepository(userName, repositoryName)).delete
- IssueComments .filter(_.byRepository(userName, repositoryName)).delete
- PullRequests .filter(_.byRepository(userName, repositoryName)).delete
- Issues .filter(_.byRepository(userName, repositoryName)).delete
- IssueId .filter(_.byRepository(userName, repositoryName)).delete
- Milestones .filter(_.byRepository(userName, repositoryName)).delete
- WebHooks .filter(_.byRepository(userName, repositoryName)).delete
- Repositories .filter(_.byRepository(userName, repositoryName)).delete
-
- // Update ORIGIN_USER_NAME and ORIGIN_REPOSITORY_NAME
- Repositories
- .filter { x => (x.originUserName === userName.bind) && (x.originRepositoryName === repositoryName.bind) }
- .map { x => (x.userName, x.repositoryName) }
- .list
- .foreach { case (userName, repositoryName) =>
- Repositories
- .filter(_.byRepository(userName, repositoryName))
- .map(x => (x.originUserName?, x.originRepositoryName?))
- .update(None, None)
- }
-
- // Update PARENT_USER_NAME and PARENT_REPOSITORY_NAME
- Repositories
- .filter { x => (x.parentUserName === userName.bind) && (x.parentRepositoryName === repositoryName.bind) }
- .map { x => (x.userName, x.repositoryName) }
- .list
- .foreach { case (userName, repositoryName) =>
- Repositories
- .filter(_.byRepository(userName, repositoryName))
- .map(x => (x.parentUserName?, x.parentRepositoryName?))
- .update(None, None)
- }
- }
-
- /**
- * Returns the repository names of the specified user.
- *
- * @param userName the user name of repository owner
- * @return the list of repository names
- */
- def getRepositoryNamesOfUser(userName: String)(implicit s: Session): List[String] =
- Repositories filter(_.userName === userName.bind) map (_.repositoryName) list
-
- /**
- * Returns the specified repository information.
- *
- * @param userName the user name of the repository owner
- * @param repositoryName the repository name
- * @param baseUrl the base url of this application
- * @return the repository information
- */
- def getRepository(userName: String, repositoryName: String, baseUrl: String)(implicit s: Session): Option[RepositoryInfo] = {
- (Repositories filter { t => t.byRepository(userName, repositoryName) } firstOption) map { repository =>
- // for getting issue count and pull request count
- val issues = Issues.filter { t =>
- t.byRepository(repository.userName, repository.repositoryName) && (t.closed === false.bind)
- }.map(_.pullRequest).list
-
- new RepositoryInfo(
- JGitUtil.getRepositoryInfo(repository.userName, repository.repositoryName, baseUrl),
- repository,
- issues.count(_ == false),
- issues.count(_ == true),
- getForkedCount(
- repository.originUserName.getOrElse(repository.userName),
- repository.originRepositoryName.getOrElse(repository.repositoryName)
- ),
- getRepositoryManagers(repository.userName))
- }
- }
-
- /**
- * Returns the repositories without private repository that user does not have access right.
- * Include public repository, private own repository and private but collaborator repository.
- *
- * @param userName the user name of collaborator
- * @return the repository infomation list
- */
- def getAllRepositories(userName: String)(implicit s: Session): List[(String, String)] = {
- Repositories.filter { t1 =>
- (t1.isPrivate === false.bind) ||
- (t1.userName === userName.bind) ||
- (Collaborators.filter { t2 => t2.byRepository(t1.userName, t1.repositoryName) && (t2.collaboratorName === userName.bind)} exists)
- }.sortBy(_.lastActivityDate desc).map{ t =>
- (t.userName, t.repositoryName)
- }.list
- }
-
- def getUserRepositories(userName: String, baseUrl: String, withoutPhysicalInfo: Boolean = false)
- (implicit s: Session): List[RepositoryInfo] = {
- Repositories.filter { t1 =>
- (t1.userName === userName.bind) ||
- (Collaborators.filter { t2 => t2.byRepository(t1.userName, t1.repositoryName) && (t2.collaboratorName === userName.bind)} exists)
- }.sortBy(_.lastActivityDate desc).list.map{ repository =>
- new RepositoryInfo(
- if(withoutPhysicalInfo){
- new JGitUtil.RepositoryInfo(repository.userName, repository.repositoryName, baseUrl)
- } else {
- JGitUtil.getRepositoryInfo(repository.userName, repository.repositoryName, baseUrl)
- },
- repository,
- getForkedCount(
- repository.originUserName.getOrElse(repository.userName),
- repository.originRepositoryName.getOrElse(repository.repositoryName)
- ),
- getRepositoryManagers(repository.userName))
- }
- }
-
- /**
- * Returns the list of visible repositories for the specified user.
- * If repositoryUserName is given then filters results by repository owner.
- *
- * @param loginAccount the logged in account
- * @param baseUrl the base url of this application
- * @param repositoryUserName the repository owner (if None then returns all repositories which are visible for logged in user)
- * @param withoutPhysicalInfo if true then the result does not include physical repository information such as commit count,
- * branches and tags
- * @return the repository information which is sorted in descending order of lastActivityDate.
- */
- def getVisibleRepositories(loginAccount: Option[Account], baseUrl: String, repositoryUserName: Option[String] = None,
- withoutPhysicalInfo: Boolean = false)
- (implicit s: Session): List[RepositoryInfo] = {
- (loginAccount match {
- // for Administrators
- case Some(x) if(x.isAdmin) => Repositories
- // for Normal Users
- case Some(x) if(!x.isAdmin) =>
- Repositories filter { t => (t.isPrivate === false.bind) || (t.userName === x.userName) ||
- (Collaborators.filter { t2 => t2.byRepository(t.userName, t.repositoryName) && (t2.collaboratorName === x.userName.bind)} exists)
- }
- // for Guests
- case None => Repositories filter(_.isPrivate === false.bind)
- }).filter { t =>
- repositoryUserName.map { userName => t.userName === userName.bind } getOrElse LiteralColumn(true)
- }.sortBy(_.lastActivityDate desc).list.map{ repository =>
- new RepositoryInfo(
- if(withoutPhysicalInfo){
- new JGitUtil.RepositoryInfo(repository.userName, repository.repositoryName, baseUrl)
- } else {
- JGitUtil.getRepositoryInfo(repository.userName, repository.repositoryName, baseUrl)
- },
- repository,
- getForkedCount(
- repository.originUserName.getOrElse(repository.userName),
- repository.originRepositoryName.getOrElse(repository.repositoryName)
- ),
- getRepositoryManagers(repository.userName))
- }
- }
-
- private def getRepositoryManagers(userName: String)(implicit s: Session): Seq[String] =
- if(getAccountByUserName(userName).exists(_.isGroupAccount)){
- getGroupMembers(userName).collect { case x if(x.isManager) => x.userName }
- } else {
- Seq(userName)
- }
-
- /**
- * Updates the last activity date of the repository.
- */
- def updateLastActivityDate(userName: String, repositoryName: String)(implicit s: Session): Unit =
- Repositories.filter(_.byRepository(userName, repositoryName)).map(_.lastActivityDate).update(currentDate)
-
- /**
- * Save repository options.
- */
- def saveRepositoryOptions(userName: String, repositoryName: String,
- description: Option[String], defaultBranch: String, isPrivate: Boolean)(implicit s: Session): Unit =
- Repositories.filter(_.byRepository(userName, repositoryName))
- .map { r => (r.description.?, r.defaultBranch, r.isPrivate, r.updatedDate) }
- .update (description, defaultBranch, isPrivate, currentDate)
-
- /**
- * Add collaborator to the repository.
- *
- * @param userName the user name of the repository owner
- * @param repositoryName the repository name
- * @param collaboratorName the collaborator name
- */
- def addCollaborator(userName: String, repositoryName: String, collaboratorName: String)(implicit s: Session): Unit =
- Collaborators insert Collaborator(userName, repositoryName, collaboratorName)
-
- /**
- * Remove collaborator from the repository.
- *
- * @param userName the user name of the repository owner
- * @param repositoryName the repository name
- * @param collaboratorName the collaborator name
- */
- def removeCollaborator(userName: String, repositoryName: String, collaboratorName: String)(implicit s: Session): Unit =
- Collaborators.filter(_.byPrimaryKey(userName, repositoryName, collaboratorName)).delete
-
- /**
- * Remove all collaborators from the repository.
- *
- * @param userName the user name of the repository owner
- * @param repositoryName the repository name
- */
- def removeCollaborators(userName: String, repositoryName: String)(implicit s: Session): Unit =
- Collaborators.filter(_.byRepository(userName, repositoryName)).delete
-
- /**
- * Returns the list of collaborators name which is sorted with ascending order.
- *
- * @param userName the user name of the repository owner
- * @param repositoryName the repository name
- * @return the list of collaborators name
- */
- def getCollaborators(userName: String, repositoryName: String)(implicit s: Session): List[String] =
- Collaborators.filter(_.byRepository(userName, repositoryName)).sortBy(_.collaboratorName).map(_.collaboratorName).list
-
- def hasWritePermission(owner: String, repository: String, loginAccount: Option[Account])(implicit s: Session): Boolean = {
- loginAccount match {
- case Some(a) if(a.isAdmin) => true
- case Some(a) if(a.userName == owner) => true
- case Some(a) if(getCollaborators(owner, repository).contains(a.userName)) => true
- case _ => false
- }
- }
-
- private def getForkedCount(userName: String, repositoryName: String)(implicit s: Session): Int =
- Query(Repositories.filter { t =>
- (t.originUserName === userName.bind) && (t.originRepositoryName === repositoryName.bind)
- }.length).first
-
-
- def getForkedRepositories(userName: String, repositoryName: String)(implicit s: Session): List[(String, String)] =
- Repositories.filter { t =>
- (t.originUserName === userName.bind) && (t.originRepositoryName === repositoryName.bind)
- }
- .sortBy(_.userName asc).map(t => t.userName -> t.repositoryName).list
-
-}
-
-object RepositoryService {
-
- case class RepositoryInfo(owner: String, name: String, httpUrl: String, repository: Repository,
- issueCount: Int, pullCount: Int, commitCount: Int, forkedCount: Int,
- branchList: Seq[String], tags: Seq[util.JGitUtil.TagInfo], managers: Seq[String]){
-
- lazy val host = """^https?://(.+?)(:\d+)?/""".r.findFirstMatchIn(httpUrl).get.group(1)
-
- def sshUrl(port: Int, userName: String) = s"ssh://${userName}@${host}:${port}/${owner}/${name}.git"
-
- /**
- * Creates instance with issue count and pull request count.
- */
- def this(repo: JGitUtil.RepositoryInfo, model: Repository, issueCount: Int, pullCount: Int, forkedCount: Int, managers: Seq[String]) =
- this(repo.owner, repo.name, repo.url, model, issueCount, pullCount, repo.commitCount, forkedCount, repo.branchList, repo.tags, managers)
-
- /**
- * Creates instance without issue count and pull request count.
- */
- def this(repo: JGitUtil.RepositoryInfo, model: Repository, forkedCount: Int, managers: Seq[String]) =
- this(repo.owner, repo.name, repo.url, model, 0, 0, repo.commitCount, forkedCount, repo.branchList, repo.tags, managers)
- }
-
- case class RepositoryTreeNode(owner: String, name: String, children: List[RepositoryTreeNode])
-}
diff --git a/src/main/scala/service/RequestCache.scala b/src/main/scala/service/RequestCache.scala
deleted file mode 100644
index 4ff502b..0000000
--- a/src/main/scala/service/RequestCache.scala
+++ /dev/null
@@ -1,37 +0,0 @@
-package service
-
-import model.{Account, Issue, Session}
-import util.Implicits.request2Session
-
-/**
- * This service is used for a view helper mainly.
- *
- * It may be called many times in one request, so each method stores
- * its result into the cache which available during a request.
- */
-trait RequestCache extends SystemSettingsService with AccountService with IssuesService {
-
- private implicit def context2Session(implicit context: app.Context): Session =
- request2Session(context.request)
-
- def getIssue(userName: String, repositoryName: String, issueId: String)
- (implicit context: app.Context): Option[Issue] = {
- context.cache(s"issue.${userName}/${repositoryName}#${issueId}"){
- super.getIssue(userName, repositoryName, issueId)
- }
- }
-
- def getAccountByUserName(userName: String)
- (implicit context: app.Context): Option[Account] = {
- context.cache(s"account.${userName}"){
- super.getAccountByUserName(userName)
- }
- }
-
- def getAccountByMailAddress(mailAddress: String)
- (implicit context: app.Context): Option[Account] = {
- context.cache(s"account.${mailAddress}"){
- super.getAccountByMailAddress(mailAddress)
- }
- }
-}
diff --git a/src/main/scala/service/SshKeyService.scala b/src/main/scala/service/SshKeyService.scala
deleted file mode 100644
index 4446084..0000000
--- a/src/main/scala/service/SshKeyService.scala
+++ /dev/null
@@ -1,18 +0,0 @@
-package service
-
-import model.Profile._
-import profile.simple._
-import model.SshKey
-
-trait SshKeyService {
-
- def addPublicKey(userName: String, title: String, publicKey: String)(implicit s: Session): Unit =
- SshKeys insert SshKey(userName = userName, title = title, publicKey = publicKey)
-
- def getPublicKeys(userName: String)(implicit s: Session): List[SshKey] =
- SshKeys.filter(_.userName === userName.bind).sortBy(_.sshKeyId).list
-
- def deletePublicKey(userName: String, sshKeyId: Int)(implicit s: Session): Unit =
- SshKeys filter (_.byPrimaryKey(userName, sshKeyId)) delete
-
-}
diff --git a/src/main/scala/service/SystemSettingsService.scala b/src/main/scala/service/SystemSettingsService.scala
deleted file mode 100644
index 156a23b..0000000
--- a/src/main/scala/service/SystemSettingsService.scala
+++ /dev/null
@@ -1,213 +0,0 @@
-package service
-
-import util.Directory._
-import util.ControlUtil._
-import SystemSettingsService._
-import javax.servlet.http.HttpServletRequest
-
-trait SystemSettingsService {
-
- def baseUrl(implicit request: HttpServletRequest): String = loadSystemSettings().baseUrl(request)
-
- def saveSystemSettings(settings: SystemSettings): Unit = {
- defining(new java.util.Properties()){ props =>
- settings.baseUrl.foreach(x => props.setProperty(BaseURL, x.replaceFirst("/\\Z", "")))
- settings.information.foreach(x => props.setProperty(Information, x))
- props.setProperty(AllowAccountRegistration, settings.allowAccountRegistration.toString)
- props.setProperty(AllowAnonymousAccess, settings.allowAnonymousAccess.toString)
- props.setProperty(IsCreateRepoOptionPublic, settings.isCreateRepoOptionPublic.toString)
- props.setProperty(Gravatar, settings.gravatar.toString)
- props.setProperty(Notification, settings.notification.toString)
- props.setProperty(Ssh, settings.ssh.toString)
- settings.sshPort.foreach(x => props.setProperty(SshPort, x.toString))
- if(settings.notification) {
- settings.smtp.foreach { smtp =>
- props.setProperty(SmtpHost, smtp.host)
- smtp.port.foreach(x => props.setProperty(SmtpPort, x.toString))
- smtp.user.foreach(props.setProperty(SmtpUser, _))
- smtp.password.foreach(props.setProperty(SmtpPassword, _))
- smtp.ssl.foreach(x => props.setProperty(SmtpSsl, x.toString))
- smtp.fromAddress.foreach(props.setProperty(SmtpFromAddress, _))
- smtp.fromName.foreach(props.setProperty(SmtpFromName, _))
- }
- }
- props.setProperty(LdapAuthentication, settings.ldapAuthentication.toString)
- if(settings.ldapAuthentication){
- settings.ldap.map { ldap =>
- props.setProperty(LdapHost, ldap.host)
- ldap.port.foreach(x => props.setProperty(LdapPort, x.toString))
- ldap.bindDN.foreach(x => props.setProperty(LdapBindDN, x))
- ldap.bindPassword.foreach(x => props.setProperty(LdapBindPassword, x))
- props.setProperty(LdapBaseDN, ldap.baseDN)
- props.setProperty(LdapUserNameAttribute, ldap.userNameAttribute)
- ldap.additionalFilterCondition.foreach(x => props.setProperty(LdapAdditionalFilterCondition, x))
- ldap.fullNameAttribute.foreach(x => props.setProperty(LdapFullNameAttribute, x))
- ldap.mailAttribute.foreach(x => props.setProperty(LdapMailAddressAttribute, x))
- ldap.tls.foreach(x => props.setProperty(LdapTls, x.toString))
- ldap.ssl.foreach(x => props.setProperty(LdapSsl, x.toString))
- ldap.keystore.foreach(x => props.setProperty(LdapKeystore, x))
- }
- }
- using(new java.io.FileOutputStream(GitBucketConf)){ out =>
- props.store(out, null)
- }
- }
- }
-
-
- def loadSystemSettings(): SystemSettings = {
- defining(new java.util.Properties()){ props =>
- if(GitBucketConf.exists){
- using(new java.io.FileInputStream(GitBucketConf)){ in =>
- props.load(in)
- }
- }
- SystemSettings(
- getOptionValue[String](props, BaseURL, None).map(x => x.replaceFirst("/\\Z", "")),
- getOptionValue[String](props, Information, None),
- getValue(props, AllowAccountRegistration, false),
- getValue(props, AllowAnonymousAccess, true),
- getValue(props, IsCreateRepoOptionPublic, true),
- getValue(props, Gravatar, true),
- getValue(props, Notification, false),
- getValue(props, Ssh, false),
- getOptionValue(props, SshPort, Some(DefaultSshPort)),
- if(getValue(props, Notification, false)){
- Some(Smtp(
- getValue(props, SmtpHost, ""),
- getOptionValue(props, SmtpPort, Some(DefaultSmtpPort)),
- getOptionValue(props, SmtpUser, None),
- getOptionValue(props, SmtpPassword, None),
- getOptionValue[Boolean](props, SmtpSsl, None),
- getOptionValue(props, SmtpFromAddress, None),
- getOptionValue(props, SmtpFromName, None)))
- } else {
- None
- },
- getValue(props, LdapAuthentication, false),
- if(getValue(props, LdapAuthentication, false)){
- Some(Ldap(
- getValue(props, LdapHost, ""),
- getOptionValue(props, LdapPort, Some(DefaultLdapPort)),
- getOptionValue(props, LdapBindDN, None),
- getOptionValue(props, LdapBindPassword, None),
- getValue(props, LdapBaseDN, ""),
- getValue(props, LdapUserNameAttribute, ""),
- getOptionValue(props, LdapAdditionalFilterCondition, None),
- getOptionValue(props, LdapFullNameAttribute, None),
- getOptionValue(props, LdapMailAddressAttribute, None),
- getOptionValue[Boolean](props, LdapTls, None),
- getOptionValue[Boolean](props, LdapSsl, None),
- getOptionValue(props, LdapKeystore, None)))
- } else {
- None
- }
- )
- }
- }
-
-}
-
-object SystemSettingsService {
- import scala.reflect.ClassTag
-
- case class SystemSettings(
- baseUrl: Option[String],
- information: Option[String],
- allowAccountRegistration: Boolean,
- allowAnonymousAccess: Boolean,
- isCreateRepoOptionPublic: Boolean,
- gravatar: Boolean,
- notification: Boolean,
- ssh: Boolean,
- sshPort: Option[Int],
- smtp: Option[Smtp],
- ldapAuthentication: Boolean,
- ldap: Option[Ldap]){
- def baseUrl(request: HttpServletRequest): String = baseUrl.getOrElse {
- defining(request.getRequestURL.toString){ url =>
- url.substring(0, url.length - (request.getRequestURI.length - request.getContextPath.length))
- }
- }.stripSuffix("/")
- }
-
- case class Ldap(
- host: String,
- port: Option[Int],
- bindDN: Option[String],
- bindPassword: Option[String],
- baseDN: String,
- userNameAttribute: String,
- additionalFilterCondition: Option[String],
- fullNameAttribute: Option[String],
- mailAttribute: Option[String],
- tls: Option[Boolean],
- ssl: Option[Boolean],
- keystore: Option[String])
-
- case class Smtp(
- host: String,
- port: Option[Int],
- user: Option[String],
- password: Option[String],
- ssl: Option[Boolean],
- fromAddress: Option[String],
- fromName: Option[String])
-
- val DefaultSshPort = 29418
- val DefaultSmtpPort = 25
- val DefaultLdapPort = 389
-
- private val BaseURL = "base_url"
- private val Information = "information"
- private val AllowAccountRegistration = "allow_account_registration"
- private val AllowAnonymousAccess = "allow_anonymous_access"
- private val IsCreateRepoOptionPublic = "is_create_repository_option_public"
- private val Gravatar = "gravatar"
- private val Notification = "notification"
- private val Ssh = "ssh"
- private val SshPort = "ssh.port"
- private val SmtpHost = "smtp.host"
- private val SmtpPort = "smtp.port"
- private val SmtpUser = "smtp.user"
- private val SmtpPassword = "smtp.password"
- private val SmtpSsl = "smtp.ssl"
- private val SmtpFromAddress = "smtp.from_address"
- private val SmtpFromName = "smtp.from_name"
- private val LdapAuthentication = "ldap_authentication"
- private val LdapHost = "ldap.host"
- private val LdapPort = "ldap.port"
- private val LdapBindDN = "ldap.bindDN"
- private val LdapBindPassword = "ldap.bind_password"
- private val LdapBaseDN = "ldap.baseDN"
- private val LdapUserNameAttribute = "ldap.username_attribute"
- private val LdapAdditionalFilterCondition = "ldap.additional_filter_condition"
- private val LdapFullNameAttribute = "ldap.fullname_attribute"
- private val LdapMailAddressAttribute = "ldap.mail_attribute"
- private val LdapTls = "ldap.tls"
- private val LdapSsl = "ldap.ssl"
- private val LdapKeystore = "ldap.keystore"
-
- private def getValue[A: ClassTag](props: java.util.Properties, key: String, default: A): A =
- defining(props.getProperty(key)){ value =>
- if(value == null || value.isEmpty) default
- else convertType(value).asInstanceOf[A]
- }
-
- private def getOptionValue[A: ClassTag](props: java.util.Properties, key: String, default: Option[A]): Option[A] =
- defining(props.getProperty(key)){ value =>
- if(value == null || value.isEmpty) default
- else Some(convertType(value)).asInstanceOf[Option[A]]
- }
-
- private def convertType[A: ClassTag](value: String) =
- defining(implicitly[ClassTag[A]].runtimeClass){ c =>
- if(c == classOf[Boolean]) value.toBoolean
- else if(c == classOf[Int]) value.toInt
- else value
- }
-
-// // TODO temporary flag
-// val enablePluginSystem = Option(System.getProperty("enable.plugin")).getOrElse("false").toBoolean
-
-}
diff --git a/src/main/scala/service/WebHookService.scala b/src/main/scala/service/WebHookService.scala
deleted file mode 100644
index 83c40ac..0000000
--- a/src/main/scala/service/WebHookService.scala
+++ /dev/null
@@ -1,271 +0,0 @@
-package service
-
-import model.Profile._
-import profile.simple._
-import model.{WebHook, Account, Issue, PullRequest, IssueComment, Repository, CommitStatus, CommitState}
-import org.slf4j.LoggerFactory
-import service.RepositoryService.RepositoryInfo
-import util.JGitUtil
-import util.JGitUtil.CommitInfo
-import org.eclipse.jgit.api.Git
-import org.apache.http.message.BasicNameValuePair
-import org.apache.http.client.entity.UrlEncodedFormEntity
-import org.apache.http.NameValuePair
-import java.util.Date
-import api._
-
-trait WebHookService {
- import WebHookService._
-
- private val logger = LoggerFactory.getLogger(classOf[WebHookService])
-
- def getWebHookURLs(owner: String, repository: String)(implicit s: Session): List[WebHook] =
- WebHooks.filter(_.byRepository(owner, repository)).sortBy(_.url).list
-
- def addWebHookURL(owner: String, repository: String, url :String)(implicit s: Session): Unit =
- WebHooks insert WebHook(owner, repository, url)
-
- def deleteWebHookURL(owner: String, repository: String, url :String)(implicit s: Session): Unit =
- WebHooks.filter(_.byPrimaryKey(owner, repository, url)).delete
-
- def callWebHookOf(owner: String, repository: String, eventName: String)(makePayload: => Option[WebHookPayload])(implicit s: Session, c: JsonFormat.Context): Unit = {
- val webHookURLs = getWebHookURLs(owner, repository)
- if(webHookURLs.nonEmpty){
- makePayload.map(callWebHook(eventName, webHookURLs, _))
- }
- }
-
- def callWebHook(eventName: String, webHookURLs: List[WebHook], payload: WebHookPayload)(implicit c: JsonFormat.Context): Unit = {
- import org.apache.http.client.methods.HttpPost
- import org.apache.http.impl.client.HttpClientBuilder
- import scala.concurrent._
- import ExecutionContext.Implicits.global
-
- if(webHookURLs.nonEmpty){
- val json = JsonFormat(payload)
- val httpClient = HttpClientBuilder.create.build
-
- webHookURLs.foreach { webHookUrl =>
- val f = Future {
- logger.debug(s"start web hook invocation for ${webHookUrl}")
- val httpPost = new HttpPost(webHookUrl.url)
- httpPost.addHeader("X-Github-Event", eventName)
-
- val params: java.util.List[NameValuePair] = new java.util.ArrayList()
- params.add(new BasicNameValuePair("payload", json))
- httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"))
-
- httpClient.execute(httpPost)
- httpPost.releaseConnection()
- logger.debug(s"end web hook invocation for ${webHookUrl}")
- }
- f.onSuccess {
- case s => logger.debug(s"Success: web hook request to ${webHookUrl.url}")
- }
- f.onFailure {
- case t => logger.error(s"Failed: web hook request to ${webHookUrl.url}", t)
- }
- }
- }
- logger.debug("end callWebHook")
- }
-}
-
-
-trait WebHookPullRequestService extends WebHookService {
- self: AccountService with RepositoryService with PullRequestService with IssuesService =>
-
- import WebHookService._
- // https://developer.github.com/v3/activity/events/types/#issuesevent
- def callIssuesWebHook(action: String, repository: RepositoryService.RepositoryInfo, issue: Issue, baseUrl: String, sender: model.Account)(implicit s: Session, context:JsonFormat.Context): Unit = {
- callWebHookOf(repository.owner, repository.name, "issues"){
- val users = getAccountsByUserNames(Set(repository.owner, issue.userName), Set(sender))
- for{
- repoOwner <- users.get(repository.owner)
- issueUser <- users.get(issue.userName)
- } yield {
- WebHookIssuesPayload(
- action = action,
- number = issue.issueId,
- repository = ApiRepository(repository, ApiUser(repoOwner)),
- issue = ApiIssue(issue, ApiUser(issueUser)),
- sender = ApiUser(sender))
- }
- }
- }
-
- def callPullRequestWebHook(action: String, repository: RepositoryService.RepositoryInfo, issueId: Int, baseUrl: String, sender: model.Account)(implicit s: Session, context:JsonFormat.Context): Unit = {
- import WebHookService._
- callWebHookOf(repository.owner, repository.name, "pull_request"){
- for{
- (issue, pullRequest) <- getPullRequest(repository.owner, repository.name, issueId)
- users = getAccountsByUserNames(Set(repository.owner, pullRequest.requestUserName), Set(sender))
- baseOwner <- users.get(repository.owner)
- headOwner <- users.get(pullRequest.requestUserName)
- headRepo <- getRepository(pullRequest.requestUserName, pullRequest.requestRepositoryName, baseUrl)
- } yield {
- WebHookPullRequestPayload(
- action = action,
- issue = issue,
- pullRequest = pullRequest,
- headRepository = headRepo,
- headOwner = headOwner,
- baseRepository = repository,
- baseOwner = baseOwner,
- sender = sender)
- }
- }
- }
-
- def getPullRequestsByRequestForWebhook(userName:String, repositoryName:String, branch:String)
- (implicit s: Session): Map[(Issue, PullRequest, Account, Account), List[WebHook]] =
- (for{
- is <- Issues if is.closed === false.bind
- pr <- PullRequests if pr.byPrimaryKey(is.userName, is.repositoryName, is.issueId)
- if pr.requestUserName === userName.bind
- if pr.requestRepositoryName === repositoryName.bind
- if pr.requestBranch === branch.bind
- bu <- Accounts if bu.userName === pr.userName
- ru <- Accounts if ru.userName === pr.requestUserName
- wh <- WebHooks if wh.byRepository(is.userName , is.repositoryName)
- } yield {
- ((is, pr, bu, ru), wh)
- }).list.groupBy(_._1).mapValues(_.map(_._2))
-
- def callPullRequestWebHookByRequestBranch(action: String, requestRepository: RepositoryService.RepositoryInfo, requestBranch: String, baseUrl: String, sender: model.Account)(implicit s: Session, context:JsonFormat.Context): Unit = {
- import WebHookService._
- for{
- ((issue, pullRequest, baseOwner, headOwner), webHooks) <- getPullRequestsByRequestForWebhook(requestRepository.owner, requestRepository.name, requestBranch)
- baseRepo <- getRepository(pullRequest.userName, pullRequest.repositoryName, baseUrl)
- } yield {
- val payload = WebHookPullRequestPayload(
- action = action,
- issue = issue,
- pullRequest = pullRequest,
- headRepository = requestRepository,
- headOwner = headOwner,
- baseRepository = baseRepo,
- baseOwner = baseOwner,
- sender = sender)
- callWebHook("pull_request", webHooks, payload)
- }
- }
-}
-
-trait WebHookIssueCommentService extends WebHookPullRequestService {
- self: AccountService with RepositoryService with PullRequestService with IssuesService =>
-
- import WebHookService._
- def callIssueCommentWebHook(repository: RepositoryService.RepositoryInfo, issue: Issue, issueCommentId: Int, sender: model.Account)(implicit s: Session, context:JsonFormat.Context): Unit = {
- callWebHookOf(repository.owner, repository.name, "issue_comment"){
- for{
- issueComment <- getComment(repository.owner, repository.name, issueCommentId.toString())
- users = getAccountsByUserNames(Set(issue.userName, repository.owner, issueComment.userName), Set(sender))
- issueUser <- users.get(issue.userName)
- repoOwner <- users.get(repository.owner)
- commenter <- users.get(issueComment.userName)
- } yield {
- WebHookIssueCommentPayload(
- issue = issue,
- issueUser = issueUser,
- comment = issueComment,
- commentUser = commenter,
- repository = repository,
- repositoryUser = repoOwner,
- sender = sender)
- }
- }
- }
-}
-
-object WebHookService {
- trait WebHookPayload
-
- // https://developer.github.com/v3/activity/events/types/#pushevent
- case class WebHookPushPayload(
- pusher: ApiUser,
- ref: String,
- commits: List[ApiCommit],
- repository: ApiRepository
- ) extends WebHookPayload
-
- object WebHookPushPayload {
- def apply(git: Git, pusher: Account, refName: String, repositoryInfo: RepositoryInfo,
- commits: List[CommitInfo], repositoryOwner: Account): WebHookPushPayload =
- WebHookPushPayload(
- ApiUser(pusher),
- refName,
- commits.map{ commit => ApiCommit(git, util.RepositoryName(repositoryInfo), commit) },
- ApiRepository(
- repositoryInfo,
- owner= ApiUser(repositoryOwner)
- )
- )
- }
-
- // https://developer.github.com/v3/activity/events/types/#issuesevent
- case class WebHookIssuesPayload(
- action: String,
- number: Int,
- repository: ApiRepository,
- issue: ApiIssue,
- sender: ApiUser) extends WebHookPayload
-
- // https://developer.github.com/v3/activity/events/types/#pullrequestevent
- case class WebHookPullRequestPayload(
- action: String,
- number: Int,
- repository: ApiRepository,
- pull_request: ApiPullRequest,
- sender: ApiUser
- ) extends WebHookPayload
-
- object WebHookPullRequestPayload{
- def apply(action: String,
- issue: Issue,
- pullRequest: PullRequest,
- headRepository: RepositoryInfo,
- headOwner: Account,
- baseRepository: RepositoryInfo,
- baseOwner: Account,
- sender: model.Account): WebHookPullRequestPayload = {
- val headRepoPayload = ApiRepository(headRepository, headOwner)
- val baseRepoPayload = ApiRepository(baseRepository, baseOwner)
- val senderPayload = ApiUser(sender)
- val pr = ApiPullRequest(issue, pullRequest, headRepoPayload, baseRepoPayload, senderPayload)
- WebHookPullRequestPayload(
- action = action,
- number = issue.issueId,
- repository = pr.base.repo,
- pull_request = pr,
- sender = senderPayload
- )
- }
- }
-
- // https://developer.github.com/v3/activity/events/types/#issuecommentevent
- case class WebHookIssueCommentPayload(
- action: String,
- repository: ApiRepository,
- issue: ApiIssue,
- comment: ApiComment,
- sender: ApiUser
- ) extends WebHookPayload
-
- object WebHookIssueCommentPayload{
- def apply(
- issue: Issue,
- issueUser: Account,
- comment: IssueComment,
- commentUser: Account,
- repository: RepositoryInfo,
- repositoryUser: Account,
- sender: Account): WebHookIssueCommentPayload =
- WebHookIssueCommentPayload(
- action = "created",
- repository = ApiRepository(repository, repositoryUser),
- issue = ApiIssue(issue, ApiUser(issueUser)),
- comment = ApiComment(comment, ApiUser(commentUser)),
- sender = ApiUser(sender))
- }
-}
diff --git a/src/main/scala/service/WikiService.scala b/src/main/scala/service/WikiService.scala
deleted file mode 100644
index add5021..0000000
--- a/src/main/scala/service/WikiService.scala
+++ /dev/null
@@ -1,281 +0,0 @@
-package service
-
-import java.util.Date
-import org.eclipse.jgit.api.Git
-import util._
-import _root_.util.ControlUtil._
-import org.eclipse.jgit.treewalk.CanonicalTreeParser
-import org.eclipse.jgit.lib._
-import org.eclipse.jgit.dircache.DirCache
-import org.eclipse.jgit.diff.{DiffEntry, DiffFormatter}
-import java.io.ByteArrayInputStream
-import org.eclipse.jgit.patch._
-import org.eclipse.jgit.api.errors.PatchFormatException
-import scala.collection.JavaConverters._
-import service.RepositoryService.RepositoryInfo
-
-object WikiService {
-
- /**
- * The model for wiki page.
- *
- * @param name the page name
- * @param content the page content
- * @param committer the last committer
- * @param time the last modified time
- * @param id the latest commit id
- */
- case class WikiPageInfo(name: String, content: String, committer: String, time: Date, id: String)
-
- /**
- * The model for wiki page history.
- *
- * @param name the page name
- * @param committer the committer the committer
- * @param message the commit message
- * @param date the commit date
- */
- case class WikiPageHistoryInfo(name: String, committer: String, message: String, date: Date)
-
- def httpUrl(repository: RepositoryInfo) = repository.httpUrl.replaceFirst("\\.git\\Z", ".wiki.git")
-
- def sshUrl(repository: RepositoryInfo, settings: SystemSettingsService.SystemSettings, userName: String) =
- repository.sshUrl(settings.sshPort.getOrElse(SystemSettingsService.DefaultSshPort), userName).replaceFirst("\\.git\\Z", ".wiki.git")
-}
-
-trait WikiService {
- import WikiService._
-
- def createWikiRepository(loginAccount: model.Account, owner: String, repository: String): Unit =
- LockUtil.lock(s"${owner}/${repository}/wiki"){
- defining(Directory.getWikiRepositoryDir(owner, repository)){ dir =>
- if(!dir.exists){
- JGitUtil.initRepository(dir)
- saveWikiPage(owner, repository, "Home", "Home", s"Welcome to the ${repository} wiki!!", loginAccount, "Initial Commit", None)
- }
- }
- }
-
- /**
- * Returns the wiki page.
- */
- def getWikiPage(owner: String, repository: String, pageName: String): Option[WikiPageInfo] = {
- using(Git.open(Directory.getWikiRepositoryDir(owner, repository))){ git =>
- if(!JGitUtil.isEmpty(git)){
- JGitUtil.getFileList(git, "master", ".").find(_.name == pageName + ".md").map { file =>
- WikiPageInfo(file.name, StringUtil.convertFromByteArray(git.getRepository.open(file.id).getBytes),
- file.author, file.time, file.commitId)
- }
- } else None
- }
- }
-
- /**
- * Returns the content of the specified file.
- */
- def getFileContent(owner: String, repository: String, path: String): Option[Array[Byte]] =
- using(Git.open(Directory.getWikiRepositoryDir(owner, repository))){ git =>
- if(!JGitUtil.isEmpty(git)){
- val index = path.lastIndexOf('/')
- val parentPath = if(index < 0) "." else path.substring(0, index)
- val fileName = if(index < 0) path else path.substring(index + 1)
-
- JGitUtil.getFileList(git, "master", parentPath).find(_.name == fileName).map { file =>
- git.getRepository.open(file.id).getBytes
- }
- } else None
- }
-
- /**
- * Returns the list of wiki page names.
- */
- def getWikiPageList(owner: String, repository: String): List[String] = {
- using(Git.open(Directory.getWikiRepositoryDir(owner, repository))){ git =>
- JGitUtil.getFileList(git, "master", ".")
- .filter(_.name.endsWith(".md"))
- .map(_.name.stripSuffix(".md"))
- .sortBy(x => x)
- }
- }
-
- /**
- * Reverts specified changes.
- */
- def revertWikiPage(owner: String, repository: String, from: String, to: String,
- committer: model.Account, pageName: Option[String]): Boolean = {
-
- case class RevertInfo(operation: String, filePath: String, source: String)
-
- try {
- LockUtil.lock(s"${owner}/${repository}/wiki"){
- using(Git.open(Directory.getWikiRepositoryDir(owner, repository))){ git =>
-
- val reader = git.getRepository.newObjectReader
- val oldTreeIter = new CanonicalTreeParser
- oldTreeIter.reset(reader, git.getRepository.resolve(from + "^{tree}"))
-
- val newTreeIter = new CanonicalTreeParser
- newTreeIter.reset(reader, git.getRepository.resolve(to + "^{tree}"))
-
- val diffs = git.diff.setNewTree(oldTreeIter).setOldTree(newTreeIter).call.asScala.filter { diff =>
- pageName match {
- case Some(x) => diff.getNewPath == x + ".md"
- case None => true
- }
- }
-
- val patch = using(new java.io.ByteArrayOutputStream()){ out =>
- val formatter = new DiffFormatter(out)
- formatter.setRepository(git.getRepository)
- formatter.format(diffs.asJava)
- new String(out.toByteArray, "UTF-8")
- }
-
- val p = new Patch()
- p.parse(new ByteArrayInputStream(patch.getBytes("UTF-8")))
- if(!p.getErrors.isEmpty){
- throw new PatchFormatException(p.getErrors())
- }
- val revertInfo = (p.getFiles.asScala.map { fh =>
- fh.getChangeType match {
- case DiffEntry.ChangeType.MODIFY => {
- val source = getWikiPage(owner, repository, fh.getNewPath.stripSuffix(".md")).map(_.content).getOrElse("")
- val applied = PatchUtil.apply(source, patch, fh)
- if(applied != null){
- Seq(RevertInfo("ADD", fh.getNewPath, applied))
- } else Nil
- }
- case DiffEntry.ChangeType.ADD => {
- val applied = PatchUtil.apply("", patch, fh)
- if(applied != null){
- Seq(RevertInfo("ADD", fh.getNewPath, applied))
- } else Nil
- }
- case DiffEntry.ChangeType.DELETE => {
- Seq(RevertInfo("DELETE", fh.getNewPath, ""))
- }
- case DiffEntry.ChangeType.RENAME => {
- val applied = PatchUtil.apply("", patch, fh)
- if(applied != null){
- Seq(RevertInfo("DELETE", fh.getOldPath, ""), RevertInfo("ADD", fh.getNewPath, applied))
- } else {
- Seq(RevertInfo("DELETE", fh.getOldPath, ""))
- }
- }
- case _ => Nil
- }
- }).flatten
-
- if(revertInfo.nonEmpty){
- val builder = DirCache.newInCore.builder()
- val inserter = git.getRepository.newObjectInserter()
- val headId = git.getRepository.resolve(Constants.HEAD + "^{commit}")
-
- JGitUtil.processTree(git, headId){ (path, tree) =>
- if(revertInfo.find(x => x.filePath == path).isEmpty){
- builder.add(JGitUtil.createDirCacheEntry(path, tree.getEntryFileMode, tree.getEntryObjectId))
- }
- }
-
- revertInfo.filter(_.operation == "ADD").foreach { x =>
- builder.add(JGitUtil.createDirCacheEntry(x.filePath, FileMode.REGULAR_FILE, inserter.insert(Constants.OBJ_BLOB, x.source.getBytes("UTF-8"))))
- }
- builder.finish()
-
- JGitUtil.createNewCommit(git, inserter, headId, builder.getDirCache.writeTree(inserter),
- Constants.HEAD, committer.fullName, committer.mailAddress,
- pageName match {
- case Some(x) => s"Revert ${from} ... ${to} on ${x}"
- case None => s"Revert ${from} ... ${to}"
- })
- }
- }
- }
- true
- } catch {
- case e: Exception => {
- e.printStackTrace()
- false
- }
- }
- }
-
- /**
- * Save the wiki page.
- */
- def saveWikiPage(owner: String, repository: String, currentPageName: String, newPageName: String,
- content: String, committer: model.Account, message: String, currentId: Option[String]): Option[String] = {
- LockUtil.lock(s"${owner}/${repository}/wiki"){
- using(Git.open(Directory.getWikiRepositoryDir(owner, repository))){ git =>
- val builder = DirCache.newInCore.builder()
- val inserter = git.getRepository.newObjectInserter()
- val headId = git.getRepository.resolve(Constants.HEAD + "^{commit}")
- var created = true
- var updated = false
- var removed = false
-
- if(headId != null){
- JGitUtil.processTree(git, headId){ (path, tree) =>
- if(path == currentPageName + ".md" && currentPageName != newPageName){
- removed = true
- } else if(path != newPageName + ".md"){
- builder.add(JGitUtil.createDirCacheEntry(path, tree.getEntryFileMode, tree.getEntryObjectId))
- } else {
- created = false
- updated = JGitUtil.getContentFromId(git, tree.getEntryObjectId, true).map(new String(_, "UTF-8") != content).getOrElse(false)
- }
- }
- }
-
- if(created || updated || removed){
- builder.add(JGitUtil.createDirCacheEntry(newPageName + ".md", FileMode.REGULAR_FILE, inserter.insert(Constants.OBJ_BLOB, content.getBytes("UTF-8"))))
- builder.finish()
- val newHeadId = JGitUtil.createNewCommit(git, inserter, headId, builder.getDirCache.writeTree(inserter),
- Constants.HEAD, committer.fullName, committer.mailAddress,
- if(message.trim.length == 0) {
- if(removed){
- s"Rename ${currentPageName} to ${newPageName}"
- } else if(created){
- s"Created ${newPageName}"
- } else {
- s"Updated ${newPageName}"
- }
- } else {
- message
- })
-
- Some(newHeadId.getName)
- } else None
- }
- }
- }
-
- /**
- * Delete the wiki page.
- */
- def deleteWikiPage(owner: String, repository: String, pageName: String,
- committer: String, mailAddress: String, message: String): Unit = {
- LockUtil.lock(s"${owner}/${repository}/wiki"){
- using(Git.open(Directory.getWikiRepositoryDir(owner, repository))){ git =>
- val builder = DirCache.newInCore.builder()
- val inserter = git.getRepository.newObjectInserter()
- val headId = git.getRepository.resolve(Constants.HEAD + "^{commit}")
- var removed = false
-
- JGitUtil.processTree(git, headId){ (path, tree) =>
- if(path != pageName + ".md"){
- builder.add(JGitUtil.createDirCacheEntry(path, tree.getEntryFileMode, tree.getEntryObjectId))
- } else {
- removed = true
- }
- }
- if(removed){
- builder.finish()
- JGitUtil.createNewCommit(git, inserter, headId, builder.getDirCache.writeTree(inserter),
- Constants.HEAD, committer, mailAddress, message)
- }
- }
- }
- }
-
-}
diff --git a/src/main/scala/servlet/AccessTokenAuthenticationFilter.scala b/src/main/scala/servlet/AccessTokenAuthenticationFilter.scala
deleted file mode 100644
index 56e50c2..0000000
--- a/src/main/scala/servlet/AccessTokenAuthenticationFilter.scala
+++ /dev/null
@@ -1,41 +0,0 @@
-package servlet
-
-import javax.servlet._
-import javax.servlet.http.{HttpServletRequest, HttpServletResponse}
-
-import service.AccessTokenService
-import util.Keys
-import org.scalatra.servlet.ServletApiImplicits._
-import model.Account
-import org.scalatra._
-
-class AccessTokenAuthenticationFilter extends Filter with AccessTokenService {
- private val tokenHeaderPrefix = "token "
-
- override def init(filterConfig: FilterConfig): Unit = {}
-
- override def destroy(): Unit = {}
-
- override def doFilter(req: ServletRequest, res: ServletResponse, chain: FilterChain): Unit = {
- implicit val request = req.asInstanceOf[HttpServletRequest]
- implicit val session = req.getAttribute(Keys.Request.DBSession).asInstanceOf[slick.jdbc.JdbcBackend#Session]
- val response = res.asInstanceOf[HttpServletResponse]
- Option(request.getHeader("Authorization")).map{
- case auth if auth.startsWith("token ") => AccessTokenService.getAccountByAccessToken(auth.substring(6).trim).toRight(Unit)
- // TODO Basic Authentication Support
- case _ => Left(Unit)
- }.orElse{
- Option(request.getSession.getAttribute(Keys.Session.LoginAccount).asInstanceOf[Account]).map(Right(_))
- } match {
- case Some(Right(account)) => request.setAttribute(Keys.Session.LoginAccount, account); chain.doFilter(req, res)
- case None => chain.doFilter(req, res)
- case Some(Left(_)) => {
- response.setStatus(HttpServletResponse.SC_UNAUTHORIZED)
- response.setContentType("Content-Type: application/json; charset=utf-8")
- val w = response.getWriter()
- w.print("""{ "message": "Bad credentials" }""")
- w.close()
- }
- }
- }
-}
diff --git a/src/main/scala/servlet/BasicAuthenticationFilter.scala b/src/main/scala/servlet/BasicAuthenticationFilter.scala
deleted file mode 100644
index cbecfc1..0000000
--- a/src/main/scala/servlet/BasicAuthenticationFilter.scala
+++ /dev/null
@@ -1,92 +0,0 @@
-package servlet
-
-import javax.servlet._
-import javax.servlet.http._
-import service.{SystemSettingsService, AccountService, RepositoryService}
-import model._
-import org.slf4j.LoggerFactory
-import util.Implicits._
-import util.ControlUtil._
-import util.Keys
-
-/**
- * Provides BASIC Authentication for [[servlet.GitRepositoryServlet]].
- */
-class BasicAuthenticationFilter extends Filter with RepositoryService with AccountService with SystemSettingsService {
-
- private val logger = LoggerFactory.getLogger(classOf[BasicAuthenticationFilter])
-
- def init(config: FilterConfig) = {}
-
- def destroy(): Unit = {}
-
- def doFilter(req: ServletRequest, res: ServletResponse, chain: FilterChain): Unit = {
- implicit val request = req.asInstanceOf[HttpServletRequest]
- val response = res.asInstanceOf[HttpServletResponse]
-
- val wrappedResponse = new HttpServletResponseWrapper(response){
- override def setCharacterEncoding(encoding: String) = {}
- }
-
- val isUpdating = request.getRequestURI.endsWith("/git-receive-pack") || "service=git-receive-pack".equals(request.getQueryString)
-
- val settings = loadSystemSettings()
-
- try {
- defining(request.paths){
- case Array(_, repositoryOwner, repositoryName, _*) =>
- getRepository(repositoryOwner, repositoryName.replaceFirst("\\.wiki\\.git$|\\.git$", ""), "") match {
- case Some(repository) => {
- if(!isUpdating && !repository.repository.isPrivate && settings.allowAnonymousAccess){
- chain.doFilter(req, wrappedResponse)
- } else {
- request.getHeader("Authorization") match {
- case null => requireAuth(response)
- case auth => decodeAuthHeader(auth).split(":") match {
- case Array(username, password) => {
- authenticate(settings, username, password) match {
- case Some(account) => {
- if(isUpdating && hasWritePermission(repository.owner, repository.name, Some(account))){
- request.setAttribute(Keys.Request.UserName, account.userName)
- }
- chain.doFilter(req, wrappedResponse)
- }
- case None => requireAuth(response)
- }
- }
- case _ => requireAuth(response)
- }
- }
- }
- }
- case None => {
- logger.debug(s"Repository ${repositoryOwner}/${repositoryName} is not found.")
- response.sendError(HttpServletResponse.SC_NOT_FOUND)
- }
- }
- case _ => {
- logger.debug(s"Not enough path arguments: ${request.paths}")
- response.sendError(HttpServletResponse.SC_NOT_FOUND)
- }
- }
- } catch {
- case ex: Exception => {
- logger.error("error", ex)
- requireAuth(response)
- }
- }
- }
-
- private def requireAuth(response: HttpServletResponse): Unit = {
- response.setHeader("WWW-Authenticate", "BASIC realm=\"GitBucket\"")
- response.sendError(HttpServletResponse.SC_UNAUTHORIZED)
- }
-
- private def decodeAuthHeader(header: String): String = {
- try {
- new String(new sun.misc.BASE64Decoder().decodeBuffer(header.substring(6)))
- } catch {
- case _: Throwable => ""
- }
- }
-}
\ No newline at end of file
diff --git a/src/main/scala/servlet/GitRepositoryServlet.scala b/src/main/scala/servlet/GitRepositoryServlet.scala
deleted file mode 100644
index 9ebb4ac..0000000
--- a/src/main/scala/servlet/GitRepositoryServlet.scala
+++ /dev/null
@@ -1,217 +0,0 @@
-package servlet
-
-import org.eclipse.jgit.http.server.GitServlet
-import org.eclipse.jgit.lib._
-import org.eclipse.jgit.transport._
-import org.eclipse.jgit.transport.resolver._
-import org.slf4j.LoggerFactory
-
-import javax.servlet.ServletConfig
-import javax.servlet.ServletContext
-import javax.servlet.http.{HttpServletResponse, HttpServletRequest}
-import util.{StringUtil, Keys, JGitUtil, Directory}
-import util.ControlUtil._
-import util.Implicits._
-import service._
-import WebHookService._
-import org.eclipse.jgit.api.Git
-import util.JGitUtil.CommitInfo
-import service.IssuesService.IssueSearchCondition
-import model.Session
-
-/**
- * Provides Git repository via HTTP.
- *
- * This servlet provides only Git repository functionality.
- * Authentication is provided by [[servlet.BasicAuthenticationFilter]].
- */
-class GitRepositoryServlet extends GitServlet with SystemSettingsService {
-
- private val logger = LoggerFactory.getLogger(classOf[GitRepositoryServlet])
-
- override def init(config: ServletConfig): Unit = {
- setReceivePackFactory(new GitBucketReceivePackFactory())
-
- // TODO are there any other ways...?
- super.init(new ServletConfig(){
- def getInitParameter(name: String): String = name match {
- case "base-path" => Directory.RepositoryHome
- case "export-all" => "true"
- case name => config.getInitParameter(name)
- }
- def getInitParameterNames(): java.util.Enumeration[String] = {
- config.getInitParameterNames
- }
-
- def getServletContext(): ServletContext = config.getServletContext
- def getServletName(): String = config.getServletName
- })
-
- super.init(config)
- }
-
- override def service(req: HttpServletRequest, res: HttpServletResponse): Unit = {
- val agent = req.getHeader("USER-AGENT")
- val index = req.getRequestURI.indexOf(".git")
- if(index >= 0 && (agent == null || agent.toLowerCase.indexOf("git/") < 0)){
- // redirect for browsers
- val paths = req.getRequestURI.substring(0, index).split("/")
- res.sendRedirect(baseUrl(req) + "/" + paths.dropRight(1).last + "/" + paths.last)
- } else {
- // response for git client
- super.service(req, res)
- }
- }
-}
-
-class GitBucketReceivePackFactory extends ReceivePackFactory[HttpServletRequest] with SystemSettingsService {
-
- private val logger = LoggerFactory.getLogger(classOf[GitBucketReceivePackFactory])
-
- override def create(request: HttpServletRequest, db: Repository): ReceivePack = {
- val receivePack = new ReceivePack(db)
- val pusher = request.getAttribute(Keys.Request.UserName).asInstanceOf[String]
-
- logger.debug("requestURI: " + request.getRequestURI)
- logger.debug("pusher:" + pusher)
-
- defining(request.paths){ paths =>
- val owner = paths(1)
- val repository = paths(2).stripSuffix(".git")
-
- logger.debug("repository:" + owner + "/" + repository)
-
- if(!repository.endsWith(".wiki")){
- defining(request) { implicit r =>
- val hook = new CommitLogHook(owner, repository, pusher, baseUrl)
- receivePack.setPreReceiveHook(hook)
- receivePack.setPostReceiveHook(hook)
- }
- }
- receivePack
- }
- }
-}
-
-import scala.collection.JavaConverters._
-
-class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl: String)(implicit session: Session)
- extends PostReceiveHook with PreReceiveHook
- with RepositoryService with AccountService with IssuesService with ActivityService with PullRequestService with WebHookService
- with WebHookPullRequestService {
-
- private val logger = LoggerFactory.getLogger(classOf[CommitLogHook])
- private var existIds: Seq[String] = Nil
-
- def onPreReceive(receivePack: ReceivePack, commands: java.util.Collection[ReceiveCommand]): Unit = {
- try {
- using(Git.open(Directory.getRepositoryDir(owner, repository))) { git =>
- existIds = JGitUtil.getAllCommitIds(git)
- }
- } catch {
- case ex: Exception => {
- logger.error(ex.toString, ex)
- throw ex
- }
- }
- }
-
- def onPostReceive(receivePack: ReceivePack, commands: java.util.Collection[ReceiveCommand]): Unit = {
- try {
- using(Git.open(Directory.getRepositoryDir(owner, repository))) { git =>
- val pushedIds = scala.collection.mutable.Set[String]()
- commands.asScala.foreach { command =>
- logger.debug(s"commandType: ${command.getType}, refName: ${command.getRefName}")
- implicit val apiContext = api.JsonFormat.Context(baseUrl)
- val refName = command.getRefName.split("/")
- val branchName = refName.drop(2).mkString("/")
- val commits = if (refName(1) == "tags") {
- Nil
- } else {
- command.getType match {
- case ReceiveCommand.Type.DELETE => Nil
- case _ => JGitUtil.getCommitLog(git, command.getOldId.name, command.getNewId.name)
- }
- }
-
- // Retrieve all issue count in the repository
- val issueCount =
- countIssue(IssueSearchCondition(state = "open"), false, owner -> repository) +
- countIssue(IssueSearchCondition(state = "closed"), false, owner -> repository)
-
- val repositoryInfo = getRepository(owner, repository, baseUrl).get
-
- // Extract new commit and apply issue comment
- val defaultBranch = repositoryInfo.repository.defaultBranch
- val newCommits = commits.flatMap { commit =>
- if (!existIds.contains(commit.id) && !pushedIds.contains(commit.id)) {
- if (issueCount > 0) {
- pushedIds.add(commit.id)
- createIssueComment(commit)
- // close issues
- if(refName(1) == "heads" && branchName == defaultBranch && command.getType == ReceiveCommand.Type.UPDATE){
- closeIssuesFromMessage(commit.fullMessage, pusher, owner, repository)
- }
- }
- Some(commit)
- } else None
- }
-
- // record activity
- if(refName(1) == "heads"){
- command.getType match {
- case ReceiveCommand.Type.CREATE => recordCreateBranchActivity(owner, repository, pusher, branchName)
- case ReceiveCommand.Type.UPDATE => recordPushActivity(owner, repository, pusher, branchName, newCommits)
- case ReceiveCommand.Type.DELETE => recordDeleteBranchActivity(owner, repository, pusher, branchName)
- case _ =>
- }
- } else if(refName(1) == "tags"){
- command.getType match {
- case ReceiveCommand.Type.CREATE => recordCreateTagActivity(owner, repository, pusher, branchName, newCommits)
- case ReceiveCommand.Type.DELETE => recordDeleteTagActivity(owner, repository, pusher, branchName, newCommits)
- case _ =>
- }
- }
-
- if(refName(1) == "heads"){
- command.getType match {
- case ReceiveCommand.Type.CREATE |
- ReceiveCommand.Type.UPDATE |
- ReceiveCommand.Type.UPDATE_NONFASTFORWARD =>
- updatePullRequests(owner, repository, branchName)
- getAccountByUserName(pusher).map{ pusherAccount =>
- callPullRequestWebHookByRequestBranch("synchronize", repositoryInfo, branchName, baseUrl, pusherAccount)
- }
- case _ =>
- }
- }
-
- // call web hook
- callWebHookOf(owner, repository, "push"){
- for(pusherAccount <- getAccountByUserName(pusher);
- ownerAccount <- getAccountByUserName(owner)) yield {
- WebHookPushPayload(git, pusherAccount, command.getRefName, repositoryInfo, newCommits, ownerAccount)
- }
- }
- }
- }
- // update repository last modified time.
- updateLastActivityDate(owner, repository)
- } catch {
- case ex: Exception => {
- logger.error(ex.toString, ex)
- throw ex
- }
- }
- }
-
- private def createIssueComment(commit: CommitInfo) = {
- StringUtil.extractIssueId(commit.fullMessage).foreach { issueId =>
- if(getIssue(owner, repository, issueId).isDefined){
- getAccountByMailAddress(commit.committerEmailAddress).foreach { account =>
- createComment(owner, repository, account.userName, issueId.toInt, commit.fullMessage + " " + commit.id, "commit")
- }
- }
- }
- }
-}
diff --git a/src/main/scala/servlet/InitializeListener.scala b/src/main/scala/servlet/InitializeListener.scala
deleted file mode 100644
index a4b1e1e..0000000
--- a/src/main/scala/servlet/InitializeListener.scala
+++ /dev/null
@@ -1,205 +0,0 @@
-package servlet
-
-import java.io.File
-import java.sql.{DriverManager, Connection}
-import org.apache.commons.io.FileUtils
-import javax.servlet.{ServletContextListener, ServletContextEvent}
-import org.slf4j.LoggerFactory
-import util.Directory._
-import util.ControlUtil._
-import util.JDBCUtil._
-import org.eclipse.jgit.api.Git
-import util.{Version, Versions}
-import plugin._
-import util.{DatabaseConfig, Directory}
-
-object AutoUpdate {
-
- /**
- * The history of versions. A head of this sequence is the current BitBucket version.
- */
- val versions = Seq(
- new Version(2, 9),
- new Version(2, 8),
- new Version(2, 7) {
- override def update(conn: Connection, cl: ClassLoader): Unit = {
- super.update(conn, cl)
- conn.select("SELECT * FROM REPOSITORY"){ rs =>
- // Rename attached files directory from /issues to /comments
- val userName = rs.getString("USER_NAME")
- val repoName = rs.getString("REPOSITORY_NAME")
- defining(Directory.getAttachedDir(userName, repoName)){ newDir =>
- val oldDir = new File(newDir.getParentFile, "issues")
- if(oldDir.exists && oldDir.isDirectory){
- oldDir.renameTo(newDir)
- }
- }
- // Update ORIGIN_USER_NAME and ORIGIN_REPOSITORY_NAME if it does not exist
- val originalUserName = rs.getString("ORIGIN_USER_NAME")
- val originalRepoName = rs.getString("ORIGIN_REPOSITORY_NAME")
- if(originalUserName != null && originalRepoName != null){
- if(conn.selectInt("SELECT COUNT(*) FROM REPOSITORY WHERE USER_NAME = ? AND REPOSITORY_NAME = ?",
- originalUserName, originalRepoName) == 0){
- conn.update("UPDATE REPOSITORY SET ORIGIN_USER_NAME = NULL, ORIGIN_REPOSITORY_NAME = NULL " +
- "WHERE USER_NAME = ? AND REPOSITORY_NAME = ?", userName, repoName)
- }
- }
- // Update PARENT_USER_NAME and PARENT_REPOSITORY_NAME if it does not exist
- val parentUserName = rs.getString("PARENT_USER_NAME")
- val parentRepoName = rs.getString("PARENT_REPOSITORY_NAME")
- if(parentUserName != null && parentRepoName != null){
- if(conn.selectInt("SELECT COUNT(*) FROM REPOSITORY WHERE USER_NAME = ? AND REPOSITORY_NAME = ?",
- parentUserName, parentRepoName) == 0){
- conn.update("UPDATE REPOSITORY SET PARENT_USER_NAME = NULL, PARENT_REPOSITORY_NAME = NULL " +
- "WHERE USER_NAME = ? AND REPOSITORY_NAME = ?", userName, repoName)
- }
- }
- }
- }
- },
- new Version(2, 6),
- new Version(2, 5),
- new Version(2, 4),
- new Version(2, 3) {
- override def update(conn: Connection, cl: ClassLoader): Unit = {
- super.update(conn, cl)
- conn.select("SELECT ACTIVITY_ID, ADDITIONAL_INFO FROM ACTIVITY WHERE ACTIVITY_TYPE='push'"){ rs =>
- val curInfo = rs.getString("ADDITIONAL_INFO")
- val newInfo = curInfo.split("\n").filter(_ matches "^[0-9a-z]{40}:.*").mkString("\n")
- if (curInfo != newInfo) {
- conn.update("UPDATE ACTIVITY SET ADDITIONAL_INFO = ? WHERE ACTIVITY_ID = ?", newInfo, rs.getInt("ACTIVITY_ID"))
- }
- }
- ignore {
- FileUtils.deleteDirectory(Directory.getPluginCacheDir())
- //FileUtils.deleteDirectory(new File(Directory.PluginHome))
- }
- }
- },
- new Version(2, 2),
- new Version(2, 1),
- new Version(2, 0){
- override def update(conn: Connection, cl: ClassLoader): Unit = {
- import eu.medsea.mimeutil.{MimeUtil2, MimeType}
-
- val mimeUtil = new MimeUtil2()
- mimeUtil.registerMimeDetector("eu.medsea.mimeutil.detector.MagicMimeMimeDetector")
-
- super.update(conn, cl)
- conn.select("SELECT USER_NAME, REPOSITORY_NAME FROM REPOSITORY"){ rs =>
- defining(Directory.getAttachedDir(rs.getString("USER_NAME"), rs.getString("REPOSITORY_NAME"))){ dir =>
- if(dir.exists && dir.isDirectory){
- dir.listFiles.foreach { file =>
- if(file.getName.indexOf('.') < 0){
- val mimeType = MimeUtil2.getMostSpecificMimeType(mimeUtil.getMimeTypes(file, new MimeType("application/octet-stream"))).toString
- if(mimeType.startsWith("image/")){
- file.renameTo(new File(file.getParent, file.getName + "." + mimeType.split("/")(1)))
- }
- }
- }
- }
- }
- }
- }
- },
- Version(1, 13),
- Version(1, 12),
- Version(1, 11),
- Version(1, 10),
- Version(1, 9),
- Version(1, 8),
- Version(1, 7),
- Version(1, 6),
- Version(1, 5),
- Version(1, 4),
- new Version(1, 3){
- override def update(conn: Connection, cl: ClassLoader): Unit = {
- super.update(conn, cl)
- // Fix wiki repository configuration
- conn.select("SELECT USER_NAME, REPOSITORY_NAME FROM REPOSITORY"){ rs =>
- using(Git.open(getWikiRepositoryDir(rs.getString("USER_NAME"), rs.getString("REPOSITORY_NAME")))){ git =>
- defining(git.getRepository.getConfig){ config =>
- if(!config.getBoolean("http", "receivepack", false)){
- config.setBoolean("http", null, "receivepack", true)
- config.save
- }
- }
- }
- }
- }
- },
- Version(1, 2),
- Version(1, 1),
- Version(1, 0),
- Version(0, 0)
- )
-
- /**
- * The head version of BitBucket.
- */
- val headVersion = versions.head
-
- /**
- * The version file (GITBUCKET_HOME/version).
- */
- lazy val versionFile = new File(GitBucketHome, "version")
-
- /**
- * Returns the current version from the version file.
- */
- def getCurrentVersion(): Version = {
- if(versionFile.exists){
- FileUtils.readFileToString(versionFile, "UTF-8").trim.split("\\.") match {
- case Array(majorVersion, minorVersion) => {
- versions.find { v =>
- v.majorVersion == majorVersion.toInt && v.minorVersion == minorVersion.toInt
- }.getOrElse(Version(0, 0))
- }
- case _ => Version(0, 0)
- }
- } else Version(0, 0)
- }
-
-}
-
-/**
- * Initialize GitBucket system.
- * Update database schema and load plug-ins automatically in the context initializing.
- */
-class InitializeListener extends ServletContextListener {
- import AutoUpdate._
-
- private val logger = LoggerFactory.getLogger(classOf[InitializeListener])
-
- override def contextInitialized(event: ServletContextEvent): Unit = {
- val dataDir = event.getServletContext.getInitParameter("gitbucket.home")
- if(dataDir != null){
- System.setProperty("gitbucket.home", dataDir)
- }
- org.h2.Driver.load()
-
- defining(getConnection()){ conn =>
- // Migration
- logger.debug("Start schema update")
- Versions.update(conn, headVersion, getCurrentVersion(), versions, Thread.currentThread.getContextClassLoader){ conn =>
- FileUtils.writeStringToFile(versionFile, headVersion.versionString, "UTF-8")
- }
- // Load plugins
- logger.debug("Initialize plugins")
- PluginRegistry.initialize(event.getServletContext, conn)
- }
-
- }
-
- def contextDestroyed(event: ServletContextEvent): Unit = {
- // Shutdown plugins
- PluginRegistry.shutdown(event.getServletContext)
- }
-
- private def getConnection(): Connection =
- DriverManager.getConnection(
- DatabaseConfig.url,
- DatabaseConfig.user,
- DatabaseConfig.password)
-
-}
diff --git a/src/main/scala/servlet/SessionCleanupListener.scala b/src/main/scala/servlet/SessionCleanupListener.scala
deleted file mode 100644
index ee4ea7b..0000000
--- a/src/main/scala/servlet/SessionCleanupListener.scala
+++ /dev/null
@@ -1,16 +0,0 @@
-package servlet
-
-import javax.servlet.http.{HttpSessionEvent, HttpSessionListener}
-import org.apache.commons.io.FileUtils
-import util.Directory._
-
-/**
- * Removes session associated temporary files when session is destroyed.
- */
-class SessionCleanupListener extends HttpSessionListener {
-
- def sessionCreated(se: HttpSessionEvent): Unit = {}
-
- def sessionDestroyed(se: HttpSessionEvent): Unit = FileUtils.deleteDirectory(getTemporaryDir(se.getSession.getId))
-
-}
diff --git a/src/main/scala/servlet/TransactionFilter.scala b/src/main/scala/servlet/TransactionFilter.scala
deleted file mode 100644
index 20d37f5..0000000
--- a/src/main/scala/servlet/TransactionFilter.scala
+++ /dev/null
@@ -1,59 +0,0 @@
-package servlet
-
-import javax.servlet._
-import javax.servlet.http.HttpServletRequest
-import com.mchange.v2.c3p0.ComboPooledDataSource
-import org.slf4j.LoggerFactory
-import slick.jdbc.JdbcBackend.{Database => SlickDatabase, Session}
-import util.{DatabaseConfig, Keys}
-
-/**
- * Controls the transaction with the open session in view pattern.
- */
-class TransactionFilter extends Filter {
-
- private val logger = LoggerFactory.getLogger(classOf[TransactionFilter])
-
- def init(config: FilterConfig) = {}
-
- def destroy(): Unit = {}
-
- def doFilter(req: ServletRequest, res: ServletResponse, chain: FilterChain): Unit = {
- if(req.asInstanceOf[HttpServletRequest].getRequestURI().startsWith("/assets/")){
- // assets don't need transaction
- chain.doFilter(req, res)
- } else {
- Database() withTransaction { session =>
- logger.debug("begin transaction")
- req.setAttribute(Keys.Request.DBSession, session)
- chain.doFilter(req, res)
- logger.debug("end transaction")
- }
- }
- }
-
-}
-
-object Database {
-
- private val logger = LoggerFactory.getLogger(Database.getClass)
-
- private val db: SlickDatabase = {
- val datasource = new ComboPooledDataSource
-
- datasource.setDriverClass(DatabaseConfig.driver)
- datasource.setJdbcUrl(DatabaseConfig.url)
- datasource.setUser(DatabaseConfig.user)
- datasource.setPassword(DatabaseConfig.password)
-
- logger.debug("load database connection pool")
-
- SlickDatabase.forDataSource(datasource)
- }
-
- def apply(): SlickDatabase = db
-
- def getSession(req: ServletRequest): Session =
- req.getAttribute(Keys.Request.DBSession).asInstanceOf[Session]
-
-}
diff --git a/src/main/scala/ssh/GitCommand.scala b/src/main/scala/ssh/GitCommand.scala
deleted file mode 100644
index 35fb67b..0000000
--- a/src/main/scala/ssh/GitCommand.scala
+++ /dev/null
@@ -1,132 +0,0 @@
-package ssh
-
-import org.apache.sshd.server.{CommandFactory, Environment, ExitCallback, Command}
-import org.slf4j.LoggerFactory
-import java.io.{InputStream, OutputStream}
-import util.ControlUtil._
-import org.eclipse.jgit.api.Git
-import util.Directory._
-import org.eclipse.jgit.transport.{ReceivePack, UploadPack}
-import org.apache.sshd.server.command.UnknownCommand
-import servlet.{Database, CommitLogHook}
-import service.{AccountService, RepositoryService, SystemSettingsService}
-import org.eclipse.jgit.errors.RepositoryNotFoundException
-import model.Session
-
-object GitCommand {
- val CommandRegex = """\Agit-(upload|receive)-pack '/([a-zA-Z0-9\-_.]+)/([a-zA-Z0-9\-_.]+).git'\Z""".r
-}
-
-abstract class GitCommand(val owner: String, val repoName: String) extends Command {
- self: RepositoryService with AccountService =>
-
- private val logger = LoggerFactory.getLogger(classOf[GitCommand])
- protected var err: OutputStream = null
- protected var in: InputStream = null
- protected var out: OutputStream = null
- protected var callback: ExitCallback = null
-
- protected def runTask(user: String)(implicit session: Session): Unit
-
- private def newTask(user: String): Runnable = new Runnable {
- override def run(): Unit = {
- Database() withSession { implicit session =>
- try {
- runTask(user)
- callback.onExit(0)
- } catch {
- case e: RepositoryNotFoundException =>
- logger.info(e.getMessage)
- callback.onExit(1, "Repository Not Found")
- case e: Throwable =>
- logger.error(e.getMessage, e)
- callback.onExit(1)
- }
- }
- }
- }
-
- override def start(env: Environment): Unit = {
- val user = env.getEnv.get("USER")
- val thread = new Thread(newTask(user))
- thread.start()
- }
-
- override def destroy(): Unit = {}
-
- override def setExitCallback(callback: ExitCallback): Unit = {
- this.callback = callback
- }
-
- override def setErrorStream(err: OutputStream): Unit = {
- this.err = err
- }
-
- override def setOutputStream(out: OutputStream): Unit = {
- this.out = out
- }
-
- override def setInputStream(in: InputStream): Unit = {
- this.in = in
- }
-
- protected def isWritableUser(username: String, repositoryInfo: RepositoryService.RepositoryInfo)
- (implicit session: Session): Boolean =
- getAccountByUserName(username) match {
- case Some(account) => hasWritePermission(repositoryInfo.owner, repositoryInfo.name, Some(account))
- case None => false
- }
-
-}
-
-class GitUploadPack(owner: String, repoName: String, baseUrl: String) extends GitCommand(owner, repoName)
- with RepositoryService with AccountService {
-
- override protected def runTask(user: String)(implicit session: Session): Unit = {
- getRepository(owner, repoName.replaceFirst("\\.wiki\\Z", ""), baseUrl).foreach { repositoryInfo =>
- if(!repositoryInfo.repository.isPrivate || isWritableUser(user, repositoryInfo)){
- using(Git.open(getRepositoryDir(owner, repoName))) { git =>
- val repository = git.getRepository
- val upload = new UploadPack(repository)
- upload.upload(in, out, err)
- }
- }
- }
- }
-
-}
-
-class GitReceivePack(owner: String, repoName: String, baseUrl: String) extends GitCommand(owner, repoName)
- with SystemSettingsService with RepositoryService with AccountService {
-
- override protected def runTask(user: String)(implicit session: Session): Unit = {
- getRepository(owner, repoName.replaceFirst("\\.wiki\\Z", ""), baseUrl).foreach { repositoryInfo =>
- if(isWritableUser(user, repositoryInfo)){
- using(Git.open(getRepositoryDir(owner, repoName))) { git =>
- val repository = git.getRepository
- val receive = new ReceivePack(repository)
- if(!repoName.endsWith(".wiki")){
- val hook = new CommitLogHook(owner, repoName, user, baseUrl)
- receive.setPreReceiveHook(hook)
- receive.setPostReceiveHook(hook)
- }
- receive.receive(in, out, err)
- }
- }
- }
- }
-
-}
-
-class GitCommandFactory(baseUrl: String) extends CommandFactory {
- private val logger = LoggerFactory.getLogger(classOf[GitCommandFactory])
-
- override def createCommand(command: String): Command = {
- logger.debug(s"command: $command")
- command match {
- case GitCommand.CommandRegex("upload", owner, repoName) => new GitUploadPack(owner, repoName, baseUrl)
- case GitCommand.CommandRegex("receive", owner, repoName) => new GitReceivePack(owner, repoName, baseUrl)
- case _ => new UnknownCommand(command)
- }
- }
-}
diff --git a/src/main/scala/ssh/NoShell.scala b/src/main/scala/ssh/NoShell.scala
deleted file mode 100644
index c107be6..0000000
--- a/src/main/scala/ssh/NoShell.scala
+++ /dev/null
@@ -1,62 +0,0 @@
-package ssh
-
-import org.apache.sshd.common.Factory
-import org.apache.sshd.server.{Environment, ExitCallback, Command}
-import java.io.{OutputStream, InputStream}
-import org.eclipse.jgit.lib.Constants
-import service.SystemSettingsService
-
-class NoShell extends Factory[Command] with SystemSettingsService {
- override def create(): Command = new Command() {
- private var in: InputStream = null
- private var out: OutputStream = null
- private var err: OutputStream = null
- private var callback: ExitCallback = null
-
- override def start(env: Environment): Unit = {
- val user = env.getEnv.get("USER")
- val port = loadSystemSettings().sshPort.getOrElse(SystemSettingsService.DefaultSshPort)
- val message =
- """
- | Welcome to
- | _____ _ _ ____ _ _
- | / ____| (_) | | | _ \ | | | |
- | | | __ _ | |_ | |_) | _ _ ___ | | __ ___ | |_
- | | | |_ | | | | __| | _ < | | | | / __| | |/ / / _ \ | __|
- | | |__| | | | | |_ | |_) | | |_| | | (__ | < | __/ | |_
- | \_____| |_| \__| |____/ \__,_| \___| |_|\_\ \___| \__|
- |
- | Successfully SSH Access.
- | But interactive shell is disabled.
- |
- | Please use:
- |
- | git clone ssh://%s@GITBUCKET_HOST:%d/OWNER/REPOSITORY_NAME.git
- """.stripMargin.format(user, port).replace("\n", "\r\n") + "\r\n"
- err.write(Constants.encode(message))
- err.flush()
- in.close()
- out.close()
- err.close()
- callback.onExit(127)
- }
-
- override def destroy(): Unit = {}
-
- override def setInputStream(in: InputStream): Unit = {
- this.in = in
- }
-
- override def setOutputStream(out: OutputStream): Unit = {
- this.out = out
- }
-
- override def setErrorStream(err: OutputStream): Unit = {
- this.err = err
- }
-
- override def setExitCallback(callback: ExitCallback): Unit = {
- this.callback = callback
- }
- }
-}
diff --git a/src/main/scala/ssh/PublicKeyAuthenticator.scala b/src/main/scala/ssh/PublicKeyAuthenticator.scala
deleted file mode 100644
index ddcc724..0000000
--- a/src/main/scala/ssh/PublicKeyAuthenticator.scala
+++ /dev/null
@@ -1,22 +0,0 @@
-package ssh
-
-import org.apache.sshd.server.PublickeyAuthenticator
-import org.apache.sshd.server.session.ServerSession
-import java.security.PublicKey
-import service.SshKeyService
-import servlet.Database
-
-class PublicKeyAuthenticator extends PublickeyAuthenticator with SshKeyService {
-
- override def authenticate(username: String, key: PublicKey, session: ServerSession): Boolean = {
- Database() withSession { implicit session =>
- getPublicKeys(username).exists { sshKey =>
- SshUtil.str2PublicKey(sshKey.publicKey) match {
- case Some(publicKey) => key.equals(publicKey)
- case _ => false
- }
- }
- }
- }
-
-}
diff --git a/src/main/scala/ssh/SshServerListener.scala b/src/main/scala/ssh/SshServerListener.scala
deleted file mode 100644
index b441cae..0000000
--- a/src/main/scala/ssh/SshServerListener.scala
+++ /dev/null
@@ -1,69 +0,0 @@
-package ssh
-
-import javax.servlet.{ServletContextEvent, ServletContextListener}
-import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider
-import org.slf4j.LoggerFactory
-import util.Directory
-import service.SystemSettingsService
-import java.util.concurrent.atomic.AtomicBoolean
-
-object SshServer {
- private val logger = LoggerFactory.getLogger(SshServer.getClass)
- private val server = org.apache.sshd.SshServer.setUpDefaultServer()
- private val active = new AtomicBoolean(false)
-
- private def configure(port: Int, baseUrl: String) = {
- server.setPort(port)
- server.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(s"${Directory.GitBucketHome}/gitbucket.ser"))
- server.setPublickeyAuthenticator(new PublicKeyAuthenticator)
- server.setCommandFactory(new GitCommandFactory(baseUrl))
- server.setShellFactory(new NoShell)
- }
-
- def start(port: Int, baseUrl: String) = {
- if(active.compareAndSet(false, true)){
- configure(port, baseUrl)
- server.start()
- logger.info(s"Start SSH Server Listen on ${server.getPort}")
- }
- }
-
- def stop() = {
- if(active.compareAndSet(true, false)){
- server.stop(true)
- logger.info("SSH Server is stopped.")
- }
- }
-
- def isActive = active.get
-}
-
-/*
- * Start a SSH Server Daemon
- *
- * How to use:
- * git clone ssh://username@host_or_ip:29418/owner/repository_name.git
- */
-class SshServerListener extends ServletContextListener with SystemSettingsService {
-
- private val logger = LoggerFactory.getLogger(classOf[SshServerListener])
-
- override def contextInitialized(sce: ServletContextEvent): Unit = {
- val settings = loadSystemSettings()
- if(settings.ssh){
- settings.baseUrl match {
- case None =>
- logger.error("Could not start SshServer because the baseUrl is not configured.")
- case Some(baseUrl) =>
- SshServer.start(settings.sshPort.getOrElse(SystemSettingsService.DefaultSshPort), baseUrl)
- }
- }
- }
-
- override def contextDestroyed(sce: ServletContextEvent): Unit = {
- if(loadSystemSettings().ssh){
- SshServer.stop()
- }
- }
-
-}
diff --git a/src/main/scala/ssh/SshUtil.scala b/src/main/scala/ssh/SshUtil.scala
deleted file mode 100644
index 9d6484c..0000000
--- a/src/main/scala/ssh/SshUtil.scala
+++ /dev/null
@@ -1,36 +0,0 @@
-package ssh
-
-import java.security.PublicKey
-import org.slf4j.LoggerFactory
-import org.apache.commons.codec.binary.Base64
-import org.eclipse.jgit.lib.Constants
-import org.apache.sshd.common.util.{KeyUtils, Buffer}
-
-object SshUtil {
-
- private val logger = LoggerFactory.getLogger(SshUtil.getClass)
-
- def str2PublicKey(key: String): Option[PublicKey] = {
- // TODO RFC 4716 Public Key is not supported...
- val parts = key.split(" ")
- if (parts.size < 2) {
- logger.debug(s"Invalid PublicKey Format: ${key}")
- return None
- }
- try {
- val encodedKey = parts(1)
- val decode = Base64.decodeBase64(Constants.encodeASCII(encodedKey))
- Some(new Buffer(decode).getRawPublicKey)
- } catch {
- case e: Throwable =>
- logger.debug(e.getMessage, e)
- None
- }
- }
-
- def fingerPrint(key: String): Option[String] = str2PublicKey(key) match {
- case Some(publicKey) => Some(KeyUtils.getFingerPrint(publicKey))
- case None => None
- }
-
-}
diff --git a/src/main/scala/util/Authenticator.scala b/src/main/scala/util/Authenticator.scala
deleted file mode 100644
index f40af7b..0000000
--- a/src/main/scala/util/Authenticator.scala
+++ /dev/null
@@ -1,181 +0,0 @@
-package util
-
-import app.ControllerBase
-import service._
-import RepositoryService.RepositoryInfo
-import util.Implicits._
-import util.ControlUtil._
-
-/**
- * Allows only oneself and administrators.
- */
-trait OneselfAuthenticator { self: ControllerBase =>
- protected def oneselfOnly(action: => Any) = { authenticate(action) }
- protected def oneselfOnly[T](action: T => Any) = (form: T) => { authenticate(action(form)) }
-
- private def authenticate(action: => Any) = {
- {
- defining(request.paths){ paths =>
- context.loginAccount match {
- case Some(x) if(x.isAdmin) => action
- case Some(x) if(paths(0) == x.userName) => action
- case _ => Unauthorized()
- }
- }
- }
- }
-}
-
-/**
- * Allows only the repository owner and administrators.
- */
-trait OwnerAuthenticator { self: ControllerBase with RepositoryService with AccountService =>
- protected def ownerOnly(action: (RepositoryInfo) => Any) = { authenticate(action) }
- protected def ownerOnly[T](action: (T, RepositoryInfo) => Any) = (form: T) => { authenticate(action(form, _)) }
-
- private def authenticate(action: (RepositoryInfo) => Any) = {
- {
- defining(request.paths){ paths =>
- getRepository(paths(0), paths(1), baseUrl).map { repository =>
- context.loginAccount match {
- case Some(x) if(x.isAdmin) => action(repository)
- case Some(x) if(repository.owner == x.userName) => action(repository)
- case Some(x) if(getGroupMembers(repository.owner).exists { member =>
- member.userName == x.userName && member.isManager == true
- }) => action(repository)
- case _ => Unauthorized()
- }
- } getOrElse NotFound()
- }
- }
- }
-}
-
-/**
- * Allows only signed in users.
- */
-trait UsersAuthenticator { self: ControllerBase =>
- protected def usersOnly(action: => Any) = { authenticate(action) }
- protected def usersOnly[T](action: T => Any) = (form: T) => { authenticate(action(form)) }
-
- private def authenticate(action: => Any) = {
- {
- context.loginAccount match {
- case Some(x) => action
- case None => Unauthorized()
- }
- }
- }
-}
-
-/**
- * Allows only administrators.
- */
-trait AdminAuthenticator { self: ControllerBase =>
- protected def adminOnly(action: => Any) = { authenticate(action) }
- protected def adminOnly[T](action: T => Any) = (form: T) => { authenticate(action(form)) }
-
- private def authenticate(action: => Any) = {
- {
- context.loginAccount match {
- case Some(x) if(x.isAdmin) => action
- case _ => Unauthorized()
- }
- }
- }
-}
-
-/**
- * Allows only collaborators and administrators.
- */
-trait CollaboratorsAuthenticator { self: ControllerBase with RepositoryService =>
- protected def collaboratorsOnly(action: (RepositoryInfo) => Any) = { authenticate(action) }
- protected def collaboratorsOnly[T](action: (T, RepositoryInfo) => Any) = (form: T) => { authenticate(action(form, _)) }
-
- private def authenticate(action: (RepositoryInfo) => Any) = {
- {
- defining(request.paths){ paths =>
- getRepository(paths(0), paths(1), baseUrl).map { repository =>
- context.loginAccount match {
- case Some(x) if(x.isAdmin) => action(repository)
- case Some(x) if(paths(0) == x.userName) => action(repository)
- case Some(x) if(getCollaborators(paths(0), paths(1)).contains(x.userName)) => action(repository)
- case _ => Unauthorized()
- }
- } getOrElse NotFound()
- }
- }
- }
-}
-
-/**
- * Allows only the repository owner (or manager for group repository) and administrators.
- */
-trait ReferrerAuthenticator { self: ControllerBase with RepositoryService =>
- protected def referrersOnly(action: (RepositoryInfo) => Any) = { authenticate(action) }
- protected def referrersOnly[T](action: (T, RepositoryInfo) => Any) = (form: T) => { authenticate(action(form, _)) }
-
- private def authenticate(action: (RepositoryInfo) => Any) = {
- {
- defining(request.paths){ paths =>
- getRepository(paths(0), paths(1), baseUrl).map { repository =>
- if(!repository.repository.isPrivate){
- action(repository)
- } else {
- context.loginAccount match {
- case Some(x) if(x.isAdmin) => action(repository)
- case Some(x) if(paths(0) == x.userName) => action(repository)
- case Some(x) if(getCollaborators(paths(0), paths(1)).contains(x.userName)) => action(repository)
- case _ => Unauthorized()
- }
- }
- } getOrElse NotFound()
- }
- }
- }
-}
-
-/**
- * Allows only signed in users which can access the repository.
- */
-trait ReadableUsersAuthenticator { self: ControllerBase with RepositoryService =>
- protected def readableUsersOnly(action: (RepositoryInfo) => Any) = { authenticate(action) }
- protected def readableUsersOnly[T](action: (T, RepositoryInfo) => Any) = (form: T) => { authenticate(action(form, _)) }
-
- private def authenticate(action: (RepositoryInfo) => Any) = {
- {
- defining(request.paths){ paths =>
- getRepository(paths(0), paths(1), baseUrl).map { repository =>
- context.loginAccount match {
- case Some(x) if(x.isAdmin) => action(repository)
- case Some(x) if(!repository.repository.isPrivate) => action(repository)
- case Some(x) if(paths(0) == x.userName) => action(repository)
- case Some(x) if(getCollaborators(paths(0), paths(1)).contains(x.userName)) => action(repository)
- case _ => Unauthorized()
- }
- } getOrElse NotFound()
- }
- }
- }
-}
-
-/**
- * Allows only the group managers.
- */
-trait GroupManagerAuthenticator { self: ControllerBase with AccountService =>
- protected def managersOnly(action: => Any) = { authenticate(action) }
- protected def managersOnly[T](action: T => Any) = (form: T) => { authenticate(action(form)) }
-
- private def authenticate(action: => Any) = {
- {
- defining(request.paths){ paths =>
- context.loginAccount match {
- case Some(x) if(getGroupMembers(paths(0)).exists { member =>
- member.userName == x.userName && member.isManager
- }) => action
- case _ => Unauthorized()
- }
- }
- }
- }
-}
diff --git a/src/main/scala/util/ControlUtil.scala b/src/main/scala/util/ControlUtil.scala
deleted file mode 100644
index 7945f32..0000000
--- a/src/main/scala/util/ControlUtil.scala
+++ /dev/null
@@ -1,46 +0,0 @@
-package util
-
-import org.eclipse.jgit.api.Git
-import org.eclipse.jgit.revwalk.RevWalk
-import org.eclipse.jgit.treewalk.TreeWalk
-import scala.util.control.Exception._
-import scala.language.reflectiveCalls
-
-/**
- * Provides control facilities.
- */
-object ControlUtil {
-
- def defining[A, B](value: A)(f: A => B): B = f(value)
-
- def using[A <% { def close(): Unit }, B](resource: A)(f: A => B): B =
- try f(resource) finally {
- if(resource != null){
- ignoring(classOf[Throwable]) {
- resource.close()
- }
- }
- }
-
- def using[T](git: Git)(f: Git => T): T =
- try f(git) finally git.getRepository.close()
-
- def using[T](git1: Git, git2: Git)(f: (Git, Git) => T): T =
- try f(git1, git2) finally {
- git1.getRepository.close()
- git2.getRepository.close()
- }
-
- def using[T](revWalk: RevWalk)(f: RevWalk => T): T =
- try f(revWalk) finally revWalk.release()
-
- def using[T](treeWalk: TreeWalk)(f: TreeWalk => T): T =
- try f(treeWalk) finally treeWalk.release()
-
- def ignore[T](f: => Unit): Unit = try {
- f
- } catch {
- case e: Exception => ()
- }
-
-}
diff --git a/src/main/scala/util/DatabaseConfig.scala b/src/main/scala/util/DatabaseConfig.scala
deleted file mode 100644
index 86453e3..0000000
--- a/src/main/scala/util/DatabaseConfig.scala
+++ /dev/null
@@ -1,19 +0,0 @@
-package util
-
-import com.typesafe.config.ConfigFactory
-import util.Directory.DatabaseHome
-
-object DatabaseConfig {
-
- private val config = ConfigFactory.load("database")
- private val dbUrl = config.getString("db.url")
-
- def url(directory: Option[String]): String =
- dbUrl.replace("${DatabaseHome}", directory.getOrElse(DatabaseHome))
-
- val url: String = url(None)
- val user: String = config.getString("db.user")
- val password: String = config.getString("db.password")
- val driver: String = config.getString("db.driver")
-
-}
diff --git a/src/main/scala/util/Directory.scala b/src/main/scala/util/Directory.scala
deleted file mode 100644
index 9008171..0000000
--- a/src/main/scala/util/Directory.scala
+++ /dev/null
@@ -1,87 +0,0 @@
-package util
-
-import java.io.File
-import util.ControlUtil._
-import org.apache.commons.io.FileUtils
-
-/**
- * Provides directories used by GitBucket.
- */
-object Directory {
-
- val GitBucketHome = (System.getProperty("gitbucket.home") match {
- // -Dgitbucket.home=")
- var text: String = node.getText
- while (text.charAt(0) == '\n') {
- printer.print("
")
- text = text.substring(1)
- }
- printer.printEncoded(text)
- printer.print("")
- }
-}
-
-class GitBucketHtmlSerializer(
- markdown: String,
- repository: service.RepositoryService.RepositoryInfo,
- enableWikiLink: Boolean,
- enableRefsLink: Boolean,
- enableTaskList: Boolean,
- hasWritePermission: Boolean,
- pages: List[String]
- )(implicit val context: app.Context) extends ToHtmlSerializer(
- new GitBucketLinkRender(context, repository, enableWikiLink, pages),
- Map[String, VerbatimSerializer](VerbatimSerializer.DEFAULT -> new GitBucketVerbatimSerializer).asJava
- ) with LinkConverter with RequestCache {
-
- override protected def printImageTag(imageNode: SuperNode, url: String): Unit = {
- printer.print("")
- .print("${value.body.trim.split("\n").map(_.trim).mkString("\n")}")
-
- /**
- * Implicit conversion to add mkHtml() to Seq[Html].
- */
- implicit class RichHtmlSeq(seq: Seq[Html]) {
- def mkHtml(separator: String) = Html(seq.mkString(separator))
- def mkHtml(separator: scala.xml.Elem) = Html(seq.mkString(separator.toString))
- }
-
- def commitStateIcon(state: CommitState) = Html(state match {
- case CommitState.PENDING => "●"
- case CommitState.SUCCESS => "✔"
- case CommitState.ERROR => "×"
- case CommitState.FAILURE => "×"
- })
-
- def commitStateText(state: CommitState, commitId:String) = state match {
- case CommitState.PENDING => "Waiting to hear about "+commitId.substring(0,8)
- case CommitState.SUCCESS => "All is well"
- case CommitState.ERROR => "Failed"
- case CommitState.FAILURE => "Failed"
- }
-}
diff --git a/src/main/twirl/account/activity.scala.html b/src/main/twirl/account/activity.scala.html
deleted file mode 100644
index ca4c3c7..0000000
--- a/src/main/twirl/account/activity.scala.html
+++ /dev/null
@@ -1,9 +0,0 @@
-@(account: model.Account, groupNames: List[String], activities: List[model.Activity])(implicit context: app.Context)
-@import context._
-@import view.helpers._
-@main(account, groupNames, "activity"){
-
- @helper.html.activities(activities)
-}
diff --git a/src/main/twirl/account/application.scala.html b/src/main/twirl/account/application.scala.html
deleted file mode 100644
index e6a5d06..0000000
--- a/src/main/twirl/account/application.scala.html
+++ /dev/null
@@ -1,55 +0,0 @@
-@(account: model.Account, personalTokens: List[model.AccessToken], gneratedToken:Option[(model.AccessToken, String)])(implicit context: app.Context)
-@import context._
-@import view.helpers._
-@html.main("Applications"){
-|
-
-
- @avatar(account.userName, 20)
- @account.userName
- @if(account.isGroupAccount){
- (Group)
- } else {
- @if(account.isAdmin){
- (Administrator)
- } else {
- (Normal)
- }
- }
- @if(account.isGroupAccount){
- @members(account.userName).map { userName =>
- @avatar(userName, 20, tooltip = true)
- }
- }
-
-
-
- - @if(!account.isGroupAccount){ - @account.mailAddress - } - @account.url.map { url => - @url - } -
- Registered: @datetime(account.registeredDate)
- Updated: @datetime(account.updatedDate)
- @if(!account.isGroupAccount){
- Last Login: @account.lastLoginDate.map(datetime)
- }
-
- |
-
| - @dashboard.html.header(openCount, closedCount, condition, groups) - | -
|---|
- @if(issue.isPullRequest){
- @commentCount
-
- } else {
-
- @commentCount
-
- }
-
-
- #@issue.issueId opened by @user(issue.openedUserName, styleClass="username") @datetime(issue.registeredDate)
- @milestone.map { milestone =>
-
- @milestone
- }
- |
-
|
+
+
+ @avatar(account.userName, 20)
+ @account.userName
+ @if(account.isGroupAccount){
+ (Group)
+ } else {
+ @if(account.isAdmin){
+ (Administrator)
+ } else {
+ (Normal)
+ }
+ }
+ @if(account.isGroupAccount){
+ @members(account.userName).map { userName =>
+ @avatar(userName, 20, tooltip = true)
+ }
+ }
+
+
+
+ + @if(!account.isGroupAccount){ + @account.mailAddress + } + @account.url.map { url => + @url + } +
+ Registered: @datetime(account.registeredDate)
+ Updated: @datetime(account.updatedDate)
+ @if(!account.isGroupAccount){
+ Last Login: @account.lastLoginDate.map(datetime)
+ }
+
+ |
+
| + @dashboard.html.header(openCount, closedCount, condition, groups) + | +
|---|
+ @if(issue.isPullRequest){
+ @commentCount
+
+ } else {
+
+ @commentCount
+
+ }
+
+
+ #@issue.issueId opened by @user(issue.openedUserName, styleClass="username") @datetime(issue.registeredDate)
+ @milestone.map { milestone =>
+
+ @milestone
+ }
+ |
+
+ @if(diff.changeType == ChangeType.COPY || diff.changeType == ChangeType.RENAME){
+ @diff.oldPath -> @diff.newPath
+ @if(newCommitId.isDefined){
+
+ }
+ }
+ @if(diff.changeType == ChangeType.ADD || diff.changeType == ChangeType.MODIFY){
+ @if(diff.changeType == ChangeType.ADD){
+
+ }else{
+
+ } @diff.newPath
+ @if(newCommitId.isDefined){
+
+ }
+ }
+ @if(diff.changeType == ChangeType.DELETE){
+ @diff.oldPath
+ @if(oldCommitId.isDefined){
+
+ }
+ }
+ |
+
|---|
| + @if(diff.newContent != None || diff.oldContent != None){ + + + + } else { + Not supported + } + | +
|
+
+ New repository
+
+ Your repositories (@userRepositories.size)
+ |
+
|---|
| No repositories | +
| + @helper.html.repositoryicon(repository, false) + @if(repository.owner == loginAccount.get.userName){ + @repository.name + } else { + @repository.owner/@repository.name + } + | +
| + Recent updated repositories + | +
|---|
| No repositories | +
| + @helper.html.repositoryicon(repository, false) + @repository.owner/@repository.name + | +
@pullreq.map(_.commitIdTo.substring(0, 7)) into
+ @if(pullreq.get.requestUserName == repository.owner){
+ @pullreq.map(_.branch) from @pullreq.map(_.requestBranch)
+ } else {
+ @pullreq.map(_.userName):@pullreq.map(_.branch) from @pullreq.map(_.requestUserName):@pullreq.map(_.requestBranch)
+ }
+ @helper.html.datetimeago(comment.registeredDate)
+
Due by @date(dueDate)
+ } else {
+ Due by @date(dueDate)
+ }
+ }.getOrElse {
+ No due date
+ }
+ | + @labels.size labels + | +
|---|
| + No labels to show. + @if(hasWritePermission){ + Create a new label. + } + | +
|
+
+
+
+
+ @helper.html.dropdown("Author", flat = true) {
+ @collaborators.map { collaborator =>
+
+ @if(hasWritePermission){
+
+ @helper.html.dropdown("Mark as", flat = true) {
+
+ }
+ |
+
|---|
| + @if(target == "issues"){ + No issues to show. + } else { + No pull requests to show. + } + @if(condition.labels.nonEmpty || condition.milestone.isDefined){ + Clear active filters. + } else { + @if(repository.isDefined){ + @if(target == "issues"){ + Create a new issue. + } else { + Create a new pull request. + } + } + } + | +
+ @if(hasWritePermission){
+
+ }
+ @commentCount
+
+ } else {
+
+ @commentCount
+
+ }
+
+
+ #@issue.issueId opened @helper.html.datetimeago(issue.registeredDate) by @user(issue.openedUserName, styleClass="username")
+ @milestone.map { milestone =>
+
+ @milestone
+ }
+ |
+
|
+
+
+ |
+
|---|
|
+
+
+ @if(milestone.description.isDefined){
+
+ @milestone.title
+
+
+ @if(milestone.closedDate.isDefined){
+ Closed @helper.html.datetimeago(milestone.closedDate.get)
+ } else {
+ @milestone.dueDate.map { dueDate =>
+ @if(isPast(dueDate)){
+
+ Due by @date(dueDate)
+ } else {
+ Due by @date(dueDate)
+ }
+ }.getOrElse {
+ No due date
+ }
+ }
+
+ @progress(openCount + closedCount, closedCount)
+
+
+
+
+ @if(closedCount == 0){
+ 0%
+ } else {
+ @((closedCount.toDouble / (openCount + closedCount).toDouble * 100).toInt)%
+ } complete
+ @openCount open
+ @closedCount closed
+
+
+
+ @markdown(milestone.description.get, repository, false, false)
+
+ }
+ |
+
| + No milestones to show. + @if(hasWritePermission){ + Create a new milestone. + } + | +
+ } else {
+
+
+ }
+ @if(expand){ @label}
+ @if(expand && count > 0){
+ @description
+ } + + } + @body +| @date(day.head.commitTime) | +|||
|---|---|---|---|
| + @avatar(commit, 20) + @user(commit.authorName, commit.authorEmailAddress, "username") + | +@commit.shortMessage | ++ @if(comments.isDefined){ + @comments.get.flatMap @{ + case comment: CommitComment => Some(comment) + case other => None + }.count(t => t.commitId == commit.id && !t.pullRequest) + } + | ++ @commit.id.substring(0, 7) + | +
+ There isn't anything to compare.+ @originRepository.owner:@originId and @forkedRepository.owner:@forkedId are identical. + |
+
Showing you all comments on commits in this comparison.
+ @issues.html.commentlist(None, comments, hasWritePermission, repository, None) + } + } +} + diff --git a/src/main/twirl/gitbucket/core/pulls/conversation.scala.html b/src/main/twirl/gitbucket/core/pulls/conversation.scala.html new file mode 100644 index 0000000..d005b40 --- /dev/null +++ b/src/main/twirl/gitbucket/core/pulls/conversation.scala.html @@ -0,0 +1,68 @@ +@(issue: gitbucket.core.model.Issue, + pullreq: gitbucket.core.model.PullRequest, + comments: List[gitbucket.core.model.Comment], + issueLabels: List[gitbucket.core.model.Label], + collaborators: List[String], + milestones: List[(gitbucket.core.model.Milestone, Int, Int)], + labels: List[gitbucket.core.model.Label], + hasWritePermission: Boolean, + repository: gitbucket.core.service.RepositoryService.RepositoryInfo)(implicit context: gitbucket.core.controller.Context) +@import context._ +@import gitbucket.core.view.helpers._ +@import gitbucket.core.model._ + +Don't worry, you can still submit the pull request.
+} else { +These branches can be automatically merged.
+} + diff --git a/src/main/twirl/gitbucket/core/pulls/mergeguide.scala.html b/src/main/twirl/gitbucket/core/pulls/mergeguide.scala.html new file mode 100644 index 0000000..f6c1d4a --- /dev/null +++ b/src/main/twirl/gitbucket/core/pulls/mergeguide.scala.html @@ -0,0 +1,153 @@ +@(hasConflict: Boolean, + hasProblem: Boolean, + issue: gitbucket.core.model.Issue, + pullreq: gitbucket.core.model.PullRequest, + statuses: List[model.CommitStatus], + repository: gitbucket.core.service.RepositoryService.RepositoryInfo, + requestRepositoryUrl: String)(implicit context: gitbucket.core.controller.Context) +@import context._ +@import gitbucket.core.view.helpers._ +@import model.CommitState +@pullreq.userName:@pullreq.branch from @pullreq.requestUserName:@pullreq.requestBranch
+ @helper.html.datetimeago(comment.registeredDate)
+
+ }.getOrElse {
+ Closed
+
+ @user(issue.openedUserName, styleClass="username strong") wants to merge @commits.size @plural(commits.size, "commit")
+ into @pullreq.userName:@pullreq.branch from @pullreq.requestUserName:@pullreq.requestBranch
+
+ }
+ } else {
+ Open
+
+ @user(issue.openedUserName, styleClass="username strong") wants to merge @commits.size @plural(commits.size, "commit")
+ into @pullreq.userName:@pullreq.branch from @pullreq.requestUserName:@pullreq.requestBranch
+
+ }
+ |
+
+ @avatar(latestCommit, 20)
+ @user(latestCommit.authorName, latestCommit.authorEmailAddress, "username strong")
+ @helper.html.datetimeago(latestCommit.commitTime)
+
+
+
+ |
+
|---|
|
+ @if(content.viewType == "text"){
+ @defining(pathList.reverse.head) { file =>
+ @if(renderableSuffixes.find(suffix => file.toLowerCase.endsWith(suffix))) {
+
+ @renderMarkup(pathList, content.content.get, branch, repository, false, false)
+
+ } else {
+ @content.content.get+ } + } + } + @if(content.viewType == "image"){ + |
+
| All branches | +
|---|
|
+
+ @branch.mergeInfo.map{ info =>
+ @prs.map{ case (pull, issue) =>
+ #@issue.issueId
+ @if(issue.closed) {
+ @if(info.isMerged){
+ Merged
+ }else{
+ Closed
+ }
+ } else {
+ Open
+ }
+ }.getOrElse{
+ @if(context.loginAccount.isDefined){
+ New Pull Request
+ }else{
+ Compare
+ }
+ }
+ @if(hasWritePermission){
+ @if(prs.map(!_._2.closed).getOrElse(false)){
+
+ }else{
+
+ }
+ }
+ }
+
+
+ @branch.name
+
+
+
+ @if(branch.mergeInfo.isEmpty){
+ Default
+ }else{
+ @branch.mergeInfo.map{ info =>
+
+ }
+ }
+
+
+
+
+ |
|
+
+ Browse code
+
+ @link(commit.summary, repository)
+ @if(commit.description.isDefined){
+ @link(commit.description.get, repository)+ } + + |
+
|---|
|
+
+
+
+
+
+ @if(commit.parents.size == 0){
+ 0 parent
+ }
+ @if(commit.parents.size == 1){
+ 1 parent
+ @commit.parents(0).substring(0, 7)
+ }
+ commit @commit.id
+
+ @if(commit.parents.size > 1){
+
+ @commit.parents.size parents
+ @commit.parents.map { parent =>
+ @parent.substring(0, 7)
+ }.mkHtml(" + ")
+
+
+ }
+ |
+
| @date(day.head.commitTime) | +
|---|
|
+
+
+
+ @avatar(commit, 40)
+
+ |
+
+ }
+ | + + @if(latestCommit.description.isDefined){ + ... + + } + | +|||
|---|---|---|---|
| + + | +|||
| + | .. | ++ | + |
+ @if(file.isDirectory){
+ @if(file.linkUrl.isDefined){
+
+ } else {
+
+ }
+ } else {
+
+ }
+ |
+ + @if(file.isDirectory){ + @if(file.linkUrl.isDefined){ + + @file.name.split("/").toList.init match { + case Nil => {} + case list => {@list.mkString("", "/", "/")} + }@file.name.split("/").toList.last + + } else { + + @file.name.split("/").toList.init match { + case Nil => {} + case list => {@list.mkString("", "/", "/")} + }@file.name.split("/").toList.last + + } + } else { + @file.name + } + | ++ + [@user(file.author, file.mailAddress)] + | +@helper.html.datetimeago(file.time, false) | +
| Tag | +Date | +Commit | +Download | +
|---|---|---|---|
| @tag.name | +@helper.html.datetimeago(tag.time, false) | +@tag.id.substring(0, 10) | ++ ZIP + TAR.GZ + | +
@Html(file.highlightText)+
@Html(issue.highlightText)+ } +
| + @if(systemSettings.allowAccountRegistration){ + + } + Sign in + | +
|---|
| + + | +
|
+ Revisions
+
+
+
+ |
+ ||
|---|---|---|
| + | @avatar(commit, 20) @user(commit.authorName, commit.authorEmailAddress) | ++ @helper.html.datetimeago(commit.authorTime): @commit.shortMessage + | +
| Pages @pages.length | +
|---|
+
|
+
- @if(diff.changeType == ChangeType.COPY || diff.changeType == ChangeType.RENAME){
- @diff.oldPath -> @diff.newPath
- @if(newCommitId.isDefined){
-
- }
- }
- @if(diff.changeType == ChangeType.ADD || diff.changeType == ChangeType.MODIFY){
- @if(diff.changeType == ChangeType.ADD){
-
- }else{
-
- } @diff.newPath
- @if(newCommitId.isDefined){
-
- }
- }
- @if(diff.changeType == ChangeType.DELETE){
- @diff.oldPath
- @if(oldCommitId.isDefined){
-
- }
- }
- |
-
|---|
| - @if(diff.newContent != None || diff.oldContent != None){ - - - - } else { - Not supported - } - | -
|
-
- New repository
-
- Your repositories (@userRepositories.size)
- |
-
|---|
| No repositories | -
| - @helper.html.repositoryicon(repository, false) - @if(repository.owner == loginAccount.get.userName){ - @repository.name - } else { - @repository.owner/@repository.name - } - | -
| - Recent updated repositories - | -
|---|
| No repositories | -
| - @helper.html.repositoryicon(repository, false) - @repository.owner/@repository.name - | -
@pullreq.map(_.commitIdTo.substring(0, 7)) into
- @if(pullreq.get.requestUserName == repository.owner){
- @pullreq.map(_.branch) from @pullreq.map(_.requestBranch)
- } else {
- @pullreq.map(_.userName):@pullreq.map(_.branch) from @pullreq.map(_.requestUserName):@pullreq.map(_.requestBranch)
- }
- @helper.html.datetimeago(comment.registeredDate)
-
Due by @date(dueDate)
- } else {
- Due by @date(dueDate)
- }
- }.getOrElse {
- No due date
- }
- | - @labels.size labels - | -
|---|
| - No labels to show. - @if(hasWritePermission){ - Create a new label. - } - | -
|
-
-
-
-
- @helper.html.dropdown("Author", flat = true) {
- @collaborators.map { collaborator =>
-
- @if(hasWritePermission){
-
- @helper.html.dropdown("Mark as", flat = true) {
-
- }
- |
-
|---|
| - @if(target == "issues"){ - No issues to show. - } else { - No pull requests to show. - } - @if(condition.labels.nonEmpty || condition.milestone.isDefined){ - Clear active filters. - } else { - @if(repository.isDefined){ - @if(target == "issues"){ - Create a new issue. - } else { - Create a new pull request. - } - } - } - | -
- @if(hasWritePermission){
-
- }
- @commentCount
-
- } else {
-
- @commentCount
-
- }
-
-
- #@issue.issueId opened @helper.html.datetimeago(issue.registeredDate) by @user(issue.openedUserName, styleClass="username")
- @milestone.map { milestone =>
-
- @milestone
- }
- |
-
|
-
-
- |
-
|---|
|
-
-
- @if(milestone.description.isDefined){
-
- @milestone.title
-
-
- @if(milestone.closedDate.isDefined){
- Closed @helper.html.datetimeago(milestone.closedDate.get)
- } else {
- @milestone.dueDate.map { dueDate =>
- @if(isPast(dueDate)){
-
- Due by @date(dueDate)
- } else {
- Due by @date(dueDate)
- }
- }.getOrElse {
- No due date
- }
- }
-
- @progress(openCount + closedCount, closedCount)
-
-
-
-
- @if(closedCount == 0){
- 0%
- } else {
- @((closedCount.toDouble / (openCount + closedCount).toDouble * 100).toInt)%
- } complete
- @openCount open
- @closedCount closed
-
-
-
- @markdown(milestone.description.get, repository, false, false)
-
- }
- |
-
| - No milestones to show. - @if(hasWritePermission){ - Create a new milestone. - } - | -
- } else {
-
-
- }
- @if(expand){ @label}
- @if(expand && count > 0){
- @description
- } - - } - @body -| @date(day.head.commitTime) | -|||
|---|---|---|---|
| - @avatar(commit, 20) - @user(commit.authorName, commit.authorEmailAddress, "username") - | -@commit.shortMessage | -- @if(comments.isDefined){ - @comments.get.flatMap @{ - case comment: model.CommitComment => Some(comment) - case other => None - }.count(t => t.commitId == commit.id && !t.pullRequest) - } - | -- @commit.id.substring(0, 7) - | -
- There isn't anything to compare.- @originRepository.owner:@originId and @forkedRepository.owner:@forkedId are identical. - |
-
Showing you all comments on commits in this comparison.
- @issues.html.commentlist(None, comments, hasWritePermission, repository, None) - } - } -} - diff --git a/src/main/twirl/pulls/conversation.scala.html b/src/main/twirl/pulls/conversation.scala.html deleted file mode 100644 index 82a8982..0000000 --- a/src/main/twirl/pulls/conversation.scala.html +++ /dev/null @@ -1,67 +0,0 @@ -@(issue: model.Issue, - pullreq: model.PullRequest, - comments: List[model.Comment], - issueLabels: List[model.Label], - collaborators: List[String], - milestones: List[(model.Milestone, Int, Int)], - labels: List[model.Label], - hasWritePermission: Boolean, - repository: service.RepositoryService.RepositoryInfo)(implicit context: app.Context) -@import context._ -@import model.{IssueComment, CommitState} -@import view.helpers._ -Don't worry, you can still submit the pull request.
-} else { -These branches can be automatically merged.
-} - diff --git a/src/main/twirl/pulls/mergeguide.scala.html b/src/main/twirl/pulls/mergeguide.scala.html deleted file mode 100644 index 21733ad..0000000 --- a/src/main/twirl/pulls/mergeguide.scala.html +++ /dev/null @@ -1,154 +0,0 @@ -@(hasConflict: Boolean, - hasProblem: Boolean, - issue: model.Issue, - pullreq: model.PullRequest, - statuses: List[model.CommitStatus], - repository: service.RepositoryService.RepositoryInfo, - requestRepositoryUrl: String)(implicit context: app.Context) -@import context._ -@import view.helpers._ -@import model.CommitState -@pullreq.userName:@pullreq.branch from @pullreq.requestUserName:@pullreq.requestBranch
- @helper.html.datetimeago(comment.registeredDate)
-
- }.getOrElse {
- Closed
-
- @user(issue.openedUserName, styleClass="username strong") wants to merge @commits.size @plural(commits.size, "commit")
- into @pullreq.userName:@pullreq.branch from @pullreq.requestUserName:@pullreq.requestBranch
-
- }
- } else {
- Open
-
- @user(issue.openedUserName, styleClass="username strong") wants to merge @commits.size @plural(commits.size, "commit")
- into @pullreq.userName:@pullreq.branch from @pullreq.requestUserName:@pullreq.requestBranch
-
- }
- |
-
- @avatar(latestCommit, 20)
- @user(latestCommit.authorName, latestCommit.authorEmailAddress, "username strong")
- @helper.html.datetimeago(latestCommit.commitTime)
-
-
-
- |
-
|---|
|
- @if(content.viewType == "text"){
- @defining(pathList.reverse.head) { file =>
- @if(renderableSuffixes.find(suffix => file.toLowerCase.endsWith(suffix))) {
-
- @renderMarkup(pathList, content.content.get, branch, repository, false, false)
-
- } else {
- @content.content.get- } - } - } - @if(content.viewType == "image"){ - |
-
| All branches | -
|---|
|
-
- @branch.mergeInfo.map{ info =>
- @prs.map{ case (pull, issue) =>
- #@issue.issueId
- @if(issue.closed) {
- @if(info.isMerged){
- Merged
- }else{
- Closed
- }
- } else {
- Open
- }
- }.getOrElse{
- @if(context.loginAccount.isDefined){
- New Pull Request
- }else{
- Compare
- }
- }
- @if(hasWritePermission){
- @if(prs.map(!_._2.closed).getOrElse(false)){
-
- }else{
-
- }
- }
- }
-
-
- @branch.name
-
-
-
- @if(branch.mergeInfo.isEmpty){
- Default
- }else{
- @branch.mergeInfo.map{ info =>
-
- }
- }
-
-
-
-
- |
|
-
- Browse code
-
- @link(commit.summary, repository)
- @if(commit.description.isDefined){
- @link(commit.description.get, repository)- } - - |
-
|---|
|
-
-
-
-
-
- @if(commit.parents.size == 0){
- 0 parent
- }
- @if(commit.parents.size == 1){
- 1 parent
- @commit.parents(0).substring(0, 7)
- }
- commit @commit.id
-
- @if(commit.parents.size > 1){
-
- @commit.parents.size parents
- @commit.parents.map { parent =>
- @parent.substring(0, 7)
- }.mkHtml(" + ")
-
-
- }
- |
-
| @date(day.head.commitTime) | -
|---|
|
-
-
-
- @avatar(commit, 40)
-
- |
-
- }
- | - - @if(latestCommit.description.isDefined){ - ... - - } - | -|||
|---|---|---|---|
| - - | -|||
| - | .. | -- | - |
- @if(file.isDirectory){
- @if(file.linkUrl.isDefined){
-
- } else {
-
- }
- } else {
-
- }
- |
- - @if(file.isDirectory){ - @if(file.linkUrl.isDefined){ - - @file.name.split("/").toList.init match { - case Nil => {} - case list => {@list.mkString("", "/", "/")} - }@file.name.split("/").toList.last - - } else { - - @file.name.split("/").toList.init match { - case Nil => {} - case list => {@list.mkString("", "/", "/")} - }@file.name.split("/").toList.last - - } - } else { - @file.name - } - | -- - [@user(file.author, file.mailAddress)] - | -@helper.html.datetimeago(file.time, false) | -
| Tag | -Date | -Commit | -Download | -
|---|---|---|---|
| @tag.name | -@helper.html.datetimeago(tag.time, false) | -@tag.id.substring(0, 10) | -- ZIP - TAR.GZ - | -
@Html(file.highlightText)-
@Html(issue.highlightText)- } -
| - @if(systemSettings.allowAccountRegistration){ - - } - Sign in - | -
|---|
| - - | -
|
- Revisions
-
-
-
- |
- ||
|---|---|---|
| - | @avatar(commit, 20) @user(commit.authorName, commit.authorEmailAddress) | -- @helper.html.datetimeago(commit.authorTime): @commit.shortMessage - | -
| Pages @pages.length | -
|---|
-
|
-