Commit 3992cde8 authored by Peter Harrison's avatar Peter Harrison

Merge pull request #44 from cheetah100/experimental

Assignment of Tasks Support
parents e5a31864 a32ab114
/**
* GRAVITY WORKFLOW AUTOMATION
* (C) Copyright 2015 Orcon Limited
* (C) Copyright 2016 Peter Harrison
*
* This file is part of Gravity Workflow Automation.
*
......@@ -859,6 +860,46 @@ public class CardController {
}
return cardTask;
}
@PreAuthorize("hasPermission(#boardId, 'BOARD', 'WRITE,ADMIN')")
@RequestMapping(value = "/{cardId}/tasks/{taskId}/take", method=RequestMethod.GET)
public @ResponseBody CardTask takeTask(@PathVariable String boardId,
@PathVariable String phaseId,
@PathVariable String cardId,
@PathVariable String taskId) throws Exception {
ObjectContentManager ocm = ocmFactory.getOcm();
CardTask cardTask;
try {
cardTask = cardTools.getCardTask(boardId, phaseId, cardId, taskId, ocm);
if(cardTask==null){
cardTask = createTask( boardId, phaseId, cardId, taskId, true, ocm);
return cardTask;
}
if(cardTask.getComplete() || !StringUtils.isEmpty(cardTask.getUser())){
return cardTask;
}
cardTask.setUser(listTools.getCurrentUser());
ocm.update(cardTask);
Card card = new Card();
card.setPath(cardTask.getPath());
storeCardEvent(URI.HISTORY_URI,"Assigning Task " + cardTask.getDetail() + " to " + cardTask.getUser(),
card.getBoard(), card.getPhase(), cardId, "info", "assign-" + cardTask.getTaskid(), ocm);
ocm.save();
} finally {
ocm.logout();
}
return cardTask;
}
@PreAuthorize("hasPermission(#boardId, 'BOARD', 'WRITE,ADMIN')")
@RequestMapping(value = "/{cardId}/tasks/{taskId}/revert", method=RequestMethod.GET)
public @ResponseBody CardTask revertTask(@PathVariable String boardId,
......@@ -876,10 +917,6 @@ public class CardController {
throw new ResourceNotFoundException();
}
if(!cardTask.getComplete()){
return cardTask;
}
cardTask.setComplete(false);
cardTask.setOccuredTime(null);
cardTask.setUser(null);
......
......@@ -90,13 +90,16 @@ public class RuleController {
}
ObjectContentManager ocm = ocmFactory.getOcm();
listTools.ensurePresence(String.format(URI.BOARD_URI, boardId), "rules", ocm.getSession());
rule.setPath(String.format(URI.RULE_URI, boardId, IdentifierTools.getIdFromNamedModelClass(rule)));
ocm.insert(rule);
try{
ocm.save();
ocm.logout();
listTools.ensurePresence(String.format(URI.BOARD_URI, boardId), "rules", ocm.getSession());
rule.setPath(String.format(URI.RULE_URI, boardId, IdentifierTools.getIdFromNamedModelClass(rule)));
ocm.insert(rule);
ocm.save();
} finally {
ocm.logout();
}
return rule;
}
......@@ -132,17 +135,19 @@ public class RuleController {
}
ObjectContentManager ocm = ocmFactory.getOcm();
Node node = ocm.getSession().getNode(String.format(URI.RULE_URI, boardId, ruleId));
try {
Node node = ocm.getSession().getNode(String.format(URI.RULE_URI, boardId, ruleId));
if(node==null){
if(node==null){
throw new ResourceNotFoundException();
}
node.remove();
ocm.save();
this.cacheInvalidationManager.invalidate(RULE, ruleCache.getCacheId(boardId,ruleId));
} finally {
ocm.logout();
throw new ResourceNotFoundException();
}
node.remove();
ocm.save();
ocm.logout();
this.cacheInvalidationManager.invalidate(RULE, ruleCache.getCacheId(boardId,ruleId));
}
public void setJmsTemplate(JmsTemplate jmsTemplate) {
......
/**
* GRAVITY WORKFLOW AUTOMATION
* (C) Copyright 2015 Orcon Limited
* (C) Copyright 2016 Peter Harrison
*
* This file is part of Gravity Workflow Automation.
*
......@@ -76,5 +77,4 @@ public class TeamCache extends CacheImpl<Team> {
}
return result;
}
}
/**
* GRAVITY WORKFLOW AUTOMATION
* (C) Copyright 2015 Orcon Limited
* (C) Copyright 2016 Peter Harrison
*
* This file is part of Gravity Workflow Automation.
*
......@@ -76,9 +77,8 @@ public class TeamController {
throw new Exception("Attempt to Update team using POST. Use PUT instead");
}
ObjectContentManager ocm = null;
try {
ocm = ocmFactory.getOcm();
ObjectContentManager ocm = ocmFactory.getOcm();
try {
String newId = IdentifierTools.getIdFromNamedModelClass(team);
team.setPath(String.format(URI.TEAM_URI, newId.toString()));
......@@ -90,9 +90,7 @@ public class TeamController {
ocm.save();
this.cacheInvalidationManager.invalidate(TEAM, newId);
} finally {
if(ocm!=null){
ocm.logout();
}
ocm.logout();
}
return team;
}
......@@ -106,16 +104,13 @@ public class TeamController {
@PreAuthorize("hasPermission(#teamId, 'TEAM', 'ADMIN')")
@RequestMapping(value = "/{teamId}", method=RequestMethod.DELETE)
public @ResponseBody void deleteTeam(@PathVariable String teamId) throws Exception {
ObjectContentManager ocm = null;
try{
ocm = ocmFactory.getOcm();
ObjectContentManager ocm = ocmFactory.getOcm();
try{
ocm.getSession().removeItem(String.format(URI.TEAM_URI, teamId));
ocm.save();
this.cacheInvalidationManager.invalidate(TEAM, teamId);
} finally {
if(ocm!=null){
ocm.logout();
}
ocm.logout();
}
}
......@@ -129,7 +124,6 @@ public class TeamController {
ObjectContentManager ocm = ocmFactory.getOcm();
try{
listTools.ensurePresence(String.format( URI.TEAM_URI, teamId), "owners", ocm.getSession());
Node node = ocm.getSession().getNode(String.format(URI.TEAM_OWNERS, teamId,""));
......@@ -192,6 +186,4 @@ public class TeamController {
ocm.logout();
}
}
}
/**
* GRAVITY WORKFLOW AUTOMATION
* (C) Copyright 2015 Orcon Limited
* (C) Copyright 2016 Peter Harrison
*
* This file is part of Gravity Workflow Automation.
*
......@@ -21,12 +22,15 @@
package nz.net.orcon.kanban.controllers;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import javax.jcr.Session;
import nz.net.orcon.kanban.model.CardTask;
import nz.net.orcon.kanban.model.User;
import nz.net.orcon.kanban.tools.CardTools;
import nz.net.orcon.kanban.tools.IdentifierTools;
import nz.net.orcon.kanban.tools.ListTools;
import nz.net.orcon.kanban.tools.OcmMapperFactory;
......@@ -52,6 +56,9 @@ public class UserController {
@Autowired
private ListTools listTools;
@Autowired
CardTools cardTools;
@Resource(name="ocmFactory")
OcmMapperFactory ocmFactory;
......@@ -70,9 +77,7 @@ public class UserController {
ocm.insert(user);
ocm.save();
} finally {
if(ocm!=null){
ocm.logout();
}
ocm.logout();
}
return user;
}
......@@ -92,13 +97,24 @@ public class UserController {
user.setPasswordhash(null);
} finally {
if(ocm!=null){
ocm.logout();
}
ocm.logout();
}
return user;
}
@RequestMapping(value = "/{userId}/tasks", method=RequestMethod.GET)
public @ResponseBody List<CardTask> getUserTasks(@PathVariable String userId) throws Exception {
ObjectContentManager ocm = ocmFactory.getOcm();
List<CardTask> taskList;
try{
taskList = cardTools.getCardTasksByUser(userId, ocm);
} finally {
ocm.logout();
}
return taskList;
}
@RequestMapping(value = "/{userId}", method=RequestMethod.DELETE)
public @ResponseBody void deleteUser(@PathVariable String userId) throws Exception {
Session session = ocmFactory.getOcm().getSession();
......@@ -106,9 +122,7 @@ public class UserController {
session.removeItem(String.format(URI.USER_URI, userId));
session.save();
} finally {
if(session!=null){
session.logout();
}
session.logout();
}
}
......@@ -147,8 +161,6 @@ public class UserController {
} else {
logger.warn("Wrong user credentials while changing password.");
}
} catch( Exception e){
logger.error("Exception changing password.", e);
} finally {
if(ocm!=null){
ocm.logout();
......
/**
* GRAVITY WORKFLOW AUTOMATION
* (C) Copyright 2015 Orcon Limited
* (C) Copyright 2016 Peter Harrison
*
* This file is part of Gravity Workflow Automation.
*
......@@ -81,13 +82,16 @@ public class ViewController {
throw new Exception("Attempt to Update Template using POST. Use PUT instead");
}
ObjectContentManager ocm = ocmFactory.getOcm();
listTools.ensurePresence(String.format(URI.BOARD_URI, boardId), "views", ocm.getSession());
String newId = IdentifierTools.getIdFromNamedModelClass(view);
view.setPath(String.format(URI.VIEW_URI, boardId, newId.toString()));
ocm.insert(view);
ocm.save();
ocm.logout();
this.cacheInvalidationManager.invalidate(BoardController.BOARD, boardId);
try {
listTools.ensurePresence(String.format(URI.BOARD_URI, boardId), "views", ocm.getSession());
String newId = IdentifierTools.getIdFromNamedModelClass(view);
view.setPath(String.format(URI.VIEW_URI, boardId, newId.toString()));
ocm.insert(view);
ocm.save();
this.cacheInvalidationManager.invalidate(BoardController.BOARD, boardId);
} finally {
ocm.logout();
}
return view;
}
......@@ -117,15 +121,17 @@ public class ViewController {
public @ResponseBody View getView(@PathVariable String boardId,
@PathVariable String viewId) throws Exception {
ObjectContentManager ocm = ocmFactory.getOcm();
View view = (View) ocm.getObject(View.class,String.format(URI.VIEW_URI, boardId, viewId));
ocm.logout();
if(view==null){
ObjectContentManager ocm = ocmFactory.getOcm();
View view;
try {
view = (View) ocm.getObject(View.class,String.format(URI.VIEW_URI, boardId, viewId));
if(view==null){
throw new ResourceNotFoundException();
}
} finally {
ocm.logout();
throw new ResourceNotFoundException();
}
return view;
}
......@@ -133,12 +139,15 @@ public class ViewController {
public @ResponseBody void deleteView(@PathVariable String boardId,
@PathVariable String viewId) throws Exception {
ObjectContentManager ocm = ocmFactory.getOcm();
String path = String.format(URI.VIEW_URI, boardId, viewId);
ocm.getSession().removeItem(path);
ocm.save();
ocm.logout();
this.cacheInvalidationManager.invalidate(BoardController.BOARD, boardId);
ObjectContentManager ocm = ocmFactory.getOcm();
try {
String path = String.format(URI.VIEW_URI, boardId, viewId);
ocm.getSession().removeItem(path);
ocm.save();
this.cacheInvalidationManager.invalidate(BoardController.BOARD, boardId);
} finally {
ocm.logout();
}
}
@RequestMapping(value = "/{viewId}/fields/{fieldId}", method=RequestMethod.GET)
......@@ -146,14 +155,16 @@ public class ViewController {
@PathVariable String viewId,
@PathVariable String fieldId) throws Exception {
ObjectContentManager ocm = ocmFactory.getOcm();
ViewField viewField = (ViewField) ocm.getObject(ViewField.class,String.format(URI.VIEW_FIELD_URI, boardId, viewId, fieldId));
ocm.logout();
if(viewField==null){
throw new ResourceNotFoundException();
ObjectContentManager ocm = ocmFactory.getOcm();
ViewField viewField;
try {
viewField = (ViewField) ocm.getObject(ViewField.class,String.format(URI.VIEW_FIELD_URI, boardId, viewId, fieldId));
if(viewField==null){
throw new ResourceNotFoundException();
}
} finally {
ocm.logout();
}
return viewField;
}
......@@ -162,11 +173,14 @@ public class ViewController {
@PathVariable String viewId,
@RequestBody ViewField viewField) throws Exception {
ObjectContentManager ocm = ocmFactory.getOcm();
viewField.setPath(String.format(URI.VIEW_FIELD_URI, boardId, viewId, viewField.getName()));
ocm.insert(viewField);
ocm.save();
ocm.logout();
ObjectContentManager ocm = ocmFactory.getOcm();
try {
viewField.setPath(String.format(URI.VIEW_FIELD_URI, boardId, viewId, viewField.getName()));
ocm.insert(viewField);
ocm.save();
} finally {
ocm.logout();
}
this.cacheInvalidationManager.invalidate(BoardController.BOARD, boardId);
return viewField;
}
......@@ -176,20 +190,27 @@ public class ViewController {
@PathVariable String viewId,
@PathVariable String fieldId) throws Exception {
ObjectContentManager ocm = ocmFactory.getOcm();
String path = String.format(URI.VIEW_FIELD_URI, boardId, viewId, fieldId);
ocm.getSession().removeItem(path);
ocm.save();
ocm.logout();
this.cacheInvalidationManager.invalidate(BoardController.BOARD, boardId);
ObjectContentManager ocm = ocmFactory.getOcm();
try {
String path = String.format(URI.VIEW_FIELD_URI, boardId, viewId, fieldId);
ocm.getSession().removeItem(path);
ocm.save();
this.cacheInvalidationManager.invalidate(BoardController.BOARD, boardId);
} finally {
ocm.logout();
}
}
@RequestMapping(value = "", method=RequestMethod.GET)
public @ResponseBody Map<String,String> listViews(@PathVariable String boardId) throws Exception {
Session session = ocmFactory.getOcm().getSession();
Map<String,String> result = listTools.list(String.format(URI.VIEW_URI, boardId,""), "name", session);
session.logout();
Map<String,String> result;
try {
result = listTools.list(String.format(URI.VIEW_URI, boardId,""), "name", session);
} finally {
session.logout();
}
return result;
}
}
......@@ -82,7 +82,7 @@ public class XmlFileController {
try{
ocm = ocmFactory.getOcm();
cardList = cardTools.getCardList(boardId,includeArchive, ocm);
}finally{
} finally {
ocm.logout();
}
......
......@@ -69,6 +69,11 @@ public interface CardTools {
String cardId,
String taskId,
ObjectContentManager ocm ) throws ResourceNotFoundException;
public List<CardTask> getCardTasksByUser(
String userId,
ObjectContentManager ocm)
throws ResourceNotFoundException;
public List<Card> getCardList(
String boardId,
......
......@@ -23,6 +23,7 @@ package nz.net.orcon.kanban.tools;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
......@@ -132,6 +133,28 @@ public class CardToolsImpl implements CardTools{
return cardTask;
}
@Override
public List<CardTask> getCardTasksByUser(
String user,
ObjectContentManager ocm)
throws ResourceNotFoundException {
QueryManager qm = ocm.getQueryManager();
Filter filter = qm.createFilter(CardTask.class);
filter.setScope("//");
filter.addEqualTo("user", user);
filter.addEqualTo("complete", "false");
Query query = qm.createQuery(filter);
Collection objects = ocm.getObjects(query);
List<CardTask> returnList = new ArrayList<CardTask>();
for( Object object : objects){
returnList.add((CardTask)object);
}
return returnList;
}
public Map<String, Object> getFieldsForCard(Card card,
ObjectContentManager ocm) throws RepositoryException {
......
......@@ -357,10 +357,18 @@ div.validation-message.validation-message-invalid {
background: #8c8;
}
.row.card-task.task-take:hover {
background: #f2ff26;
}
.row.card-task.task-complete {
background: #ada;
}
.row.card-task.task-take {
background: #f8ff89;
}
.row.card-task.task-incomplete {
padding: 6px 12px;
}
......@@ -377,6 +385,11 @@ div.validation-message.validation-message-invalid {
color: black;
}
.task-take .card-task-name {
font-weight: bold;
color: black;
}
.card-task .card-task-toggle {
border: none;
background-color: transparent;
......@@ -396,11 +409,15 @@ div.validation-message.validation-message-invalid {
opacity: 0.8;
}
.card-task.task-take .card-task-toggle {
background: url('../../images/glyphicons_136_cogwheel.png') no-repeat center center;
opacity: 0.8;
}
.card-task.task-incomplete .card-task-toggle {
background: url('../../images/glyphicons_197_remove.png') no-repeat center center;
}
.card-task-details {
font-size: 9pt;
line-height: 11pt;
......@@ -412,7 +429,7 @@ div.validation-message.validation-message-invalid {
}
.card-task.task-incomplete .card-task-details {
display: none;
opacity: 1.0;
}
......
......@@ -2,7 +2,6 @@
<html>
<head>
<!-- STYLE SHEETS -->
<link href="http://use.typekit.com/k/saa3wbx-d.css?3bb2a6e53c9684ffdc9a9bfe1b5b2a6216bc43f667eade1f8c67b88a89fc1532774479e9777421c424ed97e8e14d0fb546f13194b30807eeda3296c10f544bb7db153146d52c54b3a5cb454d4a95ae02d61ba37044a79b04b084080315204291e7bd2afa40b6fb5a0c7954a3980643774aa97cc57573715ef96e11e691c895e406181ff7e11de555a7e7ec0a6d0e080ff680715601d604daf2035a1ac10303d3799bb39b39e705a27ea465b2dd491c91ad743951e1" rel="stylesheet">
<link rel="stylesheet" href="css/core/main.css"/>
<link rel="stylesheet" href="css/core/splash.css"/>
<link rel="stylesheet" href="css/core/board.css"/>
......
......@@ -92,6 +92,21 @@
If you are a manager frustrated with the glacial speed at which your
business processes can adapt to changing conditions you could benefit
from Gravity Workflow Automation.</p>
<md-content>
<md-list>
<md-subheader class="md-no-sticky">Subheading</md-subheader>
<md-list-item class="md-3-line" ng-repeat="card in cards">
<div class="md-list-item-text" layout="column">
<h3>{{ card }}</h3>
</div>
</md-list-item>
</md-list>
</md-content>
</div>
</div> <!-- /container -->
......@@ -99,7 +114,8 @@
</div>
<script src= "http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<!-- <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> -->
<script src="scripts/lib/jquery-1.11.1.min.js" type="text/javascript"></script>
<script src="js/bootstrap.min.js"></script>
<script src="scripts/core/gravityApp.js"></script>
......
......@@ -143,42 +143,59 @@ var card = {
$block.append('<h2>Tasks</h2>');
jQuery.each(data, function(i,t) {
var state = t.complete?"complete":"incomplete";
var state = "incomplete";
if( t.complete ) state = "complete"
else if( t.user != "" && t.user!=null ) state = "take";
$block.append('<div class="row card-task task-' + state + '" data-state="' + state + '">' +
'<button name="card-task-toggle" class="card-task-toggle" data-taskid="' + t.id + '"/>' +
'<div class="card-task-name">' + t.detail + '</div>' +
'<div class="card-task-details"></div>' +
'</div>');
if (state == "complete")
if (state == "complete") {
$block.find('div.row.card-task').last().find('div.card-task-details').html('Completed by <strong>' + (t.user && t.user != null? t.user:"system") + '</strong> on ' + convertDateToString(t.occuredTime));
} else if (state == "take") {
$block.find('div.row.card-task').last().find('div.card-task-details').html('Assigned to <strong>' + t.user + '</strong>');
}
$('button[name="card-task-toggle"]').last().bind("click", function(e) {
var $parent = $(this).parent(),
state = $parent.data('state'),
newstate = state == "complete"?"incomplete":"complete",
$details = $parent.find('div.card-task-details');
method = '';
if(state=='take') method='complete'
else if(state=='incomplete') method='take'
else if(state=='complete') method='revert';
if (state != newstate) {
$parent.removeClass('error');
$details = $parent.find('div.card-task-details');
$parent.removeClass('error');
jQuery.ajax({
url: ajaxUrl + card.carddata.path + '/tasks/' + $(this).data('taskid') + '/' + method,
success: function(data) {
var newstate = "incomplete";
if( data.complete ) newstate = "complete"
else if( data.user != "" && data.user!=null ) newstate = "take";
if (newstate == "complete")
$parent.find('div.card-task-details').html('Completed by <strong>' + data.user + '</strong> on ' + convertDateToString(data.occuredTime));
else if (newstate == "take")
$parent.find('div.card-task-details').html('Assigned to <strong>' + data.user + '</strong>')
else if (newstate == "incomplete")
$parent.find('div.card-task-details').html('')
$parent.removeClass('task-' + state);
$parent.addClass('task-' + newstate);
$parent.data('state', newstate);
},
error: function() {
$parent.addClass('error');
}
});
jQuery.ajax({
url: ajaxUrl + card.carddata.path + '/tasks/' + $(this).data('taskid') + '/' + (newstate == "complete"?"complete":"revert"),
success: function(data) {
if (newstate == "complete")
$parent.find('div.card-task-details').html('Completed by <strong>' + (data.user && data.user != null? data.user:"system") + '</strong> on ' + convertDateToString(data.occuredTime));
else
$details.html('');
$parent.removeClass('task-' + state);
$parent.addClass('task-' + newstate);
$parent.data('state', newstate);
},
error: function() {
$parent.addClass('error');
}
});
}
});
});
},
......
......@@ -18,16 +18,20 @@ app.controller('boardCtrl', function($scope, $http) {
}
$scope.phases = phases;
$scope.phase = phases[0].name;
$scope.phasid = phases[0].id;
$scope.phaseid = phases[0].id;
$scope.views = response.views;
$scope.filters = response.filters;
});