aboutsummaryrefslogblamecommitdiff
path: root/mimioClient.go
blob: a3cfdfcd649e25af00fe7a47492044ae11443b10 (plain) (tree)



















































































































































































































































                                                                                                                                                                                     
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"
)

//Upload image through guichet server.
func uploadImage(w http.ResponseWriter, r *http.Request, login *LoginStatus) (bool, string, error) {
	file, _, err := r.FormFile("image")

	if err == http.ErrMissingFile {
		return false, "", nil
	}
	if err != nil {
		return false, "", err
	}
	defer file.Close()
	fileType, err := checkImage(file)
	if err != nil {
		return false, "", err
	}
	if fileType == "" {
		return false, "", nil
	}

	buff := bytes.NewBuffer([]byte{})
	buff_thumbnail := bytes.NewBuffer([]byte{})
	err = resizeThumb(file, buff, buff_thumbnail)
	if err != nil {
		return false, "", err
	}

	mc, err := newMimioClient()
	if err != nil {
		return false, "", err
	}
	if mc == nil {
		return false, "", err
	}

	var name, nameFull string

	if nameConsul := login.UserEntry.GetAttributeValue("profilImage"); nameConsul != "" {
		name = nameConsul
		nameFull = "full_" + name
	} else {
		name = uuid.New().String() + ".jpeg"
		nameFull = "full_" + name
	}

	_, err = mc.PutObject(context.Background(), "bottin-pictures", name, buff_thumbnail, int64(buff_thumbnail.Len()), minio.PutObjectOptions{
		ContentType: "image/jpeg",
	})
	if err != nil {
		return false, "", err
	}

	_, err = mc.PutObject(context.Background(), "bottin-pictures", nameFull, buff, int64(buff.Len()), minio.PutObjectOptions{
		ContentType: "image/jpeg",
	})
	if err != nil {
		return false, "", err
	}

	return true, name, nil
}

func newMimioClient() (*minio.Client, error) {
	endpoint := config.Endpoint
	accessKeyID := config.AccesKey
	secretKeyID := config.SecretKey
	useSSL := true

	//Initialize Minio
	minioCLient, err := minio.New(endpoint, &minio.Options{
		Creds:  credentials.NewStaticV4(accessKeyID, secretKeyID, ""),
		Secure: useSSL,
		Region: "garage",
	})

	if err != nil {
		return nil, err
	}

	return minioCLient, nil

}

func checkImage(file multipart.File) (string, 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 fileType, 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 errors.New("Decode: " + err.Error())
	}
	//Encode image to jpeg a first time to eliminate all problems
	err = jpeg.Encode(buff, images, &jpeg.Options{
		Quality: 100, //Between 1 to 100, higher is better
	})
	if err != nil {
		return err
	}
	images, _, err = image.Decode(buff)
	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{"profilImage"},
			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("profilImage")
		if imageName == "" {
			http.Error(w, "User doesn't have profile image", http.StatusInternalServerError)
			return
		}
	} else {
		imageName = "unknown_profile.jpg"
	}

	if size == "full" {
		imageName = "full_" + imageName
	}

	//Get the object after connect MC
	mc, err := newMimioClient()
	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, "MinioObjet: "+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)))
	//http.Error(w, fmt.Sprintf("Length buffer: %d", objStat.Size), http.StatusInternalServerError)
	buff := make([]byte, objStat.Size)

	obj.Seek(0, 0)
	n, err := obj.Read(buff)
	if err != nil && err != io.EOF {
		http.Error(w, fmt.Sprintf("Read Error: %s, bytes Read: %d, bytes in file: %d", err.Error(), n, objStat.Size), http.StatusInternalServerError)
		return
	}
	if int64(n) != objStat.Size {
		http.Error(w, fmt.Sprintf("Read %d bytes on %d bytes", n, objStat.Size), http.StatusInternalServerError)
		return
	}

	if _, err := w.Write(buff); err != nil {
		http.Error(w, "WriteBody: "+err.Error(), http.StatusInternalServerError)
		return
	}
}