export task complete
This commit is contained in:
parent
126575f0bf
commit
7640c1dab6
@ -1,18 +1,27 @@
|
||||
package com.pudonghot.ambition.crm.controller;
|
||||
|
||||
import lombok.val;
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import javax.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chyxion.tigon.mybatis.Search;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import com.pudonghot.ambition.crm.model.User;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import me.chyxion.tigon.web.controller2.ArgQuery;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import com.pudonghot.ambition.crm.model.ExportTask;
|
||||
import com.pudonghot.ambition.crm.auth.SessionAbility;
|
||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||
import com.pudonghot.ambition.crm.util.FileDownloadUtils;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import me.chyxion.tigon.web.controller2.BaseQueryController;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import com.pudonghot.ambition.crm.service.ExportTaskService;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import com.pudonghot.ambition.crm.ws.service.WebSocketService;
|
||||
@ -43,6 +52,40 @@ public class ExportTaskController
|
||||
return list(req, new Search());
|
||||
}
|
||||
|
||||
/**
|
||||
* download file
|
||||
* @param id id
|
||||
* @return file
|
||||
*/
|
||||
@RequiresRoles(User.ROLE_ADMIN)
|
||||
@RequestMapping("/download")
|
||||
public ResponseEntity file(@NotNull @RequestParam("id") final Long id) {
|
||||
val exportTask = service.find(id);
|
||||
if (exportTask == null) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
val userId = getUserId();
|
||||
|
||||
if (!userId.equals(exportTask.getCreatedBy())) {
|
||||
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
|
||||
}
|
||||
|
||||
exportTask.setDownloaded(true);
|
||||
exportTask.setUpdatedBy(userId);
|
||||
((ExportTaskService) service).update(exportTask);
|
||||
|
||||
val location = exportTask.getLocation();
|
||||
if (StringUtils.isNotBlank(location)) {
|
||||
val file = new File(location);
|
||||
if (file.exists() && file.isFile()) {
|
||||
((ExportTaskService) service).notifyTaskUpdated(userId);
|
||||
return FileDownloadUtils.toResponseEntity(file, file.getName());
|
||||
}
|
||||
}
|
||||
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
@ -62,8 +105,7 @@ public class ExportTaskController
|
||||
|
||||
@PostMapping("/test-push")
|
||||
@RequiresRoles(User.ROLE_ADMIN)
|
||||
public void testPush(@RequestBody ExportTaskUpdatedWsResp resp) {
|
||||
resp.setEmployeeKey(getUserId());
|
||||
webSocketService.publish(resp);
|
||||
public void testPush(@RequestBody Map<String, Object> resp) {
|
||||
webSocketService.publish(getUserId(), resp);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.pudonghot.ambition.crm.service;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import com.pudonghot.ambition.crm.model.ExportTask;
|
||||
import me.chyxion.tigon.service2.BaseQueryService;
|
||||
@ -26,5 +27,12 @@ public interface ExportTaskService extends BaseQueryService<Long, ExportTask> {
|
||||
* @param employeeKey employee key
|
||||
*/
|
||||
void notifyTaskUpdated(@NotBlank String employeeKey);
|
||||
|
||||
/**
|
||||
* update task
|
||||
*
|
||||
* @param exportTask task
|
||||
*/
|
||||
void update(@NotNull ExportTask exportTask);
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ import com.pudonghot.ambition.crm.ws.service.WebSocketService;
|
||||
import me.chyxion.tigon.service.support2.BaseQueryServiceSupport;
|
||||
import com.pudonghot.ambition.crm.enumeration.EnumExportTaskStatus;
|
||||
import com.pudonghot.ambition.crm.ws.model.ExportTaskUpdatedWsResp;
|
||||
import com.pudonghot.ambition.crm.ws.model.ExportTaskCompletedWsResp;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
@ -73,15 +74,16 @@ public class ExportTaskServiceSupport
|
||||
exportTask.setLocation(new File(distDir, exportFile.getName()).getPath());
|
||||
exportTask.setDateUpdated(new Date());
|
||||
mapper.update(exportTask);
|
||||
} catch (final Throwable e) {
|
||||
notifyTaskComplete(employeeKey, true, null);
|
||||
}
|
||||
catch (final Throwable e) {
|
||||
log.error("Export file error caused.", e);
|
||||
exportTask.setStatus(EnumExportTaskStatus.FAILED);
|
||||
exportTask.setNote(ExceptionUtils.getStackTrace(e));
|
||||
exportTask.setDateUpdated(new Date());
|
||||
mapper.update(exportTask);
|
||||
notifyTaskComplete(employeeKey, false, e.getMessage());
|
||||
}
|
||||
|
||||
notifyTaskUpdated(employeeKey);
|
||||
}
|
||||
finally {
|
||||
LOCK_MAP.remove(employeeKey);
|
||||
@ -89,6 +91,15 @@ public class ExportTaskServiceSupport
|
||||
});
|
||||
}
|
||||
|
||||
void notifyTaskComplete(final String employeeKey, final boolean success, final String message) {
|
||||
val resp = new ExportTaskCompletedWsResp(employeeKey,
|
||||
mapper.count(new Search(ExportTask.CREATED_BY, employeeKey)
|
||||
.isFalse(ExportTask.DOWNLOADED)));
|
||||
resp.setSuccess(success);
|
||||
resp.setMessage(message);
|
||||
webSocketService.publish(resp);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@ -99,4 +110,12 @@ public class ExportTaskServiceSupport
|
||||
mapper.count(new Search(ExportTask.CREATED_BY, employeeKey)
|
||||
.isFalse(ExportTask.DOWNLOADED))));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void update(final ExportTask exportTask) {
|
||||
mapper.update(exportTask);
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import org.springframework.http.MediaType;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
@ -36,16 +36,11 @@ public class FileDownloadUtils {
|
||||
headers.add("Pragma", "no-cache");
|
||||
headers.add("Expires", "0");
|
||||
|
||||
try (val fin = new FileInputStream(file)) {
|
||||
return ResponseEntity.ok()
|
||||
.headers(headers)
|
||||
.contentLength(file.length())
|
||||
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
||||
.body(new InputStreamResource(fin));
|
||||
}
|
||||
catch (final IOException e) {
|
||||
log.error("Download file error caused.", e);
|
||||
}
|
||||
return ResponseEntity.ok()
|
||||
.headers(headers)
|
||||
.contentLength(file.length())
|
||||
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
||||
.body(new FileSystemResource(file));
|
||||
}
|
||||
|
||||
return ResponseEntity.notFound().build();
|
||||
|
@ -0,0 +1,30 @@
|
||||
package com.pudonghot.ambition.crm.ws.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Jun 17, 2022 15:01:49
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class ExportTaskCompletedWsResp extends BaseWsResp {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Integer countUndownloaded;
|
||||
private Boolean success;
|
||||
private String message;
|
||||
|
||||
public ExportTaskCompletedWsResp() {
|
||||
setType("EXPORT_TASK_COMPLETED");
|
||||
}
|
||||
|
||||
public ExportTaskCompletedWsResp(final String employeeKey, final Integer countUndownloaded) {
|
||||
this();
|
||||
this.countUndownloaded = countUndownloaded;
|
||||
setEmployeeKey(employeeKey);
|
||||
}
|
||||
}
|
@ -15,7 +15,6 @@ public class ExportTaskUpdatedWsResp extends BaseWsResp {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Integer countUndownloaded;
|
||||
private Integer countFailed;
|
||||
|
||||
public ExportTaskUpdatedWsResp() {
|
||||
setType("EXPORT_TASK_UPDATED");
|
||||
|
@ -21,7 +21,7 @@ datasource:
|
||||
username: root
|
||||
|
||||
database:
|
||||
backup-dir: /Users/chyxion/Workspaces/ambition-crm/database_backups
|
||||
backup-dir: d:/data/database_backups
|
||||
restore-shell: /data/program/mysql-backup/bin/mysql_restore.sh
|
||||
|
||||
file:
|
||||
|
@ -1,5 +1,12 @@
|
||||
import BaseListRoute from './../base-list';
|
||||
import { set } from '@ember/object';
|
||||
|
||||
export default BaseListRoute.extend({
|
||||
breadcrumbs: [{text: 'Export Tasks'}]
|
||||
breadcrumbs: [{text: 'Export Tasks'}],
|
||||
actions: {
|
||||
download(rec) {
|
||||
const me = this;
|
||||
set(rec, 'downloaded', true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -7,8 +7,20 @@ export default BaseService.extend({
|
||||
const me = this;
|
||||
$.on('WEBSOCKET', function(e, data) {
|
||||
console.log('Export task: On websocket message trigger.', e, data);
|
||||
if (data.type == 'EXPORT_TASK_UPDATED') {
|
||||
me.set('countUndownloaded', data ? data.countUndownloaded : null);
|
||||
if (!data) {
|
||||
console.log('Event data is null, ignore.', e);
|
||||
return;
|
||||
}
|
||||
|
||||
me.set('countUndownloaded', data.countUndownloaded);
|
||||
|
||||
if (data.type == 'EXPORT_TASK_COMPLETED') {
|
||||
if (data.success) {
|
||||
me.get('message').alert('Export task completed.');
|
||||
}
|
||||
else {
|
||||
me.get('message').error('Export task error caused: ' + data.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -11,6 +11,11 @@ export default Service.extend({
|
||||
warn(msg) {
|
||||
toastr.warning(msg);
|
||||
},
|
||||
error(msg) {
|
||||
toastr.options.closeButton = true;
|
||||
toastr.error(msg);
|
||||
toastr.options.closeButton = false;
|
||||
},
|
||||
alert2(msg) {
|
||||
this._show_alert_(msg);
|
||||
},
|
||||
|
@ -118,7 +118,7 @@ input[type="number"] {
|
||||
font-size: 10px;
|
||||
border-radius: 50%;
|
||||
color: #fff;
|
||||
background-color: rgba(255, 0, 0, 0.8);
|
||||
background-color: rgba(209, 91, 71, 0.9);
|
||||
// rgba(0, 0, 0, 0.7);
|
||||
|
||||
display: flex;
|
||||
|
@ -100,9 +100,11 @@
|
||||
</li>
|
||||
<li>
|
||||
<LinkTo @route="export-task.list" @model=1>
|
||||
<i class="menu-icon fa fa-tasks {{if this.exportTaskService.countUndownloaded 'green' 'blue'}}"></i>
|
||||
<span class="export-task-badge">21</span>
|
||||
<span class="menu-text"> Export Task {{#if this.exportTaskService.countUndownloaded}}<span class="badge badge-danger">{{this.exportTaskService.countUndownloaded}}</span>{{/if}}</span>
|
||||
<i class="menu-icon fa fa-tasks blue"></i>
|
||||
{{#if this.exportTaskService.countUndownloaded}}
|
||||
<span class="export-task-badge">{{this.exportTaskService.countUndownloaded}}</span>
|
||||
{{/if}}
|
||||
<span class="menu-text"> Export Task </span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
@ -7,7 +7,9 @@
|
||||
<table class="table table-striped table-bordered table-hover dataTable" style="border: 1px solid #ddd;">
|
||||
<thead class="thin-border-bottom">
|
||||
<tr>
|
||||
{{sortable-th name='dateCreated' text='Date Created' style='min-width: 105px;'}}
|
||||
<th>
|
||||
Date Created
|
||||
</th>
|
||||
<th>
|
||||
<i class="ace-icon fa fa-exchange bigger-110"></i>
|
||||
Status
|
||||
@ -32,32 +34,24 @@
|
||||
{{it.status}}
|
||||
</td>
|
||||
<td>
|
||||
{{status-cell model=it field='downloaded' enabledText='DOWNLOADED' disabledText='NOT DOWNLOAD'}}
|
||||
{{#if it.downloaded}}
|
||||
<span class="green">
|
||||
<i class="ace-icon fa fa-check-square bigger-120"></i>
|
||||
DOWNLOADED
|
||||
</span>
|
||||
{{else}}
|
||||
<span class="blue">
|
||||
<i class="ace-icon fa fa-spinner bigger-120"></i>
|
||||
NOT DOWNLOAD
|
||||
</span>
|
||||
{{/if}}
|
||||
</td>
|
||||
<td>
|
||||
<div class="hidden-sm hidden-xs btn-group">
|
||||
{{#link-to 'user.edit' it.id class='btn btn-xs btn-info' data-rel='tooltip' title='Download'}}
|
||||
<i class="ace-icon fa fa-pencil bigger-120"></i>
|
||||
<div class="btn-group">
|
||||
<a {{on 'click' (route-action 'download' it)}} target="_blank" href="/export-task/download?id={{it.id}}" class="btn btn-xs btn-info" data-rel="tooltip" title="Download">
|
||||
<i class="ace-icon fa fa-download bigger-120"></i>
|
||||
Download
|
||||
{{/link-to}}
|
||||
</div>
|
||||
<div class="hidden-md hidden-lg">
|
||||
<div class="inline pos-rel">
|
||||
<button class="btn btn-minier btn-primary dropdown-toggle" data-toggle="dropdown" data-position="auto">
|
||||
<i class="ace-icon fa fa-cog icon-only bigger-110"></i>
|
||||
</button>
|
||||
|
||||
<ul class="dropdown-menu dropdown-only-icon dropdown-yellow dropdown-menu-right dropdown-caret dropdown-close">
|
||||
<li>
|
||||
{{#link-to 'user.edit' it.id class='tooltip-info' data-rel='tooltip' title='Download'}}
|
||||
<span class="blue">
|
||||
<i class="ace-icon fa fa-pencil-square-o bigger-120"></i>
|
||||
Download
|
||||
</span>
|
||||
{{/link-to}}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
Loading…
x
Reference in New Issue
Block a user