diff --git a/appinfo/routes.php b/appinfo/routes.php index 7f79fbf4..931cd368 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -31,7 +31,8 @@ return [ ['name' => 'utils#setAllowAnonymousCreation', 'url' => '/setAllowAnonymousCreation', 'verb' => 'POST'], ['name' => 'page#getUserList', 'url' => '/getUserList', 'verb' => 'POST'], ['name' => 'page#addUserShare', 'url' => '/addUserShare', 'verb' => 'POST'], - ['name' => 'page#getPublicShare', 'url' => '/getPublicShare', 'verb' => 'POST'], + ['name' => 'page#getPublicFileShare', 'url' => '/getPublicFileShare', 'verb' => 'POST'], + ['name' => 'page#importCsvProject', 'url' => '/importCsvProject', 'verb' => 'POST'], ['name' => 'page#deleteUserShare', 'url' => '/deleteUserShare', 'verb' => 'POST'], ['name' => 'page#webGetProjects', 'url' => 'getProjects', 'verb' => 'POST'], ['name' => 'page#webCreateProject', 'url' => 'createProject', 'verb' => 'POST'], diff --git a/controller/pagecontroller.php b/controller/pagecontroller.php index 44611afe..32355c61 100644 --- a/controller/pagecontroller.php +++ b/controller/pagecontroller.php @@ -2027,7 +2027,7 @@ class PageController extends Controller { /** * @NoAdminRequired */ - public function getPublicShare($path) { + public function getPublicFileShare($path) { $cleanPath = str_replace(array('../', '..\\'), '', $path); $userFolder = \OC::$server->getUserFolder(); if ($userFolder->nodeExists($cleanPath)) { @@ -2069,4 +2069,152 @@ class PageController extends Controller { return $response; } + /** + * @NoAdminRequired + */ + public function importCsvProject($path) { + $cleanPath = str_replace(array('../', '..\\'), '', $path); + $userFolder = \OC::$server->getUserFolder(); + if ($userFolder->nodeExists($cleanPath)) { + $file = $userFolder->get($cleanPath); + if ($file->getType() === \OCP\Files\FileInfo::TYPE_FILE) { + if (($handle = $file->fopen('r')) !== false) { + $columns = []; + $membersWeight = []; + $bills = []; + $row = 0; + while (($data = fgetcsv($handle, 1000, ',')) !== false) { + // first line : get column order + if ($row === 0) { + $nbCol = count($data); + if ($nbCol !== 6) { + fclose($handle); + $response = new DataResponse(['message'=>'Malformed CSV, bad column number'], 401); + return $response; + } + else { + for ($c=0; $c < $nbCol; $c++) { + $columns[$data[$c]] = $c; + } + } + if (!array_key_exists('what', $columns) or + !array_key_exists('amount', $columns) or + !array_key_exists('date', $columns) or + !array_key_exists('payer_name', $columns) or + !array_key_exists('payer_weight', $columns) or + !array_key_exists('owers', $columns) + ) { + fclose($handle); + $response = new DataResponse(['message'=>'Malformed CSV, bad column names'], 401); + return $response; + } + } + // normal line : bill + else { + $what = $data[$columns['what']]; + $amount = $data[$columns['amount']]; + $date = $data[$columns['date']]; + $payer_name = $data[$columns['payer_name']]; + $payer_weight = $data[$columns['payer_weight']]; + $owers = $data[$columns['owers']]; + + // manage members + if (is_numeric($payer_weight)) { + $membersWeight[$payer_name] = floatval($payer_weight); + } + else { + fclose($handle); + $response = new DataResponse(['message'=>'Malformed CSV, bad payer weight on line '.$row], 401); + return $response; + } + if (strlen($owers) === 0) { + fclose($handle); + $response = new DataResponse(['message'=>'Malformed CSV, bad owers on line '.$row], 401); + return $response; + } + $owersArray = explode(', ', $owers); + foreach ($owersArray as $ower) { + if (strlen($ower) === 0) { + fclose($handle); + $response = new DataResponse(['message'=>'Malformed CSV, bad owers on line '.$row], 401); + return $response; + } + if (!array_key_exists($ower, $membersWeight)) { + $membersWeight[$ower] = 1.0; + } + } + if (!is_numeric($amount)) { + fclose($handle); + $response = new DataResponse(['message'=>'Malformed CSV, bad amount on line '.$row], 401); + return $response; + } + array_push($bills, + [ + 'what'=>$what, + 'date'=>$date, + 'amount'=>$amount, + 'payer_name'=>$payer_name, + 'owers'=>$owersArray, + ] + ); + } + $row++; + } + fclose($handle); + + $memberNameToId = []; + + // add project + $user = $this->userManager->get($this->userId); + $userEmail = $user->getEMailAddress(); + $projectid = str_replace('.csv', '', $file->getName()); + $projectName = $projectid; + $projResult = $this->createProject($projectName, $projectid, 'password', $userEmail, $this->userId); + if ($projResult->getStatus() !== 200) { + $response = new DataResponse(['message'=>'Error in project creation'], 401); + return $response; + } + // add members + foreach ($membersWeight as $memberName => $weight) { + $addMemberResult = $this->addMember($projectid, $memberName, $weight); + if ($addMemberResult->getStatus() !== 200) { + $response = new DataResponse(['message'=>'Error when adding member '.$memberName], 401); + return $response; + } + $data = $addMemberResult->getData(); + $memberId = $data; + + $memberNameToId[$memberName] = $memberId; + } + // add bills + foreach ($bills as $bill) { + $payerId = $memberNameToId[$bill['payer_name']]; + $owerIds = []; + foreach ($bill['owers'] as $owerName) { + array_push($owerIds, $memberNameToId[$owerName]); + } + $owerIdsStr = implode(',', $owerIds); + $addBillResult = $this->addBill($projectid, $bill['date'], $bill['what'], $payerId, $owerIdsStr, $bill['amount']); + if ($addBillResult->getStatus() !== 200) { + $response = new DataResponse(['message'=>'Error when adding bill '.$bill['what']], 401); + return $response; + } + } + $response = new DataResponse($projectid); + } + else { + $response = new DataResponse(['message'=>'Access denied'], 403); + } + } + else { + $response = new DataResponse(['message'=>'Access denied'], 403); + } + } + else { + $response = new DataResponse(['message'=>'Access denied'], 403); + } + + return $response; + } + } diff --git a/js/cospend.js b/js/cospend.js index 25e56270..1d886f46 100644 --- a/js/cospend.js +++ b/js/cospend.js @@ -602,6 +602,11 @@ } }).done(function (response) { if (!cospend.pageIsPublic) { + $('.projectitem').remove(); + $('#bill-list').html(''); + cospend.bills = {}; + cospend.members = {}; + cospend.projects = {}; for (var i = 0; i < response.length; i++) { addProject(response[i]); } @@ -1518,7 +1523,7 @@ var req = { path: targetPath }; - var url = OC.generateUrl('/apps/cospend/getPublicShare'); + var url = OC.generateUrl('/apps/cospend/getPublicFileShare'); $.ajax({ type: 'POST', url: url, @@ -1540,6 +1545,31 @@ }); } + function importProject(targetPath) { + if (!endsWith(targetPath, '.csv')) { + OC.Notification.showTemporary(t('cospend', 'Only CSV files can be imported')); + return; + } + $('#addFileLinkButton').addClass('icon-loading-small'); + var req = { + path: targetPath + }; + var url = OC.generateUrl('/apps/cospend/importCsvProject'); + $.ajax({ + type: 'POST', + url: url, + data: req, + async: true + }).done(function (response) { + $('#addFileLinkButton').removeClass('icon-loading-small'); + getProjects(); + }).always(function() { + }).fail(function(response) { + $('#addFileLinkButton').removeClass('icon-loading-small'); + OC.Notification.showTemporary(t('cospend', 'Failed to import project file') + ' ' + response.responseText); + }); + } + $(document).ready(function() { cospend.pageIsPublic = (document.URL.indexOf('/cospend/project') !== -1); if ( !cospend.pageIsPublic ) { @@ -1548,6 +1578,7 @@ else { //restoreOptionsFromUrlParams(); $('#newprojectbutton').hide(); + $('#importProjectButton').hide(); cospend.projectid = $('#projectid').text(); cospend.password = $('#password').text(); cospend.restoredSelectedProjectId = cospend.projectid; @@ -2004,6 +2035,16 @@ ); }); + $('body').on('click', '#importProjectButton', function() { + OC.dialogs.filepicker( + t('cospend', 'Choose csv project file'), + function(targetPath) { + importProject(targetPath); + }, + false, null, true + ); + }); + // last thing to do : get the projects getProjects(); } diff --git a/templates/mainnavigation.php b/templates/mainnavigation.php index 1a2f1287..8ea3444b 100644 --- a/templates/mainnavigation.php +++ b/templates/mainnavigation.php @@ -49,6 +49,9 @@ +