forked from Deuxfleurs/guichet
217 lines
5 KiB
Go
217 lines
5 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"strconv"
|
|
|
|
"image"
|
|
"image/jpeg"
|
|
_ "image/png"
|
|
|
|
"mime/multipart"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/go-ldap/ldap/v3"
|
|
"github.com/google/uuid"
|
|
"github.com/gorilla/mux"
|
|
"github.com/minio/minio-go/v7"
|
|
"github.com/minio/minio-go/v7/pkg/credentials"
|
|
"github.com/nfnt/resize"
|
|
)
|
|
|
|
const PROFILE_PICTURE_FIELD_NAME = "profilePicture"
|
|
|
|
//Upload image through guichet server.
|
|
func uploadImage(w http.ResponseWriter, r *http.Request, login *LoginStatus) (string, error) {
|
|
file, _, err := r.FormFile("image")
|
|
|
|
if err == http.ErrMissingFile {
|
|
return "", nil
|
|
}
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer file.Close()
|
|
err = checkImage(file)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
buff := bytes.NewBuffer([]byte{})
|
|
buff_thumbnail := bytes.NewBuffer([]byte{})
|
|
err = resizeThumb(file, buff, buff_thumbnail)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
mc, err := newMinioClient()
|
|
if err != nil || mc == nil {
|
|
return "", err
|
|
}
|
|
|
|
var name, nameFull string
|
|
|
|
if nameConsul := login.UserEntry.GetAttributeValue(PROFILE_PICTURE_FIELD_NAME); nameConsul != "" {
|
|
name = nameConsul
|
|
nameFull = "full_" + name
|
|
} else {
|
|
name = uuid.New().String() + ".jpeg"
|
|
nameFull = "full_" + name
|
|
}
|
|
|
|
_, err = mc.PutObject(context.Background(), config.S3_Bucket, name, buff_thumbnail, int64(buff_thumbnail.Len()), minio.PutObjectOptions{
|
|
ContentType: "image/jpeg",
|
|
})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
_, err = mc.PutObject(context.Background(), config.S3_Bucket, nameFull, buff, int64(buff.Len()), minio.PutObjectOptions{
|
|
ContentType: "image/jpeg",
|
|
})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return name, nil
|
|
}
|
|
|
|
func newMinioClient() (*minio.Client, error) {
|
|
endpoint := config.S3_Endpoint
|
|
accessKeyID := config.S3_AccesKey
|
|
secretKeyID := config.S3_SecretKey
|
|
useSSL := true
|
|
|
|
//Initialize Minio
|
|
minioCLient, err := minio.New(endpoint, &minio.Options{
|
|
Creds: credentials.NewStaticV4(accessKeyID, secretKeyID, ""),
|
|
Secure: useSSL,
|
|
Region: config.S3_Region,
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return minioCLient, nil
|
|
|
|
}
|
|
|
|
func checkImage(file multipart.File) error {
|
|
buff := make([]byte, 512) //Detect read only the first 512 bytes
|
|
_, err := file.Read(buff)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
file.Seek(0, 0)
|
|
|
|
fileType := http.DetectContentType(buff)
|
|
fileType = strings.Split(fileType, "/")[0]
|
|
switch fileType {
|
|
case "image":
|
|
return nil
|
|
default:
|
|
return errors.New("bad type")
|
|
}
|
|
|
|
}
|
|
|
|
func resizeThumb(file multipart.File, buff, buff_thumbnail *bytes.Buffer) error {
|
|
file.Seek(0, 0)
|
|
images, _, err := image.Decode(file)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
buff.Reset()
|
|
images = resize.Thumbnail(200, 200, images, resize.Lanczos3)
|
|
images_thumbnail := resize.Thumbnail(80, 80, images, resize.Lanczos3)
|
|
|
|
err = jpeg.Encode(buff, images, &jpeg.Options{
|
|
Quality: 95,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = jpeg.Encode(buff_thumbnail, images_thumbnail, &jpeg.Options{
|
|
Quality: 95,
|
|
})
|
|
|
|
return err
|
|
}
|
|
|
|
func handleDownloadImage(w http.ResponseWriter, r *http.Request) {
|
|
//Get input value by user
|
|
dn := mux.Vars(r)["name"]
|
|
size := mux.Vars(r)["size"]
|
|
//Check login
|
|
login := checkLogin(w, r)
|
|
if login == nil {
|
|
return
|
|
}
|
|
var imageName string
|
|
if dn != "unknown_profile" {
|
|
//Search values with ldap and filter
|
|
|
|
searchRequest := ldap.NewSearchRequest(
|
|
dn,
|
|
ldap.ScopeBaseObject, ldap.NeverDerefAliases, 0, 0, false,
|
|
"(objectclass=*)",
|
|
[]string{PROFILE_PICTURE_FIELD_NAME},
|
|
nil)
|
|
|
|
sr, err := login.conn.Search(searchRequest)
|
|
if err != nil {
|
|
http.Error(w, "Search: "+err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
if len(sr.Entries) != 1 {
|
|
http.Error(w, fmt.Sprintf("Not found user: %s cn: %s and numberEntries: %d", dn, strings.Split(dn, ",")[0], len(sr.Entries)), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
imageName = sr.Entries[0].GetAttributeValue(PROFILE_PICTURE_FIELD_NAME)
|
|
if imageName == "" {
|
|
http.Error(w, "User doesn't have profile image", http.StatusNotFound)
|
|
return
|
|
}
|
|
} else {
|
|
imageName = "unknown_profile.jpg"
|
|
}
|
|
|
|
if size == "full" {
|
|
imageName = "full_" + imageName
|
|
}
|
|
//Get the object after connect MC
|
|
mc, err := newMinioClient()
|
|
if err != nil {
|
|
http.Error(w, "MinioClient: "+err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
obj, err := mc.GetObject(context.Background(), "bottin-pictures", imageName, minio.GetObjectOptions{})
|
|
if err != nil {
|
|
http.Error(w, "MinioClient: GetObject: "+err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
defer obj.Close()
|
|
objStat, err := obj.Stat()
|
|
if err != nil {
|
|
http.Error(w, "MiniObjet: "+err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
//Send JSON through xhttp
|
|
w.Header().Set("Content-Type", objStat.ContentType)
|
|
w.Header().Set("Content-Length", strconv.Itoa(int(objStat.Size)))
|
|
//Copy obj in w
|
|
writting, err := io.Copy(w, obj)
|
|
if writting != objStat.Size || err != nil {
|
|
http.Error(w, fmt.Sprintf("WriteBody: %s, bytes wrote %d on %d", err.Error(), writting, objStat.Size), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
}
|