Revision control

Copy as Markdown

/*
* OpenAPI Petstore
*
* This is a sample of Petstore application. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
import (
"github.com/gin-gonic/gin"
"encoding/base64"
"fmt"
"io"
"net/http"
"net/url"
"os"
"slices"
"strconv"
"strings"
)
type PetAPI struct {
Pets map[int64]Pet
}
func (api *PetAPI) InitializePetsMap() {
if api.Pets == nil {
api.Pets = make(map[int64]Pet)
}
}
// Post /v2/pet
// Add a new pet to the store
func (api *PetAPI) AddPet(c *gin.Context) {
api.InitializePetsMap()
// first check the authorization headers
authHeader := c.GetHeader("authorization")
b64encoded, ok := strings.CutPrefix(authHeader, "Basic ")
if !ok {
c.JSON(http.StatusUnauthorized, gin.H{"error": "No authorization header"})
return
}
data, err := base64.StdEncoding.DecodeString(b64encoded)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Failed to decode authorization header"})
return
}
decodedStr := string(data)
nameAndPassword := strings.Split(decodedStr, ":")
if len(nameAndPassword) != 2 || nameAndPassword[0] != "User1" || nameAndPassword[1] != "1234" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Incorrect credentials"})
return
}
var requestPet Pet
if err := c.ShouldBindJSON(&requestPet); err != nil {
fmt.Println("AddPet: failed to parse pet", err)
c.JSON(http.StatusMethodNotAllowed, gin.H{"error": err.Error()})
return
}
api.Pets[requestPet.Id] = requestPet
c.JSON(http.StatusOK, requestPet)
}
// Delete /v2/pet/:petId
// Deletes a pet
func (api *PetAPI) DeletePet(c *gin.Context) {
api.InitializePetsMap()
// This test also checks authorization
// apiKeyHeader := c.GetHeader("api-key") // unused in the test!
authHeader := c.GetHeader("authorization")
if authHeader != "Bearer BEARER-TOKEN" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Incorrect bearer token"})
return
}
idStr := c.Param("petId")
petId, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to parse pet id"})
return
}
delete(api.Pets, petId)
c.JSON(http.StatusOK, gin.H{"status": "OK"})
}
// Get /v2/pet/findPetsByAgeAndPatience/:petData
// get a pet by age and patience
func (api *PetAPI) FindPetsByAgeAndPatience(c *gin.Context) {
api.InitializePetsMap()
dataStr := c.Param("petData")
// dataStr has the following format:
// "100,9,33,0"
// Here, the first value is age, the second is patience, and so on.
dataArr := strings.Split(dataStr, ",")
total := len(dataArr)
if total % 2 != 0 {
c.JSON(http.StatusBadRequest, gin.H{"error": "Incorrect parameter format"})
return
}
var pets []Pet
for i := 0; i < total; i = i + 2 {
val, _ := strconv.ParseInt(dataArr[i], 10, 32)
age := int32(val)
val, _ = strconv.ParseInt(dataArr[i + 1], 10, 32)
patience := int32(val)
for _, pet := range api.Pets {
if pet.Age == age && pet.Patience == patience {
pets = append(pets, pet)
}
}
}
c.JSON(http.StatusOK, pets)
}
// Get /v2/pet/findByStatus
// Finds Pets by status
func (api *PetAPI) FindPetsByStatus(c *gin.Context) {
api.InitializePetsMap()
m, err := url.ParseQuery(c.Request.URL.RawQuery)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "failed to parse query"})
return
}
// The map contains desired statuses, e.g.
// map[status:[available,sold]]
// Note that "available,sold" is a single entry, we need to manually split it
s, ok := m["status"]
if !ok {
c.JSON(http.StatusBadRequest, gin.H{"error": "no statuses provided"})
return
}
statuses := strings.Split(s[0], ",")
var foundPets []Pet
for _, pet := range api.Pets {
if slices.Contains(statuses, string(pet.Status)) {
foundPets = append(foundPets, pet)
}
}
c.JSON(http.StatusOK, foundPets)
}
// Get /v2/pet/findByTags
// Finds Pets by tags
// Deprecated
func (api *PetAPI) FindPetsByTags(c *gin.Context) {
// Apparently not tested...
c.JSON(http.StatusOK, gin.H{"status": "OK"})
}
// Get /v2/pet/findPetsImageById
// get a pet png image
func (api *PetAPI) FindPetsImageById(c *gin.Context) {
api.InitializePetsMap()
m, err := url.ParseQuery(c.Request.URL.RawQuery)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "failed to parse query"})
return
}
ids, ok := m["petId"]
if !ok {
c.JSON(http.StatusBadRequest, gin.H{"error": "no petId parameter"})
return
}
petId, err := strconv.ParseInt(ids[0], 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "failed to parse petId"})
return
}
_, ok = api.Pets[petId]
if !ok {
c.JSON(http.StatusNotFound, gin.H{"error": "pet not found"})
return
}
bytes, _ := os.ReadFile("./qt-logo.png")
b64encoded := base64.StdEncoding.EncodeToString(bytes)
c.Header("Content-Type", "img/png")
c.String(http.StatusOK, b64encoded)
}
// Get /v2/pet/:petId/uploadImage
// get a pet json information file
func (api *PetAPI) GetJsonFile(c *gin.Context) {
api.InitializePetsMap()
idStr := c.Param("petId")
petId, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to parse pet id"})
return
}
_, ok := api.Pets[petId]
if !ok {
c.JSON(http.StatusNotFound, gin.H{"error": "pet not found"})
return
}
// We could use FileAttachement(), but it adds extra quotes for the filename
c.Header("Content-Disposition", "attachment; filename=response.json")
c.Header("Content-Type", "application/octet-stream")
c.File("./response.json")
c.Status(http.StatusOK)
}
// Get /v2/pet/:petId
// Find pet by ID
func (api *PetAPI) GetPetById(c *gin.Context) {
api.InitializePetsMap()
idStr := c.Param("petId")
petId, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to parse pet id"})
return
}
pet, ok := api.Pets[petId]
if !ok {
c.JSON(http.StatusNotFound, gin.H{"error": "pet not found"})
return
}
c.JSON(http.StatusOK, pet)
}
// Put /v2/pet
// Update an existing pet
func (api *PetAPI) UpdatePet(c *gin.Context) {
api.InitializePetsMap()
var requestPet Pet
if err := c.ShouldBindJSON(&requestPet); err != nil {
fmt.Println("UpdatePet: failed to parse pet", err)
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// The C++ server didn't check if the pet exists or not, so we
// won't either
api.Pets[requestPet.Id] = requestPet
c.JSON(http.StatusOK, requestPet)
}
// Post /v2/pet/:petId
// Updates a pet in the store with form data
func (api *PetAPI) UpdatePetWithForm(c *gin.Context) {
api.InitializePetsMap()
idStr := c.Param("petId")
petId, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to parse pet id"})
return
}
pet, ok := api.Pets[petId]
if !ok {
c.JSON(http.StatusNotFound, gin.H{"error": "pet not found"})
return
}
// Both name and status are optional parameters!
newName, ok := c.GetPostForm("name")
if ok {
pet.Name = newName
}
newStatus, ok := c.GetPostForm("status")
if ok {
pet.Status = PetStatus(newStatus)
}
api.Pets[petId] = pet
c.JSON(http.StatusOK, gin.H{"status": "OK"})
}
// Post /v2/pet/:petId/uploadImage
// uploads an image
func (api *PetAPI) UploadFile(c *gin.Context) {
api.InitializePetsMap()
idStr := c.Param("petId")
petId, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to parse pet id"})
return
}
_, ok := api.Pets[petId]
if !ok {
c.JSON(http.StatusNotFound, gin.H{"error": "pet not found"})
return
}
// The C++ server returns a default-constructed ApiResponse object,
// but we'd like to do better.
// So, write the additionalMetadata into the response.Type string,
// and the contents of the file into response.Message string.
var response ApiResponse
// both additional metadata and file are optional
form, err := c.MultipartForm()
metadata, ok := form.Value["additionalMetadata"]
if ok {
response.Type = metadata[0]
}
fileHdrs, ok := form.File["file"]
if ok {
fileHdr := fileHdrs[0]
file, err := fileHdr.Open()
if err == nil {
bytes := make([]byte, fileHdr.Size)
_, err := file.Read(bytes)
if err == nil || err == io.EOF {
response.Message = string(bytes)
}
}
}
response.Code = 0
c.JSON(http.StatusOK, response)
}