aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--directory.go103
-rw-r--r--main.go2
-rw-r--r--static/javascript/search.js53
-rw-r--r--templates/directory.html38
-rw-r--r--templates/directory_results.html23
-rw-r--r--templates/profile.html6
7 files changed, 110 insertions, 117 deletions
diff --git a/Makefile b/Makefile
index 62311e9..e42acb7 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
BIN=guichet
-SRC=main.go ssha.go profile.go admin.go invite.go
+SRC=main.go ssha.go profile.go admin.go invite.go directory.go picture.go
DOCKER=lxpz/guichet_amd64
all: $(BIN)
diff --git a/directory.go b/directory.go
index b1e563d..f3fa0fe 100644
--- a/directory.go
+++ b/directory.go
@@ -1,13 +1,12 @@
package main
import (
- "encoding/json"
"html/template"
"net/http"
+ "sort"
"strings"
"github.com/go-ldap/ldap/v3"
- "github.com/gorilla/mux"
)
const FIELD_NAME_PROFILE_PICTURE = "profilePicture"
@@ -25,28 +24,34 @@ func handleDirectory(w http.ResponseWriter, r *http.Request) {
}
type SearchResult struct {
- Id string `json:"id"`
- Displayname string `json:"displayname"`
- Email string `json:"email"`
- Description string `json:"description"`
- DN string `json:"dn"`
+ DN string
+ Id string
+ DisplayName string
+ Email string
+ Description string
+ ProfilePicture string
}
-type Results struct {
- Search []SearchResult `json:"search"`
- MessageID uint32 `json:"id"`
+type SearchResults struct {
+ Results []SearchResult
}
-type UniqueID struct {
- Id int `json:"id"`
-}
+func handleDirectorySearch(w http.ResponseWriter, r *http.Request) {
+ templateDirectoryResults := template.Must(template.ParseFiles("templates/directory_results.html"))
-func handleSearch(w http.ResponseWriter, r *http.Request) {
//Get input value by user
- input := mux.Vars(r)["input"]
+ r.ParseMultipartForm(1024)
+ input := strings.TrimSpace(strings.Join(r.Form["query"], ""))
+
+ if r.Method != "POST" || input == "" {
+ http.Error(w, "Invalid request", http.StatusBadRequest)
+ return
+ }
+
//Log to allow the research
login := checkLogin(w, r)
if login == nil {
+ http.Error(w, "Login required", http.StatusUnauthorized)
return
}
@@ -71,42 +76,46 @@ func handleSearch(w http.ResponseWriter, r *http.Request) {
}
//Transform the researh's result in a correct struct to send JSON
- var result Results
- for _, values := range sr.Entries {
+ results := []SearchResult{}
- if strings.Contains(values.GetAttributeValue(config.UserNameAttr), input) || strings.Contains(values.GetAttributeValue("displayname"), input) ||
- (values.GetAttributeValue("email") != "" && strings.Contains(values.GetAttributeValue("email"), input)) {
- result = Results{
- Search: append(result.Search, SearchResult{
- Id: values.GetAttributeValue(config.UserNameAttr),
- Displayname: values.GetAttributeValue("displayname"),
- Email: values.GetAttributeValue("email"),
- Description: values.GetAttributeValue("description"),
- DN: values.DN,
- }),
- }
- }
-
- }
- if result.Search == nil {
- result = Results{
- Search: append(result.Search, SearchResult{}),
+ for _, values := range sr.Entries {
+ if ContainsI(values.GetAttributeValue(config.UserNameAttr), input) ||
+ ContainsI(values.GetAttributeValue("displayname"), input) ||
+ ContainsI(values.GetAttributeValue("mail"), input) {
+ results = append(results, SearchResult{
+ DN: values.DN,
+ Id: values.GetAttributeValue(config.UserNameAttr),
+ DisplayName: values.GetAttributeValue("displayname"),
+ Email: values.GetAttributeValue("mail"),
+ Description: values.GetAttributeValue("description"),
+ ProfilePicture: values.GetAttributeValue(FIELD_NAME_PROFILE_PICTURE),
+ })
}
}
- var id UniqueID
- //Decode JSON body
- err = json.NewDecoder(r.Body).Decode(&id)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
+ search_results := SearchResults{
+ Results: results,
}
- result.MessageID = uint32(id.Id)
+ sort.Sort(&search_results)
- //Send JSON through xhttp
- w.Header().Set("Content-Type", "application/json; charset=UTF-8")
- w.WriteHeader(http.StatusCreated)
- if err := json.NewEncoder(w).Encode(result); err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- }
+ templateDirectoryResults.Execute(w, search_results)
+}
+
+func ContainsI(a string, b string) bool {
+ return strings.Contains(
+ strings.ToLower(a),
+ strings.ToLower(b),
+ )
+}
+
+func (r *SearchResults) Len() int {
+ return len(r.Results)
+}
+
+func (r *SearchResults) Less(i, j int) bool {
+ return r.Results[i].Id < r.Results[j].Id
+}
+
+func (r *SearchResults) Swap(i, j int) {
+ r.Results[i], r.Results[j] = r.Results[j], r.Results[i]
}
diff --git a/main.go b/main.go
index b5c8680..d574f3f 100644
--- a/main.go
+++ b/main.go
@@ -115,8 +115,8 @@ func main() {
r.HandleFunc("/passwd", handlePasswd)
r.HandleFunc("/picture/{name}", handleDownloadPicture)
+ r.HandleFunc("/directory/search", handleDirectorySearch)
r.HandleFunc("/directory", handleDirectory)
- r.HandleFunc("/directory/search/{input}", handleSearch)
r.HandleFunc("/invite/new_account", handleInviteNewAccount)
r.HandleFunc("/invite/send_code", handleInviteSendCode)
diff --git a/static/javascript/search.js b/static/javascript/search.js
index ea98e34..2a75889 100644
--- a/static/javascript/search.js
+++ b/static/javascript/search.js
@@ -1,51 +1,24 @@
-var perso_id = 0;
var last_id = 0;
function searchDirectory() {
var input = document.getElementById("search").value;
if(input){
- var xhttp = new XMLHttpRequest();
- xhttp.onreadystatechange = function() {
- if (this.readyState == 4 && this.status == 201) {
- // Typical action to be performed when the document is ready:
- //Response from Request Ajax
- var jsonResponse = JSON.parse(xhttp.responseText);
+ last_id++;
+ var request_id = last_id;
- if (last_id < jsonResponse.id) {
- last_id = jsonResponse.id
- //We get the old table element, we create an new table element then we increment this new table.
- //After the new add, we replace the old table by the new one.
- var old_table = document.getElementById("users");
- var table = document.createElement('tbody');
- table.setAttribute("id","users");
-
- for (let i =0; i < Object.keys(jsonResponse.search).length; i++) {
- var row = table.insertRow(0);
- var urlName = row.insertCell(0);
- var identifiant = row.insertCell(1);
- var displayname = row.insertCell(2);
- var email = row.insertCell(3);
- var description = row.insertCell(4);
- description.setAttribute("style", "word-break: break-all;");
+ var data = new FormData();
+ data.append("query", input);
- if (jsonResponse.search[i].dn.localeCompare("")!=0) {
- urlName.innerText = `<object data="/image/${jsonResponse.search[i].dn}/little" class=".img-thumbnail"><image src="/image/unknown_profile/little" class=".img-thumbnail"></object>`
- }else {
- urlName.innerText=""
- }
- identifiant.innerText = `<a href="/admin/ldap/${jsonResponse.search[i].dn}">${jsonResponse.search[i].id}</a>`
- displayname.innerText = jsonResponse.search[i].displayname
- email.innerText = jsonResponse.search[i].email
- description.innerText = jsonResponse.search[i].description
+ var xhttp = new XMLHttpRequest();
+ xhttp.onreadystatechange = function() {
+ if (request_id != last_id) return;
- }
- old_table.parentNode.replaceChild(table, old_table)
+ if (this.readyState == 4 && this.status == 200) {
+ var result_div = document.getElementById("search-results");
+ result_div.innerHTML = xhttp.responseText;
}
- }
};
- perso_id += 1
- xhttp.overrideMimeType("application/json");
- xhttp.open("POST", "/search/".concat(input), true);
- xhttp.send(JSON.stringify({"id": perso_id}));
+ xhttp.open("POST", "/directory/search", true);
+ xhttp.send(data);
}
-} \ No newline at end of file
+}
diff --git a/templates/directory.html b/templates/directory.html
index f9bad61..d995fb2 100644
--- a/templates/directory.html
+++ b/templates/directory.html
@@ -1,35 +1,23 @@
-{{define "title"}}Directory |{{end}}
+{{define "title"}}Annuaire |{{end}}
{{define "body"}}
<div class="d-flex">
- <h4>Directory</h4>
+ <h4>Annuaire</h4>
<a class="ml-auto btn btn-info" href="/">Menu principal</a>
</div>
-<div class="d-flex">
- <div class="d-flex mx-auto">
- <p class="">Name:</p>
- <form class="px-2" style="width: fit-content;">
- <input id="search" type="text" onkeyup="searchDirectory()" size="20">
- </form>
- </div>
-</div>
+<form>
+ <div class="form-group form-row">
+ <div class="col-sm-2">&nbsp;</div>
+ <label for="search" class="col-sm-2 col-form-label">Rechercher :</label>
+ <input class="form-control col-sm-4" id="search" name="search" type="text" onkeyup="searchDirectory()" size="20">
+ </div>
+</form>
+
+<div id="search-results"></div>
-<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>
- <th scope="col">Description</th>
- </thead>
- <tbody id="users">
-
-
- </tbody>
- </table>
- <script src="/static/javascript/search.js"></script>
+<script src="/static/javascript/search.js"></script>
-{{end}} \ No newline at end of file
+{{end}}
diff --git a/templates/directory_results.html b/templates/directory_results.html
new file mode 100644
index 0000000..c7dd715
--- /dev/null
+++ b/templates/directory_results.html
@@ -0,0 +1,23 @@
+{{if .Results}}
+ {{range .Results}}
+ <div class="card mt-4">
+ <div class="card-body">
+ <div class="float-right">
+ {{if .ProfilePicture}}
+ <a href="/picture/{{.ProfilePicture}}">
+ <img src="/picture/{{.ProfilePicture}}-thumb"/>
+ </a>
+ {{else}}
+ {{end}}
+ </div>
+ <h5 class="card-title">
+ {{.DisplayName}}
+ <code>{{.Id}}@</code>
+ </h5>
+ <p class="card-text">{{.Description}}</p>
+ </div>
+ </div>
+ {{end}}
+{{else}}
+ Aucun résultat.
+{{end}}
diff --git a/templates/profile.html b/templates/profile.html
index 8704e23..edf9d76 100644
--- a/templates/profile.html
+++ b/templates/profile.html
@@ -5,7 +5,7 @@
<h4>Modifier mon profil</h4>
<a class="ml-auto btn btn-info" href="/">Retour</a>
</div>
-<h5>Photo de profil</h5>
+
{{if .ErrorMessage}}
<div class="alert alert-danger mt-4">Impossible d'effectuer la modification.
<div style="font-size: 0.8em">{{ .ErrorMessage }}</div>
@@ -70,8 +70,8 @@
</div>
<div class="form-group">
- <label for="description">Description (180 caractères maximum)</label>
- <textarea id="description" name="description" class="form-control" maxlength="180">{{ .Description }}</textarea>
+ <label for="description">Description</label>
+ <textarea id="description" name="description" class="form-control">{{ .Description }}</textarea>
</div>
<button type="submit" class="btn btn-primary">Enregistrer les modifications</button>
</form>