mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-08 06:25:51 +01:00
(refs #1286) Prototyping of new permission system
This commit is contained in:
2
src/main/resources/update/gitbucket-core_4.7.sql
Normal file
2
src/main/resources/update/gitbucket-core_4.7.sql
Normal file
@@ -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)
|
||||
9
src/main/resources/update/gitbucket-core_4.7.xml
Normal file
9
src/main/resources/update/gitbucket-core_4.7.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<changeSet>
|
||||
<addColumn tableName="COLLABORATOR">
|
||||
<column name="PERMISSION" type="varchar(10)" nullable="false" defaultValue="ADMIN"/>
|
||||
</addColumn>
|
||||
<addColumn tableName="REPOSITORY">
|
||||
<column name="ALLOW_CREATE_ISSUE" type="boolean" nullable="false" defaultValueBoolean="false"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
@@ -18,5 +18,9 @@ object GitBucketCoreModule extends Module("gitbucket-core",
|
||||
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")
|
||||
)
|
||||
)
|
||||
|
||||
@@ -109,7 +109,11 @@ trait IndexControllerBase extends ControllerBase {
|
||||
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
|
||||
}))
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
@@ -182,7 +182,7 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
||||
* 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 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
||||
* Add the collaborator.
|
||||
*/
|
||||
get("/:owner/:repository/settings/collaborators/remove")(ownerOnly { repository =>
|
||||
if(!getAccountByUserName(repository.owner).get.isGroupAccount){
|
||||
removeCollaborator(repository.owner, repository.name, params("name"))
|
||||
}
|
||||
redirect(s"/${repository.owner}/${repository.name}/settings/collaborators")
|
||||
})
|
||||
|
||||
@@ -404,10 +402,10 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,49 +337,53 @@ trait RepositoryService { self: AccountService =>
|
||||
.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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 @@ trait OwnerAuthenticator { self: ControllerBase with RepositoryService with Acco
|
||||
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 @@ trait AdminAuthenticator { self: ControllerBase =>
|
||||
/**
|
||||
* 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 @@ trait CollaboratorsAuthenticator { self: ControllerBase with RepositoryService =
|
||||
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 @@ trait CollaboratorsAuthenticator { self: ControllerBase with RepositoryService =
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ trait ReferrerAuthenticator { self: ControllerBase with RepositoryService =>
|
||||
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 @@ trait ReferrerAuthenticator { self: ControllerBase with RepositoryService =>
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ trait ReadableUsersAuthenticator { self: ControllerBase with RepositoryService =
|
||||
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()
|
||||
|
||||
@@ -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)
|
||||
<span style="margin-right: 0px;">
|
||||
<input type="text" name="@id" id="@id" class="form-control" autocomplete="off" style="width: @{width}px; margin-bottom: 0px; display: inline; vertical-align: middle;"/>
|
||||
</span>
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -10,25 +10,17 @@
|
||||
@collaborators.map { collaboratorName =>
|
||||
<li>
|
||||
<a href="@helpers.url(collaboratorName)">@collaboratorName</a>
|
||||
@if(!isGroupRepository){
|
||||
<a href="@helpers.url(repository)/settings/collaborators/remove?name=@collaboratorName" class="remove">(remove)</a>
|
||||
} else {
|
||||
@if(repository.managers.contains(collaboratorName)){
|
||||
(Manager)
|
||||
}
|
||||
}
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
@if(!isGroupRepository){
|
||||
<form method="POST" action="@helpers.url(repository)/settings/collaborators/add" validate="true" autocomplete="off">
|
||||
<div>
|
||||
<span class="error" id="error-userName"></span>
|
||||
</div>
|
||||
@gitbucket.core.helper.html.account("userName", 300)
|
||||
@gitbucket.core.helper.html.account("userName", 300, false)
|
||||
<input type="submit" class="btn btn-default" value="Add"/>
|
||||
</form>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user