diff --git a/mozen/src/main/java/mozen/business/IModelManager.java b/mozen/src/main/java/mozen/business/IModelManager.java
index d383f7e3cac169a85c0d150b5ded1cdb1f80415e..61de3c2273708badff2081a9ee3737105551b8bd 100644
--- a/mozen/src/main/java/mozen/business/IModelManager.java
+++ b/mozen/src/main/java/mozen/business/IModelManager.java
@@ -20,6 +20,5 @@ public interface IModelManager {
   Model getModel(long id);
   Collection<Model> getModels();
 
-  SearchResult findModel(String name, int page, int size, String sort);
-  SearchResult findModelWithTags(String name, int page, int size, String sort, Collection<String> tags);
+  SearchResult findModel(String name, int page, int size, String sort, Collection<String> tagsName);
 }
\ No newline at end of file
diff --git a/mozen/src/main/java/mozen/business/IVoteManager.java b/mozen/src/main/java/mozen/business/IVoteManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..6c4d92fd7277c8cb3dab4f5c387a41eb99f5b7ba
--- /dev/null
+++ b/mozen/src/main/java/mozen/business/IVoteManager.java
@@ -0,0 +1,13 @@
+package mozen.business;
+
+import mozen.model.User;
+
+public interface IVoteManager {
+  void addUpvote(Long id, User user) throws Exception;
+  void addDownvote(Long id, User user) throws Exception;
+
+  void removeUpvote(Long id, User user) throws Exception;
+  void removeDownvote(Long id, User user) throws Exception;
+
+  String getStatus(Long id, User user) throws Exception;
+}
\ No newline at end of file
diff --git a/mozen/src/main/java/mozen/business/ModelManager.java b/mozen/src/main/java/mozen/business/ModelManager.java
index fd1daa802999a5d0247221cbd5678e79a6577879..349ad188bc724ef42ded9e03622fe75bacf8d636 100644
--- a/mozen/src/main/java/mozen/business/ModelManager.java
+++ b/mozen/src/main/java/mozen/business/ModelManager.java
@@ -43,10 +43,18 @@ public class ModelManager implements IModelManager {
     model.setName(message.getName());
     model.setShortDescription(message.getShortDescription());
     model.setLongDescription(message.getLongDescription());
-    model.setPerformanceUnit(message.getPerformanceUnit());
     model.setPerformance(message.getPerformance());
+    model.setPerformanceUnit(message.getPerformanceUnit());
     model.setParameterCount(message.getParameterCount());
 
+    // Standardise la mesure de performance.
+    // C'est bancale mais difficile de trier autrement en mélangeant les unitées de performances
+    if (message.getPerformanceLowerIsBetter()) {
+      model.setPerformanceIndex(message.getPerformance());
+    } else {
+      model.setPerformanceIndex(100 - message.getPerformance());
+    }
+
     if (message.getTags() != null) {
       Set<Tag> tags = new HashSet<Tag>();
       for (String tagName : message.getTags()) {
@@ -140,30 +148,26 @@ public class ModelManager implements IModelManager {
   }
 
   @Override
-  public SearchResult findModel(String name, int page, int size, String sort) {
-    Pageable paging = PageRequest.of(page - 1, size, Sort.by(sort));
-    Page<Model> resultPage = modelRepo.findByNameContainingIgnoreCase(name, paging);
-
-    SearchResult result = new SearchResult();
-    if (resultPage.hasContent()) {
-      result.setTotalResult((int) resultPage.getTotalElements());
-      result.setTotalPage((int) resultPage.getTotalPages());
-      result.setPage(resultPage.getNumber() + 1);
-      result.setModels(resultPage.getContent());
+  public SearchResult findModel(String name, int page, int size, String sort, Collection<String> tagsName) {
+    Pageable paging;
+    
+    // Tri dans le bon sens selon l'attribut
+    switch (sort) {
+      case "votes": paging = PageRequest.of(page - 1, size, Sort.by(sort).descending()); break;
+      case "lastModified": paging = PageRequest.of(page - 1, size, Sort.by(sort).descending()); break;
+      case "performance": paging = PageRequest.of(page - 1, size, Sort.by("performanceIndex")); break;
+      case "parameterCount": paging = PageRequest.of(page - 1, size, Sort.by(sort)); break;
+      default: paging = PageRequest.of(page - 1, size, Sort.by("name"));
+    }
+    
+    Page<Model> resultPage;
+    if (tagsName == null) {
+      resultPage = modelRepo.findByNameContainingIgnoreCase(name, paging);
     } else {
-      result.setPage(0);
-      result.setTotalResult(0);
-      result.setTotalPage(0);
+      Collection<Tag> tags = tagRepo.findByNameIn(tagsName);
+      resultPage = modelRepo.findDistinctByNameContainingIgnoreCaseAndTagsIn(name, tags, paging);
     }
-    return result;
-  }
-
-  @Override
-  public SearchResult findModelWithTags(String name, int page, int size, String sort, Collection<String> tagsName) {
-    Pageable paging = PageRequest.of(page - 1, size, Sort.by(sort));
-    Collection<Tag> tags = tagRepo.findByNameIn(tagsName);
-    Page<Model> resultPage = modelRepo.findDistinctByNameContainingIgnoreCaseAndTagsIn(name, tags, paging);
-
+    
     SearchResult result = new SearchResult();
     if (resultPage.hasContent()) {
       result.setTotalResult((int) resultPage.getTotalElements());
@@ -177,7 +181,7 @@ public class ModelManager implements IModelManager {
     }
     return result;
   }
-
+  
   @Override
   public Model getModel(long id) {
     Optional<Model> model = modelRepo.findById(id);
diff --git a/mozen/src/main/java/mozen/business/VoteManager.java b/mozen/src/main/java/mozen/business/VoteManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..019ce728fd964c57d1d5bea563a7eccf1a32112c
--- /dev/null
+++ b/mozen/src/main/java/mozen/business/VoteManager.java
@@ -0,0 +1,96 @@
+package mozen.business;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import mozen.model.Model;
+import mozen.model.User;
+import mozen.repos.ModelRepository;
+import mozen.repos.UserRepository;
+
+@Service
+public class VoteManager implements IVoteManager {
+  
+  @Autowired
+  private UserRepository userRepo;
+
+  @Autowired
+  private ModelRepository modelRepo;
+
+  @Override
+  public void addUpvote(Long id, User user) throws Exception {
+    Model model = modelRepo.findById(id).get();
+
+    if (model == null)
+      throw new Exception("Unknown model");
+    if (user.getUpvotes().contains(model))
+      throw new Exception("Up present");
+
+    model.setVotes(model.getVotes()+1);
+    user.getUpvotes().add(model);
+
+    modelRepo.save(model);
+    userRepo.save(user);
+  }
+
+  @Override
+  public void addDownvote(Long id, User user) throws Exception {
+    Model model = modelRepo.findById(id).get();
+
+    if (model == null)
+      throw new Exception("Unknown model");
+    if (user.getDownvotes().contains(model))
+      throw new Exception("Downvote present");
+
+    model.setVotes(model.getVotes()-1);
+    user.getDownvotes().add(model);
+
+    modelRepo.save(model);
+    userRepo.save(user);
+  }
+
+  @Override
+  public void removeUpvote(Long id, User user) throws Exception {
+    Model model = modelRepo.findById(id).get();
+
+    if (model == null)
+      throw new Exception("Unknown model");
+    if (!user.getUpvotes().contains(model))
+      throw new Exception("No upvote");
+
+    model.setVotes(model.getVotes()-1);
+    user.getUpvotes().remove(model);
+
+    modelRepo.save(model);
+    userRepo.save(user);
+  }
+
+  @Override
+  public void removeDownvote(Long id, User user) throws Exception {
+    Model model = modelRepo.findById(id).get();
+
+    if (model == null)
+      throw new Exception("Unknown model");
+    if (!user.getDownvotes().contains(model))
+      throw new Exception("No downvote");
+
+    model.setVotes(model.getVotes()+1);
+    user.getDownvotes().remove(model);
+
+    modelRepo.save(model);
+    userRepo.save(user);
+  }
+
+  @Override
+  public String getStatus(Long id, User user) throws Exception {
+    Model model = modelRepo.findById(id).get();
+
+    if (model == null)
+      throw new Exception("Unknown model");
+
+    if (user.getUpvotes().contains(model)) return "up";
+    if (user.getDownvotes().contains(model)) return "down";
+    return "none";
+  }
+  
+}
\ No newline at end of file
diff --git a/mozen/src/main/java/mozen/messages/ModelMessage.java b/mozen/src/main/java/mozen/messages/ModelMessage.java
index b8895ecccf2ad1dcc671adf589b5960afb87e466..afd579fd6190c6083c05e2038ef315bfd8bdeeba 100644
--- a/mozen/src/main/java/mozen/messages/ModelMessage.java
+++ b/mozen/src/main/java/mozen/messages/ModelMessage.java
@@ -26,12 +26,14 @@ public class ModelMessage implements Serializable {
 
   private String performanceUnit;
 
+  private boolean performanceLowerIsBetter;
+
   private int parameterCount;
 
   public ModelMessage() {
   }
 
-  public ModelMessage(String name, String shortDescription, String longDescription, String[] tags, String[] customLayers, double performance, String performanceUnit, int parameterCount) {
+  public ModelMessage(String name, String shortDescription, String longDescription, String[] tags, String[] customLayers, double performance, String performanceUnit, boolean performanceLowerIsBetter, int parameterCount) {
     this.name = name;
     this.shortDescription = shortDescription;
     this.longDescription = longDescription;
@@ -39,10 +41,10 @@ public class ModelMessage implements Serializable {
     this.customLayers = customLayers;
     this.performance = performance;
     this.performanceUnit = performanceUnit;
+    this.performanceLowerIsBetter = performanceLowerIsBetter;
     this.parameterCount = parameterCount;
   }
 
-
   public String getName() {
     return this.name;
   }
@@ -99,6 +101,18 @@ public class ModelMessage implements Serializable {
     this.performanceUnit = performanceUnit;
   }
 
+  public boolean isPerformanceLowerIsBetter() {
+    return this.performanceLowerIsBetter;
+  }
+
+  public boolean getPerformanceLowerIsBetter() {
+    return this.performanceLowerIsBetter;
+  }
+
+  public void setPerformanceLowerIsBetter(boolean performanceLowerIsBetter) {
+    this.performanceLowerIsBetter = performanceLowerIsBetter;
+  }
+
   public int getParameterCount() {
     return this.parameterCount;
   }
diff --git a/mozen/src/main/java/mozen/messages/VoteStatusMessage.java b/mozen/src/main/java/mozen/messages/VoteStatusMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..fb2963d314793efe6659ba5a9c15eff6748d28b5
--- /dev/null
+++ b/mozen/src/main/java/mozen/messages/VoteStatusMessage.java
@@ -0,0 +1,25 @@
+package mozen.messages;
+
+import java.io.Serializable;
+
+public class VoteStatusMessage implements Serializable{
+  private static final long serialVersionUID = 1L;
+
+  private String status;
+
+  public VoteStatusMessage() {
+  }
+
+  public VoteStatusMessage(String status) {
+    this.status = status;
+  }
+
+  public String getStatus() {
+    return this.status;
+  }
+
+  public void setStatus(String status) {
+    this.status = status;
+  }
+}
+  
\ No newline at end of file
diff --git a/mozen/src/main/java/mozen/model/Model.java b/mozen/src/main/java/mozen/model/Model.java
index a8eb93eccd962ce2cfdf83985366f3886fb0ce11..8ba18c82d10765501a1cf4dc63c4eb490dfc6e1f 100644
--- a/mozen/src/main/java/mozen/model/Model.java
+++ b/mozen/src/main/java/mozen/model/Model.java
@@ -72,6 +72,10 @@ public class Model implements Serializable{
 	@Column
   private String performanceUnit;
 
+  @Basic
+	@Column
+  private double performanceIndex;
+
   @Basic
 	@Column
   private int parameterCount;
@@ -113,7 +117,7 @@ public class Model implements Serializable{
   public Model() {
   }
 
-  public Model(Long id, String name, String shortDescription, String longDescription, Date added, Date lastModified, int votes, double performance, String performanceUnit, int parameterCount, byte[] file, String fileType, String checksum, boolean isVerified, User author, Set<Tag> tags, Set<CustomLayer> customLayers, Set<Comment> comments) {
+  public Model(Long id, String name, String shortDescription, String longDescription, Date added, Date lastModified, int votes, double performance, String performanceUnit, double performanceIndex, int parameterCount, byte[] file, String fileType, String checksum, boolean isVerified, User author, Set<Tag> tags, Set<CustomLayer> customLayers, Set<Comment> comments) {
     this.id = id;
     this.name = name;
     this.shortDescription = shortDescription;
@@ -123,6 +127,7 @@ public class Model implements Serializable{
     this.votes = votes;
     this.performance = performance;
     this.performanceUnit = performanceUnit;
+    this.performanceIndex = performanceIndex;
     this.parameterCount = parameterCount;
     this.file = file;
     this.fileType = fileType;
@@ -134,6 +139,15 @@ public class Model implements Serializable{
     this.comments = comments;
   }
 
+  @JsonIgnore
+  public double getPerformanceIndex() {
+    return this.performanceIndex;
+  }
+
+  public void setPerformanceIndex(double performanceIndex) {
+    this.performanceIndex = performanceIndex;
+  }  
+
   public Long getId() {
     return this.id;
   }
diff --git a/mozen/src/main/java/mozen/model/User.java b/mozen/src/main/java/mozen/model/User.java
index 4a2804437274334024fb1166115547ea8b73bb24..473af1d1466bda19432eb5e34728510c27e040b9 100644
--- a/mozen/src/main/java/mozen/model/User.java
+++ b/mozen/src/main/java/mozen/model/User.java
@@ -13,6 +13,8 @@ import javax.persistence.FetchType;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
 import javax.persistence.OneToMany;
 import javax.persistence.Table;
 import javax.validation.constraints.NotNull;
@@ -67,10 +69,23 @@ public class User implements Serializable{
   @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
   private Set<Comment> comments;
 
+  @Basic
+  @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST})
+  @JoinTable(name = "model_vote_up")
+  @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
+  private Set<Model> upvotes;
+
+  @Basic
+  @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST})
+  @JoinTable(name = "model_vote_down")
+  @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
+  private Set<Model> downvotes;
+
+
   public User() {
   }
 
-  public User(Long id, String username, String password, String email, Role role, Set<Model> models, Set<Comment> comments) {
+  public User(Long id, String username, String password, String email, Role role, Set<Model> models, Set<Comment> comments, Set<Model> upvotes, Set<Model> downvotes) {
     this.id = id;
     this.username = username;
     this.password = password;
@@ -78,6 +93,8 @@ public class User implements Serializable{
     this.role = role;
     this.models = models;
     this.comments = comments;
+    this.upvotes = upvotes;
+    this.downvotes = downvotes;
   }
   
   public Long getId() {
@@ -139,4 +156,23 @@ public class User implements Serializable{
     this.comments = comments;
   }
 
+  @JsonIgnore
+  public Set<Model> getUpvotes() {
+    return this.upvotes;
+  }
+
+  public void setUpvotes(Set<Model> upvotes) {
+    this.upvotes = upvotes;
+  }
+
+  @JsonIgnore
+  public Set<Model> getDownvotes() {
+    return this.downvotes;
+  }
+
+  public void setDownvotes(Set<Model> downvotes) {
+    this.downvotes = downvotes;
+  }
+
+
 }
\ No newline at end of file
diff --git a/mozen/src/main/java/mozen/utils/DatabaseFiller.java b/mozen/src/main/java/mozen/utils/DatabaseFiller.java
index 06c624a6c34ddb39b3ae5cc4dd0fec43def50a7b..4636076933d973332410aff64ab5a6cb61b843c0 100644
--- a/mozen/src/main/java/mozen/utils/DatabaseFiller.java
+++ b/mozen/src/main/java/mozen/utils/DatabaseFiller.java
@@ -69,6 +69,7 @@ public class DatabaseFiller {
     m1.setLongDescription("# README \n model testo");
     m1.setVotes(0);
     m1.setParameterCount(10);
+    m1.setPerformanceIndex(1.5);
     m1.setPerformance(98.5);
     m1.setPerformanceUnit("accuracy");
     m1.setAdded(new Date());
diff --git a/mozen/src/main/java/mozen/web/SearchController.java b/mozen/src/main/java/mozen/web/SearchController.java
index 49ccb20f4c6d8d11467795ecb25c44ba60eb1850..8d6c0fbfb8490154482cdf151272cc2ede9705b4 100644
--- a/mozen/src/main/java/mozen/web/SearchController.java
+++ b/mozen/src/main/java/mozen/web/SearchController.java
@@ -31,8 +31,8 @@ public class SearchController {
   {
     SearchResult result;
 
-    if (tags.isEmpty()) result = modelManager.findModel(name, page, size, sort);
-    else result = modelManager.findModelWithTags(name, page, size, sort, tags);
+    if (tags.isEmpty()) result = modelManager.findModel(name, page, size, sort, null);
+    else result = modelManager.findModel(name, page, size, sort, tags);
    
     return result;
   }
diff --git a/mozen/src/main/java/mozen/web/VoteController.java b/mozen/src/main/java/mozen/web/VoteController.java
index 72f3f24fe10e7a66d258cafeb3b5d3d9fb562348..ad0913c66606e052582cd028f3e359fbb059d878 100644
--- a/mozen/src/main/java/mozen/web/VoteController.java
+++ b/mozen/src/main/java/mozen/web/VoteController.java
@@ -5,11 +5,17 @@ import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.CrossOrigin;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
-import mozen.business.IModelManager;
 import mozen.business.IUserManager;
+import mozen.business.IVoteManager;
+import mozen.messages.ResponseMessage;
+import mozen.messages.VoteStatusMessage;
+import mozen.model.User;
+import mozen.utils.UserHelper;
+
 import org.springframework.web.bind.annotation.RequestParam;
 
 @RestController
@@ -17,18 +23,90 @@ import org.springframework.web.bind.annotation.RequestParam;
 @CrossOrigin
 public class VoteController {
   @Autowired
-  IModelManager modelManager;
+  IVoteManager voteManager;
 
   @Autowired
   IUserManager userManager;
 
   @GetMapping
-  public ResponseEntity<?> addVote(@RequestParam(value = "id", required = false) Long id) {
-    return null;
+  public ResponseEntity<?> getVoteStatus(@RequestParam(value = "id", required = true) Long id) {
+    ResponseMessage response = new ResponseMessage(false, "");
+    User user = UserHelper.getCurrentUser(userManager);
+    if(user == null) {
+      response.setError(true);
+      response.setMessage("User unknown");
+      return ResponseEntity.badRequest().body(response);
+    }
+
+    try {
+      String status = voteManager.getStatus(id, user);
+      return ResponseEntity.ok(new VoteStatusMessage(status));
+    } catch (Exception e) {
+      response.setError(true);
+      response.setMessage(e.getMessage());
+      return ResponseEntity.badRequest().body(response);
+    }
+  }
+
+  @PutMapping
+  public ResponseEntity<?> addVote(@RequestParam(value = "id", required = true) Long id, @RequestParam(value = "isDown", required = true) boolean isDown) {
+    ResponseMessage response = new ResponseMessage(false, "");
+    User user = UserHelper.getCurrentUser(userManager);
+    if(user == null) {
+      response.setError(true);
+      response.setMessage("User unknown");
+      return ResponseEntity.badRequest().body(response);
+    }
+
+    try {
+      if (isDown) {
+        voteManager.addDownvote(id, user);
+      } else {
+        voteManager.addUpvote(id, user);
+      }
+    } catch (Exception e) {
+      response.setError(true);
+      response.setMessage(e.getMessage());
+      return ResponseEntity.badRequest().body(response);
+    }
+
+    return ResponseEntity.ok(response);
   }
 
   @DeleteMapping
-  public ResponseEntity<?> removeVote(@RequestParam(value = "id", required = false) Long id) {
-    return null;
+  public ResponseEntity<?> removeVote(@RequestParam(value = "id", required = true) Long id, @RequestParam(value = "isDown", required = true) boolean isDown) {
+    ResponseMessage response = new ResponseMessage(false, "");
+    User user = UserHelper.getCurrentUser(userManager);
+    if(user == null) {
+      response.setError(true);
+      response.setMessage("User unknown");
+      return ResponseEntity.badRequest().body(response);
+    }
+
+    try {
+      if (isDown) {
+        voteManager.removeDownvote(id, user);
+      } else {
+        voteManager.removeUpvote(id, user);
+      }
+    } catch (Exception e) {
+      response.setError(true);
+      response.setMessage(e.getMessage());
+      return ResponseEntity.badRequest().body(response);
+    }
+
+    return ResponseEntity.ok(response);
+  }
+
+  @GetMapping("/likedModels")
+  public ResponseEntity<?> getLikedModels() {
+    ResponseMessage response = new ResponseMessage(false, "");
+    User user = UserHelper.getCurrentUser(userManager);
+    if(user == null) {
+      response.setError(true);
+      response.setMessage("User unknown");
+      return ResponseEntity.badRequest().body(response);
+    }
+    return ResponseEntity.ok(user.getUpvotes());
   }
 }
\ No newline at end of file