Add_Directory_and_ProfilePicture #9

Merged
lx merged 13 commits from Add_Directory into main 2021-08-16 14:44:53 +00:00
11 changed files with 350 additions and 17 deletions
Showing only changes of commit a2a484daba - Show all commits

View file

@ -47,11 +47,6 @@ func handleSearch(w http.ResponseWriter, r *http.Request) {
return
}
/**session, err := store.Get(r, SESSION_NAME)
if err != nil {
return
}**/
//Search values with ldap and filter
searchRequest := ldap.NewSearchRequest(
config.UserBaseDN,

6
go.mod
View file

@ -7,8 +7,12 @@ require (
github.com/emersion/go-smtp v0.12.1
github.com/go-ldap/ldap v3.0.3+incompatible
github.com/go-ldap/ldap/v3 v3.1.6
github.com/google/uuid v1.1.1
github.com/gorilla/mux v1.7.3
github.com/gorilla/sessions v1.2.0
github.com/sirupsen/logrus v1.4.2
github.com/minio/minio-go/v7 v7.0.0
github.com/sirupsen/logrus v1.6.0
github.com/stretchr/objx v0.1.1 // indirect
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
)

43
go.sum
View file

@ -1,4 +1,6 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/emersion/go-sasl v0.0.0-20190817083125-240c8404624e/go.mod h1:G/dpzLu16WtQpBfQ/z3LYiYJn3ZhKSGWn83fyoyQe/k=
github.com/emersion/go-sasl v0.0.0-20191210011802-430746ea8b9b h1:uhWtEWBHgop1rqEk2klKaxPAkVDCXexai6hSuRQ7Nvs=
github.com/emersion/go-sasl v0.0.0-20191210011802-430746ea8b9b/go.mod h1:G/dpzLu16WtQpBfQ/z3LYiYJn3ZhKSGWn83fyoyQe/k=
@ -10,25 +12,66 @@ github.com/go-ldap/ldap v3.0.3+incompatible h1:HTeSZO8hWMS1Rgb2Ziku6b8a7qRIZZMHj
github.com/go-ldap/ldap v3.0.3+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
github.com/go-ldap/ldap/v3 v3.1.6 h1:VTihvB7egSAvU6KOagaiA/EvgJMR2jsjRAVIho2ydBo=
github.com/go-ldap/ldap/v3 v3.1.6/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ=
github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/klauspost/cpuid v1.2.3 h1:CCtW0xUnWGVINKvE/WWOYKdsPV6mawAtvQuSl8guwQs=
github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/minio/md5-simd v1.1.0 h1:QPfiOqlZH+Cj9teu0t9b1nTBfPbyTl16Of5MeuShdK4=
github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
github.com/minio/minio-go/v7 v7.0.0 h1:99hRCmsmMi+hKK93C26iPnRQebTsdK8GEx8Xb4XLr7I=
github.com/minio/minio-go/v7 v7.0.0/go.mod h1:dJ80Mv2HeGkYLH1sqS/ksz07ON6csH3S6JUMSQ2zAns=
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6 h1:Sy5bstxEqwwbYs6n0/pBuxKENqOeZUgD45Gp3Q3pqLg=
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww=
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=

View file

@ -43,6 +43,10 @@ type ConfigFile struct {
AdminAccount string `json:"admin_account"`
GroupCanInvite string `json:"group_can_invite"`
GroupCanAdmin string `json:"group_can_admin"`
Endpoint string `json:"endpoint"`
erwan marked this conversation as resolved Outdated
Outdated
Review

Endpoint de quoi? Il faudrait appeller ça S3Endpoint pour être clair, et les autres les appeller S3AccessKey et S3SecretKey.

Endpoint de quoi? Il faudrait appeller ça `S3Endpoint` pour être clair, et les autres les appeller `S3AccessKey` et `S3SecretKey`.
AccesKey string `json:"acces_key"`
SecretKey string `json:"secret_key"`
}
var configFlag = flag.String("config", "./config.json", "Configuration file path")
@ -133,6 +137,8 @@ func main() {
r.HandleFunc("/profile", handleProfile)
r.HandleFunc("/passwd", handlePasswd)
r.HandleFunc("/image/{name}/{size}", handleDownloadImage)
r.HandleFunc("/directory", handleDirectory)
r.HandleFunc("/search/{input}", handleSearch)
@ -244,7 +250,7 @@ func checkLogin(w http.ResponseWriter, r *http.Request) *LoginStatus {
login_info.DN,
ldap.ScopeBaseObject, ldap.NeverDerefAliases, 0, 0, false,
requestKind,
[]string{"dn", "displayname", "givenname", "sn", "mail", "memberof", "visibility", "description"},
[]string{"dn", "displayname", "givenname", "sn", "mail", "memberof", "visibility", "description", "profilImage"},
erwan marked this conversation as resolved Outdated
Outdated
Review

pas de français ! appller ça profilePicture et non profilImage

pas de français ! appller ça `profilePicture` et non `profilImage`
nil)
sr, err := l.Search(searchRequest)

244
mimioClient.go Normal file
View file

@ -0,0 +1,244 @@
package main
erwan marked this conversation as resolved Outdated
Outdated
Review

il faudrait renommer ce fichier, moi je l'appellerais juste s3.go

il faudrait renommer ce fichier, moi je l'appellerais juste `s3.go`
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) {
erwan marked this conversation as resolved Outdated
Outdated
Review

Pourquoi on renvoie un bool, un string et une error ? je pense qu'on peut enlever le bool, ça complexifie trop et on se perd, et utiliser la sémantique suivante pour (string, error):

  • ("", nil): aucun fichier n'a été envoyé par l'utilisateur, il ne se passe rien
  • ("", une erreur): une erreur se produit lors du traitement
  • ("machintruc.jpg", nil): on a traîté l'image correctement et elle existe sur s3

Il suffit ensuite de checker qu'il n'y a pas d'erreur, puis copier la valeur dans LDAP seulement si elle n'est pas ""

Pourquoi on renvoie un bool, un string et une error ? je pense qu'on peut enlever le bool, ça complexifie trop et on se perd, et utiliser la sémantique suivante pour `(string, error)`: - `("", nil)`: aucun fichier n'a été envoyé par l'utilisateur, il ne se passe rien - `("", une erreur)`: une erreur se produit lors du traitement - `("machintruc.jpg", nil)`: on a traîté l'image correctement et elle existe sur s3 Il suffit ensuite de checker qu'il n'y a pas d'erreur, puis copier la valeur dans LDAP seulement si elle n'est pas `""`
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
erwan marked this conversation as resolved Outdated
Outdated
Review
  1. a-t-on vraiment besoin de ce check? car si on arrive ici on a err == nil, et le seul cas où c'est possible c'est quand le filetype est un filetype image/ correct
1. a-t-on vraiment besoin de ce check? car si on arrive ici on a `err == nil`, et le seul cas où c'est possible c'est quand le filetype est un filetype `image/` correct
}
buff := bytes.NewBuffer([]byte{})
buff_thumbnail := bytes.NewBuffer([]byte{})
err = resizeThumb(file, buff, buff_thumbnail)
if err != nil {
return false, "", err
}
mc, err := newMimioClient()
erwan marked this conversation as resolved Outdated
Outdated
Review

Minio, et pas Mimio ;)

Minio, et pas Mimio ;)
if err != nil {
return false, "", err
}
if mc == nil {
erwan marked this conversation as resolved Outdated
Outdated
Review

tu peux mettre les deux if en un seul avec ||

tu peux mettre les deux `if` en un seul avec `||`
return false, "", err
}
var name, nameFull string
if nameConsul := login.UserEntry.GetAttributeValue("profilImage"); nameConsul != "" {
erwan marked this conversation as resolved Outdated
Outdated
Review

profilePicture au lieu de profilImage. Pour être sûr d'avoir la même valeur que partout, tu peux définir ça dans une constante:

const PROFILE_PICTURE_FIELD_NAME = "profilePicture"

et ensuite dans le code tu utilises toujours la constante, tu ne répète jamais "profilePicture"

`profilePicture` au lieu de `profilImage`. Pour être sûr d'avoir la même valeur que partout, tu peux définir ça dans une constante: `const PROFILE_PICTURE_FIELD_NAME = "profilePicture"` et ensuite dans le code tu utilises toujours la constante, tu ne répète jamais `"profilePicture"`
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{
erwan marked this conversation as resolved Outdated
Outdated
Review

Le nom du bucket bottin-pictures ça doit être dans config aussi, d'autres gens peuvent avoir un bucket qui s'appelle autrement

Le nom du bucket `bottin-pictures` ça doit être dans config aussi, d'autres gens peuvent avoir un bucket qui s'appelle autrement
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) {
erwan marked this conversation as resolved Outdated
Outdated
Review

Minio*

Minio*
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",
erwan marked this conversation as resolved Outdated
Outdated
Review

La région ça devrait aussi être dans la config

La région ça devrait aussi être dans la config
})
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
erwan marked this conversation as resolved Outdated
Outdated
Review

Pas besoin du premier encodage en jpeg, tu peux le virer

Pas besoin du premier encodage en jpeg, tu peux le virer
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)
lx marked this conversation as resolved Outdated
Outdated
Review

Si l'image d'entrée est pas carrée, qu'est-ce que ça fait ?

Si l'image d'entrée est pas carrée, qu'est-ce que ça fait ?
Outdated
Review

J'ai testé avec des screenshots/ wallpapers et il n'y a eu aucun problèmes. ca les transforme en 200x196 le plus souvent. Si la taille est déjà inférieure à 200 alors il n'y touche pas.

J'ai testé avec des screenshots/ wallpapers et il n'y a eu aucun problèmes. ca les transforme en 200x196 le plus souvent. Si la taille est déjà inférieure à 200 alors il n'y touche pas.
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"},
erwan marked this conversation as resolved Outdated
Outdated
Review

PROFILE_PICTURE_FIELD_NAME

`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("profilImage")
if imageName == "" {
http.Error(w, "User doesn't have profile image", http.StatusInternalServerError)
erwan marked this conversation as resolved Outdated
Outdated
Review

ça serait plutôt une 404 Not found et pas une 500 Internal error

ça serait plutôt une 404 Not found et pas une 500 Internal error
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
}
erwan marked this conversation as resolved Outdated
Outdated
Review

tu peux simplifier tout ça en utilisant io.Copy(w, obj), ça t'évite de gérer un buffer et de prendre le risque de te planter sur les tailles ou les offset

tu peux simplifier tout ça en utilisant `io.Copy(w, obj)`, ça t'évite de gérer un buffer et de prendre le risque de te planter sur les tailles ou les offset
}

View file

@ -18,6 +18,7 @@ type ProfileTplData struct {
Surname string
Visibility string
Description string
NameImage string
}
func handleProfile(w http.ResponseWriter, r *http.Request) {
@ -42,13 +43,27 @@ func handleProfile(w http.ResponseWriter, r *http.Request) {
data.Description = login.UserEntry.GetAttributeValue("description")
if r.Method == "POST" {
r.ParseForm()
//5MB maximum size files
r.ParseMultipartForm(5 << 20)
data.DisplayName = strings.TrimSpace(strings.Join(r.Form["display_name"], ""))
data.GivenName = strings.TrimSpace(strings.Join(r.Form["given_name"], ""))
data.Surname = strings.TrimSpace(strings.Join(r.Form["surname"], ""))
data.Description = strings.Trim(strings.Join(r.Form["description"], ""), "")
data.Visibility = strings.TrimSpace(strings.Join(r.Form["visibility"], ""))
visible := strings.TrimSpace(strings.Join(r.Form["visibility"], ""))
if visible != "" {
visible = "on"
}
data.Visibility = visible
ok, name, err := uploadImage(w, r, login)
if err != nil {
data.ErrorMessage = err.Error()
}
if ok {
data.NameImage = name
}
modify_request := ldap.NewModifyRequest(login.Info.DN, nil)
modify_request.Replace("displayname", []string{data.DisplayName})
@ -56,13 +71,17 @@ func handleProfile(w http.ResponseWriter, r *http.Request) {
modify_request.Replace("sn", []string{data.Surname})
modify_request.Replace("description", []string{data.Description})
modify_request.Replace("visibility", []string{data.Visibility})
if ok {
modify_request.Replace("profilImage", []string{data.NameImage})
}
err := login.conn.Modify(modify_request)
err = login.conn.Modify(modify_request)
if err != nil {
data.ErrorMessage = err.Error()
} else {
data.Success = true
}
}
templateProfile.Execute(w, data)

BIN
static/image/34431.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 764 KiB

View file

@ -0,0 +1,5 @@
document.querySelector('.custom-file-input').addEventListener('change',function(e){
var fileName = document.getElementById("image").files[0].name;
var nextSibling = e.target.nextElementSibling
nextSibling.innerText = fileName
})

View file

@ -21,12 +21,18 @@ function searchDirectory() {
for (let i =0; i < Object.keys(jsonResponse.search).length; i++) {
var row = table.insertRow(0);
var identifiant = row.insertCell(0);
var name = row.insertCell(1);
var email = row.insertCell(2);
var description = row.insertCell(3);
var urlName = row.insertCell(0);
var identifiant = row.insertCell(1);
var name = row.insertCell(2);
var email = row.insertCell(3);
var description = row.insertCell(4);
description.setAttribute("style", "word-break: break-all;");
if (jsonResponse.search[i].dn.localeCompare("")!=0) {
urlName.innerHTML = `<object data="/image/${jsonResponse.search[i].dn}/little" class=".img-thumbnail"><image src="/image/unknown_profile/little" class=".img-thumbnail"></object>`
}else {
urlName.innerHTML=""
}
identifiant.innerHTML = `<a href="/admin/ldap/${jsonResponse.search[i].dn}">${jsonResponse.search[i].identifiant}</a>`
name.innerHTML = jsonResponse.search[i].name
email.innerHTML = jsonResponse.search[i].email

View file

@ -19,6 +19,7 @@
<table class="table mt-4">
<thead>
<th scope="col">Profil image</th>
<th scope="col">Identifiant</th>
<th scope="col">Nom complet</th>
<th scope="col">Email</th>

View file

@ -5,7 +5,10 @@
<h4>Modifier mon profil</h4>
<a class="ml-auto btn btn-info" href="/">Retour</a>
</div>
<h5>Photo de profil</h5>
<object data="/image/{{ .Status.Info.DN}}/full" class=".img-thumbnail">
<img src="/image/unknown_profile/full" alt="Stack Overflow logo and icons and such">
</object>
{{if .ErrorMessage}}
<div class="alert alert-danger mt-4">Impossible d'effectuer la modification.
<div style="font-size: 0.8em">{{ .ErrorMessage }}</div>
@ -16,7 +19,7 @@
Profil enregistré.
</div>
{{end}}
<form method="POST" class="mt-4">
<form method="POST" class="mt-4" enctype="multipart/form-data">
<div class="form-group">
<label>Nom d'utilisateur:</label>
<input type="text" disabled="true" class="form-control" value="{{ .Status.Info.Username }}" />
@ -43,12 +46,19 @@
</div>
<div class="form-group form-check">
{{if .Visibility}}
<input class="form-check-input" name="visibility" type="checkbox" id="visibility" checked>
<input class="form-check-input" name="visibility" type="checkbox" id="visibility" value="on" checked>
{{else}}
<input class="form-check-input" name="visibility" type="checkbox" id="visibility">
{{end}}
<label class="form-check-label" for="visibility">Apparaît sur l'annuaire</label>
</div>
<div class="form-group input-group mb-3">
<div class="form-group custom-file">
<input type="file" name="image" class="custom-file-input" id="image">
<label class="custom-file-label" for="image">Choose picture (jpeg, jpg or png)</label>
</div>
</div>
<button type="submit" class="btn btn-primary">Enregistrer les modifications</button>
</form>
<script src="/static/javascript/minio.js"></script>
{{end}}