(refs #8)Implementing group register/edit form.

This commit is contained in:
takezoe
2013-07-23 11:59:49 +09:00
parent ec73294900
commit e4b3f0ddef
5 changed files with 159 additions and 31 deletions

View File

@@ -5,27 +5,32 @@ import util.AdminAuthenticator
import util.StringUtil._
import jp.sf.amateras.scalatra.forms._
class UserManagementController extends UserManagementControllerBase with AccountService with AdminAuthenticator
class UserManagementController extends UserManagementControllerBase
with AccountService with RepositoryService with AdminAuthenticator
trait UserManagementControllerBase extends AccountManagementControllerBase {
self: AccountService with AdminAuthenticator =>
self: AccountService with RepositoryService with AdminAuthenticator =>
case class UserNewForm(userName: String, password: String, mailAddress: String, isAdmin: Boolean,
case class NewUserForm(userName: String, password: String, mailAddress: String, isAdmin: Boolean,
url: Option[String], fileId: Option[String])
case class UserEditForm(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)
val newForm = mapping(
case class NewGroupForm(groupName: String, fileId: Option[String], memberNames: Option[String])
case class EditGroupForm(groupName: String, fileId: Option[String], memberNames: Option[String], clearImage: Boolean)
val newUserForm = mapping(
"userName" -> trim(label("Username" , text(required, maxlength(100), identifier, uniqueUserName))),
"password" -> trim(label("Password" , text(required, maxlength(20)))),
"mailAddress" -> trim(label("Mail Address" , text(required, maxlength(100), uniqueMailAddress()))),
"isAdmin" -> trim(label("User Type" , boolean())),
"url" -> trim(label("URL" , optional(text(maxlength(200))))),
"fileId" -> trim(label("File ID" , optional(text())))
)(UserNewForm.apply)
)(NewUserForm.apply)
val editForm = mapping(
val editUserForm = mapping(
"userName" -> trim(label("Username" , text(required, maxlength(100), identifier))),
"password" -> trim(label("Password" , optional(text(maxlength(20))))),
"mailAddress" -> trim(label("Mail Address" , text(required, maxlength(100), uniqueMailAddress("userName")))),
@@ -33,8 +38,21 @@ trait UserManagementControllerBase extends AccountManagementControllerBase {
"url" -> trim(label("URL" , optional(text(maxlength(200))))),
"fileId" -> trim(label("File ID" , optional(text()))),
"clearImage" -> trim(label("Clear image" , boolean()))
)(UserEditForm.apply)
)(EditUserForm.apply)
val newGroupForm = mapping(
"groupName" -> trim(label("Group name" , text(required, maxlength(100), identifier))),
"fileId" -> trim(label("File ID" , optional(text()))),
"memberNames" -> trim(label("Member Names" , optional(text())))
)(NewGroupForm.apply)
val editGroupForm = mapping(
"groupName" -> trim(label("Group name" , text(required, maxlength(100), identifier))),
"fileId" -> trim(label("File ID" , optional(text()))),
"memberNames" -> trim(label("Member Names" , optional(text()))),
"clearImage" -> trim(label("Clear image" , boolean()))
)(EditGroupForm.apply)
get("/admin/users")(adminOnly {
admin.users.html.list(getAllUsers())
})
@@ -43,7 +61,7 @@ trait UserManagementControllerBase extends AccountManagementControllerBase {
admin.users.html.edit(None)
})
post("/admin/users/_new", newForm)(adminOnly { form =>
post("/admin/users/_new", newUserForm)(adminOnly { form =>
createAccount(form.userName, sha1(form.password), form.mailAddress, form.isAdmin, form.url)
updateImage(form.userName, form.fileId, false)
redirect("/admin/users")
@@ -54,7 +72,7 @@ trait UserManagementControllerBase extends AccountManagementControllerBase {
admin.users.html.edit(getAccountByUserName(userName))
})
post("/admin/users/:name/_edit", editForm)(adminOnly { form =>
post("/admin/users/:name/_edit", editUserForm)(adminOnly { form =>
val userName = params("userName")
getAccountByUserName(userName).map { account =>
updateAccount(getAccountByUserName(userName).get.copy(
@@ -69,9 +87,40 @@ trait UserManagementControllerBase extends AccountManagementControllerBase {
} getOrElse NotFound
})
get("/admin/users/_newgroup"){
admin.users.html.group(None)
}
get("/admin/users/_newgroup")(adminOnly {
admin.users.html.group(None, Nil)
})
post("/admin/users/_newgroup", newGroupForm)(adminOnly { form =>
createGroup(form.groupName)
updateGroupMembers(form.groupName, form.memberNames.map(_.split(",").toList).getOrElse(Nil))
updateImage(form.groupName, form.fileId, false)
redirect("/admin/users")
})
get("/admin/users/:groupName/_editgroup")(adminOnly {
val groupName = params("groupName")
admin.users.html.group(getAccountByUserName(groupName), getGroupMembers(groupName))
})
post("/admin/users/:groupName/_editgroup", editGroupForm)(adminOnly { form =>
val groupName = params("groupName")
getAccountByUserName(groupName).map { account =>
val memberNames = form.memberNames.map(_.split(",").toList).getOrElse(Nil)
updateGroupMembers(form.groupName, memberNames)
getRepositoryNamesOfUser(form.groupName).foreach { repositoryName =>
removeCollaborators(form.groupName, repositoryName)
memberNames.foreach { userName =>
addCollaborator(form.groupName, repositoryName, userName)
}
}
updateImage(form.groupName, form.fileId, form.clearImage)
redirect("/admin/users")
} getOrElse NotFound
})
/**
* JSON API for collaborator completion.

View File

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

View File

@@ -161,6 +161,15 @@ trait RepositoryService { self: AccountService =>
def removeCollaborator(userName: String, repositoryName: String, collaboratorName: String): 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): Unit =
Collaborators.filter(_.byRepository(userName, repositoryName)).delete
/**
* Returns the list of collaborators name which is sorted with ascending order.
*

View File

@@ -1,15 +1,15 @@
@(account: Option[model.Account])(implicit context: app.Context)
@(account: Option[model.Account], members: List[String])(implicit context: app.Context)
@import context._
@import view.helpers._
@html.main(if(account.isEmpty) "New User" else "Update User"){
@admin.html.menu("users"){
<form method="POST" action="@if(account.isEmpty){@path/admin/users/_new} else {@path/admin/users/@account.get.userName/_edit}" 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="span5">
<fieldset>
<label for="userName"><strong>Group name</strong></label>
<input type="text" name="userName" id="userName" value="@account.map(_.userName)"@if(account.isDefined){ readonly}/>
<span id="error-userName" class="error"></span>
<label for="groupName"><strong>Group name</strong></label>
<input type="text" name="groupName" id="groupName" value="@account.map(_.userName)"@if(account.isDefined){ readonly}/>
<span id="error-groupName" class="error"></span>
</fieldset>
<fieldset>
<label for="avatar"><strong>Image (Optional)</strong></label>
@@ -20,14 +20,22 @@
<fieldset>
<label><strong>Members</strong></label>
<ul id="members" class="collaborator">
@members.map { userName =>
<li data-userName="@userName">
<a href="@path/@url(userName)">@userName</a>
<a href="#" class="remove">(remove)</a>
</li>
}
</ul>
<input type="text" id="memberName" style="width: 300px; 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=""/>
<span class="error" id="error-memberName"></span>
</fieldset>
</div>
</div>
<fieldset class="margin">
<input type="submit" class="btn btn-success" value="@if(account.isEmpty){Create Group} else {Update Group}"/>
<input type="submit" class="btn btn-success" id="submit" value="@if(account.isEmpty){Create Group} else {Update Group}"/>
<a href="@path/admin/users" class="btn">Cancel</a>
</fieldset>
</form>
@@ -45,9 +53,23 @@ $(function(){
});
$('#addMember').click(function(){
$('#error-memberName').text('');
var userName = $('#memberName').val();
// TODO check existence
// check duplication
var exists = $('#members li').filter(function(){
return $(this).data('userName') == userName;
}).length > 0;
if(exists){
$('#error-memberName').text('User has been already added.');
return false;
}
$('#members').append($('<li>')
.append($('<a>').attr('href', '#').text(userName))
.data('userName', userName)
.append($('<a>').attr('href', '@path/' + userName).text(userName))
.append(' ')
.append($('<a>').attr('href', '#').addClass('remove').text('(remove)')));
$('#memberName').val('');
@@ -56,5 +78,13 @@ $(function(){
$(document).on('click', '.remove', function(){
$(this).parent().remove();
});
$('#submit').click(function(){
var userNames = $('#members li').map(function(i, e){
return $(e).data('userName');
}).get().join(',');
$('#memberNames').val(userNames);
return true;
});
});
</script>

View File

@@ -12,28 +12,40 @@
<tr>
<td>
<div class="pull-right">
<a href="@path/admin/users/@account.userName/_edit">Edit</a>
@if(account.isGroupAccount){
<a href="@path/admin/users/@account.userName/_editgroup">Edit</a>
} else {
<a href="@path/admin/users/@account.userName/_edit">Edit</a>
}
</div>
<div class="strong">
@avatar(account.userName, 20)
<a href="@url(account.userName)">@account.userName</a>
@if(account.isAdmin){
(Administrator)
@if(account.isGroupAccount){
(Group)
} else {
(Normal)
@if(account.isAdmin){
(Administrator)
} else {
(Normal)
}
}
</div>
<div>
<hr>
<i class="icon-envelope"></i> @account.mailAddress
@account.url.map { url =>
<i class="icon-home"></i> @url
@if(!account.isGroupAccount){
<i class="icon-envelope"></i> @account.mailAddress
@account.url.map { url =>
<i class="icon-home"></i> @url
}
}
</div>
<div>
<span class="muted">Registered:</span> @datetime(account.registeredDate)
<span class="muted">Updated:</span> @datetime(account.updatedDate)
<span class="muted">Last Login:</span> @account.lastLoginDate.map(datetime)
@if(!account.isGroupAccount){
<span class="muted">Last Login:</span> @account.lastLoginDate.map(datetime)
}
</div>
</td>
</tr>