Files
kotapi-go/routes/routes.go
T

249 lines
7.4 KiB
Go
Raw Normal View History

2021-03-16 22:04:12 +02:00
package routes
import (
"bytes"
"fmt"
"illusionman1212/kotapi-go/db"
"illusionman1212/kotapi-go/models"
"image/jpeg"
"image/png"
"log"
2021-03-16 22:04:12 +02:00
"math/rand"
"net/http"
"os"
"strconv"
"strings"
"time"
"github.com/edwvee/exiffix"
"github.com/gorilla/mux"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
)
func RandomHandler(w http.ResponseWriter, req *http.Request) {
var kot models.Kot
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Methods", "GET")
max, err := db.Kots.EstimatedDocumentCount(db.Ctx)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(`{ "error": "An error has occurred while querying the database", "status": 500, "failed": true }`))
return
}
// ids start from 1
min := 1
2021-03-16 22:04:12 +02:00
// seed the default source using the current time in unix nanosecond format
rand.Seed(time.Now().UnixNano())
2021-08-18 18:24:14 +03:00
// generate random number between min and max [min, max]
num := rand.Intn(int(max+1)-min) + min
2021-03-16 22:04:12 +02:00
// find the random kot document and store it in the `kot` variable
err = db.Kots.FindOne(db.Ctx, bson.M{"id": num}).Decode(&kot)
if err != nil {
if err == mongo.ErrNoDocuments {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(`{ "error": "Not found","status": 404, "failed": true }`))
} else {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(`{ "error": "An unknown error has occurred","status": 500, "failed": true }`))
}
return
}
// create a json from the kot struct variable and then write it as a response
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{
"id": "` + strconv.Itoa(int(kot.MyID)) + `",
"url": "` + kot.Url + `",
"compressed_url": "` + kot.CompressedUrl + `",
"status": 200,
"failed": false
}`))
}
func IdHandler(w http.ResponseWriter, req *http.Request) {
params := mux.Vars(req)
var kot models.Kot
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Methods", "GET")
id, err := strconv.Atoi(params["id"])
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(`{ "error": "Invalid or incomplete request","status": 400, "failed": true }`))
return
}
err = db.Kots.FindOne(db.Ctx, bson.M{"id": id}).Decode(&kot)
if err != nil {
if err == mongo.ErrNoDocuments {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(`{ "error": "Not found","status": 404, "failed": true }`))
} else {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(`{ "error": "An unknown error has occurred","status": 500, "failed": true }`))
}
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{
"id": "` + strconv.Itoa(int(kot.MyID)) + `",
"url": "` + kot.Url + `",
"compressed_url": "` + kot.CompressedUrl + `",
"status": 200,
"failed": false
}`))
}
func AddKotHandler(w http.ResponseWriter, req *http.Request) {
var kot models.Kot
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Methods", "POST")
// 10 MB file size limit
req.ParseMultipartForm(10 << 20)
file, handler, err := req.FormFile("image")
if err != nil {
log.Print("no image was uploaded")
2021-03-16 22:04:12 +02:00
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(`{ "error": "Invalid or incomplete request","status": 400, "failed": true }`))
return
}
password := req.Form.Get("password")
if password == "" {
log.Print("no password was sent")
2021-03-16 22:04:12 +02:00
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(`{ "error": "Invalid or incomplete request","status": 400, "failed": true }`))
return
}
if password != os.Getenv("PASSWORD") {
log.Print("password is incorrect")
2021-03-16 22:04:12 +02:00
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(`{ "error": "Not authorized","status": 401, "failed": true }`))
return
}
filename := make([]byte, 16)
rand.Seed(time.Now().UnixNano())
_, err = rand.Read(filename)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(`{ "error": "An unknown error has occurred","status": 500, "failed": true }`))
return
}
extensions := strings.Split(handler.Filename, ".")
extension := strings.ToLower(extensions[len(extensions)-1])
defer file.Close()
data := make([]byte, handler.Size)
file.Read(data)
compressedData := data
if extension == "png" {
enc := &png.Encoder{
CompressionLevel: png.BestCompression,
}
buf := &bytes.Buffer{}
decodedImage, err := png.Decode(bytes.NewReader(data))
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(`{ "error": "An error occurred while compressing the image","status": 500, "failed": true }`))
return
}
enc.Encode(buf, decodedImage)
compressedData = buf.Bytes()
} else if extension == "jpeg" || extension == "jpg" {
decodedImage, _, err := exiffix.Decode(bytes.NewReader(data))
buf := &bytes.Buffer{}
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(`{ "error": "An error occurred while compressed the image","status": 500, "failed": true }`))
return
}
jpeg.Encode(buf, decodedImage, &jpeg.Options{Quality: 75})
compressedData = buf.Bytes()
}
os.Mkdir("./kots", 0755)
os.Mkdir("./kots/compressed", 0755)
newFile, err := os.Create(fmt.Sprintf("./kots/%x.%s", filename, extension))
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(`{ "error": "An error occurred while writing the file","status": 500, "failed": true }`))
return
}
defer newFile.Close()
newFile.Write(data)
compressedNewFile, err := os.Create(fmt.Sprintf("./kots/compressed/%x.%s", filename, extension))
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(`{ "error": "An error occurred while writing compressed file","status": 500, "failed": true }`))
return
}
defer compressedNewFile.Close()
compressedNewFile.Write(compressedData)
count, err := db.Kots.EstimatedDocumentCount(db.Ctx)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(`{ "error": "An unknown error has occurred","status": 500, "failed": true }`))
return
}
kot.ID = primitive.NewObjectIDFromTimestamp(time.Now())
kot.MyID = int32(count + 1)
kot.Url = fmt.Sprintf("%s/kots/%x.%s", os.Getenv("BASE_URL"), filename, extension)
kot.CompressedUrl = fmt.Sprintf("%s/kots/compressed/%x.%s", os.Getenv("BASE_URL"), filename, extension)
_, err = db.Kots.InsertOne(db.Ctx, kot)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(`{ "error": "An unknown error has occurred","status": 500, "failed": true }`))
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{ "message": "Successfully welcomed a new kot :)" "status": 200, "failed": false }`))
}
func KotsHandler(w http.ResponseWriter, req *http.Request) {
filename := mux.Vars(req)
filepath := fmt.Sprintf("./kots/%s", filename["filename"])
_, err := os.Stat(filepath)
if err != nil {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(`{ "error": "Not found","status": 404, "failed": true }`))
return
}
http.ServeFile(w, req, filepath)
}
func KotsCompressedHandler(w http.ResponseWriter, req *http.Request) {
filename := mux.Vars(req)
filepath := fmt.Sprintf("./kots/compressed/%s", filename["filename"])
_, err := os.Stat(filepath)
if err != nil {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(`{ "error": "Not found","status": 404, "failed": true }`))
return
}
http.ServeFile(w, req, filepath)
}