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