diff --git a/database_backups/20180217030001.sql.gz b/database_backups/20180217030001.sql.gz new file mode 100644 index 0000000..21c64e0 Binary files /dev/null and b/database_backups/20180217030001.sql.gz differ diff --git a/database_backups/20180218030001.sql.gz b/database_backups/20180218030001.sql.gz new file mode 100644 index 0000000..a0bd86b Binary files /dev/null and b/database_backups/20180218030001.sql.gz differ diff --git a/database_backups/20180219030001.sql.gz b/database_backups/20180219030001.sql.gz new file mode 100644 index 0000000..723057b Binary files /dev/null and b/database_backups/20180219030001.sql.gz differ diff --git a/database_backups/20180220030001.sql.gz b/database_backups/20180220030001.sql.gz new file mode 100644 index 0000000..7e065e2 Binary files /dev/null and b/database_backups/20180220030001.sql.gz differ diff --git a/database_backups/20180221030001.sql.gz b/database_backups/20180221030001.sql.gz new file mode 100644 index 0000000..96880a3 Binary files /dev/null and b/database_backups/20180221030001.sql.gz differ diff --git a/database_backups/20180222030001.sql.gz b/database_backups/20180222030001.sql.gz new file mode 100644 index 0000000..91a4d87 Binary files /dev/null and b/database_backups/20180222030001.sql.gz differ diff --git a/database_backups/20180223030001.sql.gz b/database_backups/20180223030001.sql.gz new file mode 100644 index 0000000..e604254 Binary files /dev/null and b/database_backups/20180223030001.sql.gz differ diff --git a/server/crm/src/main/java/com/pudonghot/ambition/crm/controller/DatabaseBackupController.java b/server/crm/src/main/java/com/pudonghot/ambition/crm/controller/DatabaseBackupController.java new file mode 100644 index 0000000..5c03e35 --- /dev/null +++ b/server/crm/src/main/java/com/pudonghot/ambition/crm/controller/DatabaseBackupController.java @@ -0,0 +1,45 @@ +package com.pudonghot.ambition.crm.controller; + +import java.util.Date; +import java.util.List; +import javax.validation.constraints.NotNull; +import com.pudonghot.ambition.crm.model.User; +import org.springframework.stereotype.Controller; +import org.apache.shiro.authz.annotation.RequiresRoles; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.beans.factory.annotation.Autowired; +import com.pudonghot.ambition.crm.service.DatabaseBackupService; + +/** + * @author Shaun Chyxion
+ * chyxion@163.com
+ * Mar 10, 2017 23:15:01 + */ +@Validated +@Controller +@RequiresRoles(User.ROLE_ADMIN) +@RequestMapping("/database-backup") +public class DatabaseBackupController { + @Autowired + private DatabaseBackupService databaseBackupService; + + /** + * list backups + * @return database backups + */ + @RequestMapping("/list") + public List list() { + return databaseBackupService.list(); + } + + @RequestMapping(value = "/restore", method = RequestMethod.POST) + public void restore( + @NotNull + @RequestParam("date") + final Long date) { + databaseBackupService.restore(new Date(date)); + } +} diff --git a/server/crm/src/main/java/com/pudonghot/ambition/crm/service/DatabaseBackupService.java b/server/crm/src/main/java/com/pudonghot/ambition/crm/service/DatabaseBackupService.java new file mode 100644 index 0000000..99c3862 --- /dev/null +++ b/server/crm/src/main/java/com/pudonghot/ambition/crm/service/DatabaseBackupService.java @@ -0,0 +1,29 @@ +package com.pudonghot.ambition.crm.service; + +import java.util.Date; +import java.util.List; +import javax.validation.constraints.NotNull; +import org.springframework.validation.annotation.Validated; + +/** + * @version 0.0.1 + * @since 0.0.1 + * @author Shaun Chyxion
+ * chyxion@163.com
+ * May 4, 2016 1:18:42 PM + */ +@Validated +public interface DatabaseBackupService { + /** + * list database backup dates + * @return database backup dates + */ + List list(); + + /** + * restore to date + * @param date date + */ + void restore(@NotNull Date date); +} + diff --git a/server/crm/src/main/java/com/pudonghot/ambition/crm/service/support/DatabaseBackupServiceSupport.java b/server/crm/src/main/java/com/pudonghot/ambition/crm/service/support/DatabaseBackupServiceSupport.java new file mode 100644 index 0000000..da1de38 --- /dev/null +++ b/server/crm/src/main/java/com/pudonghot/ambition/crm/service/support/DatabaseBackupServiceSupport.java @@ -0,0 +1,74 @@ +package com.pudonghot.ambition.crm.service.support; + +import java.io.File; +import java.util.Date; +import java.util.List; +import java.io.IOException; +import java.util.Comparator; +import java.text.ParseException; +import lombok.extern.slf4j.Slf4j; +import java.util.stream.Collectors; +import org.apache.commons.io.FileUtils; +import org.springframework.stereotype.Service; +import org.apache.commons.lang3.time.DateUtils; +import org.apache.commons.lang3.time.DateFormatUtils; +import org.springframework.beans.factory.annotation.Value; +import com.pudonghot.ambition.crm.service.DatabaseBackupService; + +/** + * @version 0.0.1 + * @since 0.0.1 + * @author Shaun Chyxion
+ * chyxion@163.com
+ * Sep 22, 2015 10:45:41 AM + */ +@Slf4j +@Service +public class DatabaseBackupServiceSupport implements DatabaseBackupService { + + @Value("${database.backup-dir}") + private String backupDir; + @Value("${database.restore-shell}") + private String restoreShell; + private static final String FILE_NAME_DATE_FORMAT = "yyyyMMddHHmmss"; + + /** + * {@inheritDoc} + */ + @Override + public List list() { + return FileUtils.listFiles(new File(backupDir), new String[] { "gz" }, false) + .stream().map(this::fileNameToDate) + .sorted(Comparator.reverseOrder()) + .collect(Collectors.toList()); + } + + /** + * {@inheritDoc} + */ + @Override + public void restore(final Date date) { + log.info("Restore database backup [{}].", date); + try { + Runtime.getRuntime().exec(restoreShell + " " + + DateFormatUtils.format(date, FILE_NAME_DATE_FORMAT)).waitFor(); + } + catch (final IOException | InterruptedException e) { + throw new IllegalStateException( + "Restore database backup [" + date + "] error caused", e); + } + } + + private Date fileNameToDate(final File file) { + log.info("Parse file [{}] to date.", file); + final String name = file.getName(); + try { + return DateUtils.parseDate(name.substring(0, name.length() - 7), + FILE_NAME_DATE_FORMAT); + } + catch (ParseException e) { + throw new IllegalStateException( + "Parse file name [" + name + "] to date error caused", e); + } + } +} diff --git a/server/crm/src/main/resources/application_dev.properties b/server/crm/src/main/resources/application_dev.properties index b2949a2..e5d0400 100644 --- a/server/crm/src/main/resources/application_dev.properties +++ b/server/crm/src/main/resources/application_dev.properties @@ -8,6 +8,8 @@ datasource.port=63306 datasource.database-name=ambition_crm_test datasource.username=root datasource.password=696@2^~)oZ@^#*Q +database.backup-dir=/Users/chyxion/Workspaces/ambition-crm/database_backups +database.restore-shell=/data/program/mysql-backup/bin/mysql_restore.sh # Shiro shiro.session.validation.scheduler.enabled=true diff --git a/server/crm/src/main/resources/application_prod.properties b/server/crm/src/main/resources/application_prod.properties index a09087f..64baa7c 100644 --- a/server/crm/src/main/resources/application_prod.properties +++ b/server/crm/src/main/resources/application_prod.properties @@ -8,6 +8,8 @@ datasource.port=43306 datasource.database-name=ambition_crm datasource.username=root datasource.password=696@2^~)oZ@^#*Q +database.backup-dir=/data/program/mysql-backup/backup/ambition_crm +database.backup-shell=/data/program/mysql-backup/bin/mysql_restore.sh # Shiro shiro.session.validation.scheduler.enabled=true diff --git a/web/app/components/grid-header.js b/web/app/components/grid-header.js index d67ed90..19bc333 100644 --- a/web/app/components/grid-header.js +++ b/web/app/components/grid-header.js @@ -2,5 +2,6 @@ import Ember from 'ember'; export default Ember.Component.extend({ classNames: ['widget-header'], - dropdownMenu: true + dropdownMenu: true, + 'search-box': true }); diff --git a/web/app/router.js b/web/app/router.js index ae39069..3cb9bce 100644 --- a/web/app/router.js +++ b/web/app/router.js @@ -64,6 +64,10 @@ Router.map(function() { this.route('create'); this.route('edit', {path: '/:id/edit'}); }); + + this.route('database-backup', function() { + this.route('list'); + }); }); export default Router; diff --git a/web/app/routes/database-backup/list.js b/web/app/routes/database-backup/list.js new file mode 100644 index 0000000..b2fa1fd --- /dev/null +++ b/web/app/routes/database-backup/list.js @@ -0,0 +1,18 @@ +import BaseRoute from '../base'; + +export default BaseRoute.extend({ + breadcrumbs: [{text: 'Database Backup'}], + model() { + return this.get('store').ajaxGet('database-backup/list'); + }, + actions: { + restore(date) { + const me = this; + me.get('dialog').confirm('Are you sure to restore database backup?', () => { + me.get('store').ajaxPost('database-backup/restore', {date}).then(() => { + me.get('message').alert('Database backup restored successfully'); + }); + }); + } + } +}); diff --git a/web/app/templates/components/grid-header.hbs b/web/app/templates/components/grid-header.hbs index 37016a9..33f943d 100644 --- a/web/app/templates/components/grid-header.hbs +++ b/web/app/templates/components/grid-header.hbs @@ -15,4 +15,7 @@ {{/if}} {{reload-btn clear-search=(get this 'clear-search')}} +{{#if search-box}} {{search-box}} +{{/if}} + diff --git a/web/app/templates/components/main-container.hbs b/web/app/templates/components/main-container.hbs index 413e601..9df017a 100644 --- a/web/app/templates/components/main-container.hbs +++ b/web/app/templates/components/main-container.hbs @@ -78,6 +78,12 @@ Import Records {{/link-to}} +
  • + {{#link-to 'database-backup.list'}} + + Database Backup + {{/link-to}} +
  • {{/if}} diff --git a/web/app/templates/customer-application/list.hbs b/web/app/templates/customer-application/list.hbs index 6361b12..2d2dc75 100644 --- a/web/app/templates/customer-application/list.hbs +++ b/web/app/templates/customer-application/list.hbs @@ -59,7 +59,7 @@