diff --git a/client/package.json b/client/package.json index 5e1c0c1..e0b5ce0 100644 --- a/client/package.json +++ b/client/package.json @@ -37,13 +37,13 @@ "@angular/platform-browser": "^8.2.4", "@angular/platform-browser-dynamic": "^8.2.4", "@angular/router": "^8.2.4", - "@groupdocs.examples.angular/annotation": "^0.6.1", - "@groupdocs.examples.angular/comparison": "^0.6.1", - "@groupdocs.examples.angular/conversion": "^0.6.1", - "@groupdocs.examples.angular/editor": "^0.6.1", - "@groupdocs.examples.angular/signature": "^0.6.1", - "@groupdocs.examples.angular/viewer": "^0.6.1", - "@nrwl/angular": "^8.12.6", + "@groupdocs.examples.angular/annotation": "^0.6.3", + "@groupdocs.examples.angular/comparison": "^0.6.3", + "@groupdocs.examples.angular/conversion": "^0.6.3", + "@groupdocs.examples.angular/editor": "^0.6.3", + "@groupdocs.examples.angular/signature": "^0.6.3", + "@groupdocs.examples.angular/viewer": "^0.6.3", + "@nrwl/angular": "^8.12.7", "common-components": "^1.0.5", "core-js": "^2.6.11", "rxjs": "~6.4.0", diff --git a/configuration.yml b/configuration.yml index dce221f..3f7eab7 100644 --- a/configuration.yml +++ b/configuration.yml @@ -218,4 +218,18 @@ editor: # Absolute path to default document defaultDocument: # Enable / disable new document creation - createNewFile: true \ No newline at end of file + createNewFile: true + +################################################ +# GroupDocs.Search configurations +################################################ +search: + # Files directory path + # Absolute or relative path to files directory + filesDirectory: DocumentSamples/Search + # Fonts path + # Absolute path to custom fonts directory + fontsDirectory: + # Default document + # Absolute path to default document + defaultDocument: \ No newline at end of file diff --git a/pom.xml b/pom.xml index 585d502..26a80c1 100644 --- a/pom.xml +++ b/pom.xml @@ -147,6 +147,11 @@ 19.7 jar + + com.groupdocs + groupdocs-search + 19.12 + com.groupdocs groupdocs-viewer diff --git a/src/main/java/com/groupdocs/ui/config/DefaultDirectories.java b/src/main/java/com/groupdocs/ui/config/DefaultDirectories.java index d17e60f..e17787e 100644 --- a/src/main/java/com/groupdocs/ui/config/DefaultDirectories.java +++ b/src/main/java/com/groupdocs/ui/config/DefaultDirectories.java @@ -20,6 +20,7 @@ public class DefaultDirectories { public static final String ANNOTATION = "Annotation"; public static final String CONVERSION = "Conversion"; public static final String EDITOR = "Editor"; + public static final String SEARCH = "Search"; public static String defaultLicenseDirectory() { Path defaultLicFolder = FileSystems.getDefault().getPath(LICENSES).toAbsolutePath(); @@ -57,6 +58,10 @@ public static String defaultEditorDirectory() { return getDefaultFilesDir(EDITOR); } + public static String defaultSearchDirectory() { + return getDefaultFilesDir(SEARCH); + } + public static String getDefaultFilesDir(String folder) { String dir = DOCUMENT_SAMPLES + File.separator + folder; Path path = FileSystems.getDefault().getPath(dir).toAbsolutePath(); diff --git a/src/main/java/com/groupdocs/ui/search/config/SearchConfiguration.java b/src/main/java/com/groupdocs/ui/search/config/SearchConfiguration.java new file mode 100644 index 0000000..b2203c9 --- /dev/null +++ b/src/main/java/com/groupdocs/ui/search/config/SearchConfiguration.java @@ -0,0 +1,62 @@ +package com.groupdocs.ui.search.config; + +import com.groupdocs.ui.config.CommonConfiguration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import javax.annotation.PostConstruct; + +import static com.groupdocs.ui.config.DefaultDirectories.*; + +@Component +public class SearchConfiguration extends CommonConfiguration { + + @Value("${search.filesDirectory}") + private String filesDirectory; + + @Value("${search.defaultDocument}") + private String defaultDocument; + + @Value("${search.fontsDirectory}") + private String fontsDirectory; + + @PostConstruct + public void init() { + this.filesDirectory = StringUtils.isEmpty(this.filesDirectory) ? defaultSearchDirectory() : relativePathToAbsolute(this.filesDirectory); + } + + public String getFilesDirectory() { + return filesDirectory; + } + + public void setFilesDirectory(String filesDirectory) { + this.filesDirectory = filesDirectory; + } + + public String getDefaultDocument() { + return defaultDocument; + } + + public void setDefaultDocument(String defaultDocument) { + this.defaultDocument = defaultDocument; + } + + public String getFontsDirectory() { + return fontsDirectory; + } + + public void setFontsDirectory(String fontsDirectory) { + this.fontsDirectory = fontsDirectory; + } + + @Override + public String toString() { + return super.toString() + + "SearchConfiguration{" + + "filesDirectory='" + filesDirectory + '\'' + + ", defaultDocument='" + defaultDocument + '\'' + + ", fontsDirectory='" + fontsDirectory + '\'' + + '}'; + } +} diff --git a/src/main/java/com/groupdocs/ui/search/controller/SearchController.java b/src/main/java/com/groupdocs/ui/search/controller/SearchController.java new file mode 100644 index 0000000..d31db73 --- /dev/null +++ b/src/main/java/com/groupdocs/ui/search/controller/SearchController.java @@ -0,0 +1,104 @@ +package com.groupdocs.ui.search.controller; + +import com.groupdocs.ui.model.request.FileTreeRequest; +import com.groupdocs.ui.model.request.LoadDocumentRequest; +import com.groupdocs.ui.model.response.FileDescriptionEntity; +import com.groupdocs.ui.model.response.UploadedDocumentEntity; +import com.groupdocs.ui.search.config.SearchConfiguration; +import com.groupdocs.ui.search.model.IndexDocumentResult; +import com.groupdocs.ui.search.model.SearchDocumentResult; +import com.groupdocs.ui.search.model.SearchRequest; +import com.groupdocs.ui.search.service.SearchService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Nullable; +import java.util.List; + +import static com.groupdocs.ui.util.Utils.uploadFile; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE; + +/** + * SearchController + * + * @author Aspose Pty Ltd + */ +@Controller +@RequestMapping(value = "/search") +public class SearchController { + private static final Logger logger = LoggerFactory.getLogger(SearchController.class); + + private SearchService searchService; + + public SearchController(@Autowired SearchService searchService) { + this.searchService = searchService; + } + + @RequestMapping(method = RequestMethod.GET, value = "/loadConfig", produces = APPLICATION_JSON_VALUE) + @ResponseBody + public SearchConfiguration loadConfig() { + return searchService.getSearchConfiguration(); + } + + /** + * Get files and directories + * + * @param fileTreeRequest request's object with specified path + * @return files and directories list + */ + @RequestMapping(value = "/loadFileTree", method = RequestMethod.POST, produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) + @ResponseBody + public List loadFileTree(@RequestBody FileTreeRequest fileTreeRequest) { + return searchService.getFileList(fileTreeRequest); + } + + /** + * Get document description + * + * @return document description + */ + @RequestMapping(value = "/loadDocumentDescription", method = RequestMethod.POST, produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) + @ResponseBody + public IndexDocumentResult loadDocumentDescription(@RequestBody LoadDocumentRequest loadDocumentRequest) { + return searchService.getDocumentDescription(loadDocumentRequest); + } + + /** + * Get document description + * + * @return document description + */ + @RequestMapping(value = "/search", method = RequestMethod.POST, produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) + @ResponseBody + public List loadDocumentDescription(@RequestBody SearchRequest searchRequest) { + return searchService.search(searchRequest); + } + + /** + * Upload document + * + * @param content file data + * @param url url for document + * @param rewrite flag for rewriting file + * @return uploaded document object (the object contains uploaded document guid) + */ + @RequestMapping(value = "/uploadDocument", method = RequestMethod.POST, produces = APPLICATION_JSON_VALUE, consumes = MULTIPART_FORM_DATA_VALUE) + @ResponseBody + public UploadedDocumentEntity uploadDocument(@Nullable @RequestParam("file") MultipartFile content, + @RequestParam(value = "url", required = false) String url, + @RequestParam("rewrite") Boolean rewrite) { + // get documents storage path + String documentStoragePath = searchService.getSearchConfiguration().getFilesDirectory(); + // save the file + String pathname = uploadFile(documentStoragePath, content, url, rewrite); + // create response data + UploadedDocumentEntity uploadedDocument = new UploadedDocumentEntity(); + uploadedDocument.setGuid(pathname); + return uploadedDocument; + } +} diff --git a/src/main/java/com/groupdocs/ui/search/model/IndexDocumentResult.java b/src/main/java/com/groupdocs/ui/search/model/IndexDocumentResult.java new file mode 100644 index 0000000..af34df8 --- /dev/null +++ b/src/main/java/com/groupdocs/ui/search/model/IndexDocumentResult.java @@ -0,0 +1,16 @@ +package com.groupdocs.ui.search.model; + +import com.groupdocs.ui.model.response.LoadDocumentEntity; + +public class IndexDocumentResult extends LoadDocumentEntity { + + private String indexStatus; + + public String getIndexStatus() { + return indexStatus; + } + + public void setIndexStatus(String indexStatus) { + this.indexStatus = indexStatus; + } +} diff --git a/src/main/java/com/groupdocs/ui/search/model/SearchDocumentResult.java b/src/main/java/com/groupdocs/ui/search/model/SearchDocumentResult.java new file mode 100644 index 0000000..6043316 --- /dev/null +++ b/src/main/java/com/groupdocs/ui/search/model/SearchDocumentResult.java @@ -0,0 +1,25 @@ +package com.groupdocs.ui.search.model; + +import com.groupdocs.search.results.FoundDocumentField; + +public class SearchDocumentResult { + + private FoundDocumentField[] foundFields; + private String filePath; + + public void setFoundFields(FoundDocumentField[] foundFields) { + this.foundFields = foundFields; + } + + public FoundDocumentField[] getFoundFields() { + return foundFields; + } + + public void setFilePath(String filePath) { + this.filePath = filePath; + } + + public String getFilePath() { + return filePath; + } +} diff --git a/src/main/java/com/groupdocs/ui/search/model/SearchRequest.java b/src/main/java/com/groupdocs/ui/search/model/SearchRequest.java new file mode 100644 index 0000000..7092588 --- /dev/null +++ b/src/main/java/com/groupdocs/ui/search/model/SearchRequest.java @@ -0,0 +1,22 @@ +package com.groupdocs.ui.search.model; + +public class SearchRequest { + private String query; + private String[] guids; + + public String getQuery() { + return query; + } + + public void setQuery(String query) { + this.query = query; + } + + public String[] getGuids() { + return guids; + } + + public void setGuids(String[] guids) { + this.guids = guids; + } +} diff --git a/src/main/java/com/groupdocs/ui/search/service/SearchService.java b/src/main/java/com/groupdocs/ui/search/service/SearchService.java new file mode 100644 index 0000000..2400a41 --- /dev/null +++ b/src/main/java/com/groupdocs/ui/search/service/SearchService.java @@ -0,0 +1,21 @@ +package com.groupdocs.ui.search.service; + +import com.groupdocs.ui.model.request.FileTreeRequest; +import com.groupdocs.ui.model.request.LoadDocumentRequest; +import com.groupdocs.ui.model.response.FileDescriptionEntity; +import com.groupdocs.ui.search.config.SearchConfiguration; +import com.groupdocs.ui.search.model.IndexDocumentResult; +import com.groupdocs.ui.search.model.SearchDocumentResult; +import com.groupdocs.ui.search.model.SearchRequest; + +import java.util.List; + +public interface SearchService { + SearchConfiguration getSearchConfiguration(); + + List getFileList(FileTreeRequest fileTreeRequest); + + IndexDocumentResult getDocumentDescription(LoadDocumentRequest loadDocumentRequest); + + List search(SearchRequest searchRequest); +} diff --git a/src/main/java/com/groupdocs/ui/search/service/SearchServiceImpl.java b/src/main/java/com/groupdocs/ui/search/service/SearchServiceImpl.java new file mode 100644 index 0000000..1bfb70d --- /dev/null +++ b/src/main/java/com/groupdocs/ui/search/service/SearchServiceImpl.java @@ -0,0 +1,151 @@ +package com.groupdocs.ui.search.service; + +import com.groupdocs.search.Index; +import com.groupdocs.search.common.IndexStatus; +import com.groupdocs.search.licensing.License; +import com.groupdocs.search.results.FoundDocument; +import com.groupdocs.search.results.SearchResult; +import com.groupdocs.ui.config.GlobalConfiguration; +import com.groupdocs.ui.exception.TotalGroupDocsException; +import com.groupdocs.ui.model.request.FileTreeRequest; +import com.groupdocs.ui.model.request.LoadDocumentRequest; +import com.groupdocs.ui.model.response.FileDescriptionEntity; +import com.groupdocs.ui.search.config.SearchConfiguration; +import com.groupdocs.ui.search.model.IndexDocumentResult; +import com.groupdocs.ui.search.model.SearchDocumentResult; +import com.groupdocs.ui.search.model.SearchRequest; +import org.apache.commons.io.FilenameUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import javax.annotation.PostConstruct; +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +@Service +public class SearchServiceImpl implements SearchService { + private static final Logger logger = LoggerFactory.getLogger(SearchServiceImpl.class); + + private final GlobalConfiguration globalConfiguration; + + private final SearchConfiguration searchConfiguration; + + public SearchServiceImpl(GlobalConfiguration globalConfiguration, SearchConfiguration searchConfiguration) { + this.globalConfiguration = globalConfiguration; + this.searchConfiguration = searchConfiguration; + } + + @PostConstruct + public void init() { + try { + // set GroupDocs license + License license = new License(); + license.setLicense(globalConfiguration.getApplication().getLicensePath()); + } catch (Throwable exc) { + logger.error("Can not verify Search license!"); + } + } + + @Override + public SearchConfiguration getSearchConfiguration() { + return searchConfiguration; + } + + @Override + public List getFileList(FileTreeRequest fileTreeRequest) { + String path = fileTreeRequest.getPath(); + if (StringUtils.isEmpty(path)) { + path = searchConfiguration.getFilesDirectory(); + } + try { + File directory = new File(path); + List filesList = Arrays.asList(directory.listFiles()); + List fileList = getFileDescriptionEntities(filesList); + return fileList; + } catch (Exception ex) { + logger.error("Exception in getting file list", ex); + throw new TotalGroupDocsException(ex.getMessage(), ex); + } + } + + @Override + public IndexDocumentResult getDocumentDescription(LoadDocumentRequest loadDocumentRequest) { + Index index = new Index(searchConfiguration.getFilesDirectory()); + + index.add(loadDocumentRequest.getGuid()); + + int indexStatus = index.getIndexInfo().getIndexStatus(); + + IndexDocumentResult searchDocumentResult = new IndexDocumentResult(); + searchDocumentResult.setGuid(loadDocumentRequest.getGuid()); + searchDocumentResult.setIndexStatus(getStatus(indexStatus)); + + return searchDocumentResult; + } + + @Override + public List search(SearchRequest searchRequest) { + Index index = new Index(searchConfiguration.getFilesDirectory()); + + index.add(searchRequest.getGuids()); + + int indexStatus = index.getIndexInfo().getIndexStatus(); + + List results = new ArrayList<>(); + if (IndexStatus.Ready == indexStatus) { + SearchResult search = index.search(searchRequest.getQuery()); + + Iterator iterator = search.iterator(); + while (iterator.hasNext()) { + FoundDocument next = iterator.next(); + SearchDocumentResult searchDocumentResult = new SearchDocumentResult(); + searchDocumentResult.setFoundFields(next.getFoundFields()); + searchDocumentResult.setFilePath(next.getDocumentInfo().getFilePath()); + + results.add(searchDocumentResult); + } + } + + return results; + } + + private String getStatus(int indexStatus) { + switch (indexStatus) { + case IndexStatus.NotStarted: + return "NotStarted"; + case IndexStatus.Failed: + return "Failed"; + case IndexStatus.InProgress: + return "InProgress"; + case IndexStatus.LicenseRestrictionFinished: + return "LicenseRestrictionFinished"; + case IndexStatus.Ready: + return "Ready"; + default: + return ""; + } + } + + private List getFileDescriptionEntities(List filesList) { + List fileList = new ArrayList<>(); + for (File file : filesList) { + String guid = file.getAbsolutePath(); + String extension = FilenameUtils.getExtension(guid); + if (file.isDirectory() || !StringUtils.isEmpty(extension)) { + FileDescriptionEntity fileDescription = new FileDescriptionEntity(); + fileDescription.setGuid(guid); + fileDescription.setName(file.getName()); + fileDescription.setDirectory(file.isDirectory()); + fileDescription.setSize(file.length()); + fileList.add(fileDescription); + } + } + return fileList; + } + +}