(refs #8)Some fix for group management.

This commit is contained in:
takezoe
2013-07-24 03:36:42 +09:00
parent 2155734e23
commit 3a7391fbb3
10 changed files with 125 additions and 128 deletions

View File

@@ -42,14 +42,23 @@ trait AccountControllerBase extends AccountManagementControllerBase with FlashMa
*/ */
get("/:userName") { get("/:userName") {
val userName = params("userName") val userName = params("userName")
getAccountByUserName(userName).map { x => getAccountByUserName(userName).map { account =>
params.getOrElse("tab", "repositories") match { params.getOrElse("tab", "repositories") match {
// Public Activity // Public Activity
case "activity" => account.html.activity(x, getActivitiesByUser(userName, true)) case "activity" =>
_root_.account.html.activity(account,
if(account.isGroupAccount) Nil else getGroupsByUserName(userName),
getActivitiesByUser(userName, true))
// Members // Members
case "members" if(x.isGroupAccount) => account.html.members(x, getGroupMembers(x.userName)) case "members" if(account.isGroupAccount) =>
_root_.account.html.members(account, getGroupMembers(account.userName))
// Repositories // Repositories
case _ => account.html.repositories(x, getVisibleRepositories(userName, baseUrl, context.loginAccount.map(_.userName))) case _ =>
_root_.account.html.repositories(account,
if(account.isGroupAccount) Nil else getGroupsByUserName(userName),
getVisibleRepositories(userName, baseUrl, context.loginAccount.map(_.userName)))
} }
} getOrElse NotFound } getOrElse NotFound
} }

View File

@@ -17,9 +17,11 @@ trait UserManagementControllerBase extends AccountManagementControllerBase {
case class EditUserForm(userName: String, password: Option[String], mailAddress: String, isAdmin: Boolean, case class EditUserForm(userName: String, password: Option[String], mailAddress: String, isAdmin: Boolean,
url: Option[String], fileId: Option[String], clearImage: Boolean) url: Option[String], fileId: Option[String], clearImage: Boolean)
case class NewGroupForm(groupName: String, fileId: Option[String], memberNames: Option[String]) case class NewGroupForm(groupName: String, url: Option[String], fileId: Option[String],
memberNames: Option[String])
case class EditGroupForm(groupName: String, fileId: Option[String], memberNames: Option[String], clearImage: Boolean) case class EditGroupForm(groupName: String, url: Option[String], fileId: Option[String],
memberNames: Option[String], clearImage: Boolean)
val newUserForm = mapping( val newUserForm = mapping(
"userName" -> trim(label("Username" , text(required, maxlength(100), identifier, uniqueUserName))), "userName" -> trim(label("Username" , text(required, maxlength(100), identifier, uniqueUserName))),
@@ -42,12 +44,14 @@ trait UserManagementControllerBase extends AccountManagementControllerBase {
val newGroupForm = mapping( val newGroupForm = mapping(
"groupName" -> trim(label("Group name" , text(required, maxlength(100), identifier))), "groupName" -> trim(label("Group name" , text(required, maxlength(100), identifier))),
"url" -> trim(label("URL" , optional(text(maxlength(200))))),
"fileId" -> trim(label("File ID" , optional(text()))), "fileId" -> trim(label("File ID" , optional(text()))),
"memberNames" -> trim(label("Member Names" , optional(text()))) "memberNames" -> trim(label("Member Names" , optional(text())))
)(NewGroupForm.apply) )(NewGroupForm.apply)
val editGroupForm = mapping( val editGroupForm = mapping(
"groupName" -> trim(label("Group name" , text(required, maxlength(100), identifier))), "groupName" -> trim(label("Group name" , text(required, maxlength(100), identifier))),
"url" -> trim(label("URL" , optional(text(maxlength(200))))),
"fileId" -> trim(label("File ID" , optional(text()))), "fileId" -> trim(label("File ID" , optional(text()))),
"memberNames" -> trim(label("Member Names" , optional(text()))), "memberNames" -> trim(label("Member Names" , optional(text()))),
"clearImage" -> trim(label("Clear image" , boolean())) "clearImage" -> trim(label("Clear image" , boolean()))
@@ -96,7 +100,7 @@ trait UserManagementControllerBase extends AccountManagementControllerBase {
}) })
post("/admin/users/_newgroup", newGroupForm)(adminOnly { form => post("/admin/users/_newgroup", newGroupForm)(adminOnly { form =>
createGroup(form.groupName) createGroup(form.groupName, form.url)
updateGroupMembers(form.groupName, form.memberNames.map(_.split(",").toList).getOrElse(Nil)) updateGroupMembers(form.groupName, form.memberNames.map(_.split(",").toList).getOrElse(Nil))
updateImage(form.groupName, form.fileId, false) updateImage(form.groupName, form.fileId, false)
redirect("/admin/users") redirect("/admin/users")
@@ -110,6 +114,8 @@ trait UserManagementControllerBase extends AccountManagementControllerBase {
post("/admin/users/:groupName/_editgroup", editGroupForm)(adminOnly { form => post("/admin/users/:groupName/_editgroup", editGroupForm)(adminOnly { form =>
val groupName = params("groupName") val groupName = params("groupName")
getAccountByUserName(groupName).map { account => getAccountByUserName(groupName).map { account =>
updateGroup(groupName, form.url)
val memberNames = form.memberNames.map(_.split(",").toList).getOrElse(Nil) val memberNames = form.memberNames.map(_.split(",").toList).getOrElse(Nil)
updateGroupMembers(form.groupName, memberNames) updateGroupMembers(form.groupName, memberNames)

View File

@@ -46,22 +46,24 @@ trait AccountService {
def updateLastLoginDate(userName: String): Unit = def updateLastLoginDate(userName: String): Unit =
Accounts.filter(_.userName is userName.bind).map(_.lastLoginDate).update(currentDate) Accounts.filter(_.userName is userName.bind).map(_.lastLoginDate).update(currentDate)
def createGroup(groupName: String): Unit = def createGroup(groupName: String, url: Option[String]): Unit =
Accounts insert Account( Accounts insert Account(
userName = groupName, userName = groupName,
password = "", password = "",
mailAddress = groupName + "@devnull", mailAddress = groupName + "@devnull",
isAdmin = false, isAdmin = false,
url = None, url = url,
registeredDate = currentDate, registeredDate = currentDate,
updatedDate = currentDate, updatedDate = currentDate,
lastLoginDate = None, lastLoginDate = None,
image = None, image = None,
isGroupAccount = true) isGroupAccount = true)
def updateGroup(groupName: String, url: Option[String]): Unit =
Accounts.filter(_.userName is groupName.bind).map(_.url.?).update(url)
def updateGroupMembers(groupName: String, members: List[String]): Unit = { def updateGroupMembers(groupName: String, members: List[String]): Unit = {
Query(GroupMembers).filter(_.groupName is groupName.bind).delete Query(GroupMembers).filter(_.groupName is groupName.bind).delete
members.foreach { userName => members.foreach { userName =>
GroupMembers insert GroupMember (groupName, userName) GroupMembers insert GroupMember (groupName, userName)
} }

View File

@@ -1,23 +1,6 @@
@(account: model.Account, activities: List[model.Activity])(implicit context: app.Context) @(account: model.Account, groupNames: List[String], activities: List[model.Activity])(implicit context: app.Context)
@import context._ @import context._
@import view.helpers._ @import view.helpers._
@html.main(account.userName){ @main(account, groupNames, "activity"){
<div class="container-fluid"> @helper.html.activities(activities)
<div class="row-fluid">
<div class="span4">
<div class="block">
<div class="account-image">@avatar(account.userName, 200)</div>
<div class="block-header">@account.userName</div>
</div>
<div class="block">
<div><i class="icon-home"></i> <a href="@account.url">@account.url</a></div>
<div><i class="icon-time"></i> <span class="muted">Joined on</span> @date(account.registeredDate)</div>
</div>
</div>
<div class="span8">
@tab(account, "activity")
@helper.html.activities(activities)
</div>
</div>
</div>
} }

View File

@@ -0,0 +1,48 @@
@(account: model.Account, groupNames: List[String], active: String)(body: Html)(implicit context: app.Context)
@import context._
@import view.helpers._
@html.main(account.userName){
<div class="container-fluid">
<div class="row-fluid">
<div class="span4">
<div class="block">
<div class="account-image">@avatar(account.userName, 200)</div>
<div class="block-header">@account.userName</div>
</div>
<div class="block">
@if(account.url.isDefined){
<div><i class="icon-home"></i> <a href="@account.url">@account.url</a></div>
}
<div><i class="icon-time"></i> <span class="muted">Joined on</span> @date(account.registeredDate)</div>
</div>
@if(groupNames.nonEmpty){
<div>
<div>Groups</div>
@groupNames.map { groupName =>
<a href="@url(groupName)">@avatar(groupName, 36, tooltip = true)</a>
}
</div>
}
</div>
<div class="span8">
<ul class="nav nav-tabs">
<li@if(active == "repositories"){ class="active"}><a href="@url(account.userName)?tab=repositories">Repositories</a></li>
@if(account.isGroupAccount){
<li@if(active == "members"){ class="active"}><a href="@url(account.userName)?tab=members">Members</a></li>
} else {
<li@if(active == "activity"){ class="active"}><a href="@url(account.userName)?tab=activity">Public Activity</a></li>
}
@if(loginAccount.isDefined && loginAccount.get.userName == account.userName){
<li class="pull-right">
<div class="button-group">
<a href="@url(account.userName)/_edit" class="btn">Edit Your Profile</a>
</div>
</li>
}
</ul>
@body
</div>
</div>
</div>
}

View File

@@ -1,33 +1,16 @@
@(account: model.Account, members: List[String])(implicit context: app.Context) @(account: model.Account, members: List[String])(implicit context: app.Context)
@import context._ @import context._
@import view.helpers._ @import view.helpers._
@html.main(account.userName){ @main(account, Nil, "members"){
<div class="container-fluid"> @if(members.isEmpty){
<div class="row-fluid"> No members
<div class="span4"> } else {
<div class="block"> @members.map { userName =>
<div class="account-image">@avatar(account.userName, 200)</div> <div class="block">
<div class="block-header">@account.userName</div> <div class="block-header">
</div> @avatar(userName, 20) <a href="@url(userName)">@userName</a>
<div class="block">
<div><i class="icon-home"></i> <a href="@account.url">@account.url</a></div>
<div><i class="icon-time"></i> <span class="muted">Joined on</span> @date(account.registeredDate)</div>
</div> </div>
</div> </div>
<div class="span8"> }
@tab(account, "members") }
@if(members.isEmpty){
No members
} else {
@members.map { userName =>
<div class="block">
<div class="block-header">
@avatar(userName, 20) <a href="@url(userName)">@userName</a>
</div>
</div>
}
}
</div>
</div>
</div>
} }

View File

@@ -1,42 +1,25 @@
@(account: model.Account, repositories: List[service.RepositoryService.RepositoryInfo])(implicit context: app.Context) @(account: model.Account, groupNames: List[String], repositories: List[service.RepositoryService.RepositoryInfo])(implicit context: app.Context)
@import context._ @import context._
@import view.helpers._ @import view.helpers._
@html.main(account.userName){ @main(account, groupNames, "repositories"){
<div class="container-fluid"> @if(repositories.isEmpty){
<div class="row-fluid"> No repositories
<div class="span4"> } else {
<div class="block"> @repositories.map { repository =>
<div class="account-image">@avatar(account.userName, 200)</div> <div class="block">
<div class="block-header">@account.userName</div> <div class="block-header">
</div> <a href="@url(repository.owner)">@repository.owner</a>
<div class="block"> /
<div><i class="icon-home"></i> <a href="@account.url">@account.url</a></div> <a href="@url(repository)">@repository.name</a>
<div><i class="icon-time"></i> <span class="muted">Joined on</span> @date(account.registeredDate)</div> @if(repository.repository.isPrivate){
</div> <i class="icon-lock"></i>
</div>
<div class="span8">
@tab(account, "repositories")
@if(repositories.isEmpty){
No repositories
} else {
@repositories.map { repository =>
<div class="block">
<div class="block-header">
<a href="@url(repository.owner)">@repository.owner</a>
/
<a href="@url(repository)">@repository.name</a>
@if(repository.repository.isPrivate){
<i class="icon-lock"></i>
}
</div>
@if(repository.repository.description.isDefined){
<div>@repository.repository.description</div>
}
<div><span class="muted small">Last updated: @datetime(repository.repository.lastActivityDate)</span></div>
</div>
} }
</div>
@if(repository.repository.description.isDefined){
<div>@repository.repository.description</div>
} }
<div><span class="muted small">Last updated: @datetime(repository.repository.lastActivityDate)</span></div>
</div> </div>
</div> }
</div> }
} }

View File

@@ -1,18 +0,0 @@
@(account: model.Account, active: String)(implicit context: app.Context)
@import context._
@import view.helpers._
<ul class="nav nav-tabs">
<li@if(active == "repositories"){ class="active"}><a href="@url(account.userName)?tab=repositories">Repositories</a></li>
@if(account.isGroupAccount){
<li@if(active == "members"){ class="active"}><a href="@url(account.userName)?tab=members">Members</a></li>
} else {
<li@if(active == "activity"){ class="active"}><a href="@url(account.userName)?tab=activity">Public Activity</a></li>
}
@if(loginAccount.isDefined && loginAccount.get.userName == account.userName){
<li class="pull-right">
<div class="button-group">
<a href="@url(account.userName)/_edit" class="btn">Edit Your Profile</a>
</div>
</li>
}
</ul>

View File

@@ -5,18 +5,23 @@
@admin.html.menu("users"){ @admin.html.menu("users"){
<form method="POST" action="@if(account.isEmpty){@path/admin/users/_newgroup} else {@path/admin/users/@account.get.userName/_editgroup}" validate="true"> <form method="POST" action="@if(account.isEmpty){@path/admin/users/_newgroup} else {@path/admin/users/@account.get.userName/_editgroup}" validate="true">
<div class="row-fluid"> <div class="row-fluid">
<div class="span5"> <div class="span7">
<fieldset> <fieldset>
<label for="groupName"><strong>Group name</strong></label> <label for="groupName"><strong>Group name</strong></label>
<span id="error-groupName" class="error"></span> <span id="error-groupName" class="error"></span>
<input type="text" name="groupName" id="groupName" value="@account.map(_.userName)"@if(account.isDefined){ readonly}/> <input type="text" name="groupName" id="groupName" value="@account.map(_.userName)"@if(account.isDefined){ readonly}/>
</fieldset> </fieldset>
<fieldset>
<label><strong>URL (Optional)</strong></label>
<span id="error-url" class="error"></span>
<input type="text" name="url" id="url" style="width: 300px;" value="@account.map(_.url)"/>
</fieldset>
<fieldset> <fieldset>
<label for="avatar"><strong>Image (Optional)</strong></label> <label for="avatar"><strong>Image (Optional)</strong></label>
@helper.html.uploadavatar(account) @helper.html.uploadavatar(account)
</fieldset> </fieldset>
</div> </div>
<div class="span7"> <div class="span5">
<fieldset> <fieldset>
<label><strong>Members</strong></label> <label><strong>Members</strong></label>
<ul id="members" class="collaborator"> <ul id="members" class="collaborator">
@@ -27,7 +32,7 @@
</li> </li>
} }
</ul> </ul>
<input type="text" id="memberName" style="width: 300px; margin-bottom: 0px;"/> <input type="text" id="memberName" style="width: 200px; margin-bottom: 0px;"/>
<input type="button" class="btn" value="Add" id="addMember"/> <input type="button" class="btn" value="Add" id="addMember"/>
<input type="hidden" id="memberNames" name="memberNames" value="@members.mkString(",")"/> <input type="hidden" id="memberNames" name="memberNames" value="@members.mkString(",")"/>
<div> <div>

View File

@@ -15,7 +15,7 @@
@if(account.isGroupAccount){ @if(account.isGroupAccount){
<a href="@path/admin/users/@account.userName/_editgroup">Edit</a> <a href="@path/admin/users/@account.userName/_editgroup">Edit</a>
} else { } else {
<a href="@path/admin/users/@account.userName/_edit">Edit</a> <a href="@path/admin/users/@account.userName/_edituser">Edit</a>
} }
</div> </div>
<div class="strong"> <div class="strong">
@@ -30,23 +30,19 @@
(Normal) (Normal)
} }
} }
@if(account.isGroupAccount){
@members(account.userName).map { userName =>
@avatar(userName, 20, tooltip = true)
}
}
</div> </div>
<div> <div>
<hr> <hr>
@if(account.isGroupAccount){ @if(!account.isGroupAccount){
@if(members(account.userName).isEmpty){
No members
} else {
Members:
@members(account.userName).map { userName =>
@avatar(userName, 20, tooltip = true)
}
}
} else {
<i class="icon-envelope"></i> @account.mailAddress <i class="icon-envelope"></i> @account.mailAddress
@account.url.map { url => }
<i class="icon-home"></i> @url @account.url.map { url =>
} <i class="icon-home"></i> @url
} }
</div> </div>
<div> <div>