diff --git a/src/main/resources/update/gitbucket-core_4.7.sql b/src/main/resources/update/gitbucket-core_4.7.sql
new file mode 100644
index 0000000..ef13c70
--- /dev/null
+++ b/src/main/resources/update/gitbucket-core_4.7.sql
@@ -0,0 +1,2 @@
+-- DELETE COLLABORATORS IN GROUP REPOSITORIES
+DELETE FROM COLLABORATOR WHERE USER_NAME IN (SELECT USER_NAME FROM ACCOUNT WHERE GROUP_ACCOUNT = TRUE)
diff --git a/src/main/resources/update/gitbucket-core_4.7.xml b/src/main/resources/update/gitbucket-core_4.7.xml
new file mode 100644
index 0000000..c46a28e
--- /dev/null
+++ b/src/main/resources/update/gitbucket-core_4.7.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/main/scala/gitbucket/core/GitBucketCoreModule.scala b/src/main/scala/gitbucket/core/GitBucketCoreModule.scala
index 6830d2d..c04a687 100644
--- a/src/main/scala/gitbucket/core/GitBucketCoreModule.scala
+++ b/src/main/scala/gitbucket/core/GitBucketCoreModule.scala
@@ -18,5 +18,9 @@
new Version("4.5.0"),
new Version("4.6.0",
new LiquibaseMigration("update/gitbucket-core_4.6.xml")
+ ),
+ new Version("4.7.0",
+ new LiquibaseMigration("update/gitbucket-core_4.7.xml"),
+ new SqlMigration("update/gitbucket-core_4.7.sql")
)
)
diff --git a/src/main/scala/gitbucket/core/controller/IndexController.scala b/src/main/scala/gitbucket/core/controller/IndexController.scala
index 6bc2751..c5a17bc 100644
--- a/src/main/scala/gitbucket/core/controller/IndexController.scala
+++ b/src/main/scala/gitbucket/core/controller/IndexController.scala
@@ -109,7 +109,11 @@
get("/_user/proposals")(usersOnly {
contentType = formats("json")
org.json4s.jackson.Serialization.write(
- Map("options" -> getAllUsers(false).filter(!_.isGroupAccount).map(_.userName).toArray)
+ Map("options" -> (if(params.get("userOnly").isDefined) {
+ getAllUsers(false).filter(!_.isGroupAccount).map(_.userName).toArray
+ } else {
+ getAllUsers(false).map(_.userName).toArray
+ }))
)
})
diff --git a/src/main/scala/gitbucket/core/controller/RepositorySettingsController.scala b/src/main/scala/gitbucket/core/controller/RepositorySettingsController.scala
index 41455cc..cceb9a6 100644
--- a/src/main/scala/gitbucket/core/controller/RepositorySettingsController.scala
+++ b/src/main/scala/gitbucket/core/controller/RepositorySettingsController.scala
@@ -182,7 +182,7 @@
* Add the collaborator.
*/
post("/:owner/:repository/settings/collaborators/add", collaboratorForm)(ownerOnly { (form, repository) =>
- if(!getAccountByUserName(repository.owner).get.isGroupAccount){
+ getAccountByUserName(repository.owner).foreach { _ =>
addCollaborator(repository.owner, repository.name, form.userName)
}
redirect(s"/${repository.owner}/${repository.name}/settings/collaborators")
@@ -192,9 +192,7 @@
* Add the collaborator.
*/
get("/:owner/:repository/settings/collaborators/remove")(ownerOnly { repository =>
- if(!getAccountByUserName(repository.owner).get.isGroupAccount){
- removeCollaborator(repository.owner, repository.name, params("name"))
- }
+ removeCollaborator(repository.owner, repository.name, params("name"))
redirect(s"/${repository.owner}/${repository.name}/settings/collaborators")
})
@@ -404,10 +402,10 @@
override def validate(name: String, value: String, messages: Messages): Option[String] =
getAccountByUserName(value) match {
case None => Some("User does not exist.")
- case Some(x) if(x.isGroupAccount)
- => Some("User does not exist.")
+// case Some(x) if(x.isGroupAccount)
+// => Some("User does not exist.")
case Some(x) if(x.userName == params("owner") || getCollaborators(params("owner"), params("repository")).contains(x.userName))
- => Some("User can access this repository already.")
+ => Some(value + " is repository owner.") // TODO also group members?
case _ => None
}
}
diff --git a/src/main/scala/gitbucket/core/service/RepositoryService.scala b/src/main/scala/gitbucket/core/service/RepositoryService.scala
index 3541c07..fef9897 100644
--- a/src/main/scala/gitbucket/core/service/RepositoryService.scala
+++ b/src/main/scala/gitbucket/core/service/RepositoryService.scala
@@ -337,49 +337,53 @@
.update (defaultBranch)
/**
- * Add collaborator to the repository.
- *
- * @param userName the user name of the repository owner
- * @param repositoryName the repository name
- * @param collaboratorName the collaborator name
+ * Add collaborator (user or group) to the repository.
*/
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
+ * Remove collaborator (user or group) from the repository.
*/
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
+ * Returns the list of collaborators name (user name or group name) which is sorted with ascending order.
*/
def getCollaborators(userName: String, repositoryName: String)(implicit s: Session): List[String] =
Collaborators.filter(_.byRepository(userName, repositoryName)).sortBy(_.collaboratorName).map(_.collaboratorName).list
+ /**
+ * Returns the list of all collaborator name and permission which is sorted with ascending order.
+ * If a group is added as a collaborator, this method returns users who are belong to that group.
+ */
+ def getCollaboratorUserNames(userName: String, repositoryName: String, filter: Seq[String] = Nil)(implicit s: Session): List[(String, String)] = {
+ val q1 = Collaborators.filter(_.byRepository(userName, repositoryName))
+ .innerJoin(Accounts).on { case (t1, t2) => (t1.collaboratorName === t2.userName) && (t2.groupAccount === false.bind) }
+ .map { case (t1, t2) => (t1.collaboratorName, "ADMIN") }
+
+ val q2 = Collaborators.filter(_.byRepository(userName, repositoryName))
+ .innerJoin(Accounts).on { case (t1, t2) => (t1.collaboratorName === t2.userName) && (t2.groupAccount === true.bind) }
+ .innerJoin(GroupMembers).on { case ((t1, t2), t3) => t2.userName === t3.groupName }
+ .map { case ((t1, t2), t3) => (t3.userName, "ADMIN") }
+
+ q1.union(q2).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 Some(a) if(getGroupMembers(owner).exists(_.userName == a.userName)) => true
+ case Some(a) if(getCollaboratorUserNames(owner, repository).contains((a.userName, "ADMIN"))) => true // TODO ADMIN|WRITE
case _ => false
}
}
diff --git a/src/main/scala/gitbucket/core/util/Authenticator.scala b/src/main/scala/gitbucket/core/util/Authenticator.scala
index 0035494..ca1c394 100644
--- a/src/main/scala/gitbucket/core/util/Authenticator.scala
+++ b/src/main/scala/gitbucket/core/util/Authenticator.scala
@@ -1,11 +1,13 @@
package gitbucket.core.util
import gitbucket.core.controller.ControllerBase
-import gitbucket.core.service.{RepositoryService, AccountService}
+import gitbucket.core.service.{AccountService, RepositoryService}
import RepositoryService.RepositoryInfo
import Implicits._
import ControlUtil._
+import scala.collection.Searching.search
+
/**
* Allows only oneself and administrators.
*/
@@ -40,9 +42,9 @@
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)
+ // TODO Repository management is allowed for only group managers?
+ case Some(x) if(getGroupMembers(repository.owner).exists { m => m.userName == x.userName && m.isManager == true }) => action(repository)
+ case Some(x) if(getCollaboratorUserNames(paths(0), paths(1), Seq("ADMIN")).exists(_._1 == x.userName)) => action(repository)
case _ => Unauthorized()
}
} getOrElse NotFound()
@@ -88,7 +90,7 @@
/**
* Allows only collaborators and administrators.
*/
-trait CollaboratorsAuthenticator { self: ControllerBase with RepositoryService =>
+trait CollaboratorsAuthenticator { self: ControllerBase with RepositoryService with AccountService =>
protected def collaboratorsOnly(action: (RepositoryInfo) => Any) = { authenticate(action) }
protected def collaboratorsOnly[T](action: (T, RepositoryInfo) => Any) = (form: T) => { authenticate(action(form, _)) }
@@ -99,7 +101,8 @@
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 Some(x) if(getGroupMembers(repository.owner).exists(_.userName == x.userName)) => action(repository)
+ case Some(x) if(getCollaboratorUserNames(paths(0), paths(1), Seq("ADMIN", "WRITE")).exists(_._1 == x.userName)) => action(repository)
case _ => Unauthorized()
}
} getOrElse NotFound()
@@ -109,9 +112,9 @@
}
/**
- * Allows only the repository owner (or manager for group repository) and administrators.
+ * Allows only guests and signed in users who can access the repository.
*/
-trait ReferrerAuthenticator { self: ControllerBase with RepositoryService =>
+trait ReferrerAuthenticator { self: ControllerBase with RepositoryService with AccountService =>
protected def referrersOnly(action: (RepositoryInfo) => Any) = { authenticate(action) }
protected def referrersOnly[T](action: (T, RepositoryInfo) => Any) = (form: T) => { authenticate(action(form, _)) }
@@ -125,7 +128,8 @@
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 Some(x) if(getGroupMembers(repository.owner).exists(_.userName == x.userName)) => action(repository)
+ case Some(x) if(getCollaboratorUserNames(paths(0), paths(1)).exists(_._1 == x.userName)) => action(repository)
case _ => Unauthorized()
}
}
@@ -136,9 +140,9 @@
}
/**
- * Allows only signed in users which can access the repository.
+ * Allows only signed in users who can access the repository.
*/
-trait ReadableUsersAuthenticator { self: ControllerBase with RepositoryService =>
+trait ReadableUsersAuthenticator { self: ControllerBase with RepositoryService with AccountService =>
protected def readableUsersOnly(action: (RepositoryInfo) => Any) = { authenticate(action) }
protected def readableUsersOnly[T](action: (T, RepositoryInfo) => Any) = (form: T) => { authenticate(action(form, _)) }
@@ -150,7 +154,8 @@
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 Some(x) if(getGroupMembers(repository.owner).exists(_.userName == x.userName)) => action(repository)
+ case Some(x) if(getCollaboratorUserNames(paths(0), paths(1)).exists(_._1 == x.userName)) => action(repository)
case _ => Unauthorized()
}
} getOrElse NotFound()
diff --git a/src/main/twirl/gitbucket/core/helper/account.scala.html b/src/main/twirl/gitbucket/core/helper/account.scala.html
index e3dc42c..8fa8907 100644
--- a/src/main/twirl/gitbucket/core/helper/account.scala.html
+++ b/src/main/twirl/gitbucket/core/helper/account.scala.html
@@ -1,4 +1,4 @@
-@(id: String, width: Int)(implicit context: gitbucket.core.controller.Context)
+@(id: String, width: Int, userOnly: Boolean = true)(implicit context: gitbucket.core.controller.Context)
@@ -6,7 +6,7 @@
$(function(){
$('#@id').typeahead({
source: function (query, process) {
- return $.get('@context.path/_user/proposals', { query: query },
+ return $.get('@context.path/_user/proposals@if(userOnly){?userOnly}', { query: query },
function (data) {
return process(data.options);
});
diff --git a/src/main/twirl/gitbucket/core/settings/collaborators.scala.html b/src/main/twirl/gitbucket/core/settings/collaborators.scala.html
index 21c8423..83116e8 100644
--- a/src/main/twirl/gitbucket/core/settings/collaborators.scala.html
+++ b/src/main/twirl/gitbucket/core/settings/collaborators.scala.html
@@ -10,25 +10,17 @@
@collaborators.map { collaboratorName =>
@collaboratorName
- @if(!isGroupRepository){
- (remove)
- } else {
- @if(repository.managers.contains(collaboratorName)){
- (Manager)
- }
- }
+ (remove)
}
- @if(!isGroupRepository){
- }
}
}
}