Skip to content
This repository has been archived by the owner on Aug 30, 2022. It is now read-only.

Commit

Permalink
Conversation-management: import/export (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
ja-fra committed Sep 7, 2017
1 parent 1b1d8ba commit 7e5a67b
Show file tree
Hide file tree
Showing 10 changed files with 197 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
package io.redlink.smarti.webservice;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.redlink.smarti.model.Conversation;
import io.redlink.smarti.model.ConversationMeta;
import io.redlink.smarti.model.Message;
Expand All @@ -29,10 +30,13 @@
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.bson.types.ObjectId;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Objects;
Expand All @@ -44,10 +48,12 @@
@Api("conversation-admin")
public class ConversationAdminWebservice {

private final ObjectMapper jacksonObjectMapper;
private final ConversationService conversationService;
private final ClientService clientService;

public ConversationAdminWebservice(ConversationService conversationService, ClientService clientService) {
public ConversationAdminWebservice(ObjectMapper jacksonObjectMapper, ConversationService conversationService, ClientService clientService) {
this.jacksonObjectMapper = jacksonObjectMapper;
this.conversationService = conversationService;
this.clientService = clientService;
}
Expand Down Expand Up @@ -141,7 +147,7 @@ public ResponseEntity<?> exportConversations(@RequestParam("owner") ObjectId own
}

@ApiOperation(value = "import conversations")
@RequestMapping(value = "import", method = RequestMethod.POST)
@RequestMapping(value = "import", method = RequestMethod.POST, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE)
public ResponseEntity<?> importConversations(
@RequestParam("owner") ObjectId owner,
@RequestParam(value = "replace", defaultValue = "false", required = false) boolean replace,
Expand All @@ -155,4 +161,24 @@ public ResponseEntity<?> importConversations(
}
}

@ApiOperation(value = "import conversations")
@RequestMapping(value = "import", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<?> importConversations(
@RequestParam("owner") ObjectId owner,
@RequestParam(value = "replace", defaultValue = "false", required = false) boolean replace,
@RequestParam("file") MultipartFile file
) {
if (clientService.exists(owner)) {
try {
final List<Conversation> conversations = jacksonObjectMapper.readValue(file.getInputStream(),
jacksonObjectMapper.getTypeFactory().constructCollectionType(List.class, Conversation.class));
return importConversations(owner, replace, conversations);
} catch (IOException e) {
return ResponseEntity.unprocessableEntity().build();
}
} else {
return ResponseEntity.badRequest().build();
}
}

}
5 changes: 5 additions & 0 deletions frontend/src/app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ <h1>Smarti Configuration</h1>
<script src="bower_components/angular-bootstrap/ui-bootstrap-tpls.js"></script>
<script src="bower_components/angular-toastr/dist/angular-toastr.tpls.js"></script>
<script src="bower_components/angular-animate/angular-animate.js"></script>
<script src="bower_components/ng-file-upload/ng-file-upload.js"></script>
<!-- endbower -->
<script src="bower_components/codemirror/mode/javascript/javascript.js"></script>
<!-- endbuild -->
Expand All @@ -71,5 +72,9 @@ <h1>Smarti Configuration</h1>
<script src="scripts/controllers/conversation.js"></script>
<script src="scripts/controllers/conversationEdit.js"></script>
<!-- endbuild -->

<!-- build:remove -->
<script src="scripts/dev.js"></script>
<!-- endbuild -->
</body>
</html>
1 change: 1 addition & 0 deletions frontend/src/app/scripts/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ angular
'ngAnimate',
'ui.codemirror',
'ui.bootstrap',
'ngFileUpload',
'toastr'
])
.config(function ($routeProvider) {
Expand Down
28 changes: 27 additions & 1 deletion frontend/src/app/scripts/controllers/conversation.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
* Controller of the smartiApp
*/
angular.module('smartiApp')
.controller('ConversationCtrl', function ($scope, $location, client, ConversationService) {
.controller('ConversationCtrl', function ($scope, $location, $route, $uibModal, client, ConversationService) {
var $ctrl = this;

$ctrl.conversations = null;
Expand All @@ -36,6 +36,9 @@ angular.module('smartiApp')

$ctrl.openConversation = openConversation;
$ctrl.backToList = backToList;
$ctrl.import = importConversations;

$scope.downloadLink = ConversationService.buildExportLink(client.data.id);

$scope.$watch('$ctrl.paging.currentPage', loadConversations);
$scope.$watch('$ctrl.paging.pageSize', loadConversations);
Expand Down Expand Up @@ -63,5 +66,28 @@ angular.module('smartiApp')
$location.path('client/' + client.data.id + '/conversations/' + conversationId);
}

function importConversations() {
$uibModal.open({
templateUrl: 'views/modal/import-conversations.html',
controller: function ($uibModalInstance) {
const $modal = this;

$modal.upload = function () {
ConversationService.importConversations(client.data.id, $modal.uploadFile, $modal.uploadReplace)
.then($uibModalInstance.close, $uibModalInstance.dismiss);
};
$modal.cancel = $uibModalInstance.dismiss;

},
controllerAs: '$modal'
}).result
.then(
function() {
$route.reload();
},
function () {

});
}

});
37 changes: 37 additions & 0 deletions frontend/src/app/scripts/dev.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2017 Redlink GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

angular
.module('smartiApp')
.config(function ($httpProvider) {
// $httpProvider.interceptors.push('devAuthInterceptor');
})
.factory('devAuthInterceptor', function($location, $log) {
var user = $location.search().user || 'user',
passwd = $location.search().passwd || user;

$log.error('!!Warning!! Using hard-coded credentials for user "' + user + '"');
return {
'request': function(config) {
if (user && passwd) {
config.withCredentials = true;
config.headers['Authorization'] = 'Basic ' + btoa(user+':'+passwd);
}
return config;
}
};
});
45 changes: 45 additions & 0 deletions frontend/src/app/scripts/services/conversation.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ angular.module('smartiApp')
this.deleteMessage = deleteMessage;

this.setConversationStatus = setConversationStatus;
this.buildExportLink = buildExportLink;
this.importConversations = importConversations;

function getForClient(clientId, page, pageSize) {
return $http.get(ENV.serviceBaseUrl + 'admin/conversation', {
Expand Down Expand Up @@ -73,7 +75,50 @@ angular.module('smartiApp')
.then(function (response) {
return response.data;
});
}

function buildExportLink(owner) {
return `${ENV.serviceBaseUrl}admin/conversation/export?owner=${owner}`
}

function importConversations(owner, file, replaceExisting) {
let data = new FormData();
data.append("file", file);

return $http.post(`${ENV.serviceBaseUrl}admin/conversation/import`, data, {
params: {
owner: owner,
replace: replaceExisting || false
},
headers: {
'Content-Type': undefined
}
})
.then(function (response) {
return response.data;
});
}

function importConversations2(owner, file, replaceExisting) {
let defer = $q.defer(),
reader = new FileReader();

reader.onloadend = function (e) {
let data = e.target.result;

defer.resolve($http.post(`${ENV.serviceBaseUrl}admin/conversation/import`, data, {
params: {
owner: owner,
replace: replaceExisting || false
}
})
.then(function (response) {
return response.data;
}));
};
reader.readAsText(file);

return defer.promise;
}

});
12 changes: 11 additions & 1 deletion frontend/src/app/views/conversations.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,20 @@
</div>
<h2>Conversations for <span ng-bind="$resolve.client.data.name"></span></h2>
</div>
<div>
<a class="btn btn-default"
download="conversations.json"
ng-href="{{downloadLink}}">
<i class="glyphicon glyphicon-download"></i> Export
</a>
<button class="btn btn-default"
ng-click="$ctrl.import()">
<i class="glyphicon glyphicon-upload"></i> Import</button>
</div>
<div>
<div class="clearfix">
<div class="pull-right">
<select ng-model="$ctrl.paging.pageSize" ng-options="s for s in [5, 10, 15, 20]"></select>
<select class="form-control" ng-model="$ctrl.paging.pageSize" ng-options="s for s in [5, 10, 15, 20]"></select>
</div>
</div>
<div>
Expand Down
40 changes: 40 additions & 0 deletions frontend/src/app/views/modal/import-conversations.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!--
~ Copyright 2017 Redlink GmbH
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
~
-->

<form class="form" name="uploadForm" ng-submit="$modal.upload()">
<div class="modal-header">
<h3 class="modal-title">Import Conversations</h3>
</div>
<div class="modal-body" id="modal-body">
<div class="form-group">
<input type="file" name="file"
ngf-select
accept="application/json"
ng-model="$modal.uploadFile" required/>
<p></p>
</div>
<div class="checkbox">
<label><input type="checkbox" ng-model="$modal.uploadReplace" class="checkbox">Replace</label>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-disabled="uploadForm.$invalid">
<i class="glyphicon glyphicon-upload"></i> Importieren
</button>
<button class="btn btn-default" type="reset" ng-click="$modal.cancel()">Cancel</button>
</div>
</form>
3 changes: 2 additions & 1 deletion frontend/src/bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"angular-ui-codemirror": "^0.3.0",
"angular-bootstrap": "^2.5.0",
"angular-toastr": "^2.1.1",
"angular-animate": "^1.6.6"
"angular-animate": "^1.6.6",
"ng-file-upload": "^12.2.13"
},
"devDependencies": {
"angular-mocks": "^1.4.0"
Expand Down
1 change: 1 addition & 0 deletions frontend/src/test/karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ module.exports = function(config) {
'bower_components/angular-bootstrap/ui-bootstrap-tpls.js',
'bower_components/angular-toastr/dist/angular-toastr.tpls.js',
'bower_components/angular-animate/angular-animate.js',
'bower_components/ng-file-upload/ng-file-upload.js',
'bower_components/angular-mocks/angular-mocks.js',
// endbower
"app/scripts/**/*.js",
Expand Down

0 comments on commit 7e5a67b

Please sign in to comment.