diff --git a/appinfo/database.xml b/appinfo/database.xml
index 50af46975..a49526952 100644
--- a/appinfo/database.xml
+++ b/appinfo/database.xml
@@ -38,6 +38,14 @@
boolean
false
+
+ deleted_at
+ integer
+ 0
+ 8
+ false
+ true
+
diff --git a/appinfo/info.xml b/appinfo/info.xml
index 05f092643..6db4b30dd 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -16,7 +16,7 @@
💥 This is still alpha software: it may not be stable enough for production!
- 0.1.4.1
+ 0.1.4.2
agpl
Julius Härtl
Deck
@@ -30,6 +30,9 @@
+
+ OCA\Deck\Cron\DeleteCron
+
OCA\Deck\Migration\UnknownUsers
diff --git a/appinfo/routes.php b/appinfo/routes.php
index 52ddf0455..2f0e32af5 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -31,6 +31,7 @@ return [
['name' => 'board#read', 'url' => '/boards/{boardId}', 'verb' => 'GET'],
['name' => 'board#update', 'url' => '/boards/{boardId}', 'verb' => 'PUT'],
['name' => 'board#delete', 'url' => '/boards/{boardId}', 'verb' => 'DELETE'],
+ ['name' => 'board#deleteUndo', 'url' => '/boards/{boardId}/deleteUndo', 'verb' => 'POST'],
['name' => 'board#getUserPermissions', 'url' => '/boards/{boardId}/permissions', 'verb' => 'GET'],
['name' => 'board#addAcl', 'url' => '/boards/{boardId}/acl', 'verb' => 'POST'],
['name' => 'board#updateAcl', 'url' => '/boards/{boardId}/acl', 'verb' => 'PUT'],
diff --git a/css/style.css b/css/style.css
index 0345bf781..6d5417436 100644
--- a/css/style.css
+++ b/css/style.css
@@ -705,6 +705,10 @@ button.button-inline:hover {
width: 50%;
}
+#boardlist tr.deleted td * {
+ opacity: 0.5;
+}
+
#boardlist td form {
display: flex;
width: 100%;
@@ -722,11 +726,17 @@ button.button-inline:hover {
width: 32px;
}
-#boardlist .popovermenu {
- top: 9px;
- right: -36px;
+#boardlist td .app-popover-menu-utils {
+ float: right;
}
+#boardlist .popovermenu {
+ top: 33px;
+ right: -5px;
+}
+
+
+
/**
* Board details
*/
diff --git a/js/app/Config.js b/js/app/Config.js
index 845979171..68cfcb471 100644
--- a/js/app/Config.js
+++ b/js/app/Config.js
@@ -37,9 +37,10 @@ app.config(function ($provide, $routeProvider, $interpolateProvider, $httpProvid
$stateProvider
.state('list', {
- url: "/",
+ url: "/:filter",
templateUrl: "/boardlist.mainView.html",
controller: 'ListController',
+ reloadOnSearch: false,
params: {
filter: { value: '', dynamic: true }
}
diff --git a/js/controller/BoardController.js b/js/controller/BoardController.js
index 0ad8211d9..46260f2eb 100644
--- a/js/controller/BoardController.js
+++ b/js/controller/BoardController.js
@@ -114,7 +114,6 @@ app.controller('BoardController', function ($rootScope, $scope, $stateParams, St
// Handle initial Loading
BoardService.fetchOne($scope.id).then(function (data) {
- BoardService.getPermissions();
$scope.statusservice.releaseWaiting();
}, function (error) {
$scope.statusservice.setError('Error occured', error);
diff --git a/js/controller/ListController.js b/js/controller/ListController.js
index db21ee0d7..6068b78c3 100644
--- a/js/controller/ListController.js
+++ b/js/controller/ListController.js
@@ -21,7 +21,7 @@
*
*/
-app.controller('ListController', function ($scope, $location, $filter, BoardService, $element, $timeout, $stateParams) {
+app.controller('ListController', function ($scope, $location, $filter, BoardService, $element, $timeout, $stateParams, $state) {
$scope.boards = [];
$scope.newBoard = {};
$scope.status = {
@@ -58,7 +58,7 @@ app.controller('ListController', function ($scope, $location, $filter, BoardServ
} else {
$scope.boardservice.sorted = $filter('cardFilter')($scope.boardservice.sorted, {archived: false});
}
- $scope.boardservice.sorted = $filter('orderBy')($scope.boardservice.sorted, 'title');
+ $scope.boardservice.sorted = $filter('orderBy')($scope.boardservice.sorted, ['deletedAt', 'title']);
};
$scope.$state = $stateParams;
@@ -71,6 +71,13 @@ app.controller('ListController', function ($scope, $location, $filter, BoardServ
$scope.newBoard.color = color;
};
+ $scope.gotoBoard = function(board) {
+ if(board.deletedAt > 0) {
+ return false;
+ }
+ return $state.go('board', {boardId: board.id});
+ };
+
$scope.boardCreate = function() {
if(!$scope.newBoard.title || !$scope.newBoard.color) {
$scope.status.addBoard=false;
@@ -109,24 +116,15 @@ app.controller('ListController', function ($scope, $location, $filter, BoardServ
};
$scope.boardDelete = function(board) {
- var boardId = board.id;
- $scope.status.deleteUndo[boardId] = 10;
- $scope.boardDeleteCountdown = function () {
- if($scope.status.deleteUndo[boardId] > 0) {
- $scope.status.deleteUndo[boardId]--;
- $timeout($scope.boardDeleteCountdown, 1000);
- }
- if($scope.status.deleteUndo[boardId] === 0) {
- BoardService.delete(board.id).then(function (data) {
- $scope.filterData();
- });
- }
- };
- $timeout($scope.boardDeleteCountdown, 1000);
+ BoardService.delete(board.id).then(function (data) {
+ $scope.filterData();
+ });
};
$scope.boardDeleteUndo = function (board) {
- delete $scope.status.deleteUndo[board.id];
+ BoardService.deleteUndo(board.id).then(function (data) {
+ $scope.filterData();
+ })
};
});
diff --git a/js/service/BoardService.js b/js/service/BoardService.js
index 84034e990..1ebb9ef3e 100644
--- a/js/service/BoardService.js
+++ b/js/service/BoardService.js
@@ -26,6 +26,33 @@ app.factory('BoardService', function(ApiService, $http, $q){
};
BoardService.prototype = angular.copy(ApiService.prototype);
+ BoardService.prototype.delete = function (id) {
+ var deferred = $q.defer();
+ var self = this;
+
+ $http.delete(this.baseUrl + '/' + id).then(function (response) {
+ self.data[id].deletedAt = response.data.deletedAt;
+ deferred.resolve(response.data);
+ }, function (error) {
+ deferred.reject('Deleting ' + self.endpoint + ' failed');
+ });
+ return deferred.promise;
+ };
+
+ BoardService.prototype.deleteUndo = function (id) {
+ var deferred = $q.defer();
+ var self = this;
+ var _id = id;
+ $http.post(this.baseUrl + '/' + id + '/deleteUndo').then(function (response) {
+ self.data[_id].deletedAt = 0;
+ console.log(self.data[_id]);
+ deferred.resolve(response.data);
+ }, function (error) {
+ deferred.reject('Deleting ' + self.endpoint + ' failed');
+ });
+ return deferred.promise;
+ };
+
BoardService.prototype.searchUsers = function (search) {
var deferred = $q.defer();
var self = this;
@@ -151,17 +178,6 @@ app.factory('BoardService', function(ApiService, $http, $q){
return deferred.promise;
};
- BoardService.prototype.getPermissions = function() {
- var board = this.getCurrent();
- var deferred = $q.defer();
- $http.get(this.baseUrl + '/' + board.id + '/permissions').then(function (response) {
- board.permissions = response.data;
- deferred.resolve(response.data);
- }, function (error) {
- deferred.reject('Error fetching board permissions ' + board);
- });
- };
-
BoardService.prototype.canRead = function() {
if(!this.getCurrent() || !this.getCurrent().permissions) {
return false;
diff --git a/lib/Controller/BoardController.php b/lib/Controller/BoardController.php
index 52c9641df..f497455d0 100644
--- a/lib/Controller/BoardController.php
+++ b/lib/Controller/BoardController.php
@@ -108,6 +108,14 @@ class BoardController extends Controller {
public function delete($boardId) {
return $this->boardService->delete($boardId);
}
+ /**
+ * @NoAdminRequired
+ * @param $boardId
+ * @return \OCP\AppFramework\Db\Entity
+ */
+ public function deleteUndo($boardId) {
+ return $this->boardService->deleteUndo($boardId);
+ }
/**
* @NoAdminRequired
diff --git a/lib/Cron/DeleteCron.php b/lib/Cron/DeleteCron.php
new file mode 100644
index 000000000..cdf35cedb
--- /dev/null
+++ b/lib/Cron/DeleteCron.php
@@ -0,0 +1,49 @@
+
+ *
+ * @author Julius Härtl
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+/**
+ * Created by PhpStorm.
+ * User: jus
+ * Date: 16.05.17
+ * Time: 12:34
+ */
+
+namespace OCA\Deck\Cron;
+
+use OC\BackgroundJob\Job;
+use OCA\Deck\Db\BoardMapper;
+
+class DeleteCron extends Job {
+
+ public function __construct(BoardMapper $boardMapper) {
+ $this->boardMapper = $boardMapper;
+ }
+
+ protected function run($argument) {
+ $boards = $this->boardMapper->findToDelete();
+ foreach ($boards as $board) {
+ $this->boardMapper->delete($board);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/lib/Db/Board.php b/lib/Db/Board.php
index 3c14c2177..93510ddeb 100644
--- a/lib/Db/Board.php
+++ b/lib/Db/Board.php
@@ -36,11 +36,13 @@ class Board extends RelationalEntity implements JsonSerializable {
protected $acl = [];
protected $permissions = [];
protected $shared;
+ protected $deletedAt;
public function __construct() {
$this->addType('id', 'integer');
$this->addType('shared', 'integer');
$this->addType('archived', 'boolean');
+ $this->addType('deletedAt', 'integer');
$this->addRelation('labels');
$this->addRelation('acl');
$this->addRelation('shared');
diff --git a/lib/Db/BoardMapper.php b/lib/Db/BoardMapper.php
index e1b2d0598..0c16d9d6c 100644
--- a/lib/Db/BoardMapper.php
+++ b/lib/Db/BoardMapper.php
@@ -59,7 +59,7 @@ class BoardMapper extends DeckMapper implements IPermissionMapper {
* @return \OCP\AppFramework\Db\Entity if not found
*/
public function find($id, $withLabels = false, $withAcl = false) {
- $sql = 'SELECT id, title, owner, color, archived FROM `*PREFIX*deck_boards` ' .
+ $sql = 'SELECT id, title, owner, color, archived, deleted_at FROM `*PREFIX*deck_boards` ' .
'WHERE `id` = ?';
$board = $this->findEntity($sql, [$id]);
@@ -87,8 +87,8 @@ class BoardMapper extends DeckMapper implements IPermissionMapper {
* @return array
*/
public function findAllByUser($userId, $limit = null, $offset = null) {
- $sql = 'SELECT id, title, owner, color, archived, 0 as shared FROM `*PREFIX*deck_boards` WHERE owner = ? UNION ' .
- 'SELECT boards.id, title, owner, color, archived, 1 as shared FROM `*PREFIX*deck_boards` as boards ' .
+ $sql = 'SELECT id, title, owner, color, archived, deleted_at, 0 as shared FROM `*PREFIX*deck_boards` WHERE owner = ? UNION ' .
+ 'SELECT boards.id, title, owner, color, archived, deleted_at, 1 as shared FROM `*PREFIX*deck_boards` as boards ' .
'JOIN `*PREFIX*deck_board_acl` as acl ON boards.id=acl.board_id WHERE acl.participant=? AND acl.type=? AND boards.owner != ?';
$entries = $this->findEntities($sql, [$userId, $userId, Acl::PERMISSION_TYPE_USER, $userId], $limit, $offset);
/* @var Board $entry */
@@ -112,7 +112,7 @@ class BoardMapper extends DeckMapper implements IPermissionMapper {
if (count($groups) <= 0) {
return [];
}
- $sql = 'SELECT boards.id, title, owner, color, archived, 2 as shared FROM `*PREFIX*deck_boards` as boards ' .
+ $sql = 'SELECT boards.id, title, owner, color, archived, deleted_at, 2 as shared FROM `*PREFIX*deck_boards` as boards ' .
'INNER JOIN `*PREFIX*deck_board_acl` as acl ON boards.id=acl.board_id WHERE owner != ? AND type=? AND (';
for ($i = 0; $i < count($groups); $i++) {
$sql .= 'acl.participant = ? ';
@@ -135,6 +135,15 @@ class BoardMapper extends DeckMapper implements IPermissionMapper {
return $this->findEntities($sql, []);
}
+ public function findToDelete() {
+ // add buffer of 5 min
+ $timeLimit = time()-(60*5);
+ $sql = 'SELECT id, title, owner, color, archived, deleted_at FROM `*PREFIX*deck_boards` ' .
+ 'WHERE `deleted_at` > 0 AND `deleted_at` < ?';
+ \OC::$server->getLogger()->error($sql);
+ return $this->findEntities($sql, [$timeLimit]);
+ }
+
public function delete(/** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */
\OCP\AppFramework\Db\Entity $entity) {
// delete acl
diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php
index 0aac91b07..e7037553c 100644
--- a/lib/Service/BoardService.php
+++ b/lib/Service/BoardService.php
@@ -107,6 +107,23 @@ class BoardService {
return $board->getArchived();
}
+ public function isDeleted($mapper, $id) {
+ try {
+ if ($mapper instanceof IPermissionMapper) {
+ $boardId = $mapper->findBoardId($id);
+ } else {
+ $boardId = $id;
+ }
+ if ($boardId === null) {
+ return false;
+ }
+ } catch (DoesNotExistException $exception) {
+ return false;
+ }
+ $board = $this->find($boardId);
+ return $board->getDeletedAt() > 0;
+ }
+
public function create($title, $userId, $color) {
@@ -139,7 +156,17 @@ class BoardService {
public function delete($id) {
$this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_READ);
- return $this->boardMapper->delete($this->find($id));
+ $board = $this->find($id);
+ $board->setDeletedAt(time());
+ $this->boardMapper->update($board);
+ return $board;
+ }
+
+ public function deleteUndo($id) {
+ $this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_READ);
+ $board = $this->find($id);
+ $board->setDeletedAt(0);
+ $this->boardMapper->update($board);
}
public function update($id, $title, $color, $archived) {
diff --git a/templates/part.boardlist.php b/templates/part.boardlist.php
index 32892494a..35380a435 100644
--- a/templates/part.boardlist.php
+++ b/templates/part.boardlist.php
@@ -9,12 +9,12 @@
-
- |
+ |
+ |
|
- {{ b.title }} |
+ {{ b.title }} |
|
- |
diff --git a/templates/part.navigation.php b/templates/part.navigation.php
index 8d151fb81..96c9264fb 100644
--- a/templates/part.navigation.php
+++ b/templates/part.navigation.php
@@ -1,7 +1,7 @@