add swagger

This commit is contained in:
Lee 2024-04-10 09:51:31 +01:00
parent d959169f0b
commit 8990a6308a
16 changed files with 63 additions and 13 deletions

21
LICENSE Normal file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024, Fascinated
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -116,6 +116,14 @@
<artifactId>jedis</artifactId>
</dependency>
<!-- SwaggerUI -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.0.2</version>
<scope>compile</scope>
</dependency>
<!-- Unit Tests -->
<dependency>
<groupId>org.junit.jupiter</groupId>

@ -1,6 +1,10 @@
package cc.fascinated;
import com.google.gson.Gson;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Contact;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.annotations.info.License;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import org.springframework.boot.SpringApplication;
@ -12,7 +16,15 @@ import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.Objects;
@SpringBootApplication @Log4j2
@Log4j2
@SpringBootApplication
@OpenAPIDefinition(info = @Info(
title = "Minecraft Utilities API",
version = "1.0",
description = "Wrapper for the Minecraft APIs to make them easier to use.",
contact = @Contact(name = "Liam", email = "liam@fascinated.cc", url = "https://fascinated.cc"),
license = @License(name = "MIT License", url = "https://opensource.org/licenses/MIT")
))
public class Main {
public static final Gson GSON = new Gson();

@ -19,6 +19,7 @@ public class HomeController {
public String home(Model model) {
model.addAttribute("player_example_url", Config.INSTANCE.getWebPublicUrl() + "/player/" + exampleUuid);
model.addAttribute("java_server_example_url", Config.INSTANCE.getWebPublicUrl() + "/server/java/play.hypixel.net");
model.addAttribute("swagger_url", Config.INSTANCE.getWebPublicUrl() + "/swagger-ui.html");
return "index";
}
}

@ -4,6 +4,7 @@ import cc.fascinated.common.PlayerUtils;
import cc.fascinated.model.player.Player;
import cc.fascinated.model.player.Skin;
import cc.fascinated.service.PlayerService;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.CacheControl;
import org.springframework.http.HttpHeaders;
@ -14,6 +15,7 @@ import org.springframework.web.bind.annotation.*;
import java.util.concurrent.TimeUnit;
@RestController
@Tag(name = "Player Controller", description = "The Player Controller is used to get information about a player.")
@RequestMapping(value = "/player/")
public class PlayerController {

@ -3,10 +3,8 @@ package cc.fascinated.controller;
import cc.fascinated.common.ServerUtils;
import cc.fascinated.common.Tuple;
import cc.fascinated.model.cache.CachedMinecraftServer;
import cc.fascinated.model.server.JavaMinecraftServer;
import cc.fascinated.model.server.MinecraftServer;
import cc.fascinated.service.ServerService;
import cc.fascinated.service.pinger.impl.JavaMinecraftServerPinger;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
@ -14,6 +12,7 @@ import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@Tag(name = "Server Controller", description = "The Server Controller is used to get information about a server.")
@RequestMapping(value = "/server/")
public class ServerController {

@ -1,6 +1,5 @@
package cc.fascinated.model.cache;
import cc.fascinated.model.mojang.MojangProfile;
import cc.fascinated.model.player.Cape;
import cc.fascinated.model.player.Player;
import cc.fascinated.model.player.Skin;

@ -3,7 +3,6 @@ package cc.fascinated.model.player;
import cc.fascinated.common.Tuple;
import cc.fascinated.common.UUIDUtils;
import cc.fascinated.model.mojang.MojangProfile;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.data.annotation.Id;

@ -11,7 +11,6 @@ import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;

@ -1,11 +1,8 @@
package cc.fascinated.repository;
import cc.fascinated.model.cache.CachedPlayer;
import cc.fascinated.model.cache.CachedPlayerName;
import org.springframework.data.repository.CrudRepository;
import java.util.UUID;
/**
* A cache repository for player usernames.
* <p>

@ -44,6 +44,7 @@ public class PlayerService {
*/
public CachedPlayer getPlayer(String id) {
id = id.toUpperCase(); // Convert the id to uppercase to prevent case sensitivity
log.info("Getting player: {}", id);
UUID uuid = PlayerUtils.getUuidFromString(id);
if (uuid == null) { // If the id is not a valid uuid, get the uuid from the username
uuid = usernameToUuid(id);
@ -51,11 +52,14 @@ public class PlayerService {
Optional<CachedPlayer> cachedPlayer = playerCacheRepository.findById(uuid);
if (cachedPlayer.isPresent()) { // Return the cached player if it exists
log.info("Player {} is cached", id);
return cachedPlayer.get();
}
try {
log.info("Getting player profile from Mojang: {}", id);
MojangProfile mojangProfile = mojangAPIService.getProfile(uuid.toString()); // Get the player profile from Mojang
log.info("Got player profile from Mojang: {}", id);
Tuple<Skin, Cape> skinAndCape = mojangProfile.getSkinAndCape();
CachedPlayer player = new CachedPlayer(
uuid, // Player UUID
@ -80,6 +84,7 @@ public class PlayerService {
* @return the uuid of the player
*/
private UUID usernameToUuid(String username) {
log.info("Getting UUID from username: {}", username);
Optional<CachedPlayerName> cachedPlayerName = playerNameCacheRepository.findById(username);
if (cachedPlayerName.isPresent()) {
return cachedPlayerName.get().getUniqueId();
@ -87,10 +92,12 @@ public class PlayerService {
try {
MojangUsernameToUuid mojangUsernameToUuid = mojangAPIService.getUuidFromUsername(username);
if (mojangUsernameToUuid == null) {
log.info("Player with username '{}' not found", username);
throw new ResourceNotFoundException("Player with username '%s' not found".formatted(username));
}
UUID uuid = UUIDUtils.addDashes(mojangUsernameToUuid.getId());
playerNameCacheRepository.save(new CachedPlayerName(username, uuid));
log.info("Got UUID from username: {} -> {}", username, uuid);
return uuid;
} catch (RateLimitException exception) {
throw new MojangAPIRateLimitException();

@ -1,7 +1,7 @@
package cc.fascinated.service;
import cc.fascinated.common.EnumUtils;
import cc.fascinated.common.DNSUtils;
import cc.fascinated.common.EnumUtils;
import cc.fascinated.exception.impl.BadRequestException;
import cc.fascinated.exception.impl.ResourceNotFoundException;
import cc.fascinated.model.cache.CachedMinecraftServer;

@ -1,6 +1,8 @@
server:
address: 0.0.0.0
port: 80
servlet:
context-path: /
error:
whitelabel:
enabled: false

@ -21,7 +21,8 @@
<div class="flex flex-col mt-3">
<p>Player Data: <a class="text-blue-600" target=”_blank” th:href="${player_example_url}" th:text="${player_example_url}">???</a></p>
<p>Java Server: <a class="text-blue-600" target=”_blank” th:href="${java_server_example_url}" th:text="${java_server_example_url}">???</a></p>
<p>Player Data: <a class="text-blue-600" target=”_blank” th:href="${java_server_example_url}" th:text="${java_server_example_url}">???</a></p>
<p>Swagger Docs: <a class="text-blue-600" target=”_blank” th:href="${swagger_url}" th:text="${swagger_url}">???</a></p>
</div>
</body>
</html>

@ -1,6 +1,8 @@
server:
address: 0.0.0.0
port: 80
servlet:
context-path: /
error:
whitelabel:
enabled: false

@ -21,7 +21,8 @@
<div class="flex flex-col mt-3">
<p>Player Data: <a class="text-blue-600" target=”_blank” th:href="${player_example_url}" th:text="${player_example_url}">???</a></p>
<p>Java Server: <a class="text-blue-600" target=”_blank” th:href="${java_server_example_url}" th:text="${java_server_example_url}">???</a></p>
<p>Player Data: <a class="text-blue-600" target=”_blank” th:href="${java_server_example_url}" th:text="${java_server_example_url}">???</a></p>
<p>Swagger Docs: <a class="text-blue-600" target=”_blank” th:href="${swagger_url}" th:text="${swagger_url}">???</a></p>
</div>
</body>
</html>