From 1da2262efd272a4cf086f1cf1a033699a43df857 Mon Sep 17 00:00:00 2001
From: dreis <christoph.dreis@innogames.de>
Date: Fri, 11 Jul 2014 18:29:51 +0200
Subject: [PATCH] Added public groups area to enhance searching and exploring
 of projects

fixed whitespaces and quotes

fixed whitespaces

fixed devise.html.haml

fixed method parenthesis in app/models/group.rb

removed links from header

removed links from devise.html

added tests
---
 app/controllers/public/groups_controller.rb | 14 +++++
 app/models/group.rb                         | 16 ++++++
 app/views/layouts/public_groups.html.haml   | 11 ++++
 app/views/public/groups/index.html.haml     | 59 +++++++++++++++++++++
 config/routes.rb                            |  1 +
 features/public/public_groups.feature       | 32 +++++++++++
 features/steps/shared/group.rb              |  8 +++
 features/steps/shared/paths.rb              |  8 +++
 8 files changed, 149 insertions(+)
 create mode 100644 app/controllers/public/groups_controller.rb
 create mode 100644 app/views/layouts/public_groups.html.haml
 create mode 100644 app/views/public/groups/index.html.haml

diff --git a/app/controllers/public/groups_controller.rb b/app/controllers/public/groups_controller.rb
new file mode 100644
index 00000000000..7eb159c577d
--- /dev/null
+++ b/app/controllers/public/groups_controller.rb
@@ -0,0 +1,14 @@
+class Public::GroupsController < ApplicationController
+  skip_before_filter :authenticate_user!,
+                     :reject_blocked, :set_current_user_for_observers,
+                     :add_abilities
+
+  layout "public_groups"
+
+  def index
+    @groups = GroupsFinder.new.execute(current_user)
+    @groups = @groups.search(params[:search]) if params[:search].present?
+    @groups = @groups.sort(@sort = params[:sort])
+    @groups = @groups.page(params[:page]).per(20)
+  end
+end
diff --git a/app/models/group.rb b/app/models/group.rb
index 3a5c5e11354..66239f7fe6f 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -73,4 +73,20 @@ class Group < Namespace
   def public_profile?
     projects.public_only.any?
   end
+
+  class << self
+    def search(query)
+      where("LOWER(namespaces.name) LIKE :query", query: "%#{query.downcase}%")
+    end
+
+    def sort(method)
+      case method.to_s
+      when "newest" then reorder("namespaces.created_at DESC")
+      when "oldest" then reorder("namespaces.created_at ASC")
+      when "recently_updated" then reorder("namespaces.updated_at DESC")
+      when "last_updated" then reorder("namespaces.updated_at ASC")
+      else reorder("namespaces.path, namespaces.name ASC")
+      end
+    end
+  end
 end
diff --git a/app/views/layouts/public_groups.html.haml b/app/views/layouts/public_groups.html.haml
new file mode 100644
index 00000000000..bfa37b067b9
--- /dev/null
+++ b/app/views/layouts/public_groups.html.haml
@@ -0,0 +1,11 @@
+!!! 5
+%html{ lang: "en"}
+  = render "layouts/head", title: "Public Groups"
+  %body{class: "#{app_theme} application", :'data-page' => body_data_page}
+    = render "layouts/broadcast"
+    - if current_user
+      = render "layouts/head_panel", title: "Public Groups"
+    - else
+      = render "layouts/public_head_panel", title: "Public Groups"
+    .container.navless-container
+      .content= yield
diff --git a/app/views/public/groups/index.html.haml b/app/views/public/groups/index.html.haml
new file mode 100644
index 00000000000..7a2e5737804
--- /dev/null
+++ b/app/views/public/groups/index.html.haml
@@ -0,0 +1,59 @@
+%h3.page-title
+  Groups (#{@groups.total_count})
+
+%p.light
+  Group allows you to keep projects organized.
+  Use groups for uniting related projects.
+
+%hr
+.clearfix
+  .pull-left
+    = form_tag public_groups_path, method: :get, class: 'form-inline form-tiny' do |f|
+      .form-group
+        = search_field_tag :search, params[:search], placeholder: "Filter by name", class: "form-control search-text-input input-mn-300", id: "groups_search"
+      .form-group
+        = submit_tag 'Search', class: "btn btn-primary wide"
+
+  .pull-right
+    .dropdown.inline
+      %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+        %span.light sort:
+        - if @sort.present?
+          = @sort.humanize
+        - else
+          Name
+        %b.caret
+      %ul.dropdown-menu
+        %li
+          = link_to public_groups_path(sort: nil) do
+            Name
+          = link_to public_groups_path(sort: 'newest') do
+            Newest
+          = link_to public_groups_path(sort: 'oldest') do
+            Oldest
+          = link_to public_groups_path(sort: 'recently_updated') do
+            Recently updated
+          = link_to public_groups_path(sort: 'last_updated') do
+            Last updated
+
+%hr
+
+%ul.bordered-list
+  - @groups.each do |group|
+    %li
+      .clearfix
+        %h4
+          = link_to group_path(id: group.path) do
+            %i.icon-group
+            = group.name
+      .clearfix
+        %p
+          = truncate group.description, length: 150
+      .clearfix
+        %p.light
+          #{pluralize(group.members.size, 'member')}, #{pluralize(group.projects.count, 'project')}
+  - unless @groups.present?
+    .nothing-here-block No public groups
+
+
+= paginate @groups, theme: "gitlab"
diff --git a/config/routes.rb b/config/routes.rb
index 244cb339898..ebae54c5d81 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -51,6 +51,7 @@ Gitlab::Application.routes.draw do
   #
   namespace :public do
     resources :projects, only: [:index]
+    resources :groups, only: [:index]
     root to: "projects#index"
   end
 
diff --git a/features/public/public_groups.feature b/features/public/public_groups.feature
index 8bbda8cb6d4..ff3e1e3e955 100644
--- a/features/public/public_groups.feature
+++ b/features/public/public_groups.feature
@@ -117,3 +117,35 @@ Feature: Public Projects Feature
     And I visit group "TestGroup" members page
     Then I should see group member "John Doe"
     And I should not see member roles
+
+  Scenario: I should see group with public project in public groups area
+    Given group "TestGroup" has public project "Community"
+    When I visit the public groups area
+    Then I should see group "TestGroup"
+
+  Scenario: I should not see group with internal project in public groups area
+    Given group "TestGroup" has internal project "Internal"
+    When I visit the public groups area
+    Then I should not see group "TestGroup"
+
+  Scenario: I should not see group with private project in public groups area
+    When I visit the public groups area
+    Then I should not see group "TestGroup"
+
+  Scenario: I should see group with public project in public groups area as user
+    Given group "TestGroup" has public project "Community"
+    When I sign in as a user
+    And I visit the public groups area
+    Then I should see group "TestGroup"
+
+  Scenario: I should see group with internal project in public groups area as user
+    Given group "TestGroup" has internal project "Internal"
+    When I sign in as a user
+    And I visit the public groups area
+    Then I should see group "TestGroup"
+
+  Scenario: I should not see group with private project in public groups area as user
+    When I sign in as a user
+    And I visit the public groups area
+    Then I should not see group "TestGroup"
+
diff --git a/features/steps/shared/group.rb b/features/steps/shared/group.rb
index 6b4c47312a7..1b225dd61a6 100644
--- a/features/steps/shared/group.rb
+++ b/features/steps/shared/group.rb
@@ -21,6 +21,14 @@ module SharedGroup
     is_member_of("Mary Jane", "Guest", Gitlab::Access::GUEST)
   end
 
+  step 'I should see group "TestGroup"' do
+    page.should have_content "TestGroup"
+  end
+
+  step 'I should not see group "TestGroup"' do
+    page.should_not have_content "TestGroup"
+  end
+
   protected
 
   def is_member_of(username, groupname, role)
diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb
index 2090b642059..d92c70c952e 100644
--- a/features/steps/shared/paths.rb
+++ b/features/steps/shared/paths.rb
@@ -331,6 +331,14 @@ module SharedPaths
     visit public_project_path(Project.find_by(name: "Community"))
   end
 
+  # ----------------------------------------
+  # Public Groups
+  # ----------------------------------------
+
+  step 'I visit the public groups area' do
+    visit public_groups_path
+  end
+
   # ----------------------------------------
   # Snippets
   # ----------------------------------------
-- 
GitLab