Added searching for all relevant data types
This commit is contained in:
parent
4df0a804b3
commit
a8cf583569
39 changed files with 1159 additions and 233 deletions
|
@ -60,7 +60,10 @@ public class SteamAPI extends PlatformAPI {
|
||||||
var newGame = new APIResponse.Game();
|
var newGame = new APIResponse.Game();
|
||||||
newGame.setPlatformGameId(Integer.toString(game.getAppid()));
|
newGame.setPlatformGameId(Integer.toString(game.getAppid()));
|
||||||
newGame.setName(game.getName());
|
newGame.setName(game.getName());
|
||||||
newGame.setThumbnail("https://cdn.cloudflare.steamstatic.com/steamcommunity/public/images/apps/" + game.getAppid() + "/" + game.getImg_logo_url() + ".jpg");
|
// Technically this is not the advertised logo url, but it's used be steamcommunity.com
|
||||||
|
// and steamdb.info and it gives better aspect ratios and it means I don't need the random
|
||||||
|
// logo_url field
|
||||||
|
newGame.setThumbnail("https://cdn.cloudflare.steamstatic.com/steam/apps/" + game.getAppid() + "/header.jpg");
|
||||||
newGame.setPlayed(game.getPlaytime_forever() > 0);
|
newGame.setPlayed(game.getPlaytime_forever() > 0);
|
||||||
|
|
||||||
var achievements = new HashMap<String, APIResponse.Game.Achievement>();
|
var achievements = new HashMap<String, APIResponse.Game.Achievement>();
|
||||||
|
@ -72,7 +75,6 @@ public class SteamAPI extends PlatformAPI {
|
||||||
.queryParam("appid", game.getAppid())
|
.queryParam("appid", game.getAppid())
|
||||||
.toUriString();
|
.toUriString();
|
||||||
|
|
||||||
|
|
||||||
var schemaResponse = rest.exchange(gameSchemaUrl, HttpMethod.GET, entity, GetSchemaForGameBody.class).getBody().getGame().getAvailableGameStats();
|
var schemaResponse = rest.exchange(gameSchemaUrl, HttpMethod.GET, entity, GetSchemaForGameBody.class).getBody().getGame().getAvailableGameStats();
|
||||||
if (schemaResponse != null && schemaResponse.getAchievements() != null) {
|
if (schemaResponse != null && schemaResponse.getAchievements() != null) {
|
||||||
for (var schema : schemaResponse.getAchievements()) {
|
for (var schema : schemaResponse.getAchievements()) {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package achievements.controllers;
|
package achievements.controllers;
|
||||||
|
|
||||||
import achievements.data.query.SearchAchievements;
|
import achievements.data.request.SearchAchievements;
|
||||||
|
import achievements.data.request.SearchGames;
|
||||||
|
import achievements.data.request.SearchUsers;
|
||||||
import achievements.services.SearchService;
|
import achievements.services.SearchService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
@ -23,4 +25,24 @@ public class SearchController {
|
||||||
return ResponseEntity.badRequest().body("[]");
|
return ResponseEntity.badRequest().body("[]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "/users", consumes = "application/json", produces = "application/json")
|
||||||
|
public ResponseEntity searchAchievements(@RequestBody SearchUsers searchUsers) {
|
||||||
|
var users = searchService.searchUsers(searchUsers);
|
||||||
|
if (users != null) {
|
||||||
|
return ResponseEntity.ok(users);
|
||||||
|
} else {
|
||||||
|
return ResponseEntity.badRequest().body("[]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "/games", consumes = "application/json", produces = "application/json")
|
||||||
|
public ResponseEntity searchAchievements(@RequestBody SearchGames searchGames) {
|
||||||
|
var users = searchService.searchGames(searchGames);
|
||||||
|
if (users != null) {
|
||||||
|
return ResponseEntity.ok(users);
|
||||||
|
} else {
|
||||||
|
return ResponseEntity.badRequest().body("[]");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@ package achievements.controllers;
|
||||||
|
|
||||||
import achievements.data.APError;
|
import achievements.data.APError;
|
||||||
import achievements.data.APPostRequest;
|
import achievements.data.APPostRequest;
|
||||||
import achievements.data.query.AddPlatform;
|
import achievements.data.request.AddPlatform;
|
||||||
import achievements.data.query.RemovePlatform;
|
import achievements.data.request.RemovePlatform;
|
||||||
import achievements.data.query.SetUsername;
|
import achievements.data.request.SetUsername;
|
||||||
import achievements.services.ImageService;
|
import achievements.services.ImageService;
|
||||||
import achievements.services.UserService;
|
import achievements.services.UserService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
package achievements.data;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class Game {
|
|
||||||
|
|
||||||
@JsonProperty("ID")
|
|
||||||
private int id;
|
|
||||||
@JsonProperty("name")
|
|
||||||
private String name;
|
|
||||||
@JsonProperty("platforms")
|
|
||||||
private List<String> platforms;
|
|
||||||
@JsonProperty("achievementCount")
|
|
||||||
private int achievementCount;
|
|
||||||
|
|
||||||
public int getId() { return id; }
|
|
||||||
|
|
||||||
public void setId(int id) { this.id = id; }
|
|
||||||
|
|
||||||
public String getName() { return name; }
|
|
||||||
|
|
||||||
public void setName(String name) { this.name = name; }
|
|
||||||
|
|
||||||
public List<String> getPlatforms() { return platforms; }
|
|
||||||
|
|
||||||
public void setPlatforms(List<String> platforms) { this.platforms = platforms; }
|
|
||||||
|
|
||||||
public void addToPlatforms(String platform) { this.platforms.add(platform); }
|
|
||||||
}
|
|
|
@ -1,5 +1,6 @@
|
||||||
package achievements.data;
|
package achievements.data;
|
||||||
|
|
||||||
|
import achievements.data.response.search.Achievement;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package achievements.data.query;
|
package achievements.data.request;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package achievements.data.query;
|
package achievements.data.request;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package achievements.data.query;
|
package achievements.data.request;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
@ -22,6 +22,10 @@ public class SearchAchievements {
|
||||||
private Float minQuality;
|
private Float minQuality;
|
||||||
@JsonProperty("maxQuality")
|
@JsonProperty("maxQuality")
|
||||||
private Float maxQuality;
|
private Float maxQuality;
|
||||||
|
@JsonProperty("ordering")
|
||||||
|
private String ordering;
|
||||||
|
@JsonProperty("orderDirection")
|
||||||
|
private String orderDirection;
|
||||||
|
|
||||||
public String getSearchTerm() {
|
public String getSearchTerm() {
|
||||||
return searchTerm;
|
return searchTerm;
|
||||||
|
@ -94,4 +98,20 @@ public class SearchAchievements {
|
||||||
public void setMaxQuality(Float maxQuality) {
|
public void setMaxQuality(Float maxQuality) {
|
||||||
this.maxQuality = maxQuality;
|
this.maxQuality = maxQuality;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getOrdering() {
|
||||||
|
return ordering;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrdering(String ordering) {
|
||||||
|
this.ordering = ordering;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOrderDirection() {
|
||||||
|
return orderDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrderDirection(String orderDirection) {
|
||||||
|
this.orderDirection = orderDirection;
|
||||||
|
}
|
||||||
}
|
}
|
117
backend/src/main/java/achievements/data/request/SearchGames.java
Normal file
117
backend/src/main/java/achievements/data/request/SearchGames.java
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
package achievements.data.request;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
public class SearchGames {
|
||||||
|
|
||||||
|
@JsonProperty("searchTerm")
|
||||||
|
private String searchTerm;
|
||||||
|
@JsonProperty("userId")
|
||||||
|
private Integer userId;
|
||||||
|
@JsonProperty("owned")
|
||||||
|
private boolean owned;
|
||||||
|
@JsonProperty("minAvgCompletion")
|
||||||
|
private Float minAvgCompletion;
|
||||||
|
@JsonProperty("maxAvgCompletion")
|
||||||
|
private Float maxAvgCompletion;
|
||||||
|
@JsonProperty("minNumOwners")
|
||||||
|
private Float minNumOwners;
|
||||||
|
@JsonProperty("maxNumOwners")
|
||||||
|
private Float maxNumOwners;
|
||||||
|
@JsonProperty("minNumPerfects")
|
||||||
|
private Float minNumPerfects;
|
||||||
|
@JsonProperty("maxNumPerfects")
|
||||||
|
private Float maxNumPerfects;
|
||||||
|
@JsonProperty("ordering")
|
||||||
|
private String ordering;
|
||||||
|
@JsonProperty("orderDirection")
|
||||||
|
private String orderDirection;
|
||||||
|
|
||||||
|
public String getSearchTerm() {
|
||||||
|
return searchTerm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSearchTerm(String searchTerm) {
|
||||||
|
this.searchTerm = searchTerm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserId(Integer userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOwned() {
|
||||||
|
return owned;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOwned(boolean owned) {
|
||||||
|
this.owned = owned;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Float getMinAvgCompletion() {
|
||||||
|
return minAvgCompletion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinAvgCompletion(Float minAvgCompletion) {
|
||||||
|
this.minAvgCompletion = minAvgCompletion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Float getMaxAvgCompletion() {
|
||||||
|
return maxAvgCompletion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxAvgCompletion(Float maxAvgCompletion) {
|
||||||
|
this.maxAvgCompletion = maxAvgCompletion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Float getMinNumOwners() {
|
||||||
|
return minNumOwners;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinNumOwners(Float minNumOwners) {
|
||||||
|
this.minNumOwners = minNumOwners;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Float getMaxNumOwners() {
|
||||||
|
return maxNumOwners;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxNumOwners(Float maxNumOwners) {
|
||||||
|
this.maxNumOwners = maxNumOwners;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Float getMinNumPerfects() {
|
||||||
|
return minNumPerfects;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinNumPerfects(Float minNumPerfects) {
|
||||||
|
this.minNumPerfects = minNumPerfects;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Float getMaxNumPerfects() {
|
||||||
|
return maxNumPerfects;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxNumPerfects(Float maxNumPerfects) {
|
||||||
|
this.maxNumPerfects = maxNumPerfects;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOrdering() {
|
||||||
|
return ordering;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrdering(String ordering) {
|
||||||
|
this.ordering = ordering;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOrderDirection() {
|
||||||
|
return orderDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrderDirection(String orderDirection) {
|
||||||
|
this.orderDirection = orderDirection;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
package achievements.data.request;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
public class SearchUsers {
|
||||||
|
|
||||||
|
@JsonProperty("searchTerm")
|
||||||
|
private String searchTerm;
|
||||||
|
@JsonProperty("minOwned")
|
||||||
|
private Float minOwned;
|
||||||
|
@JsonProperty("maxOwned")
|
||||||
|
private Float maxOwned;
|
||||||
|
@JsonProperty("minCompleted")
|
||||||
|
private Float minCompleted;
|
||||||
|
@JsonProperty("maxCompleted")
|
||||||
|
private Float maxCompleted;
|
||||||
|
@JsonProperty("minAvgCompletion")
|
||||||
|
private Float minAvgCompletion;
|
||||||
|
@JsonProperty("maxAvgCompletion")
|
||||||
|
private Float maxAvgCompletion;
|
||||||
|
@JsonProperty("ordering")
|
||||||
|
private String ordering;
|
||||||
|
@JsonProperty("orderDirection")
|
||||||
|
private String orderDirection;
|
||||||
|
|
||||||
|
public String getSearchTerm() {
|
||||||
|
return searchTerm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSearchTerm(String searchTerm) {
|
||||||
|
this.searchTerm = searchTerm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Float getMinOwned() {
|
||||||
|
return minOwned;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinOwned(Float minOwned) {
|
||||||
|
this.minOwned = minOwned;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Float getMaxOwned() {
|
||||||
|
return maxOwned;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxOwned(Float maxOwned) {
|
||||||
|
this.maxOwned = maxOwned;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Float getMinCompleted() {
|
||||||
|
return minCompleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinCompleted(Float minCompleted) {
|
||||||
|
this.minCompleted = minCompleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Float getMaxCompleted() {
|
||||||
|
return maxCompleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxCompleted(Float maxCompleted) {
|
||||||
|
this.maxCompleted = maxCompleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Float getMinAvgCompletion() {
|
||||||
|
return minAvgCompletion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinAvgCompletion(Float minAvgCompletion) {
|
||||||
|
this.minAvgCompletion = minAvgCompletion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Float getMaxAvgCompletion() {
|
||||||
|
return maxAvgCompletion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxAvgCompletion(Float maxAvgCompletion) {
|
||||||
|
this.maxAvgCompletion = maxAvgCompletion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOrdering() {
|
||||||
|
return ordering;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrdering(String ordering) {
|
||||||
|
this.ordering = ordering;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOrderDirection() {
|
||||||
|
return orderDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrderDirection(String orderDirection) {
|
||||||
|
this.orderDirection = orderDirection;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package achievements.data.query;
|
package achievements.data.request;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package achievements.data;
|
package achievements.data.response.search;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
package achievements.data.response.search;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
public class Game {
|
||||||
|
|
||||||
|
@JsonProperty("ID")
|
||||||
|
private int ID;
|
||||||
|
@JsonProperty("name")
|
||||||
|
private String name;
|
||||||
|
@JsonProperty("achievement_count")
|
||||||
|
private int achievement_count;
|
||||||
|
@JsonProperty("avg_completion")
|
||||||
|
private Integer avg_completion;
|
||||||
|
@JsonProperty("num_owners")
|
||||||
|
private int num_owners;
|
||||||
|
@JsonProperty("num_perfects")
|
||||||
|
private int num_perfects;
|
||||||
|
|
||||||
|
public int getID() { return ID; }
|
||||||
|
|
||||||
|
public void setID(int ID) { this.ID = ID; }
|
||||||
|
|
||||||
|
public String getName() { return name; }
|
||||||
|
|
||||||
|
public void setName(String name) { this.name = name; }
|
||||||
|
|
||||||
|
public int getAchievement_count() {
|
||||||
|
return achievement_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAchievement_count(int achievement_count) {
|
||||||
|
this.achievement_count = achievement_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getAvg_completion() {
|
||||||
|
return avg_completion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAvg_completion(Integer avg_completion) {
|
||||||
|
this.avg_completion = avg_completion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNum_owners() {
|
||||||
|
return num_owners;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNum_owners(int num_owners) {
|
||||||
|
this.num_owners = num_owners;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNum_perfects() {
|
||||||
|
return num_perfects;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNum_perfects(int num_perfects) {
|
||||||
|
this.num_perfects = num_perfects;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
package achievements.data.response.search;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
public class User {
|
||||||
|
|
||||||
|
@JsonProperty("ID")
|
||||||
|
private int ID;
|
||||||
|
@JsonProperty("username")
|
||||||
|
private String username;
|
||||||
|
@JsonProperty("game_count")
|
||||||
|
private int game_count;
|
||||||
|
@JsonProperty("achievement_count")
|
||||||
|
private int achievement_count;
|
||||||
|
@JsonProperty("avg_completion")
|
||||||
|
private Integer avg_completion;
|
||||||
|
@JsonProperty("perfect_games")
|
||||||
|
private int perfect_games;
|
||||||
|
|
||||||
|
public int getID() {
|
||||||
|
return ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setID(int ID) {
|
||||||
|
this.ID = ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGame_count() {
|
||||||
|
return game_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGame_count(int game_count) {
|
||||||
|
this.game_count = game_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAchievement_count() {
|
||||||
|
return achievement_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAchievement_count(int achievement_count) {
|
||||||
|
this.achievement_count = achievement_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getAvg_completion() {
|
||||||
|
return avg_completion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAvg_completion(Integer avg_completion) {
|
||||||
|
this.avg_completion = avg_completion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPerfect_games() {
|
||||||
|
return perfect_games;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPerfect_games(int perfect_games) {
|
||||||
|
this.perfect_games = perfect_games;
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class APIService {
|
public class APIService {
|
||||||
|
@ -37,10 +38,10 @@ public class APIService {
|
||||||
try {
|
try {
|
||||||
var response = apis.apis.get(platformId).get(platformUserId);
|
var response = apis.apis.get(platformId).get(platformUserId);
|
||||||
|
|
||||||
var addIfNotGame = db.prepareCall("{call AddIfNotGame(?, ?, ?)}");
|
var addIfNotGame = db.prepareCall("{call AddIfNotGame(?, ?, ?)}");
|
||||||
var addGameToPlatform = db.prepareCall("{call AddGameToPlatform(?, ?, ?)}");
|
var addGameToPlatform = db.prepareCall("{call AddGameToPlatform(?, ?, ?)}");
|
||||||
var addGameToUser = db.prepareCall("{call AddGameToPlatform(?, ?, ?)}");
|
var addGameToUser = db.prepareCall("{call AddGameToUser(?, ?, ?)}");
|
||||||
var addIfNotAchievement = db.prepareCall("{call AddIfNotAchievement(?, ?, ?, ?, ?, ?)}");
|
var addIfNotAchievement = db.prepareCall("{call AddIfNotAchievement(?, ?, ?, ?, ?, ?)}");
|
||||||
var setAchievementProgressForUser = db.prepareCall("{call SetAchievementProgressForUser(?, ?, ?, ?)}");
|
var setAchievementProgressForUser = db.prepareCall("{call SetAchievementProgressForUser(?, ?, ?, ?)}");
|
||||||
|
|
||||||
addIfNotGame.registerOutParameter(3, Types.INTEGER);
|
addIfNotGame.registerOutParameter(3, Types.INTEGER);
|
||||||
|
@ -70,6 +71,7 @@ public class APIService {
|
||||||
addGameToUser.setInt(3, platformId);
|
addGameToUser.setInt(3, platformId);
|
||||||
addGameToUser.execute();
|
addGameToUser.execute();
|
||||||
|
|
||||||
|
var set = new HashSet<Integer>();
|
||||||
for (var achievement : game.getAchievements()) {
|
for (var achievement : game.getAchievements()) {
|
||||||
addIfNotAchievement.setInt(1, gameId);
|
addIfNotAchievement.setInt(1, gameId);
|
||||||
addIfNotAchievement.setString(2, achievement.getName());
|
addIfNotAchievement.setString(2, achievement.getName());
|
||||||
|
@ -78,6 +80,7 @@ public class APIService {
|
||||||
addIfNotAchievement.setString(5, getFileType(achievement.getThumbnail()));
|
addIfNotAchievement.setString(5, getFileType(achievement.getThumbnail()));
|
||||||
addIfNotAchievement.execute();
|
addIfNotAchievement.execute();
|
||||||
var achievementId = addIfNotAchievement.getInt(6);
|
var achievementId = addIfNotAchievement.getInt(6);
|
||||||
|
set.add(achievementId);
|
||||||
|
|
||||||
var achievementIcon = new File("storage/images/achievement/" + achievementId + "." + getFileType(achievement.getThumbnail()));
|
var achievementIcon = new File("storage/images/achievement/" + achievementId + "." + getFileType(achievement.getThumbnail()));
|
||||||
if (!achievementIcon.exists()) {
|
if (!achievementIcon.exists()) {
|
||||||
|
|
|
@ -24,7 +24,7 @@ public class GameService {
|
||||||
|
|
||||||
public String[] getIcon(int gameId) {
|
public String[] getIcon(int gameId) {
|
||||||
try {
|
try {
|
||||||
var stmt = db.prepareCall("{call GetAchievementIcon(?)}");
|
var stmt = db.prepareCall("{call GetGameIcon(?)}");
|
||||||
return imageService.getImageType(stmt, gameId);
|
return imageService.getImageType(stmt, gameId);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
package achievements.services;
|
package achievements.services;
|
||||||
|
|
||||||
import achievements.data.Achievement;
|
import achievements.data.request.SearchGames;
|
||||||
import achievements.data.query.SearchAchievements;
|
import achievements.data.request.SearchUsers;
|
||||||
|
import achievements.data.response.search.Achievement;
|
||||||
|
import achievements.data.request.SearchAchievements;
|
||||||
|
import achievements.data.response.search.Game;
|
||||||
|
import achievements.data.response.search.User;
|
||||||
import achievements.misc.DbConnection;
|
import achievements.misc.DbConnection;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
@ -9,8 +13,7 @@ import org.springframework.stereotype.Service;
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class SearchService {
|
public class SearchService {
|
||||||
|
@ -26,16 +29,18 @@ public class SearchService {
|
||||||
|
|
||||||
public List<Achievement> searchAchievements(SearchAchievements query) {
|
public List<Achievement> searchAchievements(SearchAchievements query) {
|
||||||
try {
|
try {
|
||||||
var stmt = db.prepareCall("{call SearchAchievements(?, ?, ?, ?, ?, ?, ?, ?, ?)}");
|
var stmt = db.prepareCall("{call SearchAchievements(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)}");
|
||||||
stmt.setString(1, query.getSearchTerm());
|
stmt.setString(1, query.getSearchTerm());
|
||||||
stmt.setBoolean(3, query.isCompleted());
|
stmt.setBoolean(3, query.isCompleted());
|
||||||
if (query.getUserId() != null) { stmt.setInt( 2, query.getUserId() ); } else { stmt.setString(2, null); }
|
if (query.getUserId() != null) { stmt.setInt (2, query.getUserId()); } else { stmt.setString(2, null); }
|
||||||
if (query.getMinCompletion() != null) { stmt.setFloat(4, query.getMinCompletion()); } else { stmt.setString(4, null); }
|
if (query.getMinCompletion() != null) { stmt.setFloat(4, query.getMinCompletion()); } else { stmt.setString(4, null); }
|
||||||
if (query.getMaxCompletion() != null) { stmt.setFloat(5, query.getMaxCompletion()); } else { stmt.setString(5, null); }
|
if (query.getMaxCompletion() != null) { stmt.setFloat(5, query.getMaxCompletion()); } else { stmt.setString(5, null); }
|
||||||
if (query.getMinDifficulty() != null) { stmt.setFloat(6, query.getMinDifficulty()); } else { stmt.setString(6, null); }
|
if (query.getMinDifficulty() != null) { stmt.setFloat(6, query.getMinDifficulty()); } else { stmt.setString(6, null); }
|
||||||
if (query.getMaxDifficulty() != null) { stmt.setFloat(7, query.getMaxDifficulty()); } else { stmt.setString(7, null); }
|
if (query.getMaxDifficulty() != null) { stmt.setFloat(7, query.getMaxDifficulty()); } else { stmt.setString(7, null); }
|
||||||
if (query.getMinQuality() != null) { stmt.setFloat(8, query.getMinQuality() ); } else { stmt.setString(8, null); }
|
if (query.getMinQuality() != null) { stmt.setFloat(8, query.getMinQuality()); } else { stmt.setString(8, null); }
|
||||||
if (query.getMaxQuality() != null) { stmt.setFloat(9, query.getMaxQuality() ); } else { stmt.setString(9, null); }
|
if (query.getMaxQuality() != null) { stmt.setFloat(9, query.getMaxQuality()); } else { stmt.setString(9, null); }
|
||||||
|
stmt.setString(10, query.getOrdering());
|
||||||
|
stmt.setString(11, query.getOrderDirection());
|
||||||
var results = stmt.executeQuery();
|
var results = stmt.executeQuery();
|
||||||
|
|
||||||
var achievements = new ArrayList<Achievement>();
|
var achievements = new ArrayList<Achievement>();
|
||||||
|
@ -56,4 +61,72 @@ public class SearchService {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<User> searchUsers(SearchUsers query) {
|
||||||
|
try {
|
||||||
|
var stmt = db.prepareCall("{call SearchUsers(?, ?, ?, ?, ?, ?, ?, ?, ?)}");
|
||||||
|
stmt.setString(1, query.getSearchTerm());
|
||||||
|
if (query.getMinOwned() != null) { stmt.setFloat(2, query.getMinOwned()); } else { stmt.setString(2, null); }
|
||||||
|
if (query.getMaxOwned() != null) { stmt.setFloat(3, query.getMaxOwned()); } else { stmt.setString(3, null); }
|
||||||
|
if (query.getMinCompleted() != null) { stmt.setFloat(4, query.getMinCompleted()); } else { stmt.setString(4, null); }
|
||||||
|
if (query.getMaxCompleted() != null) { stmt.setFloat(5, query.getMaxCompleted()); } else { stmt.setString(5, null); }
|
||||||
|
if (query.getMinAvgCompletion() != null) { stmt.setFloat(6, query.getMinAvgCompletion()); } else { stmt.setString(6, null); }
|
||||||
|
if (query.getMaxAvgCompletion() != null) { stmt.setFloat(7, query.getMaxAvgCompletion()); } else { stmt.setString(7, null); }
|
||||||
|
stmt.setString(8, query.getOrdering());
|
||||||
|
stmt.setString(9, query.getOrderDirection());
|
||||||
|
var results = stmt.executeQuery();
|
||||||
|
|
||||||
|
var users = new ArrayList<User>();
|
||||||
|
while (results.next()) {
|
||||||
|
var user = new User();
|
||||||
|
user.setID (results.getInt ("ID" ));
|
||||||
|
user.setUsername (results.getString("Username" ));
|
||||||
|
user.setGame_count (results.getInt ("GameCount" ));
|
||||||
|
user.setAchievement_count(results.getInt ("AchievementCount"));
|
||||||
|
user.setAvg_completion (results.getInt ("AvgCompletion" )); if (results.wasNull()) { user.setAvg_completion(null); }
|
||||||
|
user.setPerfect_games (results.getInt ("PerfectGames" ));
|
||||||
|
users.add(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
return users;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Game> searchGames(SearchGames query) {
|
||||||
|
try {
|
||||||
|
var stmt = db.prepareCall("{call SearchGames(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)}");
|
||||||
|
stmt.setString(1, query.getSearchTerm());
|
||||||
|
stmt.setBoolean(3, query.isOwned());
|
||||||
|
if (query.getUserId() != null) { stmt.setInt (2, query.getUserId()); } else { stmt.setString(2, null); }
|
||||||
|
if (query.getMinAvgCompletion() != null) { stmt.setFloat(4, query.getMinAvgCompletion()); } else { stmt.setString(4, null); }
|
||||||
|
if (query.getMaxAvgCompletion() != null) { stmt.setFloat(5, query.getMaxAvgCompletion()); } else { stmt.setString(5, null); }
|
||||||
|
if (query.getMinNumOwners() != null) { stmt.setFloat(6, query.getMinNumOwners()); } else { stmt.setString(6, null); }
|
||||||
|
if (query.getMaxNumOwners() != null) { stmt.setFloat(7, query.getMaxNumOwners()); } else { stmt.setString(7, null); }
|
||||||
|
if (query.getMinNumPerfects() != null) { stmt.setFloat(8, query.getMinNumPerfects()); } else { stmt.setString(8, null); }
|
||||||
|
if (query.getMaxNumPerfects() != null) { stmt.setFloat(9, query.getMaxNumPerfects()); } else { stmt.setString(9, null); }
|
||||||
|
stmt.setString(10, query.getOrdering());
|
||||||
|
stmt.setString(11, query.getOrderDirection());
|
||||||
|
var results = stmt.executeQuery();
|
||||||
|
|
||||||
|
var games = new ArrayList<Game>();
|
||||||
|
while (results.next()) {
|
||||||
|
var game = new Game();
|
||||||
|
game.setID (results.getInt ("ID" ));
|
||||||
|
game.setName (results.getString("Name" ));
|
||||||
|
game.setAchievement_count(results.getInt ("AchievementCount"));
|
||||||
|
game.setAvg_completion (results.getInt ("AvgCompletion" )); if (results.wasNull()) { game.setAvg_completion(null); }
|
||||||
|
game.setNum_owners (results.getInt ("NumOwners" ));
|
||||||
|
game.setNum_perfects (results.getInt ("NumPerfects" ));
|
||||||
|
games.add(game);
|
||||||
|
}
|
||||||
|
|
||||||
|
return games;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package achievements.services;
|
package achievements.services;
|
||||||
|
|
||||||
import achievements.data.Profile;
|
import achievements.data.Profile;
|
||||||
import achievements.data.query.AddPlatform;
|
import achievements.data.request.AddPlatform;
|
||||||
import achievements.data.query.RemovePlatform;
|
import achievements.data.request.RemovePlatform;
|
||||||
import achievements.data.query.SetUsername;
|
import achievements.data.request.SetUsername;
|
||||||
import achievements.misc.DbConnection;
|
import achievements.misc.DbConnection;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
@ -210,4 +210,6 @@ public class UserService {
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,3 +4,5 @@ spring.jackson.default-property-inclusion=always
|
||||||
|
|
||||||
server.session.cookie.secure = false
|
server.session.cookie.secure = false
|
||||||
|
|
||||||
|
spring.servlet.multipart.max-file-size = 10MB
|
||||||
|
spring.servlet.multipart.max-request-size = 10MB
|
|
@ -11,14 +11,10 @@ const promptly = require('promptly');
|
||||||
|
|
||||||
const config = require('./config.js').load(process.argv[2]);
|
const config = require('./config.js').load(process.argv[2]);
|
||||||
|
|
||||||
if (config.build === 'debug') {
|
|
||||||
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Running server at '${config.hosts.frontend}'`);
|
console.log(`Running server at '${config.hosts.frontend}'`);
|
||||||
|
|
||||||
passport.use(new SteamStrategy({
|
passport.use(new SteamStrategy({
|
||||||
returnURL: `${config.hosts.frontend}/profile/steam`,
|
returnURL: `${config.hosts.frontend}/user/steam`,
|
||||||
realm: `${config.hosts.frontend}`,
|
realm: `${config.hosts.frontend}`,
|
||||||
profile: false,
|
profile: false,
|
||||||
}));
|
}));
|
||||||
|
@ -41,8 +37,11 @@ app.get("/users", (req, res) => {
|
||||||
app.get("/games", (req, res) => {
|
app.get("/games", (req, res) => {
|
||||||
res.sendFile(path.join(__dirname + "/webpage/search_games.html"));
|
res.sendFile(path.join(__dirname + "/webpage/search_games.html"));
|
||||||
});
|
});
|
||||||
app.get("/profile/:id", (req, res) => {
|
app.get("/achievement/:id", (req, res) => {
|
||||||
res.sendFile(path.join(__dirname + "/webpage/profile.html"));
|
res.sendFile(path.join(__dirname + "/webpage/achievement.html"));
|
||||||
|
});
|
||||||
|
app.get("/user/:id", (req, res) => {
|
||||||
|
res.sendFile(path.join(__dirname + "/webpage/user.html"));
|
||||||
});
|
});
|
||||||
app.get("/auth/steam", passport.authenticate('steam'), (req, res) => {});
|
app.get("/auth/steam", passport.authenticate('steam'), (req, res) => {});
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
<div id="search-achievements-page" class="search page">
|
<div id="search-achievements-page" class="search page">
|
||||||
<div class="page-subsection">
|
<div class="page-subsection">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<p class="page-header-text">Search Achievements</p>
|
<p class="page-header-text">Achievement Search</p>
|
||||||
<div class="page-header-separator"></div>
|
<div class="page-header-separator"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -35,7 +35,7 @@
|
||||||
<div id="search-wrapper" class="page-subsection-wrapper">
|
<div id="search-wrapper" class="page-subsection-wrapper">
|
||||||
<div id="list-page-search-pair" class="list-page-search page-subsection-chunk">
|
<div id="list-page-search-pair" class="list-page-search page-subsection-chunk">
|
||||||
<label id="achievement-search-button" for="achievement-search">Search</label>
|
<label id="achievement-search-button" for="achievement-search">Search</label>
|
||||||
<input id="achievement-search-field" type="text" placeholder="Name" name="achievement-search"/>
|
<input id="achievement-search-field" type="text" placeholder="Game Name, Achievement Name" name="achievement-search"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="filter-dropdown-wrapper" class="page-subsection-wrapper">
|
<div id="filter-dropdown-wrapper" class="page-subsection-wrapper">
|
||||||
|
@ -46,16 +46,16 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="list-page-filters-flex">
|
<div id="list-page-filters-flex">
|
||||||
<div class="list-page-filter-section page-subsection-wrapper">
|
<div id="personal-filters" class="list-page-filter-section page-subsection-wrapper">
|
||||||
<div class="page-subheader">
|
<div class="page-subheader">
|
||||||
<p class="page-subheader-text">Me</p>
|
<p class="page-subheader-text">Personal</p>
|
||||||
<div class="page-subheader-separator"></div>
|
<div class="page-subheader-separator"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-page-filter-chunk page-subsection-chunk">
|
<div class="list-page-filter-chunk page-subsection-chunk">
|
||||||
<div class="page-subsection-wrapper">
|
<div class="page-subsection-wrapper">
|
||||||
<div id="completed-filter" class="list-page-filter">
|
<div id="completed-filter" class="list-page-filter">
|
||||||
<div class="list-page-filter-checkbox"></div>
|
<div class="list-page-filter-checkbox"></div>
|
||||||
<p class="list-page-filter-name">Completed</p>
|
<p class="list-page-filter-name">Completed By Me</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -68,19 +68,19 @@
|
||||||
<div class="list-page-filter-chunk page-subsection-chunk">
|
<div class="list-page-filter-chunk page-subsection-chunk">
|
||||||
<div class="page-subsection-wrapper">
|
<div class="page-subsection-wrapper">
|
||||||
<div class="list-page-filter">
|
<div class="list-page-filter">
|
||||||
<p class="list-page-filter-label">Min Completion</p>
|
<p class="list-page-filter-label">Min. Completion</p>
|
||||||
<input id="min-completion-filter" type="text" class="list-page-filter-param"></input>
|
<input id="min-completion-filter" type="text" class="list-page-filter-param"></input>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-page-filter">
|
<div class="list-page-filter">
|
||||||
<p class="list-page-filter-label">Max Completion</p>
|
<p class="list-page-filter-label">Max. Completion</p>
|
||||||
<input id="max-completion-filter" type="text" class="list-page-filter-param"></input>
|
<input id="max-completion-filter" type="text" class="list-page-filter-param"></input>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-page-filter">
|
<div class="list-page-filter">
|
||||||
<p class="list-page-filter-label">Min Difficulty</p>
|
<p class="list-page-filter-label">Min. Difficulty</p>
|
||||||
<input id="min-difficulty-filter" type="text" class="list-page-filter-param"></input>
|
<input id="min-difficulty-filter" type="text" class="list-page-filter-param"></input>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-page-filter">
|
<div class="list-page-filter">
|
||||||
<p class="list-page-filter-label">Max Difficulty</p>
|
<p class="list-page-filter-label">Max. Difficulty</p>
|
||||||
<input id="max-difficulty-filter" type="text" class="list-page-filter-param"></input>
|
<input id="max-difficulty-filter" type="text" class="list-page-filter-param"></input>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -94,11 +94,11 @@
|
||||||
<div class="list-page-filter-chunk page-subsection-chunk">
|
<div class="list-page-filter-chunk page-subsection-chunk">
|
||||||
<div class="page-subsection-wrapper">
|
<div class="page-subsection-wrapper">
|
||||||
<div class="list-page-filter">
|
<div class="list-page-filter">
|
||||||
<p class="list-page-filter-label">Min Quality</p>
|
<p class="list-page-filter-label">Min. Quality</p>
|
||||||
<input id="min-quality-filter" type="text" class="list-page-filter-param"></input>
|
<input id="min-quality-filter" type="text" class="list-page-filter-param"></input>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-page-filter">
|
<div class="list-page-filter">
|
||||||
<p class="list-page-filter-label">Max Quality</p>
|
<p class="list-page-filter-label">Max. Quality</p>
|
||||||
<input id="max-quality-filter" type="text" class="list-page-filter-param"></input>
|
<input id="max-quality-filter" type="text" class="list-page-filter-param"></input>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -112,15 +112,15 @@
|
||||||
<div class="list-page-list">
|
<div class="list-page-list">
|
||||||
<div class="list-page-header">
|
<div class="list-page-header">
|
||||||
<p class="list-page-entry-icon"></p>
|
<p class="list-page-entry-icon"></p>
|
||||||
<p class="list-page-entry-text achievement-game-name">Game</p>
|
<p id="achievement-header-game" class="list-page-entry-text achievement-game-name">Game</p>
|
||||||
<p class="list-page-entry-text achievement-name">Name</p>
|
<p id="achievement-header-name" class="list-page-entry-text achievement-name">Name</p>
|
||||||
<p class="list-page-entry-text achievement-completion">Completion Rate</p>
|
<p id="achievement-header-completion" class="list-page-entry-text achievement-completion">Completion Rate</p>
|
||||||
<p class="list-page-entry-text achievement-difficulty">Difficulty</p>
|
<p id="achievement-header-difficulty" class="list-page-entry-text achievement-difficulty">Difficulty</p>
|
||||||
<p class="list-page-entry-text achievement-quality">Quality</p>
|
<p id="achievement-header-quality" class="list-page-entry-text achievement-quality">Quality</p>
|
||||||
</div>
|
</div>
|
||||||
<template id="achievement-list-template" data-template="achievements-page-list: List<Basic>">
|
<template id="achievement-list-template" data-template="achievements-page-list: List<Basic>">
|
||||||
<div class="list-page-entry">
|
<div id="achievement-entry-${achievement_id}" class="list-page-entry achievement">
|
||||||
<img class="list-page-entry-icon lazy-img" data-src="/api/achievement/${achievement_id}/image" alt="Achievement Thumbnail"></img>
|
<img class="list-page-entry-icon lazy-img" data-src="/api/achievement/${achievement_id}/image" alt="Achievement Icon"></img>
|
||||||
<p class="list-page-entry-text achievement-game-name">${game_name}</p>
|
<p class="list-page-entry-text achievement-game-name">${game_name}</p>
|
||||||
<p class="list-page-entry-text achievement-name">${achievement_name}</p>
|
<p class="list-page-entry-text achievement-name">${achievement_name}</p>
|
||||||
<p class="list-page-entry-text achievement-completion">${completion}</p>
|
<p class="list-page-entry-text achievement-completion">${completion}</p>
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
<div id="search-games-page" class="search page">
|
<div id="search-games-page" class="search page">
|
||||||
<div class="page-subsection">
|
<div class="page-subsection">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<p class="page-header-text">Search Games</p>
|
<p class="page-header-text">Game Search</p>
|
||||||
<div class="page-header-separator"></div>
|
<div class="page-header-separator"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -34,8 +34,8 @@
|
||||||
<div id="list-page-search-dropdown">
|
<div id="list-page-search-dropdown">
|
||||||
<div id="search-wrapper" class="page-subsection-wrapper">
|
<div id="search-wrapper" class="page-subsection-wrapper">
|
||||||
<div id="list-page-search-pair" class="list-page-search page-subsection-chunk">
|
<div id="list-page-search-pair" class="list-page-search page-subsection-chunk">
|
||||||
<label for="achievement-search">Search</label>
|
<label id="game-search-button" for="game-search">Search</label>
|
||||||
<input id="achievement-search" type="text" placeholder="Name" name="achievement-search"/>
|
<input id="game-search-field" type="text" placeholder="Name" name="game-search"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="filter-dropdown-wrapper" class="page-subsection-wrapper">
|
<div id="filter-dropdown-wrapper" class="page-subsection-wrapper">
|
||||||
|
@ -48,14 +48,14 @@
|
||||||
<div id="list-page-filters-flex">
|
<div id="list-page-filters-flex">
|
||||||
<div class="list-page-filter-section page-subsection-wrapper">
|
<div class="list-page-filter-section page-subsection-wrapper">
|
||||||
<div class="page-subheader">
|
<div class="page-subheader">
|
||||||
<p class="page-subheader-text">Games</p>
|
<p class="page-subheader-text">Me</p>
|
||||||
<div class="page-subheader-separator"></div>
|
<div class="page-subheader-separator"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-page-filter-chunk page-subsection-chunk">
|
<div class="list-page-filter-chunk page-subsection-chunk">
|
||||||
<div class="page-subsection-wrapper">
|
<div class="page-subsection-wrapper">
|
||||||
<div id="games-owned-filter" class="list-page-filter">
|
<div id="owned-filter" class="list-page-filter">
|
||||||
<div class="list-page-filter-checkbox"></div>
|
<div class="list-page-filter-checkbox"></div>
|
||||||
<p class="list-page-filter-name">Games Owned</p>
|
<p class="list-page-filter-name">Owned By Me</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -67,31 +67,39 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="list-page-filter-chunk page-subsection-chunk">
|
<div class="list-page-filter-chunk page-subsection-chunk">
|
||||||
<div class="page-subsection-wrapper">
|
<div class="page-subsection-wrapper">
|
||||||
<div id="from-games-owned-filter" class="list-page-filter">
|
<div class="list-page-filter">
|
||||||
<div class="list-page-filter-checkbox"></div>
|
<p class="list-page-filter-label">Min Avg. Completion</p>
|
||||||
<p class="list-page-filter-name">My Games</p>
|
<input id="min-avg-completion-filter" type="text" class="list-page-filter-param"></input>
|
||||||
</div>
|
</div>
|
||||||
<div id="in-progress-filter" class="list-page-filter">
|
<div class="list-page-filter">
|
||||||
<div class="list-page-filter-checkbox"></div>
|
<p class="list-page-filter-label">Max Avg. Completion</p>
|
||||||
<p class="list-page-filter-name">In Progress</p>
|
<input id="max-avg-completion-filter" type="text" class="list-page-filter-param"></input>
|
||||||
</div>
|
|
||||||
<div id="completed-filter" class="list-page-filter">
|
|
||||||
<div class="list-page-filter-checkbox"></div>
|
|
||||||
<p class="list-page-filter-name">Completed</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-page-filter-section page-subsection-wrapper">
|
<div class="list-page-filter-section page-subsection-wrapper">
|
||||||
<div class="page-subheader">
|
<div class="page-subheader">
|
||||||
<p class="page-subheader-text">Platforms</p>
|
<p class="page-subheader-text">Users</p>
|
||||||
<div class="page-subheader-separator"></div>
|
<div class="page-subheader-separator"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-page-filter-chunk page-subsection-chunk">
|
<div class="list-page-filter-chunk page-subsection-chunk">
|
||||||
<div class="page-subsection-wrapper">
|
<div class="page-subsection-wrapper">
|
||||||
<div id="games-owned-filter" class="list-page-filter">
|
<div class="list-page-filter">
|
||||||
<div class="list-page-filter-checkbox"></div>
|
<p class="list-page-filter-label">Min Num Owners</p>
|
||||||
<p class="list-page-filter-name">Games Owned</p>
|
<input id="min-num-owners-filter" type="text" class="list-page-filter-param"></input>
|
||||||
|
</div>
|
||||||
|
<div class="list-page-filter">
|
||||||
|
<p class="list-page-filter-label">Max Num Owners</p>
|
||||||
|
<input id="max-num-owners-filter" type="text" class="list-page-filter-param"></input>
|
||||||
|
</div>
|
||||||
|
<div class="list-page-filter">
|
||||||
|
<p class="list-page-filter-label">Min Num Perfects</p>
|
||||||
|
<input id="min-num-perfects-filter" type="text" class="list-page-filter-param"></input>
|
||||||
|
</div>
|
||||||
|
<div class="list-page-filter">
|
||||||
|
<p class="list-page-filter-label">Max Num Perfects</p>
|
||||||
|
<input id="max-num-perfects-filter" type="text" class="list-page-filter-param"></input>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -103,25 +111,28 @@
|
||||||
<div class="page-subsection-chunk">
|
<div class="page-subsection-chunk">
|
||||||
<div class="list-page-list">
|
<div class="list-page-list">
|
||||||
<div class="list-page-header">
|
<div class="list-page-header">
|
||||||
<p class="list-page-entry-icon"></p>
|
<p class="list-page-entry-icon game"></p>
|
||||||
<p class="list-page-entry-text achievement-name">Name</p>
|
<p class="list-page-entry-text game-name">Game</p>
|
||||||
<p class="list-page-entry-text achievement-description">Description</p>
|
<p class="list-page-entry-text game-achievement-count">Achievement Count</p>
|
||||||
<p class="list-page-entry-text achievement-stages">Stages</p>
|
<p class="list-page-entry-text game-avg-completion">Avg. Completion</p>
|
||||||
|
<p class="list-page-entry-text game-num-owners">Num Owners</p>
|
||||||
|
<p class="list-page-entry-text game-num-perfects">Num Perfects</p>
|
||||||
</div>
|
</div>
|
||||||
<template data-template="achievements-page-list: List<Basic>">
|
<template id="game-list-template" data-template="games-page-list: List<Basic>">
|
||||||
<div class="list-page-entry">
|
<div class="list-page-entry">
|
||||||
<img class="list-page-entry-icon" src="/static/res/dummy_achievement.png" alt="Achievement Thumbnail"></img>
|
<img class="list-page-entry-icon lazy-img game" data-src="/api/game/${game_id}/image" alt="Game Thumbnail"></img>
|
||||||
<div class="list-page-entry-text-section">
|
<p class="list-page-entry-text game-name">${game_name}</p>
|
||||||
<p class="list-page-entry-text achievement-name">${achievement-name}</p>
|
<p class="list-page-entry-text game-achievement-count">${achievement_count}</p>
|
||||||
<p class="list-page-entry-text achievement-description">${achievement-description}</p>
|
<p class="list-page-entry-text game-avg-completion">${avg_completion}</p>
|
||||||
<p class="list-page-entry-text achievement-stages">${stages}</p>
|
<p class="list-page-entry-text game-num-owners">${num_owners}</p>
|
||||||
</div>
|
<p class="list-page-entry-text game-num-perfects">${num_perfects}</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<img id="loading-results" class="ap-loading" src="/static/res/loading.svg" alt="Loading Symbol" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
<div id="search-users-page" class="search page">
|
<div id="search-users-page" class="search page">
|
||||||
<div class="page-subsection">
|
<div class="page-subsection">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<p class="page-header-text">Search Users</p>
|
<p class="page-header-text">User Search</p>
|
||||||
<div class="page-header-separator"></div>
|
<div class="page-header-separator"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -34,8 +34,8 @@
|
||||||
<div id="list-page-search-dropdown">
|
<div id="list-page-search-dropdown">
|
||||||
<div id="search-wrapper" class="page-subsection-wrapper">
|
<div id="search-wrapper" class="page-subsection-wrapper">
|
||||||
<div id="list-page-search-pair" class="list-page-search page-subsection-chunk">
|
<div id="list-page-search-pair" class="list-page-search page-subsection-chunk">
|
||||||
<label for="achievement-search">Search</label>
|
<label id="user-search-button" for="user-search">Search</label>
|
||||||
<input id="achievement-search" type="text" placeholder="Name" name="achievement-search"/>
|
<input id="user-search-field" type="text" placeholder="Name" name="user-search"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="filter-dropdown-wrapper" class="page-subsection-wrapper">
|
<div id="filter-dropdown-wrapper" class="page-subsection-wrapper">
|
||||||
|
@ -53,45 +53,39 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="list-page-filter-chunk page-subsection-chunk">
|
<div class="list-page-filter-chunk page-subsection-chunk">
|
||||||
<div class="page-subsection-wrapper">
|
<div class="page-subsection-wrapper">
|
||||||
<div id="games-owned-filter" class="list-page-filter">
|
<div class="list-page-filter">
|
||||||
<div class="list-page-filter-checkbox"></div>
|
<p class="list-page-filter-label">Min Owned</p>
|
||||||
<p class="list-page-filter-name">Games Owned</p>
|
<input id="min-owned-filter" type="text" class="list-page-filter-param"></input>
|
||||||
|
</div>
|
||||||
|
<div class="list-page-filter">
|
||||||
|
<p class="list-page-filter-label">Max Owned</p>
|
||||||
|
<input id="max-owned-filter" type="text" class="list-page-filter-param"></input>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-page-filter-section page-subsection-wrapper">
|
<div class="list-page-filter-section page-subsection-wrapper">
|
||||||
<div class="page-subheader">
|
<div class="page-subheader">
|
||||||
<p class="page-subheader-text">General</p>
|
<p class="page-subheader-text">Achievements</p>
|
||||||
<div class="page-subheader-separator"></div>
|
<div class="page-subheader-separator"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-page-filter-chunk page-subsection-chunk">
|
<div class="list-page-filter-chunk page-subsection-chunk">
|
||||||
<div class="page-subsection-wrapper">
|
<div class="page-subsection-wrapper">
|
||||||
<div id="from-games-owned-filter" class="list-page-filter">
|
<div class="list-page-filter">
|
||||||
<div class="list-page-filter-checkbox"></div>
|
<p class="list-page-filter-label">Min Completed</p>
|
||||||
<p class="list-page-filter-name">From My Games</p>
|
<input id="min-completed-filter" type="text" class="list-page-filter-param"></input>
|
||||||
</div>
|
</div>
|
||||||
<div id="completed-filter" class="list-page-filter">
|
<div class="list-page-filter">
|
||||||
<div class="list-page-filter-checkbox"></div>
|
<p class="list-page-filter-label">Max Completed</p>
|
||||||
<p class="list-page-filter-name">Completed</p>
|
<input id="max-completed-filter" type="text" class="list-page-filter-param"></input>
|
||||||
</div>
|
</div>
|
||||||
<div id="completed-filter" class="list-page-filter">
|
<div class="list-page-filter">
|
||||||
<div class="list-page-filter-checkbox"></div>
|
<p class="list-page-filter-label">Min Avg. Completion</p>
|
||||||
<p class="list-page-filter-name">Completed</p>
|
<input id="min-avg-completion-filter" type="text" class="list-page-filter-param"></input>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="list-page-filter">
|
||||||
</div>
|
<p class="list-page-filter-label">Max Avg. Completion</p>
|
||||||
</div>
|
<input id="max-avg-completion-filter" type="text" class="list-page-filter-param"></input>
|
||||||
<div class="list-page-filter-section page-subsection-wrapper">
|
|
||||||
<div class="page-subheader">
|
|
||||||
<p class="page-subheader-text">Platforms</p>
|
|
||||||
<div class="page-subheader-separator"></div>
|
|
||||||
</div>
|
|
||||||
<div class="list-page-filter-chunk page-subsection-chunk">
|
|
||||||
<div class="page-subsection-wrapper">
|
|
||||||
<div id="games-owned-filter" class="list-page-filter">
|
|
||||||
<div class="list-page-filter-checkbox"></div>
|
|
||||||
<p class="list-page-filter-name">Games Owned</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -104,24 +98,27 @@
|
||||||
<div class="list-page-list">
|
<div class="list-page-list">
|
||||||
<div class="list-page-header">
|
<div class="list-page-header">
|
||||||
<p class="list-page-entry-icon"></p>
|
<p class="list-page-entry-icon"></p>
|
||||||
<p class="list-page-entry-text achievement-name">Name</p>
|
<p class="list-page-entry-text user-username">Username</p>
|
||||||
<p class="list-page-entry-text achievement-description">Description</p>
|
<p class="list-page-entry-text user-game-count">Game Count</p>
|
||||||
<p class="list-page-entry-text achievement-stages">Stages</p>
|
<p class="list-page-entry-text user-achievement-count">Achievement Count</p>
|
||||||
|
<p class="list-page-entry-text user-avg-completion">Avg. Completion</p>
|
||||||
|
<p class="list-page-entry-text user-perfect-games">Perfect Games</p>
|
||||||
</div>
|
</div>
|
||||||
<template data-template="achievements-page-list: List<Basic>">
|
<template id="user-list-template" data-template="user-page-list: List<Basic>">
|
||||||
<div class="list-page-entry">
|
<div class="list-page-entry user" data-id="${user_id}">
|
||||||
<img class="list-page-entry-icon" src="/static/res/dummy_achievement.png" alt="Achievement Thumbnail"></img>
|
<img class="list-page-entry-icon lazy-img" data-src="/api/user/${user_id}/image" alt="User Image"></img>
|
||||||
<div class="list-page-entry-text-section">
|
<p class="list-page-entry-text user-username">${username}</p>
|
||||||
<p class="list-page-entry-text achievement-name">${achievement-name}</p>
|
<p class="list-page-entry-text user-game-count">${game_count}</p>
|
||||||
<p class="list-page-entry-text achievement-description">${achievement-description}</p>
|
<p class="list-page-entry-text user-achievement-count">${achievement_count}</p>
|
||||||
<p class="list-page-entry-text achievement-stages">${stages}</p>
|
<p class="list-page-entry-text user-avg-completion">${avg_completion}</p>
|
||||||
</div>
|
<p class="list-page-entry-text user-perfect-games">${perfect_games}</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<img id="loading-results" class="ap-loading" src="/static/res/loading.svg" alt="Loading Symbol" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -63,7 +63,7 @@ const commonTemplates = async () => {
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
template.apply("navbar-section-right").values([
|
template.apply("navbar-section-right").values([
|
||||||
{ item: "login", title: "Login" }
|
{ item: "login", title: "Login / Create Account" }
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -96,7 +96,7 @@ const connectNavbar = () => {
|
||||||
window.location.href = "/login";
|
window.location.href = "/login";
|
||||||
});
|
});
|
||||||
} else if (item.dataset.pageName === "profile") {
|
} else if (item.dataset.pageName === "profile") {
|
||||||
item.addEventListener("click", (clickEvent) => window.location.href = `/profile/${session.id}`);
|
item.addEventListener("click", (clickEvent) => window.location.href = `/user/${session.id}`);
|
||||||
} else {
|
} else {
|
||||||
item.addEventListener("click", (clickEvent) => window.location.href = `/${item.dataset.pageName}`);
|
item.addEventListener("click", (clickEvent) => window.location.href = `/${item.dataset.pageName}`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ window.addEventListener("load", async (loadEvent) => {
|
||||||
const data = response.data;
|
const data = response.data;
|
||||||
if (response.status === 201) {
|
if (response.status === 201) {
|
||||||
session = data;
|
session = data;
|
||||||
window.location.href = "/";
|
window.location.href = `/user/${session.id}`;
|
||||||
} else if (response.status === 500) {
|
} else if (response.status === 500) {
|
||||||
raiseError([], "Internal server error :(");
|
raiseError([], "Internal server error :(");
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -10,6 +10,10 @@ const saveTemplate = () => {
|
||||||
const loadAchievementSearch = () => {
|
const loadAchievementSearch = () => {
|
||||||
const loading = document.querySelector("#loading-results");
|
const loading = document.querySelector("#loading-results");
|
||||||
|
|
||||||
|
const personal = document.querySelector("#personal-filters");
|
||||||
|
if (!session) {
|
||||||
|
personal.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
const searchButton = document.querySelector("#achievement-search-button");
|
const searchButton = document.querySelector("#achievement-search-button");
|
||||||
const searchField = document.querySelector("#achievement-search-field" );
|
const searchField = document.querySelector("#achievement-search-field" );
|
||||||
|
@ -22,23 +26,26 @@ const loadAchievementSearch = () => {
|
||||||
const minQuality = document.querySelector("#min-quality-filter" );
|
const minQuality = document.querySelector("#min-quality-filter" );
|
||||||
const maxQuality = document.querySelector("#max-quality-filter" );
|
const maxQuality = document.querySelector("#max-quality-filter" );
|
||||||
|
|
||||||
|
let ordering = 'name';
|
||||||
|
let direction = true;
|
||||||
let canSearch = true;
|
let canSearch = true;
|
||||||
const loadList = async () => {
|
const loadList = async () => {
|
||||||
if (canSearch) {
|
if (canSearch) {
|
||||||
canSearch = false;
|
canSearch = false;
|
||||||
|
|
||||||
const body = {
|
const body = {
|
||||||
searchTerm: searchField.value,
|
searchTerm: searchField.value,
|
||||||
userId: completed.classList.contains('active') ? session.id : null,
|
userId: completed.classList.contains('selected') ? session.id : null,
|
||||||
completed: completed.classList.contains('active'),
|
completed: completed.classList.contains('selected') ? true : null,
|
||||||
minCompletion: minCompletion.value === '' ? null : Number(minCompletion.value),
|
minCompletion: minCompletion.value === '' ? null : Number(minCompletion.value),
|
||||||
maxCompletion: maxCompletion.value === '' ? null : Number(maxCompletion.value),
|
maxCompletion: maxCompletion.value === '' ? null : Number(maxCompletion.value),
|
||||||
minDifficulty: minDifficulty.value === '' ? null : Number(minDifficulty.value),
|
minDifficulty: minDifficulty.value === '' ? null : Number(minDifficulty.value),
|
||||||
maxDifficulty: maxDifficulty.value === '' ? null : Number(maxDifficulty.value),
|
maxDifficulty: maxDifficulty.value === '' ? null : Number(maxDifficulty.value),
|
||||||
minQuality: minQuality.value === '' ? null : Number(minQuality.value ),
|
minQuality: minQuality.value === '' ? null : Number(minQuality.value ),
|
||||||
maxQuality: maxQuality.value === '' ? null : Number(maxQuality.value ),
|
maxQuality: maxQuality.value === '' ? null : Number(maxQuality.value ),
|
||||||
|
ordering: ordering,
|
||||||
|
orderDirection: direction ? 'ASC' : 'DESC',
|
||||||
};
|
};
|
||||||
console.log(body);
|
|
||||||
let successful = true;
|
let successful = true;
|
||||||
if (Number.isNaN(body.minCompletion)) { successful = false; minCompletion.style.backgroundColor = 'var(--error)'; } else { minCompletion.style.backgroundColor = 'var(--foreground)'; }
|
if (Number.isNaN(body.minCompletion)) { successful = false; minCompletion.style.backgroundColor = 'var(--error)'; } else { minCompletion.style.backgroundColor = 'var(--foreground)'; }
|
||||||
if (Number.isNaN(body.maxCompletion)) { successful = false; maxCompletion.style.backgroundColor = 'var(--error)'; } else { maxCompletion.style.backgroundColor = 'var(--foreground)'; }
|
if (Number.isNaN(body.maxCompletion)) { successful = false; maxCompletion.style.backgroundColor = 'var(--error)'; } else { maxCompletion.style.backgroundColor = 'var(--foreground)'; }
|
||||||
|
@ -72,9 +79,9 @@ const loadAchievementSearch = () => {
|
||||||
achievement_id: item.ID,
|
achievement_id: item.ID,
|
||||||
achievement_name: item.name,
|
achievement_name: item.name,
|
||||||
game_name: item.game,
|
game_name: item.game,
|
||||||
completion: item.completion == null ? 'N/A' : item.completion + '%',
|
completion: item.completion == null ? 'N/A' : `${item.completion}%`,
|
||||||
difficulty: item.difficulty == null ? 'N/A' : item.difficulty + ' / 10',
|
difficulty: item.difficulty == null ? 'N/A' : `${item.difficulty} / 10`,
|
||||||
quality: item.quality == null ? 'N/A' : item.quality + ' / 10'
|
quality: item.quality == null ? 'N/A' : `${item.quality} / 10`
|
||||||
}))));
|
}))));
|
||||||
await template.expand();
|
await template.expand();
|
||||||
data.then(data => {
|
data.then(data => {
|
||||||
|
@ -82,6 +89,25 @@ const loadAchievementSearch = () => {
|
||||||
canSearch = true;
|
canSearch = true;
|
||||||
loadLazyImages();
|
loadLazyImages();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const headers = {
|
||||||
|
game: document.querySelector(".list-page-header > .achievement-game-name" ),
|
||||||
|
name: document.querySelector(".list-page-header > .achievement-name" ),
|
||||||
|
completion: document.querySelector(".list-page-header > .achievement-completion"),
|
||||||
|
difficulty: document.querySelector(".list-page-header > .achievement-difficulty"),
|
||||||
|
quality: document.querySelector(".list-page-header > .achievement-quality" ),
|
||||||
|
}
|
||||||
|
for (const header in headers) {
|
||||||
|
headers[header].addEventListener("click", (clickEvent) => {
|
||||||
|
if (ordering === header) {
|
||||||
|
direction = !direction;
|
||||||
|
} else {
|
||||||
|
ordering = header;
|
||||||
|
direction = true;
|
||||||
|
}
|
||||||
|
loadList();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
135
frontend/webpage/static/scripts/search_games.js
Normal file
135
frontend/webpage/static/scripts/search_games.js
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
let templateList = null;
|
||||||
|
let templateText = null;
|
||||||
|
const saveTemplate = () => {
|
||||||
|
const templateElement = document.querySelector("#game-list-template");
|
||||||
|
templateList = templateElement.parentElement;
|
||||||
|
templateText = templateElement.outerHTML;
|
||||||
|
templateElement.remove();
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadGameSearch = () => {
|
||||||
|
const loading = document.querySelector("#loading-results");
|
||||||
|
|
||||||
|
const personal = document.querySelector("#personal-filters");
|
||||||
|
if (!session) {
|
||||||
|
personal.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchButton = document.querySelector("#game-search-button");
|
||||||
|
const searchField = document.querySelector("#game-search-field" );
|
||||||
|
|
||||||
|
const owned = document.querySelector("#owned-filter" );
|
||||||
|
const minAvgCompletion = document.querySelector("#min-avg-completion-filter");
|
||||||
|
const maxAvgCompletion = document.querySelector("#max-avg-completion-filter");
|
||||||
|
const minNumOwners = document.querySelector("#min-num-owners-filter" );
|
||||||
|
const maxNumOwners = document.querySelector("#max-num-owners-filter" );
|
||||||
|
const minNumPerfects = document.querySelector("#min-num-perfects-filter" );
|
||||||
|
const maxNumPerfects = document.querySelector("#max-num-perfects-filter" );
|
||||||
|
|
||||||
|
let ordering = 'name';
|
||||||
|
let direction = true;
|
||||||
|
let canSearch = true;
|
||||||
|
const loadList = async () => {
|
||||||
|
if (canSearch) {
|
||||||
|
canSearch = false;
|
||||||
|
|
||||||
|
const body = {
|
||||||
|
searchTerm: searchField.value,
|
||||||
|
userId: owned.classList.contains('selected') ? session.id : null,
|
||||||
|
owned: owned.classList.contains('selected') ? true : null,
|
||||||
|
minAvgCompletion: minAvgCompletion.value === '' ? null : Number(minAvgCompletion.value),
|
||||||
|
maxAvgCompletion: maxAvgCompletion.value === '' ? null : Number(maxAvgCompletion.value),
|
||||||
|
minNumOwners: minNumOwners.value === '' ? null : Number(minNumOwners.value ),
|
||||||
|
maxNumOwners: maxNumOwners.value === '' ? null : Number(maxNumOwners.value ),
|
||||||
|
minNumPerfects: minNumPerfects.value === '' ? null : Number(minNumPerfects.value ),
|
||||||
|
maxNumPerfects: maxNumPerfects.value === '' ? null : Number(maxNumPerfects.value ),
|
||||||
|
ordering: ordering,
|
||||||
|
orderDirection: direction ? 'ASC' : 'DESC',
|
||||||
|
};
|
||||||
|
let successful = true;
|
||||||
|
if (Number.isNaN(body.minAvgCompletion)) { successful = false; minAvgCompletion.style.backgroundColor = 'var(--error)'; } else { minAvgCompletion.style.backgroundColor = 'var(--foreground)'; }
|
||||||
|
if (Number.isNaN(body.maxAvgCompletion)) { successful = false; maxAvgCompletion.style.backgroundColor = 'var(--error)'; } else { maxAvgCompletion.style.backgroundColor = 'var(--foreground)'; }
|
||||||
|
if (Number.isNaN(body.minNumOwners)) { successful = false; minNumOwners.style.backgroundColor = 'var(--error)'; } else { minNumOwners.style.backgroundColor = 'var(--foreground)'; }
|
||||||
|
if (Number.isNaN(body.maxNumOwners)) { successful = false; maxNumOwners.style.backgroundColor = 'var(--error)'; } else { maxNumOwners.style.backgroundColor = 'var(--foreground)'; }
|
||||||
|
if (Number.isNaN(body.minNumPerfects)) { successful = false; minNumPerfects.style.backgroundColor = 'var(--error)'; } else { minNumPerfects.style.backgroundColor = 'var(--foreground)'; }
|
||||||
|
if (Number.isNaN(body.maxNumPerfects)) { successful = false; maxNumPerfects.style.backgroundColor = 'var(--error)'; } else { maxNumPerfects.style.backgroundColor = 'var(--foreground)'; }
|
||||||
|
|
||||||
|
if (!successful) {
|
||||||
|
canSearch = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const entry of templateList.querySelectorAll(".list-page-entry")) {
|
||||||
|
entry.remove();
|
||||||
|
}
|
||||||
|
templateList.innerHTML += templateText;
|
||||||
|
loading.style.display = 'block';
|
||||||
|
|
||||||
|
const data = fetch("/api/games", {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body)
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
|
||||||
|
template.clear();
|
||||||
|
template.apply('games-page-list').promise(data.then(data => data.map(item => ({
|
||||||
|
game_id: item.ID,
|
||||||
|
game_name: item.name,
|
||||||
|
achievement_count: item.achievement_count,
|
||||||
|
avg_completion: item.avg_completion == null ? 'N/A' : `${item.avg_completion}%`,
|
||||||
|
num_owners: item.num_owners,
|
||||||
|
num_perfects: item.num_perfects,
|
||||||
|
}))));
|
||||||
|
await template.expand();
|
||||||
|
data.then(data => {
|
||||||
|
console.log(data);
|
||||||
|
loading.style.display = 'none';
|
||||||
|
canSearch = true;
|
||||||
|
loadLazyImages();
|
||||||
|
});
|
||||||
|
|
||||||
|
const headers = {
|
||||||
|
game: document.querySelector(".list-page-header > .game-name" ),
|
||||||
|
achievement_count: document.querySelector(".list-page-header > .game-achievement-count"),
|
||||||
|
avg_completion: document.querySelector(".list-page-header > .game-avg-completion" ),
|
||||||
|
num_owners: document.querySelector(".list-page-header > .game-num-owners" ),
|
||||||
|
num_perfects: document.querySelector(".list-page-header > .game-num-perfects" ),
|
||||||
|
}
|
||||||
|
for (const header in headers) {
|
||||||
|
headers[header].addEventListener("click", (clickEvent) => {
|
||||||
|
if (ordering === header) {
|
||||||
|
direction = !direction;
|
||||||
|
} else {
|
||||||
|
ordering = header;
|
||||||
|
direction = true;
|
||||||
|
}
|
||||||
|
loadList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
searchButton.addEventListener("click", loadList);
|
||||||
|
searchField.addEventListener("keydown", (keyEvent) => {
|
||||||
|
if (keyEvent.key === 'Enter') {
|
||||||
|
loadList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
loadList();
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("load", async (loadEvent) => {
|
||||||
|
await loadCommonSearch();
|
||||||
|
|
||||||
|
saveTemplate();
|
||||||
|
await template.expand();
|
||||||
|
|
||||||
|
connectNavbar();
|
||||||
|
loadFilters();
|
||||||
|
|
||||||
|
await loadGameSearch();
|
||||||
|
});
|
132
frontend/webpage/static/scripts/search_users.js
Normal file
132
frontend/webpage/static/scripts/search_users.js
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
let templateList = null;
|
||||||
|
let templateText = null;
|
||||||
|
const saveTemplate = () => {
|
||||||
|
const templateElement = document.querySelector("#user-list-template");
|
||||||
|
templateList = templateElement.parentElement;
|
||||||
|
templateText = templateElement.outerHTML;
|
||||||
|
templateElement.remove();
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadUserSearch = () => {
|
||||||
|
const loading = document.querySelector("#loading-results");
|
||||||
|
|
||||||
|
|
||||||
|
const searchButton = document.querySelector("#user-search-button");
|
||||||
|
const searchField = document.querySelector("#user-search-field" );
|
||||||
|
|
||||||
|
const minOwned = document.querySelector("#min-owned-filter" );
|
||||||
|
const maxOwned = document.querySelector("#max-owned-filter" );
|
||||||
|
const minCompleted = document.querySelector("#min-completed-filter" );
|
||||||
|
const maxCompleted = document.querySelector("#max-completed-filter" );
|
||||||
|
const minAvgCompletion = document.querySelector("#min-avg-completion-filter");
|
||||||
|
const maxAvgCompletion = document.querySelector("#max-avg-completion-filter");
|
||||||
|
|
||||||
|
let ordering = 'name';
|
||||||
|
let direction = true;
|
||||||
|
let canSearch = true;
|
||||||
|
const loadList = async () => {
|
||||||
|
if (canSearch) {
|
||||||
|
canSearch = false;
|
||||||
|
|
||||||
|
const body = {
|
||||||
|
searchTerm: searchField.value,
|
||||||
|
minOwned: minOwned.value === '' ? null : Number(minOwned.value ),
|
||||||
|
maxOwned: maxOwned.value === '' ? null : Number(maxOwned.value ),
|
||||||
|
minCompleted: minCompleted.value === '' ? null : Number(minCompleted.value ),
|
||||||
|
maxCompleted: maxCompleted.value === '' ? null : Number(maxCompleted.value ),
|
||||||
|
minAvgCompletion: minAvgCompletion.value === '' ? null : Number(minAvgCompletion.value),
|
||||||
|
maxAvgCompletion: maxAvgCompletion.value === '' ? null : Number(maxAvgCompletion.value),
|
||||||
|
};
|
||||||
|
let successful = true;
|
||||||
|
if (Number.isNaN(body.minOwned )) { successful = false; minOwned.style.backgroundColor = 'var(--error)'; } else { minOwned.style.backgroundColor = 'var(--foreground)'; }
|
||||||
|
if (Number.isNaN(body.maxOwned )) { successful = false; maxOwned.style.backgroundColor = 'var(--error)'; } else { maxOwned.style.backgroundColor = 'var(--foreground)'; }
|
||||||
|
if (Number.isNaN(body.minCompleted )) { successful = false; minCompleted.style.backgroundColor = 'var(--error)'; } else { minCompleted.style.backgroundColor = 'var(--foreground)'; }
|
||||||
|
if (Number.isNaN(body.maxCompleted )) { successful = false; maxCompleted.style.backgroundColor = 'var(--error)'; } else { maxCompleted.style.backgroundColor = 'var(--foreground)'; }
|
||||||
|
if (Number.isNaN(body.minAvgCompletion)) { successful = false; minAvgCompletion.style.backgroundColor = 'var(--error)'; } else { minAvgCompletion.style.backgroundColor = 'var(--foreground)'; }
|
||||||
|
if (Number.isNaN(body.maxAvgCompletion)) { successful = false; maxAvgCompletion.style.backgroundColor = 'var(--error)'; } else { maxAvgCompletion.style.backgroundColor = 'var(--foreground)'; }
|
||||||
|
|
||||||
|
if (!successful) {
|
||||||
|
canSearch = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const entry of templateList.querySelectorAll(".list-page-entry")) {
|
||||||
|
entry.remove();
|
||||||
|
}
|
||||||
|
templateList.innerHTML += templateText;
|
||||||
|
loading.style.display = 'block';
|
||||||
|
|
||||||
|
const data = fetch("/api/users", {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body)
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
|
||||||
|
template.clear();
|
||||||
|
template.apply('user-page-list').promise(data.then(data => data.map(item => ({
|
||||||
|
user_id: item.id,
|
||||||
|
username: item.username,
|
||||||
|
game_count: item.game_count,
|
||||||
|
achievement_count: item.achievement_count,
|
||||||
|
avg_completion: item.avg_completion == null ? 'N/A' : `${item.avg_completion}%`,
|
||||||
|
perfect_games: item.perfect_games
|
||||||
|
}))));
|
||||||
|
await template.expand();
|
||||||
|
data.then(data => {
|
||||||
|
loading.style.display = 'none';
|
||||||
|
canSearch = true;
|
||||||
|
loadLazyImages();
|
||||||
|
|
||||||
|
const entries = document.querySelectorAll(".list-page-entry.user");
|
||||||
|
for (const entry of entries) {
|
||||||
|
entry.addEventListener("click", (clickEvent) => {
|
||||||
|
window.location.href = `/user/${entry.dataset.id}`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const headers = {
|
||||||
|
username: document.querySelector(".list-page-header > .user-username" ),
|
||||||
|
game_count: document.querySelector(".list-page-header > .user-game-count" ),
|
||||||
|
achievement_count: document.querySelector(".list-page-header > .user-achievement-count"),
|
||||||
|
avg_completion: document.querySelector(".list-page-header > .user-avg-completion" ),
|
||||||
|
perfect_games: document.querySelector(".list-page-header > .user-perfect-games" ),
|
||||||
|
}
|
||||||
|
for (const header in headers) {
|
||||||
|
headers[header].addEventListener("click", (clickEvent) => {
|
||||||
|
if (ordering === header) {
|
||||||
|
direction = !direction;
|
||||||
|
} else {
|
||||||
|
ordering = header;
|
||||||
|
direction = true;
|
||||||
|
}
|
||||||
|
loadList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
searchButton.addEventListener("click", loadList);
|
||||||
|
searchField.addEventListener("keydown", (keyEvent) => {
|
||||||
|
if (keyEvent.key === 'Enter') {
|
||||||
|
loadList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
loadList();
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("load", async (loadEvent) => {
|
||||||
|
await loadCommonSearch();
|
||||||
|
|
||||||
|
saveTemplate();
|
||||||
|
await template.expand();
|
||||||
|
|
||||||
|
connectNavbar();
|
||||||
|
loadFilters();
|
||||||
|
|
||||||
|
await loadUserSearch();
|
||||||
|
});
|
|
@ -160,8 +160,11 @@ const loadProfile = () => {
|
||||||
document.querySelector("#platform-0"),
|
document.querySelector("#platform-0"),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
let allowSteamImport = true;
|
||||||
steamButtons[0].addEventListener("click", (clickEvent) => {
|
steamButtons[0].addEventListener("click", (clickEvent) => {
|
||||||
window.location.href = "/auth/steam";
|
if (allowSteamImport) {
|
||||||
|
window.location.href = "/auth/steam";
|
||||||
|
}
|
||||||
});
|
});
|
||||||
steamButtons[1].addEventListener("click", (clickEvent) => {
|
steamButtons[1].addEventListener("click", (clickEvent) => {
|
||||||
fetch(`/api/user/${profileId}/platforms/remove`, {
|
fetch(`/api/user/${profileId}/platforms/remove`, {
|
||||||
|
@ -170,7 +173,10 @@ const loadProfile = () => {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ sessionKey: session.key, platformId: 0 })
|
body: JSON.stringify({ sessionKey: session.key, platformId: 0 })
|
||||||
|
}).then(() => {
|
||||||
|
allowSteamImport = true;
|
||||||
});
|
});
|
||||||
|
allowSteamImport = false;
|
||||||
steamButtons[1].parentElement.classList.remove("connected");
|
steamButtons[1].parentElement.classList.remove("connected");
|
||||||
});
|
});
|
||||||
|
|
|
@ -289,6 +289,9 @@
|
||||||
|
|
||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
|
|
||||||
|
transition-property: background-color;
|
||||||
|
transition-duration: 0.15s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-page-entry-icon {
|
.list-page-entry-icon {
|
||||||
|
@ -309,6 +312,8 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-page-entry > .list-page-entry-text {
|
.list-page-entry > .list-page-entry-text {
|
||||||
|
@ -318,6 +323,17 @@
|
||||||
|
|
||||||
.list-page-header > .list-page-entry-text {
|
.list-page-header > .list-page-entry-text {
|
||||||
border-left: 1px solid var(--accent-value0);
|
border-left: 1px solid var(--accent-value0);
|
||||||
|
|
||||||
|
transition-property: background-color;
|
||||||
|
transition-duration: 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-page-header > .list-page-entry-text:hover {
|
||||||
|
background-color: var(--accent-value1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-page-header > .list-page-entry-text:active {
|
||||||
|
background-color: var(--accent-value0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#loading-results {
|
#loading-results {
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
.list-page-entry.achievement:hover {
|
||||||
|
background-color: var(--background-light);
|
||||||
|
}
|
||||||
|
|
||||||
.list-page-entry-text.achievement-game-name { flex-grow: 1.75; }
|
.list-page-entry-text.achievement-game-name { flex-grow: 1.75; }
|
||||||
.list-page-entry-text.achievement-name { flex-grow: 2; }
|
.list-page-entry-text.achievement-name { flex-grow: 2; }
|
||||||
.list-page-entry-text.achievement-completion { flex-grow: 1; }
|
.list-page-entry-text.achievement-completion { flex-grow: 1; }
|
||||||
|
|
9
frontend/webpage/static/styles/search_games.css
Normal file
9
frontend/webpage/static/styles/search_games.css
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
.list-page-entry-icon.game {
|
||||||
|
width: 137px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-page-entry-text.game-name { flex-grow: 2.5; }
|
||||||
|
.list-page-entry-text.game-achievement-count { flex-grow: 1; }
|
||||||
|
.list-page-entry-text.game-avg-completion { flex-grow: 1; }
|
||||||
|
.list-page-entry-text.game-num-owners { flex-grow: 1; }
|
||||||
|
.list-page-entry-text.game-num-perfects { flex-grow: 1; }
|
9
frontend/webpage/static/styles/search_users.css
Normal file
9
frontend/webpage/static/styles/search_users.css
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
.list-page-entry.user:hover {
|
||||||
|
background-color: var(--background-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-page-entry-text.user-username { flex-grow: 1.5; }
|
||||||
|
.list-page-entry-text.user-game-count { flex-grow: 1; }
|
||||||
|
.list-page-entry-text.user-achievement-count { flex-grow: 1; }
|
||||||
|
.list-page-entry-text.user-avg-completion { flex-grow: 1; }
|
||||||
|
.list-page-entry-text.user-perfect-games { flex-grow: 1; }
|
|
@ -1,10 +1,11 @@
|
||||||
:root {
|
:root {
|
||||||
--background-dark: #111117;
|
--background-dark: #111117;
|
||||||
--background: #22222A;
|
--background: #22222A;
|
||||||
|
--background-light: #33333B;
|
||||||
|
--distinction: #44444C;
|
||||||
--foreground-disabled: #77777D;
|
--foreground-disabled: #77777D;
|
||||||
--foreground-dark: #AAAAAA;
|
--foreground-dark: #AAAAAA;
|
||||||
--foreground: #EEEEEE;
|
--foreground: #EEEEEE;
|
||||||
--distinction: #44444C;
|
|
||||||
|
|
||||||
--accent-hue: 0;
|
--accent-hue: 0;
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
<link rel="stylesheet" href="/static/styles/theme.css" />
|
<link rel="stylesheet" href="/static/styles/theme.css" />
|
||||||
<link rel="stylesheet" href="/static/styles/common.css" />
|
<link rel="stylesheet" href="/static/styles/common.css" />
|
||||||
<link rel="stylesheet" href="/static/styles/profile.css" />
|
<link rel="stylesheet" href="/static/styles/user.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="navbar">
|
<div id="navbar">
|
||||||
|
@ -137,6 +137,6 @@
|
||||||
</div>
|
</div>
|
||||||
<script src="/static/scripts/template.js"></script>
|
<script src="/static/scripts/template.js"></script>
|
||||||
<script src="/static/scripts/common.js"></script>
|
<script src="/static/scripts/common.js"></script>
|
||||||
<script src="/static/scripts/profile.js"></script>
|
<script src="/static/scripts/user.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -2,7 +2,7 @@
|
||||||
-- GET USER NAME AND STATS PROCEDURE --
|
-- GET USER NAME AND STATS PROCEDURE --
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
|
|
||||||
CREATE PROCEDURE GetUserNameAndStats(
|
ALTER PROCEDURE GetUserNameAndStats(
|
||||||
@userId INT,
|
@userId INT,
|
||||||
@username VARCHAR(32) OUTPUT,
|
@username VARCHAR(32) OUTPUT,
|
||||||
@completed INT OUTPUT,
|
@completed INT OUTPUT,
|
||||||
|
@ -42,7 +42,7 @@ SELECT * FROM [User]
|
||||||
-- GET USER PLATFORMS PROCEDURE --
|
-- GET USER PLATFORMS PROCEDURE --
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
|
||||||
CREATE PROCEDURE GetUserPlatforms(
|
ALTER PROCEDURE GetUserPlatforms(
|
||||||
@userId INT
|
@userId INT
|
||||||
)
|
)
|
||||||
AS
|
AS
|
||||||
|
@ -62,7 +62,7 @@ GO
|
||||||
-- GET USER RATINGS PROCEDURE --
|
-- GET USER RATINGS PROCEDURE --
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
CREATE PROCEDURE GetUserRatings(
|
ALTER PROCEDURE GetUserRatings(
|
||||||
@userId INT
|
@userId INT
|
||||||
)
|
)
|
||||||
AS
|
AS
|
||||||
|
@ -83,7 +83,7 @@ GO
|
||||||
-- GET USER IMAGE PROCEDURE --
|
-- GET USER IMAGE PROCEDURE --
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
CREATE PROCEDURE GetUserImage(
|
ALTER PROCEDURE GetUserImage(
|
||||||
@userId INT
|
@userId INT
|
||||||
)
|
)
|
||||||
AS
|
AS
|
||||||
|
@ -100,7 +100,7 @@ GO
|
||||||
-- SET USERNAME --
|
-- SET USERNAME --
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
CREATE PROCEDURE SetUsername(
|
ALTER PROCEDURE SetUsername(
|
||||||
@userId INT,
|
@userId INT,
|
||||||
@username VARCHAR(32)
|
@username VARCHAR(32)
|
||||||
)
|
)
|
||||||
|
@ -118,7 +118,7 @@ GO
|
||||||
-- SET USER IMAGE PROCEDURE --
|
-- SET USER IMAGE PROCEDURE --
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
CREATE PROCEDURE SetUserImage(
|
ALTER PROCEDURE SetUserImage(
|
||||||
@userId INT,
|
@userId INT,
|
||||||
@type ImageType,
|
@type ImageType,
|
||||||
@oldType ImageType OUTPUT
|
@oldType ImageType OUTPUT
|
||||||
|
@ -138,7 +138,7 @@ GO
|
||||||
-- ADD USER TO PLATFORM --
|
-- ADD USER TO PLATFORM --
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
CREATE PROCEDURE AddUserToPlatform(
|
ALTER PROCEDURE AddUserToPlatform(
|
||||||
@userId INT,
|
@userId INT,
|
||||||
@platformId INT,
|
@platformId INT,
|
||||||
@platformUserID VARCHAR(32)
|
@platformUserID VARCHAR(32)
|
||||||
|
@ -167,7 +167,7 @@ GO
|
||||||
-- REMOVE USER FROM PLATFORM --
|
-- REMOVE USER FROM PLATFORM --
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
CREATE PROCEDURE RemoveUserFromPlatform(
|
ALTER PROCEDURE RemoveUserFromPlatform(
|
||||||
@userId INT,
|
@userId INT,
|
||||||
@platformId INT
|
@platformId INT
|
||||||
)
|
)
|
||||||
|
@ -197,7 +197,7 @@ GO
|
||||||
-- ADD PLATFORM --
|
-- ADD PLATFORM --
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
CREATE PROCEDURE AddPlatform(
|
ALTER PROCEDURE AddPlatform(
|
||||||
@name VARCHAR(32),
|
@name VARCHAR(32),
|
||||||
@platformId INT OUTPUT
|
@platformId INT OUTPUT
|
||||||
)
|
)
|
||||||
|
@ -216,7 +216,7 @@ GO
|
||||||
-- REMOVE PLATFORM --
|
-- REMOVE PLATFORM --
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
CREATE PROCEDURE RemovePlatform(
|
ALTER PROCEDURE RemovePlatform(
|
||||||
@platformId INT
|
@platformId INT
|
||||||
)
|
)
|
||||||
AS
|
AS
|
||||||
|
@ -238,7 +238,7 @@ GO
|
||||||
-- GET PLATFORMS --
|
-- GET PLATFORMS --
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
CREATE PROCEDURE GetPlatforms
|
ALTER PROCEDURE GetPlatforms
|
||||||
AS
|
AS
|
||||||
SELECT ID, PlatformName FROM [Platform]
|
SELECT ID, PlatformName FROM [Platform]
|
||||||
RETURN 0
|
RETURN 0
|
||||||
|
@ -248,7 +248,7 @@ GO
|
||||||
-- GET PLATFORM NAME --
|
-- GET PLATFORM NAME --
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
CREATE PROCEDURE GetPlatformName(
|
ALTER PROCEDURE GetPlatformName(
|
||||||
@platformId INT,
|
@platformId INT,
|
||||||
@name VARCHAR(32) OUTPUT
|
@name VARCHAR(32) OUTPUT
|
||||||
)
|
)
|
||||||
|
@ -266,7 +266,7 @@ GO
|
||||||
-- GET PLATFORM ICON --
|
-- GET PLATFORM ICON --
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
CREATE PROCEDURE GetPlatformIcon(
|
ALTER PROCEDURE GetPlatformIcon(
|
||||||
@platformId INT
|
@platformId INT
|
||||||
)
|
)
|
||||||
AS
|
AS
|
||||||
|
@ -283,7 +283,7 @@ GO
|
||||||
-- ADD GAME --
|
-- ADD GAME --
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
CREATE PROCEDURE AddGame(
|
ALTER PROCEDURE AddGame(
|
||||||
@name VARCHAR(32),
|
@name VARCHAR(32),
|
||||||
@image ImageType,
|
@image ImageType,
|
||||||
@gameId INT OUTPUT
|
@gameId INT OUTPUT
|
||||||
|
@ -308,7 +308,7 @@ GO
|
||||||
-- ADD IF NOT GAME --
|
-- ADD IF NOT GAME --
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
CREATE PROCEDURE AddIfNotGame(
|
ALTER PROCEDURE AddIfNotGame(
|
||||||
@name VARCHAR(32),
|
@name VARCHAR(32),
|
||||||
@image VARCHAR(11),
|
@image VARCHAR(11),
|
||||||
@gameId INT OUTPUT
|
@gameId INT OUTPUT
|
||||||
|
@ -332,7 +332,7 @@ GO
|
||||||
-- REMOVE GAME --
|
-- REMOVE GAME --
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
CREATE PROCEDURE RemoveGame(
|
ALTER PROCEDURE RemoveGame(
|
||||||
@gameId INT
|
@gameId INT
|
||||||
)
|
)
|
||||||
AS
|
AS
|
||||||
|
@ -496,7 +496,7 @@ GO
|
||||||
-- ADD ACHIEVEMENT --
|
-- ADD ACHIEVEMENT --
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
CREATE PROCEDURE AddAchievement(
|
ALTER PROCEDURE AddAchievement(
|
||||||
@gameId INT,
|
@gameId INT,
|
||||||
@name VARCHAR(128),
|
@name VARCHAR(128),
|
||||||
@description VARCHAR(512),
|
@description VARCHAR(512),
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
-----------------------
|
-------------------------
|
||||||
-- SEARCH ACHIEVEMENTS --
|
-- SEARCH ACHIEVEMENTS --
|
||||||
-----------------------
|
-------------------------
|
||||||
|
|
||||||
CREATE PROCEDURE SearchAchievements(
|
ALTER PROCEDURE SearchAchievements(
|
||||||
@searchTerm VARCHAR(32),
|
@searchTerm VARCHAR(32),
|
||||||
@userId INT,
|
@userId INT,
|
||||||
@completed BIT,
|
@completed BIT,
|
||||||
@minCompletion FLOAT,
|
@minCompletion FLOAT,
|
||||||
@maxCompletion FLOAT,
|
@maxCompletion FLOAT,
|
||||||
@minDifficulty FLOAT,
|
@minDifficulty FLOAT,
|
||||||
@maxDifficulty FLOAT,
|
@maxDifficulty FLOAT,
|
||||||
@minQuality FLOAT,
|
@minQuality FLOAT,
|
||||||
@maxQuality FLOAT
|
@maxQuality FLOAT,
|
||||||
|
@orderBy VARCHAR(16),
|
||||||
|
@orderDirection VARCHAR(4)
|
||||||
)
|
)
|
||||||
AS
|
AS
|
||||||
IF @userId IS NULL AND @completed = 1
|
IF @userId IS NULL AND @completed = 1
|
||||||
|
@ -20,41 +22,179 @@ BEGIN
|
||||||
RETURN 1
|
RETURN 1
|
||||||
END
|
END
|
||||||
|
|
||||||
|
IF @completed IS NULL
|
||||||
|
SET @completed = 0
|
||||||
|
|
||||||
IF @searchTerm IS NULL OR @searchTerm = ''
|
IF @searchTerm IS NULL OR @searchTerm = ''
|
||||||
SET @searchTerm = '%'
|
SET @searchTerm = '%'
|
||||||
ELSE
|
ELSE
|
||||||
SET @searchTerm = '%' + @searchTerm + '%'
|
SET @searchTerm = '%' + @searchTerm + '%'
|
||||||
PRINT @searchTerm
|
|
||||||
|
|
||||||
IF NOT @userId IS NULL
|
SELECT TOP 100 Achievement.ID, Game.[Name] AS Game, Achievement.[Name], Completion, Difficulty, Quality
|
||||||
SELECT TOP 100 Game.[Name] AS Game, Achievement.[Name], Completion, Difficulty, Quality
|
FROM Achievement
|
||||||
FROM Achievement
|
JOIN Game ON Game.ID = GameID
|
||||||
JOIN MaxProgress ON AchievementID = Achievement.ID AND UserID = @userId
|
JOIN AchievementCompletion AC ON AC.ID = Achievement.ID
|
||||||
JOIN Game ON Game.ID = GameID
|
JOIN AchievementRatings AR ON AR.ID = Achievement.ID
|
||||||
JOIN AchievementCompletion AC ON AC.ID = Achievement.ID
|
WHERE (Game.[Name] LIKE @searchTerm OR Achievement.[Name] LIKE @searchTerm)
|
||||||
JOIN AchievementRatings AR ON AR.ID = Achievement.ID
|
AND (@completed <> 1 OR Achievement.ID IN (SELECT AchievementID FROM MaxProgress WHERE UserID = @userId AND Progress = Stages))
|
||||||
WHERE (Game.[Name] LIKE @searchTerm OR Achievement.[Name] LIKE @searchTerm)
|
AND (@minCompletion IS NULL OR @minCompletion <= Completion)
|
||||||
AND (@completed <> 1 OR Progress = Stages )
|
AND (@maxCompletion IS NULL OR @maxCompletion >= Completion)
|
||||||
AND (@minCompletion IS NULL OR @minCompletion <= Completion)
|
AND (@minDifficulty IS NULL OR @minDifficulty <= Difficulty)
|
||||||
AND (@maxCompletion IS NULL OR @maxCompletion >= Completion)
|
AND (@maxDifficulty IS NULL OR @maxDifficulty >= Difficulty)
|
||||||
AND (@minDifficulty IS NULL OR @minDifficulty <= Difficulty)
|
AND (@minQuality IS NULL OR @minQuality <= Quality )
|
||||||
AND (@maxDifficulty IS NULL OR @maxDifficulty >= Difficulty)
|
AND (@maxQuality IS NULL OR @maxQuality >= Quality )
|
||||||
AND (@minQuality IS NULL OR @minQuality <= Quality )
|
ORDER BY
|
||||||
AND (@maxQuality IS NULL OR @maxQuality >= Quality )
|
CASE WHEN @orderDirection = 'ASC' AND @orderBy = 'Game' THEN Game.[Name] ELSE NULL END ASC,
|
||||||
ELSE
|
CASE WHEN @orderDirection = 'ASC' AND @orderBy = 'Name' THEN Achievement.[Name] ELSE NULL END ASC,
|
||||||
SELECT TOP 100 Achievement.ID, Game.[Name] AS Game, Achievement.[Name], Completion, Quality, Difficulty
|
CASE WHEN @orderDirection = 'ASC' AND @orderBy = 'Completion' THEN Completion ELSE NULL END ASC,
|
||||||
FROM Achievement
|
CASE WHEN @orderDirection = 'ASC' AND @orderBy = 'Difficulty' THEN Difficulty ELSE NULL END ASC,
|
||||||
JOIN Game ON Game.ID = GameID
|
CASE WHEN @orderDirection = 'ASC' AND @orderBy = 'Quality' THEN Quality ELSE NULL END ASC,
|
||||||
JOIN AchievementCompletion AC ON AC.ID = Achievement.ID
|
CASE WHEN @orderDirection = 'DESC' AND @orderBy = 'Game' THEN Game.[Name] ELSE NULL END DESC,
|
||||||
JOIN AchievementRatings AR ON AR.ID = Achievement.ID
|
CASE WHEN @orderDirection = 'DESC' AND @orderBy = 'Name' THEN Achievement.[Name] ELSE NULL END DESC,
|
||||||
WHERE (Game.[Name] LIKE @searchTerm OR Achievement.[Name] LIKE @searchTerm)
|
CASE WHEN @orderDirection = 'DESC' AND @orderBy = 'Completion' THEN Completion ELSE NULL END DESC,
|
||||||
AND (@minCompletion IS NULL OR @minCompletion <= Completion)
|
CASE WHEN @orderDirection = 'DESC' AND @orderBy = 'Difficulty' THEN Difficulty ELSE NULL END DESC,
|
||||||
AND (@maxCompletion IS NULL OR @maxCompletion >= Completion)
|
CASE WHEN @orderDirection = 'DESC' AND @orderBy = 'Quality' THEN Quality ELSE NULL END DESC
|
||||||
AND (@minDifficulty IS NULL OR @minDifficulty <= Difficulty)
|
|
||||||
AND (@maxDifficulty IS NULL OR @maxDifficulty >= Difficulty)
|
|
||||||
AND (@minQuality IS NULL OR @minQuality <= Quality )
|
|
||||||
AND (@maxQuality IS NULL OR @maxQuality >= Quality )
|
|
||||||
RETURN 0
|
RETURN 0
|
||||||
GO
|
GO
|
||||||
|
|
||||||
EXEC SearchAchievements '', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
|
------------------
|
||||||
|
-- SEARCH USERS --
|
||||||
|
------------------
|
||||||
|
|
||||||
|
ALTER PROCEDURE SearchUsers(
|
||||||
|
@searchTerm VARCHAR(32),
|
||||||
|
@minOwned INT,
|
||||||
|
@maxOwned INT,
|
||||||
|
@minCompleted INT,
|
||||||
|
@maxCompleted INT,
|
||||||
|
@minAvgCompletion INT,
|
||||||
|
@maxAvgCompletion INT,
|
||||||
|
@orderBy VARCHAR(16),
|
||||||
|
@orderDirection VARCHAR(4)
|
||||||
|
)
|
||||||
|
AS
|
||||||
|
|
||||||
|
IF @searchTerm IS NULL OR @searchTerm = ''
|
||||||
|
SET @searchTerm = '%'
|
||||||
|
ELSE
|
||||||
|
SET @searchTerm = '%' + @searchTerm + '%'
|
||||||
|
|
||||||
|
SELECT TOP 100 *
|
||||||
|
FROM (
|
||||||
|
SELECT [User].ID, Username, ISNULL(GameCount, 0) AS GameCount, ISNULL(AchievementCount, 0) AS AchievementCount, AvgCompletion, ISNULL(PerfectGames, 0) AS PerfectGames
|
||||||
|
FROM [User]
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT
|
||||||
|
UserID,
|
||||||
|
COUNT(GameID) AS GameCount,
|
||||||
|
SUM(Completed) AS AchievementCount,
|
||||||
|
AVG((Completed * 100) / Total) AS AvgCompletion,
|
||||||
|
SUM(CASE WHEN Completed = Total THEN 1 ELSE 0 END) AS PerfectGames
|
||||||
|
FROM GameCompletionByUser
|
||||||
|
GROUP BY UserID
|
||||||
|
) AS Completion ON Completion.UserID = [User].ID
|
||||||
|
) AS Results
|
||||||
|
WHERE (Username LIKE @searchTerm)
|
||||||
|
AND (@minOwned IS NULL OR @minOwned <= GameCount )
|
||||||
|
AND (@maxOwned IS NULL OR @maxOwned >= GameCount )
|
||||||
|
AND (@minCompleted IS NULL OR @minCompleted <= AchievementCount)
|
||||||
|
AND (@maxCompleted IS NULL OR @maxCompleted >= AchievementCount)
|
||||||
|
AND (@minAvgCompletion IS NULL OR @minAvgCompletion <= AvgCompletion )
|
||||||
|
AND (@maxAvgCompletion IS NULL OR @maxAvgCompletion >= AvgCompletion )
|
||||||
|
ORDER BY
|
||||||
|
CASE WHEN @orderDirection = 'ASC' AND @orderBy = 'Username' THEN Username ELSE NULL END ASC,
|
||||||
|
CASE WHEN @orderDirection = 'ASC' AND @orderBy = 'GameCount' THEN GameCount ELSE NULL END ASC,
|
||||||
|
CASE WHEN @orderDirection = 'ASC' AND @orderBy = 'AchievementCount' THEN AchievementCount ELSE NULL END ASC,
|
||||||
|
CASE WHEN @orderDirection = 'ASC' AND @orderBy = 'AvgCompletion' THEN AvgCompletion ELSE NULL END ASC,
|
||||||
|
CASE WHEN @orderDirection = 'ASC' AND @orderBy = 'PerfectCount' THEN PerfectGames ELSE NULL END ASC,
|
||||||
|
CASE WHEN @orderDirection = 'DESC' AND @orderBy = 'Username' THEN Username ELSE NULL END DESC,
|
||||||
|
CASE WHEN @orderDirection = 'DESC' AND @orderBy = 'GameCount' THEN GameCount ELSE NULL END DESC,
|
||||||
|
CASE WHEN @orderDirection = 'DESC' AND @orderBy = 'AchievementCount' THEN AchievementCount ELSE NULL END DESC,
|
||||||
|
CASE WHEN @orderDirection = 'DESC' AND @orderBy = 'AvgCompletion' THEN AvgCompletion ELSE NULL END DESC,
|
||||||
|
CASE WHEN @orderDirection = 'DESC' AND @orderBy = 'PerfectCount' THEN PerfectGames ELSE NULL END DESC
|
||||||
|
RETURN 0
|
||||||
|
GO
|
||||||
|
------------------
|
||||||
|
-- SEARCH GAMES --
|
||||||
|
------------------
|
||||||
|
|
||||||
|
ALTER PROCEDURE SearchGames(
|
||||||
|
@searchTerm VARCHAR(32),
|
||||||
|
@userId INT,
|
||||||
|
@owned BIT,
|
||||||
|
@minAvgCompletion INT,
|
||||||
|
@maxAvgCompletion INT,
|
||||||
|
@minNumOwners INT,
|
||||||
|
@maxNumOwners INT,
|
||||||
|
@minNumPerfects INT,
|
||||||
|
@maxNumPerfects INT,
|
||||||
|
@orderBy VARCHAR(16),
|
||||||
|
@orderDirection VARCHAR(4)
|
||||||
|
)
|
||||||
|
AS
|
||||||
|
IF @userId IS NULL AND @owned = 1
|
||||||
|
BEGIN
|
||||||
|
PRINT 'Cannot search for owned games with no user specified'
|
||||||
|
RETURN 1
|
||||||
|
END
|
||||||
|
|
||||||
|
PRINT 'UserID, Owned'
|
||||||
|
PRINT @userId
|
||||||
|
PRINT @owned
|
||||||
|
|
||||||
|
IF @owned IS NULL
|
||||||
|
SET @owned = 0
|
||||||
|
|
||||||
|
IF @searchTerm IS NULL OR @searchTerm = ''
|
||||||
|
SET @searchTerm = '%'
|
||||||
|
ELSE
|
||||||
|
SET @searchTerm = '%' + @searchTerm + '%'
|
||||||
|
|
||||||
|
SELECT TOP 100 *
|
||||||
|
FROM (
|
||||||
|
SELECT
|
||||||
|
Game.ID,
|
||||||
|
[Name],
|
||||||
|
AchievementCount,
|
||||||
|
AvgCompletion,
|
||||||
|
ISNULL(NumOwners, 0) AS NumOwners,
|
||||||
|
ISNULL(NumPerfects, 0) AS NumPerfects
|
||||||
|
FROM Game
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT
|
||||||
|
GameID,
|
||||||
|
Total AS AchievementCount,
|
||||||
|
AVG((Completed * 100) / Total) AS AvgCompletion,
|
||||||
|
SUM(CASE WHEN Completed = Total THEN 1 ELSE 0 END) AS NumPerfects
|
||||||
|
FROM GameCompletionByUser
|
||||||
|
GROUP BY GameID, Total
|
||||||
|
) AS Completion ON Completion.GameID = Game.ID
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT GameID, COUNT(UserID) AS NumOwners
|
||||||
|
FROM OwnsUnique
|
||||||
|
GROUP BY GameID
|
||||||
|
) AS Owners ON Owners.GameID = Game.ID
|
||||||
|
) AS Results
|
||||||
|
WHERE ([Name] LIKE @searchTerm)
|
||||||
|
AND (@owned <> 1 OR ID IN (SELECT GameID FROM OwnsUnique WHERE UserID = @userId))
|
||||||
|
AND (@minAvgCompletion IS NULL OR @minAvgCompletion <= AvgCompletion)
|
||||||
|
AND (@maxAvgCompletion IS NULL OR @maxAvgCompletion >= AvgCompletion)
|
||||||
|
AND (@minNumOwners IS NULL OR @minNumOwners <= NumOwners )
|
||||||
|
AND (@maxNumOwners IS NULL OR @maxNumOwners >= NumOwners )
|
||||||
|
AND (@minNumPerfects IS NULL OR @minNumPerfects <= NumPerfects )
|
||||||
|
AND (@maxNumPerfects IS NULL OR @maxNumPerfects >= NumPerfects )
|
||||||
|
ORDER BY
|
||||||
|
CASE WHEN @orderDirection = 'ASC' AND @orderBy = 'Name' THEN [Name] ELSE NULL END ASC,
|
||||||
|
CASE WHEN @orderDirection = 'ASC' AND @orderBy = 'AchievementCount' THEN AchievementCount ELSE NULL END ASC,
|
||||||
|
CASE WHEN @orderDirection = 'ASC' AND @orderBy = 'AvgCompletion' THEN AvgCompletion ELSE NULL END ASC,
|
||||||
|
CASE WHEN @orderDirection = 'ASC' AND @orderBy = 'NumOwners' THEN NumOwners ELSE NULL END ASC,
|
||||||
|
CASE WHEN @orderDirection = 'ASC' AND @orderBy = 'NumPerfects' THEN NumPerfects ELSE NULL END ASC,
|
||||||
|
CASE WHEN @orderDirection = 'DESC' AND @orderBy = 'Name' THEN [Name] ELSE NULL END DESC,
|
||||||
|
CASE WHEN @orderDirection = 'DESC' AND @orderBy = 'AchievementCount' THEN AchievementCount ELSE NULL END DESC,
|
||||||
|
CASE WHEN @orderDirection = 'DESC' AND @orderBy = 'AvgCompletion' THEN AvgCompletion ELSE NULL END DESC,
|
||||||
|
CASE WHEN @orderDirection = 'DESC' AND @orderBy = 'NumOwners' THEN NumOwners ELSE NULL END DESC,
|
||||||
|
CASE WHEN @orderDirection = 'DESC' AND @orderBy = 'NumPerfects' THEN NumPerfects ELSE NULL END DESC
|
||||||
|
RETURN 0
|
||||||
|
GO
|
||||||
|
|
||||||
|
EXEC SearchGames '', 3, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
|
||||||
|
|
|
@ -33,3 +33,10 @@ AS
|
||||||
GROUP BY Achievement.ID
|
GROUP BY Achievement.ID
|
||||||
GO
|
GO
|
||||||
|
|
||||||
|
-- List of games owned by a user removing duplicate ownership if owned on multiple platforms
|
||||||
|
CREATE VIEW OwnsUnique
|
||||||
|
AS
|
||||||
|
SELECT UserID, GameID
|
||||||
|
FROM Owns
|
||||||
|
GROUP BY UserID, GameID
|
||||||
|
GO
|
||||||
|
|
Loading…
Reference in a new issue