-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
fee3917
commit a238e89
Showing
4 changed files
with
326 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
123 changes: 123 additions & 0 deletions
123
...in/java/com/github/dcysteine/nesql/server/plugin/base/AdvancedRecipeSearchController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
package com.github.dcysteine.nesql.server.plugin.base; | ||
|
||
import com.github.dcysteine.nesql.server.common.Table; | ||
import com.github.dcysteine.nesql.server.common.display.Icon; | ||
import com.github.dcysteine.nesql.server.common.util.NumberUtil; | ||
import com.github.dcysteine.nesql.server.common.util.ParamUtil; | ||
import com.github.dcysteine.nesql.server.plugin.base.display.BaseDisplayFactory; | ||
import com.github.dcysteine.nesql.server.plugin.base.spec.RecipeSpec; | ||
import com.github.dcysteine.nesql.server.plugin.base.spec.RecipeTypeSpec; | ||
import com.github.dcysteine.nesql.sql.base.recipe.Recipe; | ||
import com.github.dcysteine.nesql.sql.base.recipe.RecipeRepository; | ||
import com.github.dcysteine.nesql.sql.base.recipe.RecipeType; | ||
import com.github.dcysteine.nesql.sql.base.recipe.RecipeTypeRepository; | ||
import com.google.common.collect.ImmutableList; | ||
import com.google.common.collect.Iterables; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.data.jpa.domain.Specification; | ||
import org.springframework.stereotype.Controller; | ||
import org.springframework.ui.Model; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
|
||
@Controller | ||
@RequestMapping(path = "/base/advrecipe") | ||
public class AdvancedRecipeSearchController { | ||
@Autowired | ||
private RecipeRepository recipeRepository; | ||
|
||
@Autowired | ||
private RecipeTypeRepository recipeTypeRepository; | ||
|
||
@Autowired | ||
private BaseDisplayFactory baseDisplayFactory; | ||
|
||
@GetMapping(path = "/search") | ||
public String search( | ||
@RequestParam Map<String, String> params, | ||
@RequestParam(required = false) Optional<String> recipeCategory, | ||
@RequestParam(required = false) Optional<String> recipeType, | ||
@RequestParam(required = false) Optional<String> inputItemName, | ||
@RequestParam(required = false) Optional<String> inputItemModId, | ||
@RequestParam(required = false) Optional<String> inputItemId, | ||
@RequestParam(required = false) Optional<String> inputItemGroupId, | ||
@RequestParam(required = false) Optional<String> inputFluidName, | ||
@RequestParam(required = false) Optional<String> inputFluidModId, | ||
@RequestParam(required = false) Optional<String> inputFluidId, | ||
@RequestParam(required = false) Optional<String> inputFluidGroupId, | ||
@RequestParam(required = false) Optional<String> outputItemName, | ||
@RequestParam(required = false) Optional<String> outputItemModId, | ||
@RequestParam(required = false) Optional<String> outputItemId, | ||
@RequestParam(required = false) Optional<String> outputFluidName, | ||
@RequestParam(required = false) Optional<String> outputFluidModId, | ||
@RequestParam(required = false) Optional<String> outputFluidId, | ||
Model model) { | ||
List<Specification<Recipe>> specs = new ArrayList<>(); | ||
specs.add(ParamUtil.buildStringSpec(recipeCategory, RecipeSpec::buildRecipeCategorySpec)); | ||
specs.add(ParamUtil.buildStringSpec(recipeType, RecipeSpec::buildRecipeTypeSpec)); | ||
specs.add(ParamUtil.buildStringSpec(inputItemName, RecipeSpec::buildInputItemNameSpec)); | ||
specs.add(ParamUtil.buildStringSpec(inputItemModId, RecipeSpec::buildInputItemModIdSpec)); | ||
specs.add(ParamUtil.buildStringSpec(inputItemId, RecipeSpec::buildInputItemIdSpec)); | ||
specs.add( | ||
ParamUtil.buildStringSpec(inputItemGroupId, RecipeSpec::buildInputItemGroupIdSpec)); | ||
specs.add(ParamUtil.buildStringSpec(inputFluidName, RecipeSpec::buildInputFluidNameSpec)); | ||
specs.add(ParamUtil.buildStringSpec(inputFluidModId, RecipeSpec::buildInputFluidModIdSpec)); | ||
specs.add(ParamUtil.buildStringSpec(inputFluidId, RecipeSpec::buildInputFluidIdSpec)); | ||
specs.add( | ||
ParamUtil.buildStringSpec( | ||
inputFluidGroupId, RecipeSpec::buildInputFluidGroupIdSpec)); | ||
specs.add(ParamUtil.buildStringSpec(outputItemName, RecipeSpec::buildOutputItemNameSpec)); | ||
specs.add(ParamUtil.buildStringSpec(outputItemModId, RecipeSpec::buildOutputItemModIdSpec)); | ||
specs.add(ParamUtil.buildStringSpec(outputItemId, RecipeSpec::buildOutputItemIdSpec)); | ||
specs.add(ParamUtil.buildStringSpec(outputFluidName, RecipeSpec::buildOutputFluidNameSpec)); | ||
specs.add( | ||
ParamUtil.buildStringSpec(outputFluidModId, RecipeSpec::buildOutputFluidModIdSpec)); | ||
specs.add(ParamUtil.buildStringSpec(outputFluidId, RecipeSpec::buildOutputFluidIdSpec)); | ||
|
||
List<RecipeType> recipeTypes = | ||
recipeTypeRepository.findAll( | ||
RecipeTypeSpec.buildMinRecipeCountSpec(1), RecipeTypeSpec.DEFAULT_SORT); | ||
ImmutableList<Icon> icons = | ||
recipeTypes.stream() | ||
.map(rt -> buildIcon(params, specs, rt)) | ||
.flatMap(Optional::stream) | ||
.collect(ImmutableList.toImmutableList()); | ||
model.addAttribute("results", icons); | ||
|
||
return "plugin/base/advrecipe/search"; | ||
} | ||
|
||
private Optional<Icon> buildIcon( | ||
Map<String, String> params, List<Specification<Recipe>> specs, RecipeType recipeType) { | ||
Specification<Recipe> recipeTypeIdSpec = | ||
RecipeSpec.buildRecipeTypeIdSpec(recipeType.getId()); | ||
Iterable<Specification<Recipe>> modifiedSpecs = | ||
Iterables.concat(specs, Collections.singleton(recipeTypeIdSpec)); | ||
long size = recipeRepository.count(Specification.allOf(modifiedSpecs)); | ||
|
||
if (size == 0) { | ||
return Optional.empty(); | ||
} | ||
|
||
Map<String, String> modifiedParams = new HashMap<>(params); | ||
modifiedParams.put("recipeTypeId", recipeType.getId()); | ||
modifiedParams.remove("recipeCategory"); | ||
modifiedParams.remove("recipeType"); | ||
String url = Table.RECIPE.getSearchUrl(modifiedParams); | ||
|
||
Icon icon = | ||
baseDisplayFactory.buildDisplayRecipeTypeIcon(recipeType).toBuilder() | ||
.setUrl(url) | ||
.setBottomRight(NumberUtil.formatInteger(size)) | ||
.build(); | ||
return Optional.of(icon); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
158 changes: 158 additions & 0 deletions
158
src/main/resources/templates/plugin/base/advrecipe/search.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
<!DOCTYPE html> | ||
<html th:replace="~{fragment/template::template(~{::title}, ~{::content})}" | ||
xmlns:th="http://www.thymeleaf.org"> | ||
<head> | ||
<title>Advanced Search Recipes</title> | ||
</head> | ||
<body> | ||
|
||
<th:block th:fragment="content"> | ||
<div class="container"> | ||
<div class="row"> | ||
<h1 class="display-3 text-center"> | ||
Advanced Search Recipes | ||
</h1> | ||
</div> | ||
<div class="row"> | ||
<span class="text-center text-info"> | ||
Search recipes grouped by recipe type. | ||
</span> | ||
</div> | ||
<div class="row"> | ||
<span class="text-center"> | ||
Query fields will be joined with AND. Leave all fields blank to retrieve everything. | ||
</span> | ||
</div> | ||
|
||
<div class="row justify-content-center mt-5"> | ||
<form method="get"> | ||
<div class="container"></div> | ||
<div class="row"> | ||
<div class="col"> | ||
<div class="mt-2"> | ||
<th:block th:replace="~{fragment/search::searchFieldRegex('recipeCategory', 'Recipe category')}"> | ||
</th:block> | ||
<div class="form-text"> </div> | ||
</div> | ||
|
||
<div class="mt-2"> | ||
<th:block th:replace="~{fragment/search::searchFieldRegex('recipeType', 'Recipe type')}"> | ||
</th:block> | ||
<div class="form-text"> </div> | ||
</div> | ||
</div> | ||
<div class="col"> | ||
<div class="mt-2"> | ||
<th:block th:replace="~{fragment/search::searchFieldRegex('inputItemName', 'Input item localized name')}"> | ||
</th:block> | ||
<div class="form-text"> </div> | ||
</div> | ||
|
||
<div class="mt-2"> | ||
<th:block th:replace="~{fragment/search::searchFieldRegex('inputItemModId', 'Input item mod ID')}"> | ||
</th:block> | ||
<div class="form-text"> </div> | ||
</div> | ||
|
||
<div class="mt-2"> | ||
<th:block th:replace="~{fragment/search::searchField('inputItemId', 'Input item ID', 'search')}"> | ||
</th:block> | ||
<div class="form-text"> </div> | ||
</div> | ||
|
||
<div class="mt-2"> | ||
<th:block th:replace="~{fragment/search::searchField('inputItemGroupId', 'Input item group ID', 'search')}"> | ||
</th:block> | ||
<div class="form-text"> </div> | ||
</div> | ||
</div> | ||
<div class="col"> | ||
<div class="mt-2"> | ||
<th:block th:replace="~{fragment/search::searchFieldRegex('inputFluidName', 'Input fluid localized name')}"> | ||
</th:block> | ||
<div class="form-text"> </div> | ||
</div> | ||
|
||
<div class="mt-2"> | ||
<th:block th:replace="~{fragment/search::searchFieldRegex('inputFluidModId', 'Input fluid mod ID')}"> | ||
</th:block> | ||
<div class="form-text"> </div> | ||
</div> | ||
|
||
<div class="mt-2"> | ||
<th:block th:replace="~{fragment/search::searchField('inputFluidId', 'Input fluid ID', 'search')}"> | ||
</th:block> | ||
<div class="form-text"> </div> | ||
</div> | ||
|
||
<div class="mt-2"> | ||
<th:block th:replace="~{fragment/search::searchField('inputFluidGroupId', 'Input fluid group ID', 'search')}"> | ||
</th:block> | ||
<div class="form-text"> </div> | ||
</div> | ||
</div> | ||
<div class="col"> | ||
<div class="mt-2"> | ||
<th:block th:replace="~{fragment/search::searchFieldRegex('outputItemName', 'Output item localized name')}"> | ||
</th:block> | ||
<div class="form-text"> </div> | ||
</div> | ||
|
||
<div class="mt-2"> | ||
<th:block th:replace="~{fragment/search::searchFieldRegex('outputItemModId', 'Output item mod ID')}"> | ||
</th:block> | ||
<div class="form-text"> </div> | ||
</div> | ||
|
||
<div class="mt-2"> | ||
<th:block th:replace="~{fragment/search::searchField('outputItemId', 'Output item ID', 'search')}"> | ||
</th:block> | ||
<div class="form-text"> </div> | ||
</div> | ||
</div> | ||
<div class="col"> | ||
<div class="mt-2"> | ||
<th:block th:replace="~{fragment/search::searchFieldRegex('outputFluidName', 'Output fluid localized name')}"> | ||
</th:block> | ||
<div class="form-text"> </div> | ||
</div> | ||
|
||
<div class="mt-2"> | ||
<th:block th:replace="~{fragment/search::searchFieldRegex('outputFluidModId', 'Output fluid mod ID')}"> | ||
</th:block> | ||
<div class="form-text"> </div> | ||
</div> | ||
|
||
<div class="mt-2"> | ||
<th:block th:replace="~{fragment/search::searchField('outputFluidId', 'Output fluid ID', 'search')}"> | ||
</th:block> | ||
<div class="form-text"> </div> | ||
</div> | ||
</div> | ||
</div> | ||
<div class="row justify-content-center mt-3"> | ||
<div class="col-auto"> | ||
<button th:replace="~{fragment/search::searchButton}"></button> | ||
</div> | ||
</div> | ||
</form> | ||
</div> | ||
|
||
<div class="row my-5"> | ||
<h1 class="display-3 text-center"> | ||
Search Results | ||
</h1> | ||
</div> | ||
<div class="row"> | ||
<div class="card"> | ||
<div class="card-body"> | ||
<span th:replace="~{fragment/icon::iconList(${results})}"> | ||
</span> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</th:block> | ||
|
||
</body> | ||
</html> |