diff --git a/src/main/resources/update/1_12.sql b/src/main/resources/update/1_12.sql new file mode 100644 index 0000000..0030169 --- /dev/null +++ b/src/main/resources/update/1_12.sql @@ -0,0 +1 @@ +ALTER TABLE GROUP_MEMBER ADD COLUMN MANAGER BOOLEAN DEFAULT FALSE; \ No newline at end of file diff --git a/src/main/scala/app/AccountController.scala b/src/main/scala/app/AccountController.scala index 7fc3589..e1c293f 100644 --- a/src/main/scala/app/AccountController.scala +++ b/src/main/scala/app/AccountController.scala @@ -53,8 +53,8 @@ // Members case "members" if(account.isGroupAccount) => { val members = getGroupMembers(account.userName) - _root_.account.html.members(account, members, - context.loginAccount.exists(x => members.contains(x.userName))) + _root_.account.html.members(account, members.map(_._1), + context.loginAccount.exists(x => members.exists { case (userName, isManager) => userName == x.userName && isManager })) } // Repositories @@ -63,7 +63,7 @@ _root_.account.html.repositories(account, if(account.isGroupAccount) Nil else getGroupsByUserName(userName), getVisibleRepositories(context.loginAccount, baseUrl, Some(userName)), - context.loginAccount.exists(x => members.contains(x.userName))) + context.loginAccount.exists(x => members.exists { case (userName, isManager) => userName == x.userName && isManager })) } } } getOrElse NotFound diff --git a/src/main/scala/app/CreateController.scala b/src/main/scala/app/CreateController.scala index ccfd37b..7b2acbb 100644 --- a/src/main/scala/app/CreateController.scala +++ b/src/main/scala/app/CreateController.scala @@ -13,14 +13,14 @@ class CreateController extends CreateControllerBase with RepositoryService with AccountService with WikiService with LabelsService with ActivityService - with UsersAuthenticator with ReadableUsersAuthenticator with GroupMemberAuthenticator + with UsersAuthenticator with ReadableUsersAuthenticator with GroupManagerAuthenticator /** * Creates new repository or group. */ trait CreateControllerBase extends AccountManagementControllerBase { self: RepositoryService with AccountService with WikiService with LabelsService with ActivityService - with UsersAuthenticator with ReadableUsersAuthenticator with GroupMemberAuthenticator => + with UsersAuthenticator with ReadableUsersAuthenticator with GroupManagerAuthenticator => case class RepositoryCreationForm(owner: String, name: String, description: Option[String], isPrivate: Boolean, createReadme: Boolean) @@ -84,7 +84,7 @@ // Add collaborators for group repository if(ownerAccount.isGroupAccount){ - getGroupMembers(form.owner).foreach { userName => + getGroupMembers(form.owner).foreach { case (userName, isManager) => addCollaborator(form.owner, form.name, userName) } } @@ -202,19 +202,27 @@ post("/groups/new", newGroupForm)(usersOnly { form => createGroup(form.groupName, form.url) - updateGroupMembers(form.groupName, form.memberNames.map(_.split(",").toList).getOrElse(Nil)) + updateGroupMembers(form.groupName, form.memberNames.map(_.split(",").map { + _.split(":") match { + case Array(userName, isManager) => (userName, isManager.toBoolean) + } + }.toList).getOrElse(Nil)) updateImage(form.groupName, form.fileId, false) redirect(s"/${form.groupName}") }) - get("/:groupName/_edit")(membersOnly { + get("/:groupName/_edit")(managersOnly { defining(params("groupName")){ groupName => html.group(getAccountByUserName(groupName, true), getGroupMembers(groupName)) } }) - post("/:groupName/_edit", editGroupForm)(membersOnly { form => - defining(params("groupName"), form.memberNames.map(_.split(",").toList).getOrElse(Nil)){ case (groupName, memberNames) => + post("/:groupName/_edit", editGroupForm)(managersOnly { form => + defining(params("groupName"), form.memberNames.map(_.split(",").map { + _.split(":") match { + case Array(userName, isManager) => (userName, isManager.toBoolean) + } + }.toList).getOrElse(Nil)){ case (groupName, members) => getAccountByUserName(groupName, true).map { account => updateGroup(groupName, form.url, form.isRemoved) @@ -230,11 +238,11 @@ } } else { // Update GROUP_MEMBER - updateGroupMembers(form.groupName, memberNames) + updateGroupMembers(form.groupName, members) // Update COLLABORATOR for group repositories getRepositoryNamesOfUser(form.groupName).foreach { repositoryName => removeCollaborators(form.groupName, repositoryName) - memberNames.foreach { userName => + members.foreach { case (userName, isManager) => addCollaborator(form.groupName, repositoryName, userName) } } diff --git a/src/main/scala/app/UserManagementController.scala b/src/main/scala/app/UserManagementController.scala index 50ffb3c..dffc2e2 100644 --- a/src/main/scala/app/UserManagementController.scala +++ b/src/main/scala/app/UserManagementController.scala @@ -71,7 +71,7 @@ val users = getAllUsers(includeRemoved) val members = users.collect { case account if(account.isGroupAccount) => - account.userName -> getGroupMembers(account.userName) + account.userName -> getGroupMembers(account.userName).map(_._1) }.toMap admin.users.html.list(users, members, includeRemoved) }) @@ -127,7 +127,11 @@ post("/admin/users/_newgroup", newGroupForm)(adminOnly { form => createGroup(form.groupName, form.url) - updateGroupMembers(form.groupName, form.memberNames.map(_.split(",").toList).getOrElse(Nil)) + updateGroupMembers(form.groupName, form.memberNames.map(_.split(",").map { + _.split(":") match { + case Array(userName, isManager) => (userName, isManager.toBoolean) + } + }.toList).getOrElse(Nil)) updateImage(form.groupName, form.fileId, false) redirect("/admin/users") }) @@ -139,7 +143,11 @@ }) post("/admin/users/:groupName/_editgroup", editGroupForm)(adminOnly { form => - defining(params("groupName"), form.memberNames.map(_.split(",").toList).getOrElse(Nil)){ case (groupName, memberNames) => + defining(params("groupName"), form.memberNames.map(_.split(",").map { + _.split(":") match { + case Array(userName, isManager) => (userName, isManager.toBoolean) + } + }.toList).getOrElse(Nil)){ case (groupName, members) => getAccountByUserName(groupName, true).map { account => updateGroup(groupName, form.url, form.isRemoved) @@ -155,11 +163,11 @@ } } else { // Update GROUP_MEMBER - updateGroupMembers(form.groupName, memberNames) + updateGroupMembers(form.groupName, members) // Update COLLABORATOR for group repositories getRepositoryNamesOfUser(form.groupName).foreach { repositoryName => removeCollaborators(form.groupName, repositoryName) - memberNames.foreach { userName => + members.foreach { case (userName, isManager) => addCollaborator(form.groupName, repositoryName, userName) } } diff --git a/src/main/scala/model/GroupMembers.scala b/src/main/scala/model/GroupMembers.scala index 0bcd0af..a2a38f3 100644 --- a/src/main/scala/model/GroupMembers.scala +++ b/src/main/scala/model/GroupMembers.scala @@ -5,10 +5,12 @@ object GroupMembers extends Table[GroupMember]("GROUP_MEMBER") { def groupName = column[String]("GROUP_NAME", O PrimaryKey) def userName = column[String]("USER_NAME", O PrimaryKey) - def * = groupName ~ userName <> (GroupMember, GroupMember.unapply _) + def isManager = column[Boolean]("MANAGER") + def * = groupName ~ userName ~ isManager <> (GroupMember, GroupMember.unapply _) } case class GroupMember( groupName: String, - userName: String + userName: String, + isManager: Boolean ) \ No newline at end of file diff --git a/src/main/scala/service/AccountService.scala b/src/main/scala/service/AccountService.scala index ff1186f..2357f58 100644 --- a/src/main/scala/service/AccountService.scala +++ b/src/main/scala/service/AccountService.scala @@ -122,18 +122,18 @@ def updateGroup(groupName: String, url: Option[String], removed: Boolean): Unit = Accounts.filter(_.userName is groupName.bind).map(t => t.url.? ~ t.removed).update(url, removed) - def updateGroupMembers(groupName: String, members: List[String]): Unit = { + def updateGroupMembers(groupName: String, members: List[(String, Boolean)]): Unit = { Query(GroupMembers).filter(_.groupName is groupName.bind).delete - members.foreach { userName => - GroupMembers insert GroupMember (groupName, userName) + members.foreach { case (userName, isManager) => + GroupMembers insert GroupMember (groupName, userName, isManager) } } - def getGroupMembers(groupName: String): List[String] = + def getGroupMembers(groupName: String): List[(String, Boolean)] = Query(GroupMembers) .filter(_.groupName is groupName.bind) .sortBy(_.userName) - .map(_.userName) + .map(m => m.userName ~ m.isManager) .list def getGroupsByUserName(userName: String): List[String] = diff --git a/src/main/scala/servlet/AutoUpdateListener.scala b/src/main/scala/servlet/AutoUpdateListener.scala index bfa6992..830ca29 100644 --- a/src/main/scala/servlet/AutoUpdateListener.scala +++ b/src/main/scala/servlet/AutoUpdateListener.scala @@ -50,6 +50,7 @@ * The history of versions. A head of this sequence is the current BitBucket version. */ val versions = Seq( + Version(1, 12), Version(1, 11), Version(1, 10), Version(1, 9), diff --git a/src/main/scala/util/Authenticator.scala b/src/main/scala/util/Authenticator.scala index c43b0ec..bfa2a40 100644 --- a/src/main/scala/util/Authenticator.scala +++ b/src/main/scala/util/Authenticator.scala @@ -157,17 +157,17 @@ } /** - * Allows only the group members. + * Allows only the group managers. */ -trait GroupMemberAuthenticator { self: ControllerBase with AccountService => - protected def membersOnly(action: => Any) = { authenticate(action) } - protected def membersOnly[T](action: T => Any) = (form: T) => { authenticate(action(form)) } +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)).contains(x.userName)) => action + case Some(x) if(getGroupMembers(paths(0)).exists { case (userName, isManager) => userName == x.userName && isManager }) => action case _ => Unauthorized() } } diff --git a/src/main/twirl/account/main.scala.html b/src/main/twirl/account/main.scala.html index 2cbe257..d5f0d1f 100644 --- a/src/main/twirl/account/main.scala.html +++ b/src/main/twirl/account/main.scala.html @@ -1,5 +1,5 @@ @(account: model.Account, groupNames: List[String], active: String, - isGroupMember: Boolean = false)(body: Html)(implicit context: app.Context) + isGroupManager: Boolean = false)(body: Html)(implicit context: app.Context) @import context._ @import view.helpers._ @html.main(account.userName){ @@ -42,7 +42,7 @@ } - @if(loginAccount.isDefined && account.isGroupAccount && isGroupMember){ + @if(loginAccount.isDefined && account.isGroupAccount && isGroupManager){
  • Edit Group diff --git a/src/main/twirl/account/members.scala.html b/src/main/twirl/account/members.scala.html index b69fc0a..0e21d01 100644 --- a/src/main/twirl/account/members.scala.html +++ b/src/main/twirl/account/members.scala.html @@ -1,7 +1,7 @@ -@(account: model.Account, members: List[String], isGroupMember: Boolean)(implicit context: app.Context) +@(account: model.Account, members: List[String], isGroupManager: Boolean)(implicit context: app.Context) @import context._ @import view.helpers._ -@main(account, Nil, "members", isGroupMember){ +@main(account, Nil, "members", isGroupManager){ @if(members.isEmpty){ No members } else { diff --git a/src/main/twirl/account/repositories.scala.html b/src/main/twirl/account/repositories.scala.html index 7772088..100c2b4 100644 --- a/src/main/twirl/account/repositories.scala.html +++ b/src/main/twirl/account/repositories.scala.html @@ -1,9 +1,9 @@ @(account: model.Account, groupNames: List[String], repositories: List[service.RepositoryService.RepositoryInfo], - isGroupMember: Boolean)(implicit context: app.Context) + isGroupManager: Boolean)(implicit context: app.Context) @import context._ @import view.helpers._ -@main(account, groupNames, "repositories", isGroupMember){ +@main(account, groupNames, "repositories", isGroupManager){ @if(repositories.isEmpty){ No repositories } else { diff --git a/src/main/twirl/admin/users/group.scala.html b/src/main/twirl/admin/users/group.scala.html index abf64cb..fe037ea 100644 --- a/src/main/twirl/admin/users/group.scala.html +++ b/src/main/twirl/admin/users/group.scala.html @@ -1,4 +1,4 @@ -@(account: Option[model.Account], members: List[String])(implicit context: app.Context) +@(account: Option[model.Account], members: List[(String, Boolean)])(implicit context: app.Context) @import context._ @import view.helpers._ @html.main(if(account.isEmpty) "New Group" else "Update Group"){ @@ -35,7 +35,7 @@