Keesun Baik 2014-07-29
Search: Polish
@189fdd7157f99d15bde80e57d0d4ff9e6af50af8
app/assets/stylesheets/less/_page.less
--- app/assets/stylesheets/less/_page.less
+++ app/assets/stylesheets/less/_page.less
@@ -223,15 +223,6 @@
     }
 }
 
-.search-box-wrap {
-    border-bottom:1px solid #ddd;
-    padding-bottom:20px;
-
-    input[type="text"] {
-        margin-bottom: 0;
-    }
-}
-
 .gnb-search-form {
     margin:0;
     padding:0 10px;
@@ -5727,6 +5718,26 @@
   }
 }
 
+.search-box-wrap {
+    padding-bottom:15px;
+    border-bottom: 1px solid #ddd;
+
+    input[type="text"] {
+        margin-bottom: 0;
+    }
+
+    h3.search-result-title {
+        font-size:16px;
+        margin-top: 15px;
+        font-weight: normal;
+        padding:0 15px;
+        
+        strong {
+            color:#f36c22;
+        }
+    }
+}
+
 .search-list-wrap {
     list-style: none;
     display: block;
@@ -5736,11 +5747,11 @@
         display: block;
         float: none;
         margin:0;
-        padding:10px 15px 10px 60px;
+        padding:15px;
         border-bottom: 1px solid #ddd;
 
         &.project {
-            padding:10px 15px;
+           padding:15px 15px 15px 60px;
         }
     }
 
@@ -5773,8 +5784,8 @@
     }
 
     .title-wrap {
-        line-height: 40px;
-        font-size: 18px;
+        line-height: 30px;
+        font-size: 16px;
         font-weight: bold;
         text-overflow: ellipsis;
         white-space: nowrap;
@@ -5783,9 +5794,7 @@
         .post-id {
             color:#999;
             font-weight: normal;
-
-            
-        }
+       }
 
         .title {
             color:#333;
@@ -5806,19 +5815,27 @@
     .search-content {
         display: block;
         font-size: 14px;
-        margin-top: 15px;
-        border-left: 3px solid #DDD;
-        padding-left:13px;
+        padding-left:20px;
+
+        &.np {
+            padding-left:0 !important;
+        }
+
     }
 
     .search-content-body {
         display: block;
-        margin-top:15px;
     }
 
     .search-meta-info {
-        margin-top:15px;
+        margin-top:10px;
         font-size: 13px;
+        color:#999;
+        padding-left:20px;  
+
+        &.np {
+            padding-left:0 !important;
+        }
 
         .meta-item {
             line-height: 20px;
@@ -5826,7 +5843,13 @@
         }
     }
 
-    .project-link, .user-link {
+    .project-link {
+        &:hover {
+            color: #3592b5 !important;
+        }
+    }
+
+    .user-link { 
         color: #3592b5 !important;
         font-weight: bold;
     }
app/controllers/SearchApp.java
--- app/controllers/SearchApp.java
+++ app/controllers/SearchApp.java
@@ -1,7 +1,25 @@
+/**
+ * Yobi, Project Hosting SW
+ *
+ * Copyright 2014 NAVER Corp.
+ * http://yobi.io
+ *
+ * @Author Keesun Baik
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package controllers;
 
-import com.avaje.ebean.ExpressionList;
-import com.avaje.ebean.Page;
 import controllers.annotation.IsAllowed;
 import models.*;
 import models.enumeration.Operation;
@@ -9,40 +27,67 @@
 import org.apache.commons.lang3.StringUtils;
 import play.mvc.Controller;
 import play.mvc.Result;
+import utils.ErrorViews;
 import views.html.search.*;
-import utils.HttpUtil;
 
-import java.util.List;
-
-/**
- * @author Keeun Baik
- */
 public class SearchApp extends Controller {
 
     private static final PageParam DEFAULT_PAGE = new PageParam(0, 20);
 
     /**
-     * Search from all repositories.
+     * Search contents that current user can read in all projects.
      *
      * @return
      */
-    public static Result searchAllRepos() {
+    public static Result searchInAll() {
         // SearchCondition from param
         String searchTypeValue = request().getQueryString("searchType");
         String keyword = request().getQueryString("keyword");
-        setPage();
+        PageParam pageParam = getPage();
 
         if(StringUtils.isEmpty(keyword) || StringUtils.isEmpty(searchTypeValue)) {
-            return badRequest();
+            return badRequest(ErrorViews.BadRequest.render());
         }
 
         User user = UserApp.currentUser();
         SearchType searchType = SearchType.getValue(searchTypeValue);
 
         if(searchType == SearchType.NA) {
-            return badRequest();
+            return badRequest(ErrorViews.BadRequest.render());
         }
 
+        SearchResult searchResult = getSearchResult(keyword, user, searchType);
+
+        switch (searchType) {
+            case ISSUE:
+                searchResult.setIssues(Search.findIssues(keyword, user, pageParam));
+                break;
+            case USER:
+                searchResult.setUsers(Search.findUsers(keyword, pageParam));
+                break;
+            case PROJECT:
+                searchResult.setProjects(Search.findProjects(keyword, user, pageParam));
+                break;
+            case POST:
+                searchResult.setPosts(Search.findPosts(keyword, user, pageParam));
+                break;
+            case MILESTONE:
+                searchResult.setMilestones(Search.findMilestones(keyword, user, pageParam));
+                break;
+            case ISSUE_COMMENT:
+                searchResult.setIssueComments(Search.findIssueComments(keyword, user, pageParam));
+                break;
+            case POST_COMMENT:
+                searchResult.setPostComments(Search.findPostComments(keyword, user, pageParam));
+                break;
+            case REVIEW:
+                searchResult.setReviews(Search.findReviews(keyword, user, pageParam));
+                break;
+        }
+        return ok(result.render("title.search", null, null, searchResult));
+    }
+
+    private static SearchResult getSearchResult(String keyword, User user, SearchType searchType) {
         SearchResult searchResult = new SearchResult();
         searchResult.setKeyword(keyword);
         searchResult.setSearchType(searchType);
@@ -54,46 +99,19 @@
         searchResult.setIssueCommentsCount(Search.countIssueComments(keyword, user));
         searchResult.setPostCommentsCount(Search.countPostComments(keyword, user));
         searchResult.setReviewsCount(Search.countReviews(keyword, user));
-
-        switch (searchType) {
-            case ISSUE:
-                searchResult.setIssues(Search.findIssues(keyword, user, DEFAULT_PAGE));
-                break;
-            case USER:
-                searchResult.setUsers(Search.findUsers(keyword, DEFAULT_PAGE));
-                break;
-            case PROJECT:
-                searchResult.setProjects(Search.findProjects(keyword, user, DEFAULT_PAGE));
-                break;
-            case POST:
-                searchResult.setPosts(Search.findPosts(keyword, user, DEFAULT_PAGE));
-                break;
-            case MILESTONE:
-                searchResult.setMilestones(Search.findMilestones(keyword, user, DEFAULT_PAGE));
-                break;
-            case ISSUE_COMMENT:
-                searchResult.setIssueComments(Search.findIssueComments(keyword, user, DEFAULT_PAGE));
-                break;
-            case POST_COMMENT:
-                searchResult.setPostComments(Search.findPostComments(keyword, user, DEFAULT_PAGE));
-                break;
-            case REVIEW:
-                searchResult.setReviews(Search.findReviews(keyword, user, DEFAULT_PAGE));
-                break;
-        }
-        return ok(result.render("title.search", null, null, searchResult));
+        return searchResult;
     }
 
     /**
-     * Search from an {@link models.Organization}
+     * Search contents that current user can read in a group.
      *
      * @param organizationName
      * @return
      */
-    public static Result searchGroupRepos(String organizationName) {
+    public static Result searchInAGroup(String organizationName) {
         String searchTypeValue = request().getQueryString("searchType");
         String keyword = request().getQueryString("keyword");
-        setPage();
+        PageParam pageParam = getPage();
 
         if(StringUtils.isEmpty(organizationName)
                 || StringUtils.isEmpty(keyword)
@@ -105,10 +123,43 @@
         User user = UserApp.currentUser();
         SearchType searchType = SearchType.getValue(searchTypeValue);
 
-        if(searchType == SearchType.NA) {
-            return badRequest();
+        if(searchType == SearchType.NA || organization == null) {
+            return badRequest(ErrorViews.BadRequest.render());
         }
 
+        SearchResult searchResult = getSearchResult(keyword, user, organization, searchType);
+
+        switch (searchType) {
+            case ISSUE:
+                searchResult.setIssues(Search.findIssues(keyword, user, organization, pageParam));
+                break;
+            case USER:
+                searchResult.setUsers(Search.findUsers(keyword, organization, pageParam));
+                break;
+            case PROJECT:
+                searchResult.setProjects(Search.findProjects(keyword, user, organization, pageParam));
+                break;
+            case POST:
+                searchResult.setPosts(Search.findPosts(keyword, user, organization, pageParam));
+                break;
+            case MILESTONE:
+                searchResult.setMilestones(Search.findMilestones(keyword, user, organization, pageParam));
+                break;
+            case ISSUE_COMMENT:
+                searchResult.setIssueComments(Search.findIssueComments(keyword, user, organization, pageParam));
+                break;
+            case POST_COMMENT:
+                searchResult.setPostComments(Search.findPostComments(keyword, user, organization, pageParam));
+                break;
+            case REVIEW:
+                searchResult.setReviews(Search.findReviews(keyword, user, organization, pageParam));
+                break;            
+        }
+
+        return ok(result.render("title.search", organization, null, searchResult));
+    }
+
+    private static SearchResult getSearchResult(String keyword, User user, Organization organization, SearchType searchType) {
         SearchResult searchResult = new SearchResult();
         searchResult.setSearchType(searchType);
         searchResult.setKeyword(keyword);
@@ -120,57 +171,66 @@
         searchResult.setIssueCommentsCount(Search.countIssueComments(keyword, user, organization));
         searchResult.setPostCommentsCount(Search.countPostComments(keyword, user, organization));
         searchResult.setReviewsCount(Search.countReviews(keyword, user, organization));
-
-        switch (searchType) {
-            case ISSUE:
-                searchResult.setIssues(Search.findIssues(keyword, user, organization, DEFAULT_PAGE));
-                break;
-            case USER:
-                searchResult.setUsers(Search.findUsers(keyword, organization, DEFAULT_PAGE));
-                break;
-            case PROJECT:
-                searchResult.setProjects(Search.findProjects(keyword, user, organization, DEFAULT_PAGE));
-                break;
-            case POST:
-                searchResult.setPosts(Search.findPosts(keyword, user, organization, DEFAULT_PAGE));
-                break;
-            case MILESTONE:
-                searchResult.setMilestones(Search.findMilestones(keyword, user, organization, DEFAULT_PAGE));
-                break;
-            case ISSUE_COMMENT:
-                searchResult.setIssueComments(Search.findIssueComments(keyword, user, organization, DEFAULT_PAGE));
-                break;
-            case POST_COMMENT:
-                searchResult.setPostComments(Search.findPostComments(keyword, user, organization, DEFAULT_PAGE));
-                break;
-            case REVIEW:
-                searchResult.setReviews(Search.findReviews(keyword, user, organization, DEFAULT_PAGE));
-                break;            
-        }
-
-        return ok(result.render("title.search", organization, null, searchResult));
+        return searchResult;
     }
 
+    /**
+     * Search contents that current user can read in a project.
+     *
+     * @param loginId
+     * @param projectName
+     * @return
+     */
     @IsAllowed(Operation.READ)
-    public static Result searchProject(String loginId, String projectName) {
+    public static Result searchInAProject(String loginId, String projectName) {
         String searchTypeValue = request().getQueryString("searchType");
         String keyword = request().getQueryString("keyword");
         Project project = Project.findByOwnerAndProjectName(loginId, projectName);
-        setPage();
+        PageParam pageParam = getPage();
 
         if(StringUtils.isEmpty(keyword)
                 || StringUtils.isEmpty(searchTypeValue)
                 || project == null) {
-            return badRequest();
+            return badRequest(ErrorViews.BadRequest.render());
         }
 
         User user = UserApp.currentUser();
         SearchType searchType = SearchType.getValue(searchTypeValue);
 
         if(searchType == SearchType.NA || searchType == SearchType.PROJECT) {
-            return badRequest();
+            return badRequest(ErrorViews.BadRequest.render());
         }
 
+        SearchResult searchResult = getSearchResult(keyword, user, project, searchType);
+
+        switch (searchType) {
+            case ISSUE:
+                searchResult.setIssues(Search.findIssues(keyword, user, project, pageParam));
+                break;
+            case USER:
+                searchResult.setUsers(Search.findUsers(keyword, project, pageParam));
+                break;
+            case POST:
+                searchResult.setPosts(Search.findPosts(keyword, user, project, pageParam));
+                break;
+            case MILESTONE:
+                searchResult.setMilestones(Search.findMilestones(keyword, user, project, pageParam));
+                break;
+            case ISSUE_COMMENT:
+                searchResult.setIssueComments(Search.findIssueComments(keyword, user, project, pageParam));
+                break;
+            case POST_COMMENT:
+                searchResult.setPostComments(Search.findPostComments(keyword, user, project, pageParam));
+                break;
+            case REVIEW:
+                searchResult.setReviews(Search.findReviews(keyword, user, project, pageParam));
+                break;
+        }
+
+        return ok(result.render("title.search", null, project, searchResult));
+    }
+
+    private static SearchResult getSearchResult(String keyword, User user, Project project, SearchType searchType) {
         SearchResult searchResult = new SearchResult();
         searchResult.setSearchType(searchType);
         searchResult.setKeyword(keyword);
@@ -181,41 +241,17 @@
         searchResult.setIssueCommentsCount(Search.countIssueComments(keyword, user, project));
         searchResult.setPostCommentsCount(Search.countPostComments(keyword, user, project));
         searchResult.setReviewsCount(Search.countReviews(keyword, user, project));
-
-        switch (searchType) {
-            case ISSUE:
-                searchResult.setIssues(Search.findIssues(keyword, user, project, DEFAULT_PAGE));
-                break;
-            case USER:
-                searchResult.setUsers(Search.findUsers(keyword, project, DEFAULT_PAGE));
-                break;
-            case POST:
-                searchResult.setPosts(Search.findPosts(keyword, user, project, DEFAULT_PAGE));
-                break;
-            case MILESTONE:
-                searchResult.setMilestones(Search.findMilestones(keyword, user, project, DEFAULT_PAGE));
-                break;
-            case ISSUE_COMMENT:
-                searchResult.setIssueComments(Search.findIssueComments(keyword, user, project, DEFAULT_PAGE));
-                break;
-            case POST_COMMENT:
-                searchResult.setPostComments(Search.findPostComments(keyword, user, project, DEFAULT_PAGE));
-                break;
-            case REVIEW:
-                searchResult.setReviews(Search.findReviews(keyword, user, project, DEFAULT_PAGE));
-                break;
-        }
-
-        return ok(result.render("title.search", null, project, searchResult));
+        return searchResult;
     }
 
-    private static void setPage() {
+    private static PageParam getPage() {
+        PageParam pageParam = new PageParam(DEFAULT_PAGE.getPage(), DEFAULT_PAGE.getSize());
         String pageNumString = request().getQueryString("pageNum");
-
         if(pageNumString != null) {
             int pageNum = Integer.parseInt(pageNumString);
-            DEFAULT_PAGE.setPage(pageNum - 1);
+            pageParam.setPage(pageNum - 1);
         }
+        return pageParam;
     }
 
 }
app/models/PageParam.java
--- app/models/PageParam.java
+++ app/models/PageParam.java
@@ -1,7 +1,30 @@
+/**
+ * Yobi, Project Hosting SW
+ *
+ * Copyright 2014 NAVER Corp.
+ * http://yobi.io
+ *
+ * @Author Keesun Baik
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package models;
 
 /**
- * @author Keeun Baik
+ * To make paged result, you always have to pass at least two parameters, page and size.
+ * This class can be used to reduce parameters to pass.
+ *
+ * @see {@link Search#findUsers(String, PageParam)}
  */
 public class PageParam {
 
app/models/Search.java
--- app/models/Search.java
+++ app/models/Search.java
@@ -1,14 +1,34 @@
+/**
+ * Yobi, Project Hosting SW
+ *
+ * Copyright 2014 NAVER Corp.
+ * http://yobi.io
+ *
+ * @Author Keesun Baik
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package models;
 
 import com.avaje.ebean.*;
+import models.enumeration.Operation;
 import models.enumeration.ProjectScope;
 import models.enumeration.UserState;
+import utils.AccessControl;
 
+import java.util.ArrayList;
 import java.util.List;
 
-/**
- * @author Keeun Baik
- */
 public class Search {
 
     private static final String DEFAULT_PATH_TO_PROJECT = "project";
@@ -138,20 +158,13 @@
 
     private static ExpressionList<Issue> issuesEL(String keyword, User user, Project project) {
         ExpressionList<Issue> el = Issue.finder.where().eq("project", project);
-
-        if(isAllowed(user, project)) {
-            Junction<Issue> junction = el.disjunction();
-            containsKeywordIn(keyword, junction, new String[]{"title", "body"});
-            junction.endJunction();
-        } else {
+        if(!AccessControl.isAllowed(user, project.asResource(), Operation.READ)) {
             Junction<Issue> junction = el.disjunction();
             junction.add(Expr.eq("authorId", user.id));
             junction.add(Expr.eq("assignee.user.id", user.id));
             junction.endJunction();
-            containsKeywordIn(keyword, el.conjunction(), new String[]{"title", "body"});
-
         }
-
+        containsKeywordIn(keyword, el.conjunction(), new String[]{"title", "body"});
         el.orderBy().desc("createdDate");
         return el;
     }
@@ -270,17 +283,10 @@
     private static ExpressionList<Posting> postsEL(String keyword, User user, Project project) {
         ExpressionList<Posting> el = Posting.finder.where()
                 .eq("project", project);
-
-        if(isAllowed(user, project)) {
-            Junction<Posting> junction = el.disjunction();
-            containsKeywordIn(keyword, junction, new String[]{"title", "body"});
-            junction.endJunction();
-            equalsUserTemplate(keyword, user, junction, DEFAULT_PATH_TO_AUTHOR, containsKeywordInPosting);
-        } else {
+        if(!AccessControl.isAllowed(user, project.asResource(), Operation.READ)) {
             el.eq("authorId", user.id);
-            containsKeywordIn(keyword, el.conjunction(), new String[]{"title", "body"});
         }
-
+        containsKeywordIn(keyword, el.conjunction(), new String[]{"title", "body"});
         el.orderBy().desc("createdDate");
         return el;
     }
@@ -360,7 +366,7 @@
     }
 
     /**
-     * Find all users in a {@code project} who contains the {@code keyword} in name or loginId.
+     * Finds all users in a {@code project} who contains the {@code keyword} in name or loginId.
      *
      * @param keyword
      * @param project
@@ -396,7 +402,7 @@
     }
 
     /**
-     * Find all users in an {@code organization} who contains the {@code keyword} in name or loginId.
+     * Finds all users in an {@code organization} who contains the {@code keyword} in name or loginId.
      *
      * @param keyword
      * @param organization
@@ -460,7 +466,7 @@
     }
 
     /**
-     * Find all projects in an {@code organization} that contains the {@code keyword} in name or overview.
+     * Finds all projects in an {@code organization} that contains the {@code keyword} in name or overview.
      *
      * @param keyword
      * @param user
@@ -531,10 +537,16 @@
     }
 
     public static Page<Milestone> findMilestones(String keyword, User user, Project project, PageParam pageParam) {
+        if(!AccessControl.isAllowed(user, project.asResource(), Operation.READ)) {
+            return emptyPage();
+        }
         return milestonesEL(keyword, project).findPagingList(pageParam.getSize()).getPage(pageParam.getPage());
     }
 
     public static int countMilestones(String keyword, User user, Project project) {
+        if(!AccessControl.isAllowed(user, project.asResource(), Operation.READ)) {
+            return 0;
+        }
         return milestonesEL(keyword, project).findRowCount();
     }
 
@@ -595,17 +607,10 @@
     private static ExpressionList<IssueComment> issueCommentsEL(String keyword, User user, Project project) {
         ExpressionList<IssueComment> el = IssueComment.find.where()
                 .eq("issue.project", project);
-
-        if(isAllowed(user, project)) {
-            Junction<IssueComment> junction = el.disjunction();
-            containsKeywordIn(keyword, junction, new String[]{"contents"});
-            junction.endJunction();
-            equalsUserTemplate(keyword, user, junction, DEFAULT_PATH_TO_AUTHOR, containsKeywordInIssueComment);
-        } else {
+        if(!AccessControl.isAllowed(user, project.asResource(), Operation.READ)) {
             el.eq("authorId", user.id);
-            containsKeywordIn(keyword, el.conjunction(), new String[]{"contents"});
         }
-
+        containsKeywordIn(keyword, el.conjunction(), new String[]{"contents"});
         el.orderBy().desc("createdDate");
         return el;
     }
@@ -659,16 +664,10 @@
         ExpressionList<PostingComment> el = PostingComment.find.where()
                 .eq("posting.project", project);
 
-        if(isAllowed(user, project)) {
-            Junction<PostingComment> junction = el.disjunction();
-            containsKeywordIn(keyword, junction, new String[]{"contents"});
-            junction.endJunction();
-            equalsUserTemplate(keyword, user, junction, DEFAULT_PATH_TO_AUTHOR, containsKeywordInPostComment);
-        } else {
+        if(!AccessControl.isAllowed(user, project.asResource(), Operation.READ)) {
             el.eq("authorId", user.id);
-            containsKeywordIn(keyword, el.conjunction(), new String[]{"contents"});
         }
-
+        containsKeywordIn(keyword, el.conjunction(), new String[]{"contents"});
         el.orderBy().desc("createdDate");
         return el;
     }
@@ -721,17 +720,10 @@
     private static ExpressionList<ReviewComment> reviewsEL(String keyword, User user, Project project) {
         ExpressionList<ReviewComment> el = ReviewComment.find.where()
                 .eq("thread.project", project);
-
-        if(isAllowed(user, project)) {
-            Junction<ReviewComment> junction = el.disjunction();
-            containsKeywordIn(keyword, junction, new String[]{"contents"});
-            junction.endJunction();
-            equalsUserTemplate(keyword, user, junction, "author.id", containsKeywordInReviewComment);
-        } else {
+        if(!AccessControl.isAllowed(user, project.asResource(), Operation.READ)) {
             el.eq("author.id", user.id);
-            containsKeywordIn(keyword, el.conjunction(), new String[]{"contents"});
         }
-
+        containsKeywordIn(keyword, el.conjunction(), new String[]{"contents"});
         el.orderBy().desc("createdDate");
         return el;
     }
@@ -837,10 +829,53 @@
         }
     }
 
-    private static boolean isAllowed(User user, Project project) {
-        return project.projectScope == ProjectScope.PUBLIC
-                || ProjectUser.isMember(user.id, project.id)
-                || (project.projectScope == ProjectScope.PROTECTED && OrganizationUser.exist(project.organization.id, user.id));
+    private static <T> Page<T> emptyPage() {
+        return new Page<T>() {
+            @Override
+            public List<T> getList() {
+                return new ArrayList<>();
+            }
+
+            @Override
+            public int getTotalRowCount() {
+                return 0;
+            }
+
+            @Override
+            public int getTotalPageCount() {
+                return 0;
+            }
+
+            @Override
+            public int getPageIndex() {
+                return 0;
+            }
+
+            @Override
+            public boolean hasNext() {
+                return false;
+            }
+
+            @Override
+            public boolean hasPrev() {
+                return false;
+            }
+
+            @Override
+            public Page<T> next() {
+                return null;
+            }
+
+            @Override
+            public Page<T> prev() {
+                return null;
+            }
+
+            @Override
+            public String getDisplayXtoYofZ(String s, String s2) {
+                return null;
+            }
+        };
     }
 
 }
app/models/SearchResult.java
--- app/models/SearchResult.java
+++ app/models/SearchResult.java
@@ -1,3 +1,23 @@
+/**
+ * Yobi, Project Hosting SW
+ *
+ * Copyright 2014 NAVER Corp.
+ * http://yobi.io
+ *
+ * @Author Keesun Baik
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package models;
 
 import com.avaje.ebean.Page;
@@ -8,9 +28,6 @@
 import java.util.LinkedList;
 import java.util.List;
 
-/**
- * @author Keeun Baik
- */
 public class SearchResult {
 
     private String keyword;
@@ -34,17 +51,17 @@
     private Page<PostingComment> postComments;
     private Page<ReviewComment> reviews;
 
-    public List<String> makeSnipets(String contents, int threshold) {
+    public List<String> makeSnippets(String contents, int threshold) {
         String lowerCaseContents = contents.toLowerCase();
-        String lowerCasekeyword = keyword.toLowerCase();
+        String lowerCaseKeyword = keyword.toLowerCase();
 
         LinkedList<BeginAndEnd> beginAndEnds = new LinkedList<>();
-        List<Integer> indexes = findIndexes(lowerCaseContents, lowerCasekeyword); // 6, 40
+        List<Integer> indexes = findIndexes(lowerCaseContents, lowerCaseKeyword); // 6, 40
 
         for(int i = 0 ; i < indexes.size() ; i++) {
             int currentIndex = indexes.get(i);
             int beginIndex = beginIndex(currentIndex, threshold);
-            int endIndex = endIndex(currentIndex + lowerCasekeyword.length(), lowerCaseContents.length(), threshold);
+            int endIndex = endIndex(currentIndex + lowerCaseKeyword.length(), lowerCaseContents.length(), threshold);
             BeginAndEnd thisOne = new BeginAndEnd(beginIndex, endIndex);
             if(i == 0) {
                 beginAndEnds.push(thisOne);
@@ -62,12 +79,12 @@
 
         Collections.reverse(beginAndEnds);
 
-        List<String> snipets = new ArrayList<>();
+        List<String> snippets = new ArrayList<>();
         for(BeginAndEnd bae : beginAndEnds) {
-            snipets.add(contents.substring(bae.beginIndex, bae.endIndex));
+            snippets.add(contents.substring(bae.beginIndex, bae.endIndex));
         }
 
-        return snipets;
+        return snippets;
     }
 
     private List<Integer> findIndexes(String contents, String keyword) {
app/models/enumeration/SearchType.java
--- app/models/enumeration/SearchType.java
+++ app/models/enumeration/SearchType.java
@@ -5,7 +5,7 @@
  */
 public enum SearchType {
 
-    NA("not availeable"), USER("user"), PROJECT("project"), ISSUE("issue"), POST("post"),
+    NA("not available"), USER("user"), PROJECT("project"), ISSUE("issue"), POST("post"),
     MILESTONE("milestone"), ISSUE_COMMENT("issue_comment"), POST_COMMENT("post_comment"), REVIEW("review");
 
     private String searchType;
app/views/common/navbar.scala.html
--- app/views/common/navbar.scala.html
+++ app/views/common/navbar.scala.html
@@ -32,11 +32,11 @@
 
 @makeSearchLink() = @{
     if(project != null) {
-        routes.SearchApp.searchProject(project.owner, project.name)
+        routes.SearchApp.searchInAProject(project.owner, project.name)
     } else if (org !=null) {
-        routes.SearchApp.searchGroupRepos(org.name)
+        routes.SearchApp.searchInAGroup(org.name)
     } else {
-        routes.SearchApp.searchAllRepos()
+        routes.SearchApp.searchInAll()
     }
 }
 
@@ -79,13 +79,13 @@
                         <ul class="dropdown-menu flat right">
                             @if(project != null) {
                             <li>
-                                <a href="#" data-toggle="search-scope" data-action="@routes.SearchApp.searchProject(project.owner, project.name)">
+                                <a href="#" data-toggle="search-scope" data-action="@routes.SearchApp.searchInAProject(project.owner, project.name)">
                                     @Messages("search.scope.porject")
                                 </a>
                             </li>
                             @if(project.hasGroup) {
                             <li>
-                                <a href="#" data-toggle="search-scope" data-action="@routes.SearchApp.searchGroupRepos(project.owner)">
+                                <a href="#" data-toggle="search-scope" data-action="@routes.SearchApp.searchInAGroup(project.owner)">
                                     @Messages("search.scope.group")
                                 </a>
                             </li>
@@ -93,13 +93,13 @@
                             } 
                             @if(org != null) {
                             <li>
-                                <a href="#" data-toggle="search-scope" data-action="@routes.SearchApp.searchGroupRepos(org.name)">
+                                <a href="#" data-toggle="search-scope" data-action="@routes.SearchApp.searchInAGroup(org.name)">
                                     @Messages("search.scope.group")
                                 </a>
                             </li>
                             }
                             <li>
-                                <a href="#" data-toggle="search-scope" data-action="@routes.SearchApp.searchAllRepos()">
+                                <a href="#" data-toggle="search-scope" data-action="@routes.SearchApp.searchInAll()">
                                     @Messages("search.scope.all")
                                 </a>
                             </li>
app/views/organizationLayout.scala.html
--- app/views/organizationLayout.scala.html
+++ app/views/organizationLayout.scala.html
@@ -1,7 +1,7 @@
 @**
 * Yobi, Project Hosting SW
 *
-* Copyright 2013 NAVER Corp.
+* Copyright 2014 NAVER Corp.
 * http://yobi.io
 *
 * @Author Insanehong
app/views/search/partial_issue_comments.scala.html
--- app/views/search/partial_issue_comments.scala.html
+++ app/views/search/partial_issue_comments.scala.html
@@ -29,29 +29,21 @@
     <ul class="search-list-wrap">
         @for(comment <- page.getList) {
             @defining(User.findByLoginId(comment.authorLoginId)){ user =>
-            <li class="search-list-item @if(project != null) {project}">
-                @if(project == null) {
-                <a href="@routes.ProjectApp.project(comment.issue.project.owner, comment.issue.project.name)" class="avatar-wrap">
-                    <img src="@urlToProjectLogo(comment.issue.project)">
-                </a>
-                }
+            <li class="search-list-item">
                 <div class="title-wrap">
-                    <span class="state @comment.issue.state.state.toLowerCase">@Messages("issue.state." + comment.issue.state.state.toLowerCase)</span>
                     <span class="post-id">#@comment.issue.getNumber</span>
                     <a href="@routes.IssueApp.issue(comment.issue.project.owner, comment.issue.project.name, comment.issue.getNumber)#comment-@comment.id">
                         Re) @comment.issue.title
                     </a>
                 </div>
                 <div class="search-content">
-                   @defining(searchResult.makeSnipets(comment.contents, 40)) { snipets =>
-                        @if(snipets != null && snipets.size > 0) {
-                            @for(snipet <- snipets) {
-                            <p class="search-content-body">
-                                @snipet @if(snipet.size < comment.contents.size) { ..... }
-                            </p>
-                            }
-                        }
-                    }                        
+               @defining(searchResult.makeSnippets(comment.contents, 40)) { snippets =>
+                    @for(snippet <- snippets) {
+                    <p class="search-content-body">
+                        @snippet @if(snippet.size < comment.contents.size) { ..... }
+                    </p>
+                    }
+                }
                 </div>
                 <div class="search-meta-info">
                     @if(project == null) {
@@ -59,13 +51,6 @@
                         @comment.issue.project.owner/@comment.issue.project.name
                     </a>
                     }
-                    <a href="@routes.UserApp.userInfo(user.loginId)" class="avatar-wrap meta" data-toggle="tooltip" data-placement="top" title="@user.loginId">
-                        @if(user.avatarUrl == UserApp.DEFAULT_AVATAR_URL){
-                            <img src="@urlToPicture(user.email, 16)">
-                        } else {
-                            <img src="@user.avatarUrl" alt="@user.name" width="16" height="16"/>
-                        }
-                    </a>
                     @if(user.name){
                         <a href="@routes.UserApp.userInfo(user.loginId)" class="meta-item" data-toggle="tooltip" data-placement="top" title="@user.loginId">
                             @user.name
app/views/search/partial_issues.scala.html
--- app/views/search/partial_issues.scala.html
+++ app/views/search/partial_issues.scala.html
@@ -31,29 +31,21 @@
     <ul class="search-list-wrap">
         @for(issue <- page.getList) {
             @defining(User.findByLoginId(issue.authorLoginId)){ user =>
-            <li class="search-list-item @if(project != null) {project}">
-                @if(project == null) {
-                <a href="@routes.ProjectApp.project(issue.project.owner, issue.project.name)" class="avatar-wrap">
-                    <img src="@urlToProjectLogo(issue.project)">
-                </a>
-                }
+            <li class="search-list-item">
                 <div class="title-wrap">
-                     <span class="state @issue.state.state.toLowerCase">@Messages("issue.state." + issue.state.state.toLowerCase)</span>
                     <span class="post-id">#@issue.getNumber</span>
                     <a href="@routes.IssueApp.issue(issue.project.owner, issue.project.name, issue.getNumber)" class="title">
                         @issue.title
                     </a>
                 </div>
                 <div class="search-content">
-                    @defining(searchResult.makeSnipets(issue.body, 40)) { snipets =>
-                        @if(snipets != null && snipets.size > 0) {
-                            @for(snipet <- snipets) {
-                            <p class="search-content-body">
-                                @snipet @if(snipet.size < issue.body.size) { ..... }
-                            </p>
-                            }
-                        }
+                @defining(searchResult.makeSnippets(issue.body, 40)) { snippets =>
+                    @for(snippet <- snippets) {
+                    <p class="search-content-body">
+                        @snippet @if(snippet.size < issue.body.size) { ..... }
+                    </p>
                     }
+                }
                 </div>
                 <div class="search-meta-info">
                     @if(project == null) {
@@ -61,13 +53,6 @@
                         @issue.project.owner/@issue.project.name
                     </a>
                     }
-                    <a href="@routes.UserApp.userInfo(user.loginId)" class="avatar-wrap meta" data-toggle="tooltip" data-placement="top" title="@user.loginId">
-                        @if(user.avatarUrl == UserApp.DEFAULT_AVATAR_URL){
-                            <img src="@urlToPicture(user.email, 16)">
-                        } else {
-                            <img src="@user.avatarUrl" alt="@user.name" width="16" height="16"/>
-                        }
-                    </a>
                     @if(user.name){
                         <a href="@routes.UserApp.userInfo(user.loginId)" class="meta-item" data-toggle="tooltip" data-placement="top" title="@user.loginId">
                             @user.name
app/views/search/partial_milestones.scala.html
--- app/views/search/partial_milestones.scala.html
+++ app/views/search/partial_milestones.scala.html
@@ -37,26 +37,18 @@
     @if(page.getList.length > 0) {
     <ul class="search-list-wrap">
         @for(milestone <- page.getList) {
-        <li class="search-list-item @if(project != null) {project}">
-            @if(project == null) {
-            <a href="@routes.ProjectApp.project(milestone.project.owner, milestone.project.name)" class="avatar-wrap">
-                <img src="@urlToProjectLogo(milestone.project)">
-            </a>
-            }
+        <li class="search-list-item">
             <div class="title-wrap">
-                 <span class="state @milestone.state.state.toLowerCase">@Messages("milestone.state." + milestone.state.state.toLowerCase)</span>
                 <a href="@routes.MilestoneApp.milestone(milestone.project.owner, milestone.project.name, milestone.id)" class="title">
                     @milestone.title
                 </a>
             </div>
             <div class="search-content">
-                @defining(searchResult.makeSnipets(milestone.contents, 40)) { snipets =>
-                    @if(snipets != null && snipets.size > 0) {
-                        @for(snipet <- snipets) {
-                        <p class="search-content-body">
-                            @snipet @if(snipet.size < milestone.contents.size) { ..... }
-                        </p>
-                        }
+                @defining(searchResult.makeSnippets(milestone.contents, 40)) { snippets =>
+                    @for(snippet <- snippets) {
+                    <p class="search-content-body">
+                        @snippet @if(snippet.size < milestone.contents.size) { ..... }
+                    </p>
                     }
                 }
             </div>
app/views/search/partial_post_comments.scala.html
--- app/views/search/partial_post_comments.scala.html
+++ app/views/search/partial_post_comments.scala.html
@@ -29,12 +29,7 @@
     <ul class="search-list-wrap">
         @for(comment <- page.getList) {
             @defining(User.findByLoginId(comment.authorLoginId)){ user =>
-            <li class="search-list-item @if(project != null) {project}">
-                @if(project == null) {
-                <a href="@routes.ProjectApp.project(comment.posting.project.owner, comment.posting.project.name)" class="avatar-wrap">
-                    <img src="@urlToProjectLogo(comment.posting.project)">
-                </a>
-                }
+            <li class="search-list-item">
                 <div class="title-wrap">
                     <span class="post-id">#@comment.posting.getNumber</span>
                     <a href="@routes.BoardApp.post(comment.posting.project.owner, comment.posting.project.name, comment.posting.getNumber)#comment-@comment.id">
@@ -42,15 +37,13 @@
                     </a>
                 </div>
                 <div class="search-content">
-                   @defining(searchResult.makeSnipets(comment.contents, 40)) { snipets =>
-                        @if(snipets != null && snipets.size > 0) {
-                            @for(snipet <- snipets) {
-                            <p class="search-content-body">
-                                @snipet @if(snipet.size < comment.contents.size) { ..... }
-                            </p>
-                            }
-                        }
-                    }                        
+                @defining(searchResult.makeSnippets(comment.contents, 40)) { snippets =>
+                    @for(snippet <- snippets) {
+                    <p class="search-content-body">
+                        @snippet @if(snippet.size < comment.contents.size) { ..... }
+                    </p>
+                    }
+                }
                 </div>
                 <div class="search-meta-info">
                     @if(project == null) {
@@ -58,13 +51,6 @@
                         @comment.posting.project.owner/@comment.posting.project.name
                     </a>
                     }
-                    <a href="@routes.UserApp.userInfo(user.loginId)" class="avatar-wrap meta" data-toggle="tooltip" data-placement="top" title="@user.loginId">
-                        @if(user.avatarUrl == UserApp.DEFAULT_AVATAR_URL){
-                            <img src="@urlToPicture(user.email, 16)">
-                        } else {
-                            <img src="@user.avatarUrl" alt="@user.name" width="16" height="16"/>
-                        }
-                    </a>
                     @if(user.name){
                         <a href="@routes.UserApp.userInfo(user.loginId)" class="meta-item" data-toggle="tooltip" data-placement="top" title="@user.loginId">
                             @user.name
app/views/search/partial_posts.scala.html
--- app/views/search/partial_posts.scala.html
+++ app/views/search/partial_posts.scala.html
@@ -29,12 +29,7 @@
     <ul class="search-list-wrap">
         @for(post <- page.getList) {
             @defining(User.findByLoginId(post.authorLoginId)){ user =>
-            <li class="search-list-item @if(project != null) {project}">
-                @if(project == null) {
-                <a href="@routes.ProjectApp.project(post.project.owner, post.project.name)" class="avatar-wrap">
-                    <img src="@urlToProjectLogo(post.project)">
-                </a>
-                }
+            <li class="search-list-item">
                 <div class="title-wrap">
                     <span class="post-id">#@post.getNumber</span>
                     <a href="@routes.BoardApp.post(post.project.owner, post.project.name, post.getNumber)" class="title">
@@ -42,15 +37,13 @@
                     </a>
                 </div>
                 <div class="search-content">
-                    @defining(searchResult.makeSnipets(post.body, 40)) { snipets =>
-                        @if(snipets != null && snipets.size > 0) {
-                            @for(snipet <- snipets) {
-                            <p class="search-content-body">
-                                @snipet @if(snipet.size < post.body.size) { ..... }
-                            </p>
-                            }
-                        }
+                @defining(searchResult.makeSnippets(post.body, 40)) { snippets =>
+                    @for(snippet <- snippets) {
+                    <p class="search-content-body">
+                        @snippet @if(snippet.size < post.body.size) { ..... }
+                    </p>
                     }
+                }
                 </div>
                 <div class="search-meta-info">
                     @if(project == null) {
@@ -58,13 +51,6 @@
                         @post.project.owner/@post.project.name
                     </a>
                     }
-                    <a href="@routes.UserApp.userInfo(user.loginId)" class="avatar-wrap meta" data-toggle="tooltip" data-placement="top" title="@user.loginId">
-                        @if(user.avatarUrl == UserApp.DEFAULT_AVATAR_URL){
-                            <img src="@urlToPicture(user.email, 32)">
-                        } else {
-                            <img src="@user.avatarUrl" alt="@user.name" width="32" height="32"/>
-                        }
-                    </a>
                     @if(user.name){
                         <a href="@routes.UserApp.userInfo(user.loginId)" class="meta-item" data-toggle="tooltip" data-placement="top" title="@user.loginId">
                             @user.name
app/views/search/partial_projects.scala.html
--- app/views/search/partial_projects.scala.html
+++ app/views/search/partial_projects.scala.html
@@ -29,7 +29,7 @@
     <ul class="search-list-wrap">
         @for(project <- page.getList) {
             @defining(User.findByLoginId(project.owner)){ user =>
-            <li class="search-list-item">
+            <li class="search-list-item project">
                 <a href="@routes.ProjectApp.project(project.owner, project.name)" class="avatar-wrap">
                     <img src="@urlToProjectLogo(project)">
                 </a>
@@ -39,7 +39,7 @@
                     </a>
                 </div>
                 @if(project.isForkedFromOrigin){
-                <div class="search-meta-info nm">
+                <div class="search-meta-info nm np">
                     <span>
                        <i class="yobicon-split yobicon-white vmiddle"></i>
                         @Messages("fork.original")
@@ -51,12 +51,12 @@
                     </span>
                 </div>
                 }
-                <div class="search-content">
+                <div class="search-content np">
                     <p class="search-content-body">
                         @project.overview
                     </p>
                  </div>
-                 <div class="search-meta-info">
+                 <div class="search-meta-info np">
                     <span class="meta-info">
                         @Messages("project.create")
                         <strong title="@getDateString(project.createdDate)">@agoOrDateString(project.createdDate)</strong>
app/views/search/partial_reviews.scala.html
--- app/views/search/partial_reviews.scala.html
+++ app/views/search/partial_reviews.scala.html
@@ -29,31 +29,35 @@
     @if(page.getList.length > 0) {
     <ul class="search-list-wrap">
         @for(review <- page.getList) {
-            <li class="search-list-item @if(project != null) {project}">
+            <li class="search-list-item">
             @defining(User.findByLoginId(review.author.loginId)){ user =>
-                @if(review.thread.pullRequest != null) {
-                @if(project == null) {
-                <a href="@routes.ProjectApp.project(review.thread.project.owner, review.thread.project.name)" class="avatar-wrap">
-                    <img src="@urlToProjectLogo(review.thread.project)">
-                </a>
-                }
+                @if(review.thread.isOnPullRequest()) {
                 <div class="title-wrap">
                     <span class="post-id">#@review.thread.pullRequest.number</span>
                     <a href="@DiffRenderer.urlToCommentThread(review.thread)">
                         Re) @review.thread.pullRequest.title
                     </a>
                 </div>
-                }
+                } 
                 <div class="search-content">
-                   @defining(searchResult.makeSnipets(review.getContents, 40)) { snipets =>
-                        @if(snipets != null && snipets.size > 0) {
-                            @for(snipet <- snipets) {
+               @defining(searchResult.makeSnippets(review.getContents, 40)) { snippets =>
+                    @if(review.thread.isOnPullRequest()) {
+                        @for(snippet <- snippets) {
                             <p class="search-content-body">
-                                @snipet @if(snipet.size < review.getContents.size) { ..... }
+                                @snippet @if(snippet.size < review.getContents.size) { ..... }
                             </p>
-                            }
                         }
-                    }                        
+                    } else {
+                        <a href="@DiffRenderer.urlToCommentThread(review.thread)">
+                        @for(snippet <- snippets) {
+                            <p class="search-content-body">
+                                @snippet @if(snippet.size < review.getContents.size) { ..... }
+                            </p>
+                        }
+                        </a>
+                    }
+                    
+                }                        
                 </div>
                 <div class="search-meta-info">
                     @if(project == null) {
@@ -61,13 +65,6 @@
                         @review.thread.project.owner/@review.thread.project.name
                     </a>
                     }
-                    <a href="@routes.UserApp.userInfo(user.loginId)" class="avatar-wrap meta" data-toggle="tooltip" data-placement="top" title="@user.loginId">
-                        @if(user.avatarUrl == UserApp.DEFAULT_AVATAR_URL){
-                            <img src="@urlToPicture(user.email, 16)">
-                        } else {
-                            <img src="@user.avatarUrl" alt="@user.name" width="16" height="16"/>
-                        }
-                    </a>
                     @if(user.name){
                         <a href="@routes.UserApp.userInfo(user.loginId)" class="meta-item" data-toggle="tooltip" data-placement="top" title="@user.loginId">
                             @user.name
@@ -95,4 +92,4 @@
     } else {
         <div class="empty-result"></div>
     }
-}
(No newline at end of file)
+}
app/views/search/partial_search.scala.html
--- app/views/search/partial_search.scala.html
+++ app/views/search/partial_search.scala.html
@@ -27,14 +27,41 @@
 
 @makeSearchLink() = @{
     if(project != null) {
-        routes.SearchApp.searchProject(project.owner, project.name)
+        routes.SearchApp.searchInAProject(project.owner, project.name)
     } else if (group !=null) {
-        routes.SearchApp.searchGroupRepos(group.name)
+        routes.SearchApp.searchInAGroup(group.name)
     } else {
-        routes.SearchApp.searchAllRepos()
+        routes.SearchApp.searchInAll()
     }
 }
 
+@makeTilte(search_type:SearchType) =@{
+    search_type match {
+        case SearchType.ISSUE => { Messages("search.menu.issues") }
+        case SearchType.USER => { Messages("search.menu.users") }
+        case SearchType.PROJECT => { Messages("search.menu.projects") }
+        case SearchType.POST => { Messages("search.menu.boards") }
+        case SearchType.MILESTONE => { Messages("search.menu.milestones") }
+        case SearchType.ISSUE_COMMENT => { Messages("search.menu.issue.comments") }
+        case SearchType.POST_COMMENT => { Messages("search.menu.board.comments") }
+        case SearchType.REVIEW => { Messages("search.menu.reviews") }  
+        case SearchType.NA => { }
+    }
+}
+
+@getCurrentlySearchCount(search_type:SearchType) =@{
+    search_type match {
+        case SearchType.ISSUE => { searchResult.getIssuesCount }
+        case SearchType.USER => { searchResult.getUsersCount }
+        case SearchType.PROJECT => { searchResult.getProjectsCount }
+        case SearchType.POST => { searchResult.getPostsCount }
+        case SearchType.MILESTONE => { searchResult.getMilestonesCount }
+        case SearchType.ISSUE_COMMENT => { searchResult.getIssueCommentsCount }
+        case SearchType.POST_COMMENT => { searchResult.getPostCommentsCount }
+        case SearchType.REVIEW => { searchResult.getReviewsCount }  
+        case SearchType.NA => { }
+    }
+}
 <div class="site-breadcrumb-outer">
     <div class="site-breadcrumb-inner">
         <h3>
@@ -107,6 +134,10 @@
                             <input type="text" name="keyword" class="span11" value="@searchResult.getKeyword()">
                             <button type="submit" class="ybtn">@Messages("title.search")</button>
                         </form>
+                        
+                        <h3 class="search-result-title">
+                            @Html(Messages("search.result.title", getCurrentlySearchCount(searchResult.getSearchType()),makeTilte(searchResult.getSearchType())))
+                        </h3>
                     </div>
                     <div class="search-result-wrap">
                         @if(searchResult.getSearchType() == SearchType.ISSUE) {
@@ -164,4 +195,4 @@
         $(this).html(content);
     })
 });
-</script>
(No newline at end of file)
+</script>
app/views/search/partial_users.scala.html
--- app/views/search/partial_users.scala.html
+++ app/views/search/partial_users.scala.html
@@ -28,7 +28,7 @@
     @if(page.getList.length > 0) {
     <ul class="search-list-wrap">
         @for(user <- page.getList) {
-            <li class="search-list-item">
+            <li class="search-list-item project">
             <a href="@routes.UserApp.userInfo(user.loginId)" class="avatar-wrap" data-toggle="tooltip" data-placement="top" title="@user.loginId">
             @if(user.avatarUrl == UserApp.DEFAULT_AVATAR_URL){
                 <img src="@urlToPicture(user.email, 32)">
conf/messages
--- conf/messages
+++ conf/messages
@@ -666,6 +666,7 @@
 search.menu.projects = projects
 search.menu.reviews = Code Reviews
 search.menu.users =  Users
+search.result.title = Found <strong>{0}</strong> result(s) in {1}
 search.scope.all = All Projects
 search.scope.group = This Group
 search.scope.porject = This Project
conf/messages.ko
--- conf/messages.ko
+++ conf/messages.ko
@@ -666,6 +666,7 @@
 search.menu.projects = 프로젝트
 search.menu.reviews = 코드 리뷰
 search.menu.users =  사용자
+search.result.title = {1}에서 <strong>{0}</strong> 건이 검색 되었습니다
 search.scope.all = 모든 프로젝트
 search.scope.group = 현재 그룹
 search.scope.porject = 현재 프로젝트
conf/routes
--- conf/routes
+++ conf/routes
@@ -19,7 +19,7 @@
 GET            /UIKit                                                                 controllers.Application.UIKit()
 
 # Search
-GET            /search                                                                controllers.SearchApp.searchAllRepos()
+GET            /search                                                                controllers.SearchApp.searchInAll()
 
 # Import
 GET            /import                                                                controllers.ImportApp.importForm()
@@ -36,7 +36,7 @@
 POST           /organizations/:organizationName/member/:userId/edit                   controllers.OrganizationApp.editMember(organizationName: String, userId: Long)
 DELETE         /organizations/:organizationName/member/:userId/delete                 controllers.OrganizationApp.deleteMember(organizationName: String, userId: Long)
 DELETE         /organizations/:organizationName/member/leave                          controllers.OrganizationApp.leave(organizationName: String)
-GET            /organizations/:organizationName/search                                controllers.SearchApp.searchGroupRepos(organizationName)
+GET            /organizations/:organizationName/search                                controllers.SearchApp.searchInAGroup(organizationName)
 
 # Enrolling Organization
 POST           /organizations/:organizationName/enroll                                controllers.EnrollOrganizationApp.enroll(organizationName)
@@ -139,7 +139,7 @@
 GET            /:user/:project/transfer                                               controllers.ProjectApp.transferForm(user, project)
 PUT            /:user/:project/transfer                                               controllers.ProjectApp.transferProject(user, project)
 GET            /project/transfer/:id/:key                                             controllers.ProjectApp.acceptTransfer(id: Long, key)
-GET            /:user/:project/search                                                 controllers.SearchApp.searchProject(user, project)
+GET            /:user/:project/search                                                 controllers.SearchApp.searchInAProject(user, project)
 
 # Project Review Menu
 GET            /:user/:project/reviews                                                controllers.ReviewThreadApp.reviewThreads(user, project)
conf/test-data.yml
--- conf/test-data.yml
+++ conf/test-data.yml
@@ -3,7 +3,6 @@
     - !!models.User
         name:           Yobi
         loginId:        yobi
-        state:          ACTIVE
         password:       ys9gr1Xet/DL9RpmgczOlJg+txPvqnZCaw/z55gb0KU=
         passwordSalt:   '[B@1032a4'
         state:          ACTIVE
test/models/SearchResultTests.java
--- test/models/SearchResultTests.java
+++ test/models/SearchResultTests.java
@@ -20,7 +20,7 @@
         searchResult.setKeyword(keyword);
 
         // When
-        List<String> snipets = searchResult.makeSnipets(contents, 10);
+        List<String> snipets = searchResult.makeSnippets(contents, 10);
 
         // Then
         assertThat(snipets.size()).isEqualTo(1);
@@ -36,7 +36,7 @@
         searchResult.setKeyword(keyword);
 
         // When
-        List<String> snipets = searchResult.makeSnipets(contents, 40);
+        List<String> snipets = searchResult.makeSnippets(contents, 40);
 
         // Then
         assertThat(snipets.size()).isEqualTo(2);
test/models/SearchTests.java
--- test/models/SearchTests.java
+++ test/models/SearchTests.java
@@ -2,57 +2,63 @@
 
 import models.enumeration.ProjectScope;
 import models.enumeration.RoleType;
-import org.junit.Before;
-import org.junit.Test;
+import org.junit.*;
+import play.test.FakeApplication;
+import play.test.Helpers;
 
 import java.util.HashSet;
 import java.util.List;
 
 import static org.fest.assertions.Assertions.assertThat;
 
-public class SearchTests extends ModelTest<Search> {
+public class SearchTests {
 
-    private Organization labs;
-    private Project publicProject; // labs's project
-    private Project protectedProject; // labs's project
-    private Project privateProject; // labs's project
+    private static Organization labs;
+    private static Project publicProject; // labs's project
+    private static Project protectedProject; // labs's project
+    private static Project privateProject; // labs's project
 
-    private User author; // author of a privateProject's post and issue
-    private User projectMember; // member of a privateProject
-    private User groupMember; // member of labs
-    private User groupAndProjectMember; // member of a privateProject and member of labs
-    private User assignee; // assignee of all issues
+    private static User author; // author of a privateProject's post and issue
+    private static User projectMember; // member of a privateProject
+    private static User groupMember; // member of labs
+    private static User groupAndProjectMember; // member of a privateProject and member of labs
+    private static User assignee; // assignee of all issues
 
-    private Posting publicPost;
-    private Posting protectedPost;
-    private Posting privatePost;
+    private static Posting publicPost;
+    private static Posting protectedPost;
+    private static Posting privatePost;
 
-    private Issue privateIssue;
-    private Issue publicIssue;
-    private Issue protectedIssue;
+    private static Issue privateIssue;
+    private static Issue publicIssue;
+    private static Issue protectedIssue;
 
-    private Milestone publicMilestone;
-    private Milestone protectedMilestone;
-    private Milestone privateMilestone;
+    private static Milestone publicMilestone;
+    private static Milestone protectedMilestone;
+    private static Milestone privateMilestone;
 
-    private IssueComment publicIssueComment;
-    private IssueComment protectedIssueComment;
-    private IssueComment privateIssueComment;
+    private static IssueComment publicIssueComment;
+    private static IssueComment protectedIssueComment;
+    private static IssueComment privateIssueComment;
 
-    private PostingComment publicPostComment;
-    private PostingComment protectedPostComment;
-    private PostingComment privatePostComment;
+    private static PostingComment publicPostComment;
+    private static PostingComment protectedPostComment;
+    private static PostingComment privatePostComment;
 
-    private ReviewComment publicReviewComment;
-    private ReviewComment protectedReviewComment;
-    private ReviewComment privateReviewComment;
+    private static ReviewComment publicReviewComment;
+    private static ReviewComment protectedReviewComment;
+    private static ReviewComment privateReviewComment;
 
     private PageParam onePageFiveSize = new PageParam(0, 5);
 
-    @Before
-    public void setUp() {
+    protected static FakeApplication app;
+
+    @BeforeClass
+    public static void startApp() {
+        app = support.Helpers.makeTestApplication();
+        Helpers.start(app);
+
         // Given
-        author = User.find.byId(1l);
+        author = User.find.byId(6l);
         groupAndProjectMember = User.find.byId(2l);
         projectMember = User.find.byId(3l);
         groupMember = User.find.byId(4l);
@@ -189,6 +195,11 @@
         privateReviewComment.thread = privateCommentThread;
         privateReviewComment.author = new UserIdent(author);
         privateReviewComment.save();
+    }
+
+    @AfterClass
+    public static void stopApp() {
+        Helpers.stop(app);
     }
 
     /**
@@ -1607,4 +1618,4 @@
         assertThat(reviews).onProperty("contents").contains("private review");
     }
 
-}
(No newline at end of file)
+}
Add a comment
List