Commit dd8dd92e authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'api-default-order' into 'master'

Sorting refactoring

* refactor sorting logic for web UI
* refactor and document ordering for API: project, issues, merge requests
* explicitly define ordering in models using default_scope

See merge request !1476
parents 6b61c904 ce0811ae
class Admin::DashboardController < Admin::ApplicationController class Admin::DashboardController < Admin::ApplicationController
def index def index
@projects = Project.order("created_at DESC").limit(10) @projects = Project.limit(10)
@users = User.order("created_at DESC").limit(10) @users = User.limit(10)
@groups = Group.order("created_at DESC").limit(10) @groups = Group.limit(10)
end end
end end
...@@ -2,7 +2,8 @@ class Admin::GroupsController < Admin::ApplicationController ...@@ -2,7 +2,8 @@ class Admin::GroupsController < Admin::ApplicationController
before_filter :group, only: [:edit, :show, :update, :destroy, :project_update, :project_teams_update] before_filter :group, only: [:edit, :show, :update, :destroy, :project_update, :project_teams_update]
def index def index
@groups = Group.order('name ASC') @groups = Group.all
@groups = @groups.sort(@sort = params[:sort])
@groups = @groups.search(params[:name]) if params[:name].present? @groups = @groups.search(params[:name]) if params[:name].present?
@groups = @groups.page(params[:page]).per(20) @groups = @groups.page(params[:page]).per(20)
end end
......
...@@ -2,16 +2,16 @@ class Admin::UsersController < Admin::ApplicationController ...@@ -2,16 +2,16 @@ class Admin::UsersController < Admin::ApplicationController
before_filter :user, only: [:show, :edit, :update, :destroy] before_filter :user, only: [:show, :edit, :update, :destroy]
def index def index
@users = User.filter(params[:filter]) @users = User.order_name_asc.filter(params[:filter])
@users = @users.search(params[:name]) if params[:name].present? @users = @users.search(params[:name]) if params[:name].present?
@users = @users.sort(@sort = params[:sort]) @users = @users.sort(@sort = params[:sort])
@users = @users.alphabetically.page(params[:page]) @users = @users.page(params[:page])
end end
def show def show
@personal_projects = user.personal_projects @personal_projects = user.personal_projects
@joined_projects = user.projects.joined(@user) @joined_projects = user.projects.joined(@user)
@keys = user.keys.order('id DESC') @keys = user.keys
end end
def new def new
......
...@@ -254,7 +254,7 @@ class ApplicationController < ActionController::Base ...@@ -254,7 +254,7 @@ class ApplicationController < ActionController::Base
end end
def set_filters_params def set_filters_params
params[:sort] ||= 'newest' params[:sort] ||= 'created_desc'
params[:scope] = 'all' if params[:scope].blank? params[:scope] = 'all' if params[:scope].blank?
params[:state] = 'opened' if params[:state].blank? params[:state] = 'opened' if params[:state].blank?
...@@ -280,7 +280,7 @@ class ApplicationController < ActionController::Base ...@@ -280,7 +280,7 @@ class ApplicationController < ActionController::Base
author_id = @filter_params[:author_id] author_id = @filter_params[:author_id]
milestone_id = @filter_params[:milestone_id] milestone_id = @filter_params[:milestone_id]
@sort = @filter_params[:sort].try(:humanize) @sort = @filter_params[:sort]
@assignees = User.where(id: collection.pluck(:assignee_id)) @assignees = User.where(id: collection.pluck(:assignee_id))
@authors = User.where(id: collection.pluck(:author_id)) @authors = User.where(id: collection.pluck(:author_id))
@milestones = Milestone.where(id: collection.pluck(:milestone_id)) @milestones = Milestone.where(id: collection.pluck(:milestone_id))
......
...@@ -9,7 +9,7 @@ class DashboardController < ApplicationController ...@@ -9,7 +9,7 @@ class DashboardController < ApplicationController
# If user needs more - point to Dashboard#projects page # If user needs more - point to Dashboard#projects page
@projects_limit = 30 @projects_limit = 30
@groups = current_user.authorized_groups.sort_by(&:human_name) @groups = current_user.authorized_groups.order_name_asc
@has_authorized_projects = @projects.count > 0 @has_authorized_projects = @projects.count > 0
@projects_count = @projects.count @projects_count = @projects.count
@projects = @projects.limit(@projects_limit) @projects = @projects.limit(@projects_limit)
......
...@@ -3,7 +3,7 @@ class Profiles::KeysController < ApplicationController ...@@ -3,7 +3,7 @@ class Profiles::KeysController < ApplicationController
skip_before_filter :authenticate_user!, only: [:get_keys] skip_before_filter :authenticate_user!, only: [:get_keys]
def index def index
@keys = current_user.keys.order('id DESC') @keys = current_user.keys
end end
def show def show
......
...@@ -13,7 +13,7 @@ class Projects::CommitsController < Projects::ApplicationController ...@@ -13,7 +13,7 @@ class Projects::CommitsController < Projects::ApplicationController
@commits = @repo.commits(@ref, @path, @limit, @offset) @commits = @repo.commits(@ref, @path, @limit, @offset)
@note_counts = Note.where(commit_id: @commits.map(&:id)). @note_counts = Note.where(commit_id: @commits.map(&:id)).
group(:commit_id).count group(:commit_id).count
respond_to do |format| respond_to do |format|
format.html format.html
......
...@@ -7,7 +7,7 @@ class Projects::LabelsController < Projects::ApplicationController ...@@ -7,7 +7,7 @@ class Projects::LabelsController < Projects::ApplicationController
respond_to :js, :html respond_to :js, :html
def index def index
@labels = @project.labels.order_by_name.page(params[:page]).per(20) @labels = @project.labels.page(params[:page]).per(20)
end end
def new def new
......
...@@ -23,7 +23,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -23,7 +23,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def show def show
@note_counts = Note.where(commit_id: @merge_request.commits.map(&:id)). @note_counts = Note.where(commit_id: @merge_request.commits.map(&:id)).
group(:commit_id).count group(:commit_id).count
respond_to do |format| respond_to do |format|
format.html format.html
......
...@@ -22,6 +22,7 @@ class NotesFinder ...@@ -22,6 +22,7 @@ class NotesFinder
end end
# Use overlapping intervals to avoid worrying about race conditions # Use overlapping intervals to avoid worrying about race conditions
notes.where('updated_at > ?', last_fetched_at - FETCH_OVERLAP) notes.where('updated_at > ?', last_fetched_at - FETCH_OVERLAP).
order(created_at: :asc, id: :asc)
end end
end end
module SortingHelper module SortingHelper
def sort_options_hash
{
sort_value_name => sort_title_name,
sort_value_recently_updated => sort_title_recently_updated,
sort_value_oldest_updated => sort_title_oldest_updated,
sort_value_recently_created => sort_title_recently_created,
sort_value_oldest_created => sort_title_oldest_created,
sort_value_milestone_soon => sort_title_milestone_soon,
sort_value_milestone_later => sort_title_milestone_later,
sort_value_largest_repo => sort_title_largest_repo,
sort_value_recently_signin => sort_title_recently_signin,
sort_value_oldest_signin => sort_title_oldest_signin,
}
end
def sort_title_oldest_updated def sort_title_oldest_updated
'Oldest updated' 'Oldest updated'
end end
...@@ -14,4 +29,68 @@ module SortingHelper ...@@ -14,4 +29,68 @@ module SortingHelper
def sort_title_recently_created def sort_title_recently_created
'Recently created' 'Recently created'
end end
def sort_title_milestone_soon
'Milestone due soon'
end
def sort_title_milestone_later
'Milestone due later'
end
def sort_title_name
'Name'
end
def sort_title_largest_repo
'Largest repository'
end
def sort_title_recently_signin
'Recent sign in'
end
def sort_title_oldest_signin
'Oldest sign in'
end
def sort_value_oldest_updated
'updated_asc'
end
def sort_value_recently_updated
'updated_desc'
end
def sort_value_oldest_created
'created_asc'
end
def sort_value_recently_created
'created_desc'
end
def sort_value_milestone_soon
'milestone_due_asc'
end
def sort_value_milestone_later
'milestone_due_desc'
end
def sort_value_name
'name_asc'
end
def sort_value_largest_repo
'repository_size_desc'
end
def sort_value_recently_signin
'recent_sign_in'
end
def sort_value_oldest_signin
'oldest_sign_in'
end
end end
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
# #
class BroadcastMessage < ActiveRecord::Base class BroadcastMessage < ActiveRecord::Base
include Sortable
validates :message, presence: true validates :message, presence: true
validates :starts_at, presence: true validates :starts_at, presence: true
validates :ends_at, presence: true validates :ends_at, presence: true
......
...@@ -29,6 +29,8 @@ module Issuable ...@@ -29,6 +29,8 @@ module Issuable
scope :only_opened, -> { with_state(:opened) } scope :only_opened, -> { with_state(:opened) }
scope :only_reopened, -> { with_state(:reopened) } scope :only_reopened, -> { with_state(:reopened) }
scope :closed, -> { with_state(:closed) } scope :closed, -> { with_state(:closed) }
scope :order_milestone_due_desc, -> { joins(:milestone).reorder('milestones.due_date DESC, milestones.id DESC') }
scope :order_milestone_due_asc, -> { joins(:milestone).reorder('milestones.due_date ASC, milestones.id ASC') }
delegate :name, delegate :name,
:email, :email,
...@@ -55,13 +57,10 @@ module Issuable ...@@ -55,13 +57,10 @@ module Issuable
def sort(method) def sort(method)
case method.to_s case method.to_s
when 'newest' then reorder("#{table_name}.created_at DESC") when 'milestone_due_asc' then order_milestone_due_asc
when 'oldest' then reorder("#{table_name}.created_at ASC") when 'milestone_due_desc' then order_milestone_due_desc
when 'recently_updated' then reorder("#{table_name}.updated_at DESC") else
when 'last_updated' then reorder("#{table_name}.updated_at ASC") order_by(method)
when 'milestone_due_soon' then joins(:milestone).reorder("milestones.due_date ASC")
when 'milestone_due_later' then joins(:milestone).reorder("milestones.due_date DESC")
else reorder("#{table_name}.created_at DESC")
end end
end end
end end
......
# == Sortable concern
#
# Set default scope for ordering objects
#
module Sortable
extend ActiveSupport::Concern
included do
# By default all models should be ordered
# by created_at field starting from newest
default_scope { order(created_at: :desc, id: :desc) }
scope :order_created_desc, -> { reorder(created_at: :desc, id: :desc) }
scope :order_created_asc, -> { reorder(created_at: :asc, id: :asc) }
scope :order_updated_desc, -> { reorder(updated_at: :desc, id: :desc) }
scope :order_updated_asc, -> { reorder(updated_at: :asc, id: :asc) }
if column_names.include?('name')
scope :order_name_asc, -> { reorder(name: :asc) }
scope :order_name_desc, -> { reorder(name: :desc) }
end
end
module ClassMethods
def order_by(method)
case method.to_s
when 'name_asc' then order_name_asc
when 'name_desc' then order_name_desc
when 'updated_asc' then order_updated_asc
when 'updated_desc' then order_updated_desc
when 'created_asc' then order_created_asc
when 'created_desc' then order_created_desc
else
all
end
end
end
end
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
# #
class Email < ActiveRecord::Base class Email < ActiveRecord::Base
include Sortable
belongs_to :user belongs_to :user
validates :user_id, presence: true validates :user_id, presence: true
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
# #
class Event < ActiveRecord::Base class Event < ActiveRecord::Base
include Sortable
default_scope { where.not(author_id: nil) } default_scope { where.not(author_id: nil) }
CREATED = 1 CREATED = 1
......
...@@ -28,6 +28,16 @@ class Group < Namespace ...@@ -28,6 +28,16 @@ class Group < Namespace
after_create :post_create_hook after_create :post_create_hook
after_destroy :post_destroy_hook after_destroy :post_destroy_hook
class << self
def search(query)
where("LOWER(namespaces.name) LIKE :query or LOWER(namespaces.path) LIKE :query", query: "%#{query.downcase}%")
end
def sort(method)
order_by(method)
end
end
def human_name def human_name
name name
end end
...@@ -88,20 +98,4 @@ class Group < Namespace ...@@ -88,20 +98,4 @@ class Group < Namespace
def system_hook_service def system_hook_service
SystemHooksService.new SystemHooksService.new
end end
class << self
def search(query)
where("LOWER(namespaces.name) LIKE :query or LOWER(namespaces.path) 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 end
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# #
class WebHook < ActiveRecord::Base class WebHook < ActiveRecord::Base
include Sortable
include HTTParty include HTTParty
default_value_for :push_events, true default_value_for :push_events, true
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
# #
class Identity < ActiveRecord::Base class Identity < ActiveRecord::Base
include Sortable
belongs_to :user belongs_to :user
validates :extern_uid, allow_blank: true, uniqueness: { scope: :provider } validates :extern_uid, allow_blank: true, uniqueness: { scope: :provider }
......
...@@ -24,6 +24,7 @@ class Issue < ActiveRecord::Base ...@@ -24,6 +24,7 @@ class Issue < ActiveRecord::Base
include Issuable include Issuable
include InternalId include InternalId
include Taskable include Taskable
include Sortable
ActsAsTaggableOn.strict_case_match = true ActsAsTaggableOn.strict_case_match = true
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
require 'digest/md5' require 'digest/md5'
class Key < ActiveRecord::Base class Key < ActiveRecord::Base
include Sortable
include Gitlab::Popen include Gitlab::Popen
belongs_to :user belongs_to :user
......
...@@ -28,7 +28,7 @@ class Label < ActiveRecord::Base ...@@ -28,7 +28,7 @@ class Label < ActiveRecord::Base
format: { with: /\A[^&\?,&]+\z/ }, format: { with: /\A[^&\?,&]+\z/ },
uniqueness: { scope: :project_id } uniqueness: { scope: :project_id }
scope :order_by_name, -> { reorder("labels.title ASC") } default_scope { order(title: :asc) }
alias_attribute :name, :title alias_attribute :name, :title
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
# #
class Member < ActiveRecord::Base class Member < ActiveRecord::Base
include Sortable
include Notifiable include Notifiable
include Gitlab::Access include Gitlab::Access
......
...@@ -28,6 +28,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -28,6 +28,7 @@ class MergeRequest < ActiveRecord::Base
include Issuable include Issuable
include Taskable include Taskable
include InternalId include InternalId
include Sortable
belongs_to :target_project, foreign_key: :target_project_id, class_name: "Project" belongs_to :target_project, foreign_key: :target_project_id, class_name: "Project"
belongs_to :source_project, foreign_key: :source_project_id, class_name: "Project" belongs_to :source_project, foreign_key: :source_project_id, class_name: "Project"
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
require Rails.root.join("app/models/commit") require Rails.root.join("app/models/commit")
class MergeRequestDiff < ActiveRecord::Base class MergeRequestDiff < ActiveRecord::Base
include Sortable
# Prevent store of diff # Prevent store of diff
# if commits amount more then 200 # if commits amount more then 200
COMMITS_SAFE_SIZE = 200 COMMITS_SAFE_SIZE = 200
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
class Milestone < ActiveRecord::Base class Milestone < ActiveRecord::Base
include InternalId include InternalId
include Sortable
belongs_to :project belongs_to :project
has_many :issues has_many :issues
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
# #
class Namespace < ActiveRecord::Base class Namespace < ActiveRecord::Base
include Sortable
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
has_many :projects, dependent: :destroy has_many :projects, dependent: :destroy
......
...@@ -33,6 +33,7 @@ require 'carrierwave/orm/activerecord' ...@@ -33,6 +33,7 @@ require 'carrierwave/orm/activerecord'
require 'file_size_validator' require 'file_size_validator'
class Project < ActiveRecord::Base class Project < ActiveRecord::Base
include Sortable
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
include Gitlab::VisibilityLevel include Gitlab::VisibilityLevel
include Gitlab::ConfigHelper include Gitlab::ConfigHelper
...@@ -53,7 +54,7 @@ class Project < ActiveRecord::Base ...@@ -53,7 +54,7 @@ class Project < ActiveRecord::Base
attr_accessor :new_default_branch attr_accessor :new_default_branch
# Relations # Relations
belongs_to :creator, foreign_key: 'creator_id', class_name: 'User' belongs_to :creator, foreign_key: 'creator_id', class_name: 'User'
belongs_to :group, -> { where(type: Group) }, foreign_key: 'namespace_id' belongs_to :group, -> { where(type: Group) }, foreign_key: 'namespace_id'
belongs_to :namespace belongs_to :namespace
...@@ -86,7 +87,7 @@ class Project < ActiveRecord::Base ...@@ -86,7 +87,7 @@ class Project < ActiveRecord::Base
has_many :merge_requests, dependent: :destroy, foreign_key: 'target_project_id' has_many :merge_requests, dependent: :destroy, foreign_key: 'target_project_id'
# Merge requests from source project should be kept when source project was removed # Merge requests from source project should be kept when source project was removed
has_many :fork_merge_requests, foreign_key: 'source_project_id', class_name: MergeRequest has_many :fork_merge_requests, foreign_key: 'source_project_id', class_name: MergeRequest
has_many :issues, -> { order 'issues.state DESC, issues.created_at DESC' }, dependent: :destroy has_many :issues, dependent: :destroy
has_many :labels, dependent: :destroy has_many :labels, dependent: :destroy
has_many :services, dependent: :destroy has_many :services, dependent: :destroy
has_many :events, dependent: :destroy has_many :events, dependent: :destroy
...@@ -139,14 +140,16 @@ class Project < ActiveRecord::Base ...@@ -139,14 +140,16 @@ class Project < ActiveRecord::Base
mount_uploader :avatar, AttachmentUploader mount_uploader :avatar, AttachmentUploader
# Scopes # Scopes
scope :sorted_by_activity, -> { reorder(last_activity_at: :desc) }
scope :sorted_by_stars, -> { reorder('projects.star_count DESC') }
scope :sorted_by_names, -> { joins(:namespace).reorder('namespaces.name ASC, projects.name ASC') }
scope :without_user, ->(user) { where('projects.id NOT IN (:ids)', ids: user.authorized_projects.map(&:id) ) } scope :without_user, ->(user) { where('projects.id NOT IN (:ids)', ids: user.authorized_projects.map(&:id) ) }
scope :without_team, ->(team) { team.projects.present? ? where('projects.id NOT IN (:ids)', ids: team.projects.map(&:id)) : scoped } scope :without_team, ->(team) { team.projects.present? ? where('projects.id NOT IN (:ids)', ids: team.projects.map(&:id)) : scoped }
scope :not_in_group, ->(group) { where('projects.id NOT IN (:ids)', ids: group.project_ids ) } scope :not_in_group, ->(group) { where('projects.id NOT IN (:ids)', ids: group.project_ids ) }
scope :in_team, ->(team) { where('projects.id IN (:ids)', ids: team.projects.map(&:id)) } scope :in_team, ->(team) { where('projects.id IN (:ids)', ids: team.projects.map(&:id)) }
scope :in_namespace, ->(namespace) { where(namespace_id: namespace.id) } scope :in_namespace, ->(namespace) { where(namespace_id: namespace.id) }
scope :in_group_namespace, -> { joins(:group) } scope :in_group_namespace, -> { joins(:group) }
scope :sorted_by_activity, -> { reorder('projects.last_activity_at DESC') }
scope :sorted_by_stars, -> { reorder('projects.star_count DESC') }
scope :personal, ->(user) { where(namespace_id: user.namespace_id) } scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
scope :joined, ->(user) { where('namespace_id != ?', user.namespace_id) } scope :joined, ->(user) { where('namespace_id != ?', user.namespace_id) }
scope :public_only, -> { where(visibility_level: Project::PUBLIC) } scope :public_only, -> { where(visibility_level: Project::PUBLIC) }
...@@ -228,13 +231,10 @@ class Project < ActiveRecord::Base ...@@ -228,13 +231,10 @@ class Project < ActiveRecord::Base
end end
def sort(method) def sort(method)
case method.to_s if method == 'repository_size_desc'
when 'newest' then reorder('projects.created_at DESC') reorder(repository_size: :desc, id: :desc)
when 'oldest' then reorder('projects.created_at ASC') else
when 'recently_updated' then reorder('projects.updated_at DESC') order_by(method)
when 'last_updated' then reorder('projects.updated_at ASC')
when 'largest_repository' then reorder('projects.repository_size DESC')
else reorder('namespaces.path, projects.name ASC')
end end
end end
end end
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
# To add new service you should build a class inherited from Service # To add new service you should build a class inherited from Service
# and implement a set of methods # and implement a set of methods
class Service < ActiveRecord::Base class Service < ActiveRecord::Base
include Sortable
serialize :properties, JSON serialize :properties, JSON
default_value_for :active, false default_value_for :active, false
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# #
class Snippet < ActiveRecord::Base class Snippet < ActiveRecord::Base
include Sortable
include Linguist::BlobHelper include Linguist::BlobHelper
include Gitlab::VisibilityLevel include Gitlab::VisibilityLevel
......
...@@ -49,6 +49,7 @@ require 'carrierwave/orm/activerecord' ...@@ -49,6 +49,7 @@ require 'carrierwave/orm/activerecord'
require 'file_size_validator' require 'file_size_validator'
class User < ActiveRecord::Base class User < ActiveRecord::Base
include Sortable
include Gitlab::ConfigHelper include Gitlab::ConfigHelper
include TokenAuthenticatable include TokenAuthenticatable
extend Gitlab::ConfigHelper extend Gitlab::ConfigHelper
...@@ -176,7 +177,6 @@ class User < ActiveRecord::Base ...@@ -176,7 +177,6 @@ class User < ActiveRecord::Base
scope :admins, -> { where(admin: true) } scope :admins, -> { where(admin: true) }
scope :blocked, -> { with_state(:blocked) } scope :blocked, -> { with_state(:blocked) }
scope :active, -> { with_state(:active) } scope :active, -> { with_state(:active) }
scope :alphabetically, -> { order('name ASC') }
scope :in_team, ->(team){ where(id: team.member_ids) } scope :in_team, ->(team){ where(id: team.member_ids) }
scope :not_in_team, ->(team){ where('users.id NOT IN (:ids)', ids: team.member_ids) } scope :not_in_team, ->(team){ where('users.id NOT IN (:ids)', ids: team.member_ids) }
scope :not_in_project, ->(project) { project.users.present? ? where("id not in (:ids)", ids: project.users.map(&:id) ) : all } scope :not_in_project, ->(project) { project.users.present? ? where("id not in (:ids)", ids: project.users.map(&:id) ) : all }
...@@ -199,11 +199,10 @@ class User < ActiveRecord::Base ...@@ -199,11 +199,10 @@ class User < ActiveRecord::Base
def sort(method) def sort(method)
case method.to_s case method.to_s
when 'recent_sign_in' then reorder('users.last_sign_in_at DESC') when 'recent_sign_in' then reorder(last_sign_in_at: :desc)
when 'oldest_sign_in' then reorder('users.last_sign_in_at ASC') when 'oldest_sign_in' then reorder(last_sign_in_at: :asc)
when 'recently_created' then reorder('users.created_at DESC') else
when 'late_created' then reorder('users.created_at ASC') order_by(method)
else reorder("users.name ASC")
end end
end end
...@@ -290,7 +289,7 @@ class User < ActiveRecord::Base ...@@ -290,7 +289,7 @@ class User < ActiveRecord::Base
def authorized_groups def authorized_groups
@authorized_groups ||= begin @authorized_groups ||= begin
group_ids = (groups.pluck(:id) + authorized_projects.pluck(:namespace_id)) group_ids = (groups.pluck(:id) + authorized_projects.pluck(:namespace_id))
Group.where(id: group_ids).order('namespaces.name ASC') Group.where(id: group_ids)
end end
end end
...@@ -301,7 +300,7 @@ class User < ActiveRecord::Base ...@@ -301,7 +300,7 @@ class User < ActiveRecord::Base
project_ids = personal_projects.pluck(:id) project_ids = personal_projects.pluck(:id)
project_ids.push(*groups_projects.pluck(:id)) project_ids.push(*groups_projects.pluck(:id))
project_ids.push(*projects.pluck(:id).uniq) project_ids.push(*projects.pluck(:id).uniq)
Project.where(id: project_ids).joins(:namespace).order('namespaces.name ASC') Project.where(id: project_ids)
end end
end end
......
...@@ -8,10 +8,31 @@ ...@@ -8,10 +8,31 @@
%hr %hr
= form_tag admin_groups_path, method: :get, class: 'form-inline' do = form_tag admin_groups_path, method: :get, class: 'form-inline' do
= hidden_field_tag :sort, @sort
.form-group .form-group
= text_field_tag :name, params[:name], class: "form-control input-mn-300" = text_field_tag :name, params[:name], class: "form-control input-mn-300"
= button_tag "Search", class: "btn submit btn-primary" = button_tag "Search", class: "btn submit btn-primary"
.pull-right
.dropdown.inline
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
%span.light sort:
- if @sort.present?
= sort_options_hash[@sort]
- else
= sort_title_recently_created
%b.caret
%ul.dropdown-menu
%li
= link_to admin_groups_path(sort: sort_value_recently_created) do
= sort_title_recently_created
= link_to admin_groups_path(sort: sort_value_oldest_created) do
= sort_title_oldest_created
= link_to admin_groups_path(sort: sort_value_recently_updated) do
= sort_title_recently_updated
= link_to admin_groups_path(sort: sort_value_oldest_updated) do
= sort_title_oldest_updated
%hr %hr
%ul.bordered-list %ul.bordered-list
......
...@@ -47,24 +47,22 @@ ...@@ -47,24 +47,22 @@
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
%span.light sort: %span.light sort:
- if @sort.present? - if @sort.present?
= @sort.humanize = sort_options_hash[@sort]
- else - else
Name = sort_title_recently_created
%b.caret %b.caret
%ul.dropdown-menu %ul.dropdown-menu
%li %li
= link_to admin_projects_path(sort: nil) do = link_to admin_projects_path(sort: sort_value_recently_created) do
Name
= link_to admin_projects_path(sort: 'newest') do
= sort_title_recently_created = sort_title_recently_created
= link_to admin_projects_path(sort: 'oldest') do = link_to admin_projects_path(sort: sort_value_oldest_created) do
= sort_title_oldest_created = sort_title_oldest_created
= link_to admin_projects_path(sort: 'recently_updated') do = link_to admin_projects_path(sort: sort_value_recently_updated) do
= sort_title_recently_updated = sort_title_recently_updated
= link_to admin_projects_path(sort: 'last_updated') do = link_to admin_projects_path(sort: sort_value_oldest_updated) do
= sort_title_oldest_updated = sort_title_oldest_updated
= link_to admin_projects_path(sort: 'largest_repository') do = link_to admin_projects_path(sort: sort_value_largest_repo) do
Largest repository = sort_title_largest_repo
= link_to 'New Project', new_project_path, class: "btn btn-new" = link_to 'New Project', new_project_path, class: "btn btn-new"
%ul.well-list %ul.well-list
- @projects.each do |project| - @projects.each do |project|
......
...@@ -36,22 +36,26 @@ ...@@ -36,22 +36,26 @@
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
%span.light sort: %span.light sort:
- if @sort.present? - if @sort.present?
= @sort.humanize = sort_options_hash[@sort]
- else - else
Name = sort_title_name
%b.caret %b.caret
%ul.dropdown-menu %ul.dropdown-menu
%li %li
= link_to admin_users_path(sort: nil) do = link_to admin_users_path(sort: sort_value_name) do
Name = sort_title_name
= link_to admin_users_path(sort: 'recent_sign_in') do = link_to admin_users_path(sort: sort_value_recently_signin) do
Recent sign in = sort_title_recently_signin
= link_to admin_users_path(sort: 'oldest_sign_in') do = link_to admin_users_path(sort: sort_value_oldest_signin) do
Oldest sign in = sort_title_oldest_signin
= link_to admin_users_path(sort: 'recently_created') do = link_to admin_users_path(sort: sort_value_recently_created) do
= sort_title_recently_created = sort_title_recently_created
= link_to admin_users_path(sort: 'late_created') do = link_to admin_users_path(sort: sort_value_oldest_created) do
= sort_title_oldest_created = sort_title_oldest_created
= link_to admin_users_path(sort: sort_value_recently_updated) do
= sort_title_recently_updated
= link_to admin_users_path(sort: sort_value_oldest_updated) do
= sort_title_oldest_updated
= link_to 'New User', new_admin_user_path, class: "btn btn-new" = link_to 'New User', new_admin_user_path, class: "btn btn-new"
%ul.well-list %ul.well-list
......
...@@ -82,19 +82,19 @@ ...@@ -82,19 +82,19 @@
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
%span.light sort: %span.light sort:
- if @sort.present? - if @sort.present?
= @sort.humanize = sort_options_hash[@sort]
- else - else
Name = sort_title_recently_created
%b.caret %b.caret
%ul.dropdown-menu %ul.dropdown-menu
%li %li
= link_to projects_dashboard_filter_path(sort: nil) do = link_to projects_dashboard_filter_path(sort: sort_value_recently_created) do
Name
= link_to projects_dashboard_filter_path(sort: 'newest') do
= sort_title_recently_created = sort_title_recently_created
= link_to projects_dashboard_filter_path(sort: 'oldest') do = link_to projects_dashboard_filter_path(sort: sort_value_oldest_created) do
= sort_title_oldest_created = sort_title_oldest_created
= link_to projects_dashboard_filter_path(sort: 'recently_updated') do = link_to projects_dashboard_filter_path(sort: sort_value_recently_updated) do
= sort_title_recently_updated = sort_title_recently_updated
= link_to projects_dashboard_filter_path(sort: 'last_updated') do = link_to projects_dashboard_filter_path(sort: sort_value_oldest_updated) do
= sort_title_oldest_updated = sort_title_oldest_updated
= link_to projects_dashboard_filter_path(sort: sort_value_name) do
= sort_title_name
.clearfix .clearfix
.pull-left .pull-left
= form_tag explore_groups_path, method: :get, class: 'form-inline form-tiny' do |f| = form_tag explore_groups_path, method: :get, class: 'form-inline form-tiny' do |f|
= hidden_field_tag :sort, @sort
.form-group .form-group
= search_field_tag :search, params[:search], placeholder: "Filter by name", class: "form-control search-text-input input-mn-300", id: "groups_search" = search_field_tag :search, params[:search], placeholder: "Filter by name", class: "form-control search-text-input input-mn-300", id: "groups_search"
.form-group .form-group
...@@ -11,21 +12,19 @@ ...@@ -11,21 +12,19 @@
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
%span.light sort: %span.light sort:
- if @sort.present? - if @sort.present?
= @sort.humanize = sort_options_hash[@sort]
- else - else
Name = sort_title_recently_created
%b.caret %b.caret
%ul.dropdown-menu %ul.dropdown-menu
%li %li
= link_to explore_groups_path(sort: nil) do = link_to explore_groups_path(sort: sort_value_recently_created) do
Name
= link_to explore_groups_path(sort: 'newest') do
= sort_title_recently_created = sort_title_recently_created
= link_to explore_groups_path(sort: 'oldest') do = link_to explore_groups_path(sort: sort_value_oldest_created) do
= sort_title_oldest_created = sort_title_oldest_created
= link_to explore_groups_path(sort: 'recently_updated') do = link_to explore_groups_path(sort: sort_value_recently_updated) do
= sort_title_recently_updated = sort_title_recently_updated
= link_to explore_groups_path(sort: 'last_updated') do = link_to explore_groups_path(sort: sort_value_oldest_updated) do
= sort_title_oldest_updated = sort_title_oldest_updated
%hr %hr
......
...@@ -11,21 +11,19 @@ ...@@ -11,21 +11,19 @@
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
%span.light sort: %span.light sort:
- if @sort.present? - if @sort.present?
= @sort.humanize = sort_options_hash[@sort]
- else - else
Name = sort_title_recently_created
%b.caret %b.caret
%ul.dropdown-menu %ul.dropdown-menu
%li %li
= link_to explore_projects_path(sort: nil) do = link_to explore_projects_path(sort: sort_value_recently_created) do
Name
= link_to explore_projects_path(sort: 'newest') do
= sort_title_recently_created = sort_title_recently_created
= link_to explore_projects_path(sort: 'oldest') do = link_to explore_projects_path(sort: sort_value_oldest_created) do
= sort_title_oldest_created = sort_title_oldest_created
= link_to explore_projects_path(sort: 'recently_updated') do = link_to explore_projects_path(sort: sort_value_recently_updated) do
= sort_title_recently_updated = sort_title_recently_updated
= link_to explore_projects_path(sort: 'last_updated') do = link_to explore_projects_path(sort: sort_value_oldest_updated) do
= sort_title_oldest_updated = sort_title_oldest_updated
%hr %hr
......
...@@ -98,7 +98,7 @@ ...@@ -98,7 +98,7 @@
= link_to page_filter_path(label_name: nil) do = link_to page_filter_path(label_name: nil) do
Any Any
- if @project.labels.any? - if @project.labels.any?
- @project.labels.order_by_name.each do |label| - @project.labels.each do |label|
%li %li
= link_to page_filter_path(label_name: label.name) do = link_to page_filter_path(label_name: label.name) do
= render_colored_label(label) = render_colored_label(label)
......
...@@ -2,21 +2,21 @@ ...@@ -2,21 +2,21 @@
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
%span.light sort: %span.light sort:
- if @sort.present? - if @sort.present?
= @sort = sort_options_hash[@sort]
- else - else
Newest = sort_title_recently_created
%b.caret %b.caret
%ul.dropdown-menu.dropdown-menu-align-right %ul.dropdown-menu.dropdown-menu-align-right
%li %li
= link_to page_filter_path(sort: 'newest') do = link_to page_filter_path(sort: sort_value_recently_created) do
= sort_title_recently_created = sort_title_recently_created
= link_to page_filter_path(sort: 'oldest') do = link_to page_filter_path(sort: sort_value_oldest_created) do
= sort_title_oldest_created = sort_title_oldest_created
= link_to page_filter_path(sort: 'recently_updated') do = link_to page_filter_path(sort: sort_value_recently_updated) do
= sort_title_recently_updated = sort_title_recently_updated
= link_to page_filter_path(sort: 'last_updated') do = link_to page_filter_path(sort: sort_value_oldest_updated) do
= sort_title_oldest_updated = sort_title_oldest_updated
= link_to page_filter_path(sort: 'milestone_due_soon') do = link_to page_filter_path(sort: sort_value_milestone_soon) do
Milestone due soon = sort_title_milestone_soon
= link_to page_filter_path(sort: 'milestone_due_later') do = link_to page_filter_path(sort: sort_value_milestone_later) do
Milestone due later = sort_title_milestone_later
class AddTimestampsToIdentities < ActiveRecord::Migration
def change
add_timestamps(:identities)
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20150125163100) do ActiveRecord::Schema.define(version: 20150205211843) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -87,9 +87,11 @@ ActiveRecord::Schema.define(version: 20150125163100) do ...@@ -87,9 +87,11 @@ ActiveRecord::Schema.define(version: 20150125163100) do
add_index "forked_project_links", ["forked_to_project_id"], name: "index_forked_project_links_on_forked_to_project_id", unique: true, using: :btree add_index "forked_project_links", ["forked_to_project_id"], name: "index_forked_project_links_on_forked_to_project_id", unique: true, using: :btree
create_table "identities", force: true do |t| create_table "identities", force: true do |t|
t.string "extern_uid" t.string "extern_uid"
t.string "provider" t.string "provider"
t.integer "user_id" t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
end end
add_index "identities", ["user_id"], name: "index_identities_on_user_id", using: :btree add_index "identities", ["user_id"], name: "index_identities_on_user_id", using: :btree
...@@ -323,12 +325,12 @@ ActiveRecord::Schema.define(version: 20150125163100) do ...@@ -323,12 +325,12 @@ ActiveRecord::Schema.define(version: 20150125163100) do
t.string "import_url" t.string "import_url"
t.integer "visibility_level", default: 0, null: false t.integer "visibility_level", default: 0, null: false
t.boolean "archived", default: false, null: false t.boolean "archived", default: false, null: false
t.string "avatar"
t.string "import_status" t.string "import_status"
t.float "repository_size", default: 0.0 t.float "repository_size", default: 0.0
t.integer "star_count", default: 0, null: false t.integer "star_count", default: 0, null: false
t.string "import_type" t.string "import_type"
t.string "import_source" t.string "import_source"
t.string "avatar"
end end
add_index "projects", ["creator_id"], name: "index_projects_on_creator_id", using: :btree add_index "projects", ["creator_id"], name: "index_projects_on_creator_id", using: :btree
...@@ -426,7 +428,6 @@ ActiveRecord::Schema.define(version: 20150125163100) do ...@@ -426,7 +428,6 @@ ActiveRecord::Schema.define(version: 20150125163100) do
t.integer "notification_level", default: 1, null: false t.integer "notification_level", default: 1, null: false
t.datetime "password_expires_at" t.datetime "password_expires_at"
t.integer "created_by_id" t.integer "created_by_id"
t.datetime "last_credential_check_at"
t.string "avatar" t.string "avatar"
t.string "confirmation_token" t.string "confirmation_token"
t.datetime "confirmed_at" t.datetime "confirmed_at"
...@@ -434,6 +435,7 @@ ActiveRecord::Schema.define(version: 20150125163100) do ...@@ -434,6 +435,7 @@ ActiveRecord::Schema.define(version: 20150125163100) do
t.string "unconfirmed_email" t.string "unconfirmed_email"
t.boolean "hide_no_ssh_key", default: false t.boolean "hide_no_ssh_key", default: false
t.string "website_url", default: "", null: false t.string "website_url", default: "", null: false
t.datetime "last_credential_check_at"
t.string "github_access_token" t.string "github_access_token"
t.string "gitlab_access_token" t.string "gitlab_access_token"
end end
......
...@@ -18,6 +18,8 @@ Parameters: ...@@ -18,6 +18,8 @@ Parameters:
- `state` (optional) - Return `all` issues or just those that are `opened` or `closed` - `state` (optional) - Return `all` issues or just those that are `opened` or `closed`
- `labels` (optional) - Comma-separated list of label names - `labels` (optional) - Comma-separated list of label names
- `order_by` (optional) - Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at`
- `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
```json ```json
[ [
...@@ -105,6 +107,8 @@ Parameters: ...@@ -105,6 +107,8 @@ Parameters:
- `state` (optional) - Return `all` issues or just those that are `opened` or `closed` - `state` (optional) - Return `all` issues or just those that are `opened` or `closed`
- `labels` (optional) - Comma-separated list of label names - `labels` (optional) - Comma-separated list of label names
- `milestone` (optional) - Milestone title - `milestone` (optional) - Milestone title
- `order_by` (optional) - Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at`
- `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
## Single issue ## Single issue
......
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
## List merge requests ## List merge requests
Get all merge requests for this project. The `state` parameter can be used to get only merge requests with a given state (`opened`, `closed`, or `merged`) or all of them (`all`). The pagination parameters `page` and `per_page` can be used to restrict the list of merge requests. Get all merge requests for this project.
The `state` parameter can be used to get only merge requests with a given state (`opened`, `closed`, or `merged`) or all of them (`all`).
The pagination parameters `page` and `per_page` can be used to restrict the list of merge requests.
``` ```
GET /projects/:id/merge_requests GET /projects/:id/merge_requests
...@@ -14,8 +16,8 @@ Parameters: ...@@ -14,8 +16,8 @@ Parameters:
- `id` (required) - The ID of a project - `id` (required) - The ID of a project
- `state` (optional) - Return `all` requests or just those that are `merged`, `opened` or `closed` - `state` (optional) - Return `all` requests or just those that are `merged`, `opened` or `closed`
- `order_by` (optional) - Return requests ordered by `created_at` or `updated_at` fields - `order_by` (optional) - Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at`
- `sort` (optional) - Return requests sorted in `asc` or `desc` order - `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
```json ```json
[ [
......
...@@ -11,8 +11,8 @@ GET /projects ...@@ -11,8 +11,8 @@ GET /projects
Parameters: Parameters:
- `archived` (optional) - if passed, limit by archived status - `archived` (optional) - if passed, limit by archived status
- `order_by` (optional) - Return requests ordered by `id`, `name`, `created_at` or `last_activity_at` fields - `order_by` (optional) - Return requests ordered by `id`, `name`, `path`, `created_at`, `updated_at` or `last_activity_at` fields. Default is `created_at`
- `sort` (optional) - Return requests sorted in `asc` or `desc` order - `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
- `search` (optional) - Return list of authorized projects according to a search criteria - `search` (optional) - Return list of authorized projects according to a search criteria
```json ```json
...@@ -98,6 +98,13 @@ Get a list of projects which are owned by the authenticated user. ...@@ -98,6 +98,13 @@ Get a list of projects which are owned by the authenticated user.
GET /projects/owned GET /projects/owned
``` ```
Parameters:
- `archived` (optional) - if passed, limit by archived status
- `order_by` (optional) - Return requests ordered by `id`, `name`, `path`, `created_at`, `updated_at` or `last_activity_at` fields. Default is `created_at`
- `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
- `search` (optional) - Return list of authorized projects according to a search criteria
### List ALL projects ### List ALL projects
Get a list of all GitLab projects (admin only). Get a list of all GitLab projects (admin only).
...@@ -106,6 +113,13 @@ Get a list of all GitLab projects (admin only). ...@@ -106,6 +113,13 @@ Get a list of all GitLab projects (admin only).
GET /projects/all GET /projects/all
``` ```
Parameters:
- `archived` (optional) - if passed, limit by archived status
- `order_by` (optional) - Return requests ordered by `id`, `name`, `path`, `created_at`, `updated_at` or `last_activity_at` fields. Default is `created_at`
- `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
- `search` (optional) - Return list of authorized projects according to a search criteria
### Get single project ### Get single project
Get a specific project, identified by project ID or NAMESPACE/PROJECT_NAME, which is owned by the authenticated user. Get a specific project, identified by project ID or NAMESPACE/PROJECT_NAME, which is owned by the authenticated user.
......
...@@ -33,7 +33,7 @@ class Spinach::Features::AdminGroups < Spinach::FeatureSteps ...@@ -33,7 +33,7 @@ class Spinach::Features::AdminGroups < Spinach::FeatureSteps
end end
step 'I should be redirected to group page' do step 'I should be redirected to group page' do
current_path.should == admin_group_path(Group.last) current_path.should == admin_group_path(Group.find_by(path: 'gitlab'))
end end
When 'I select user "John Doe" from user list as "Reporter"' do When 'I select user "John Doe" from user list as "Reporter"' do
......
...@@ -83,7 +83,7 @@ class Spinach::Features::Groups < Spinach::FeatureSteps ...@@ -83,7 +83,7 @@ class Spinach::Features::Groups < Spinach::FeatureSteps
end end
step 'I should be redirected to group "Samurai" page' do step 'I should be redirected to group "Samurai" page' do
current_path.should == group_path(Group.last) current_path.should == group_path(Group.find_by(name: 'Samurai'))
end end
step 'I should see newly created group "Samurai"' do step 'I should see newly created group "Samurai"' do
......
...@@ -70,8 +70,8 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps ...@@ -70,8 +70,8 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps
find("#merge_request_source_branch").value.should have_content "new_design" find("#merge_request_source_branch").value.should have_content "new_design"
find("#merge_request_target_branch").value.should have_content "master" find("#merge_request_target_branch").value.should have_content "master"
find("#merge_request_title").value.should == "New Design" find("#merge_request_title").value.should == "New Design"
verify_commit_link(".mr_target_commit",@project) verify_commit_link(".mr_target_commit", @project)
verify_commit_link(".mr_source_commit",@forked_project) verify_commit_link(".mr_source_commit", @forked_project)
end end
step 'I update the merge request title' do step 'I update the merge request title' do
...@@ -114,7 +114,7 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps ...@@ -114,7 +114,7 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps
step 'I fill out an invalid "Merge Request On Forked Project" merge request' do step 'I fill out an invalid "Merge Request On Forked Project" merge request' do
select "Select branch", from: "merge_request_target_branch" select "Select branch", from: "merge_request_target_branch"
find(:select, "merge_request_source_project_id", {}).value.should == @forked_project.id.to_s find(:select, "merge_request_source_project_id", {}).value.should == @forked_project.id.to_s
find(:select, "merge_request_target_project_id", {}).value.should == project.id.to_s find(:select, "merge_request_target_project_id", {}).value.should == @project.id.to_s
find(:select, "merge_request_source_branch", {}).value.should == "" find(:select, "merge_request_source_branch", {}).value.should == ""
find(:select, "merge_request_target_branch", {}).value.should == "" find(:select, "merge_request_target_branch", {}).value.should == ""
click_button "Compare branches" click_button "Compare branches"
...@@ -125,7 +125,7 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps ...@@ -125,7 +125,7 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps
end end
step 'the target repository should be the original repository' do step 'the target repository should be the original repository' do
page.should have_select("merge_request_target_project_id", selected: project.path_with_namespace) page.should have_select("merge_request_target_project_id", selected: @project.path_with_namespace)
end end
# Verify a link is generated against the correct project # Verify a link is generated against the correct project
......
...@@ -174,7 +174,7 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps ...@@ -174,7 +174,7 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
click_link 'add a file' click_link 'add a file'
# Remove pre-receive hook so we can push without auth # Remove pre-receive hook so we can push without auth
FileUtils.rm(File.join(Project.last.repository.path, 'hooks', 'pre-receive')) FileUtils.rm(File.join(@project.repository.path, 'hooks', 'pre-receive'))
end end
private private
......
...@@ -154,6 +154,22 @@ module API ...@@ -154,6 +154,22 @@ module API
Gitlab::Access.options_with_owner.values.include? level.to_i Gitlab::Access.options_with_owner.values.include? level.to_i
end end
def issuable_order_by
if params["order_by"] == 'updated_at'
'updated_at'
else
'created_at'
end
end
def issuable_sort
if params["sort"] == 'asc'
:asc
else
:desc
end
end
# error helpers # error helpers
def forbidden!(reason = nil) def forbidden!(reason = nil)
......
...@@ -27,7 +27,9 @@ module API ...@@ -27,7 +27,9 @@ module API
# Parameters: # Parameters:
# state (optional) - Return "opened" or "closed" issues # state (optional) - Return "opened" or "closed" issues
# labels (optional) - Comma-separated list of label names # labels (optional) - Comma-separated list of label names
# order_by (optional) - Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at`
# sort (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
#
# Example Requests: # Example Requests:
# GET /issues # GET /issues
# GET /issues?state=opened # GET /issues?state=opened
...@@ -39,8 +41,7 @@ module API ...@@ -39,8 +41,7 @@ module API
issues = current_user.issues issues = current_user.issues
issues = filter_issues_state(issues, params[:state]) unless params[:state].nil? issues = filter_issues_state(issues, params[:state]) unless params[:state].nil?
issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil? issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil?
issues = issues.order('issues.id DESC') issues.reorder(issuable_order_by => issuable_sort)
present paginate(issues), with: Entities::Issue present paginate(issues), with: Entities::Issue
end end
end end
...@@ -53,6 +54,8 @@ module API ...@@ -53,6 +54,8 @@ module API
# state (optional) - Return "opened" or "closed" issues # state (optional) - Return "opened" or "closed" issues
# labels (optional) - Comma-separated list of label names # labels (optional) - Comma-separated list of label names
# milestone (optional) - Milestone title # milestone (optional) - Milestone title
# order_by (optional) - Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at`
# sort (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
# #
# Example Requests: # Example Requests:
# GET /projects/:id/issues # GET /projects/:id/issues
...@@ -67,11 +70,12 @@ module API ...@@ -67,11 +70,12 @@ module API
issues = user_project.issues issues = user_project.issues
issues = filter_issues_state(issues, params[:state]) unless params[:state].nil? issues = filter_issues_state(issues, params[:state]) unless params[:state].nil?
issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil? issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil?
unless params[:milestone].nil? unless params[:milestone].nil?
issues = filter_issues_milestone(issues, params[:milestone]) issues = filter_issues_milestone(issues, params[:milestone])
end end
issues = issues.order('issues.id DESC')
issues.reorder(issuable_order_by => issuable_sort)
present paginate(issues), with: Entities::Issue present paginate(issues), with: Entities::Issue
end end
......
...@@ -25,6 +25,8 @@ module API ...@@ -25,6 +25,8 @@ module API
# Parameters: # Parameters:
# id (required) - The ID of a project # id (required) - The ID of a project
# state (optional) - Return requests "merged", "opened" or "closed" # state (optional) - Return requests "merged", "opened" or "closed"
# order_by (optional) - Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at`
# sort (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
# #
# Example: # Example:
# GET /projects/:id/merge_requests # GET /projects/:id/merge_requests
...@@ -37,25 +39,18 @@ module API ...@@ -37,25 +39,18 @@ module API
# #
get ":id/merge_requests" do get ":id/merge_requests" do
authorize! :read_merge_request, user_project authorize! :read_merge_request, user_project
merge_requests = user_project.merge_requests
merge_requests =
case params["state"]
when "opened" then merge_requests.opened
when "closed" then merge_requests.closed
when "merged" then merge_requests.merged
else merge_requests
end
mrs = case params["state"] merge_requests.reorder(issuable_order_by => issuable_sort)
when "opened" then user_project.merge_requests.opened present paginate(merge_requests), with: Entities::MergeRequest
when "closed" then user_project.merge_requests.closed
when "merged" then user_project.merge_requests.merged
else user_project.merge_requests
end
sort = case params["sort"]
when 'desc' then 'DESC'
else 'ASC'
end
mrs = case params["order_by"]
when 'updated_at' then mrs.order("updated_at #{sort}")
else mrs.order("created_at #{sort}")
end
present paginate(mrs), with: Entities::MergeRequest
end end
# Show MR # Show MR
......
...@@ -11,6 +11,37 @@ module API ...@@ -11,6 +11,37 @@ module API
attrs[:visibility_level] = Gitlab::VisibilityLevel::PUBLIC if !attrs[:visibility_level].present? && publik == true attrs[:visibility_level] = Gitlab::VisibilityLevel::PUBLIC if !attrs[:visibility_level].present? && publik == true
attrs attrs
end end
def filter_projects(projects)
# If the archived parameter is passed, limit results accordingly
if params[:archived].present?
projects = projects.where(archived: parse_boolean(params[:archived]))
end
if params[:search].present?
projects = projects.search(params[:search])
end
projects.reorder(project_order_by => project_sort)
end
def project_order_by
order_fields = %w(id name path created_at updated_at last_activity_at)
if order_fields.include?(params['order_by'])
params['order_by']
else
'created_at'
end
end
def project_sort
if params["sort"] == 'asc'
:asc
else
:desc
end
end
end end
# Get a projects list for authenticated user # Get a projects list for authenticated user
...@@ -19,25 +50,7 @@ module API ...@@ -19,25 +50,7 @@ module API
# GET /projects # GET /projects
get do get do
@projects = current_user.authorized_projects @projects = current_user.authorized_projects
sort = params[:sort] == 'desc' ? 'desc' : 'asc' @projects = filter_projects(@projects)
@projects = case params["order_by"]
when 'id' then @projects.reorder("id #{sort}")
when 'name' then @projects.reorder("name #{sort}")
when 'created_at' then @projects.reorder("created_at #{sort}")
when 'last_activity_at' then @projects.reorder("last_activity_at #{sort}")
else @projects
end
# If the archived parameter is passed, limit results accordingly
if params[:archived].present?
@projects = @projects.where(archived: parse_boolean(params[:archived]))
end
if params[:search].present?
@projects = @projects.search(params[:search])
end
@projects = paginate @projects @projects = paginate @projects
present @projects, with: Entities::Project present @projects, with: Entities::Project
end end
...@@ -47,16 +60,8 @@ module API ...@@ -47,16 +60,8 @@ module API
# Example Request: # Example Request:
# GET /projects/owned # GET /projects/owned
get '/owned' do get '/owned' do
sort = params[:sort] == 'desc' ? 'desc' : 'asc'
@projects = current_user.owned_projects @projects = current_user.owned_projects
@projects = case params["order_by"] @projects = filter_projects(@projects)
when 'id' then @projects.reorder("id #{sort}")
when 'name' then @projects.reorder("name #{sort}")
when 'created_at' then @projects.reorder("created_at #{sort}")
when 'last_activity_at' then @projects.reorder("last_activity_at #{sort}")
else @projects
end
@projects = paginate @projects @projects = paginate @projects
present @projects, with: Entities::Project present @projects, with: Entities::Project
end end
...@@ -67,16 +72,8 @@ module API ...@@ -67,16 +72,8 @@ module API
# GET /projects/all # GET /projects/all
get '/all' do get '/all' do
authenticated_as_admin! authenticated_as_admin!
sort = params[:sort] == 'desc' ? 'desc' : 'asc' @projects = Project.all
@projects = filter_projects(@projects)
@projects = case params["order_by"]
when 'id' then Project.order("id #{sort}")
when 'name' then Project.order("name #{sort}")
when 'created_at' then Project.order("created_at #{sort}")
when 'last_activity_at' then Project.order("last_activity_at #{sort}")
else Project
end
@projects = paginate @projects @projects = paginate @projects
present @projects, with: Entities::Project present @projects, with: Entities::Project
end end
......
...@@ -32,14 +32,14 @@ describe "Admin::Users", feature: true do ...@@ -32,14 +32,14 @@ describe "Admin::Users", feature: true do
it "should apply defaults to user" do it "should apply defaults to user" do
click_button "Create user" click_button "Create user"
user = User.last user = User.find_by(username: 'bang')
user.projects_limit.should == Gitlab.config.gitlab.default_projects_limit user.projects_limit.should == Gitlab.config.gitlab.default_projects_limit
user.can_create_group.should == Gitlab.config.gitlab.default_can_create_group user.can_create_group.should == Gitlab.config.gitlab.default_can_create_group
end end
it "should create user with valid data" do it "should create user with valid data" do
click_button "Create user" click_button "Create user"
user = User.last user = User.find_by(username: 'bang')
user.name.should == "Big Bang" user.name.should == "Big Bang"
user.email.should == "bigbang@mail.com" user.email.should == "bigbang@mail.com"
end end
...@@ -52,7 +52,7 @@ describe "Admin::Users", feature: true do ...@@ -52,7 +52,7 @@ describe "Admin::Users", feature: true do
it "should send valid email to user with email & password" do it "should send valid email to user with email & password" do
click_button "Create user" click_button "Create user"
user = User.last user = User.find_by(username: 'bang')
email = ActionMailer::Base.deliveries.last email = ActionMailer::Base.deliveries.last
email.subject.should have_content("Account was created") email.subject.should have_content("Account was created")
email.text_part.body.should have_content(user.email) email.text_part.body.should have_content(user.email)
......
require 'spec_helper' require 'spec_helper'
describe "Issues", feature: true do describe "Issues", feature: true do
include SortingHelper
let(:project) { create(:project) } let(:project) { create(:project) }
before do before do
...@@ -80,7 +82,7 @@ describe "Issues", feature: true do ...@@ -80,7 +82,7 @@ describe "Issues", feature: true do
title: title) title: title)
end end
@issue = Issue.first # with title 'foobar' @issue = Issue.find_by(title: 'foobar')
@issue.milestone = create(:milestone, project: project) @issue.milestone = create(:milestone, project: project)
@issue.assignee = nil @issue.assignee = nil
@issue.save @issue.save
...@@ -130,14 +132,14 @@ describe "Issues", feature: true do ...@@ -130,14 +132,14 @@ describe "Issues", feature: true do
let(:later_due_milestone) { create(:milestone, due_date: '2013-12-12') } let(:later_due_milestone) { create(:milestone, due_date: '2013-12-12') }
it 'sorts by newest' do it 'sorts by newest' do
visit project_issues_path(project, sort: 'newest') visit project_issues_path(project, sort: sort_value_recently_created)
first_issue.should include("foo") first_issue.should include("foo")
last_issue.should include("baz") last_issue.should include("baz")
end end
it 'sorts by oldest' do it 'sorts by oldest' do
visit project_issues_path(project, sort: 'oldest') visit project_issues_path(project, sort: sort_value_oldest_created)
first_issue.should include("baz") first_issue.should include("baz")
last_issue.should include("foo") last_issue.should include("foo")
...@@ -146,7 +148,7 @@ describe "Issues", feature: true do ...@@ -146,7 +148,7 @@ describe "Issues", feature: true do
it 'sorts by most recently updated' do it 'sorts by most recently updated' do
baz.updated_at = Time.now + 100 baz.updated_at = Time.now + 100
baz.save baz.save
visit project_issues_path(project, sort: 'recently_updated') visit project_issues_path(project, sort: sort_value_recently_updated)
first_issue.should include("baz") first_issue.should include("baz")
end end
...@@ -154,7 +156,7 @@ describe "Issues", feature: true do ...@@ -154,7 +156,7 @@ describe "Issues", feature: true do
it 'sorts by least recently updated' do it 'sorts by least recently updated' do
baz.updated_at = Time.now - 100 baz.updated_at = Time.now - 100
baz.save baz.save
visit project_issues_path(project, sort: 'last_updated') visit project_issues_path(project, sort: sort_value_oldest_updated)
first_issue.should include("baz") first_issue.should include("baz")
end end
...@@ -168,13 +170,13 @@ describe "Issues", feature: true do ...@@ -168,13 +170,13 @@ describe "Issues", feature: true do
end end
it 'sorts by recently due milestone' do it 'sorts by recently due milestone' do
visit project_issues_path(project, sort: 'milestone_due_soon') visit project_issues_path(project, sort: sort_value_milestone_soon)
first_issue.should include("foo") first_issue.should include("foo")
end end
it 'sorts by least recently due milestone' do it 'sorts by least recently due milestone' do
visit project_issues_path(project, sort: 'milestone_due_later') visit project_issues_path(project, sort: sort_value_milestone_later)
first_issue.should include("bar") first_issue.should include("bar")
end end
...@@ -191,7 +193,7 @@ describe "Issues", feature: true do ...@@ -191,7 +193,7 @@ describe "Issues", feature: true do
end end
it 'sorts with a filter applied' do it 'sorts with a filter applied' do
visit project_issues_path(project, sort: 'oldest', assignee_id: user2.id) visit project_issues_path(project, sort: sort_value_oldest_created, assignee_id: user2.id)
first_issue.should include("bar") first_issue.should include("bar")
last_issue.should include("foo") last_issue.should include("foo")
......
...@@ -474,7 +474,7 @@ describe User do ...@@ -474,7 +474,7 @@ describe User do
@user = create :user, created_at: Date.today, last_sign_in_at: Date.today, name: 'Alpha' @user = create :user, created_at: Date.today, last_sign_in_at: Date.today, name: 'Alpha'
@user1 = create :user, created_at: Date.today - 1, last_sign_in_at: Date.today - 1, name: 'Omega' @user1 = create :user, created_at: Date.today - 1, last_sign_in_at: Date.today - 1, name: 'Omega'
end end
it "sorts users as recently_signed_in" do it "sorts users as recently_signed_in" do
User.sort('recent_sign_in').first.should == @user User.sort('recent_sign_in').first.should == @user
end end
...@@ -484,11 +484,11 @@ describe User do ...@@ -484,11 +484,11 @@ describe User do
end end
it "sorts users as recently_created" do it "sorts users as recently_created" do
User.sort('recently_created').first.should == @user User.sort('created_desc').first.should == @user
end end
it "sorts users as late_created" do it "sorts users as late_created" do
User.sort('late_created').first.should == @user1 User.sort('created_asc').first.should == @user1
end end
it "sorts users by name when nil is passed" do it "sorts users by name when nil is passed" do
......
...@@ -26,30 +26,34 @@ describe API::API, api: true do ...@@ -26,30 +26,34 @@ describe API::API, api: true do
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
json_response.length.should == 3 json_response.length.should == 3
json_response.first['title'].should == merge_request.title json_response.last['title'].should == merge_request.title
end end
it "should return an array of all merge_requests" do it "should return an array of all merge_requests" do
get api("/projects/#{project.id}/merge_requests?state", user) get api("/projects/#{project.id}/merge_requests?state", user)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
json_response.length.should == 3 json_response.length.should == 3
json_response.first['title'].should == merge_request.title json_response.last['title'].should == merge_request.title
end end
it "should return an array of open merge_requests" do it "should return an array of open merge_requests" do
get api("/projects/#{project.id}/merge_requests?state=opened", user) get api("/projects/#{project.id}/merge_requests?state=opened", user)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
json_response.length.should == 1 json_response.length.should == 1
json_response.first['title'].should == merge_request.title json_response.last['title'].should == merge_request.title
end end
it "should return an array of closed merge_requests" do it "should return an array of closed merge_requests" do
get api("/projects/#{project.id}/merge_requests?state=closed", user) get api("/projects/#{project.id}/merge_requests?state=closed", user)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
json_response.length.should == 2 json_response.length.should == 2
json_response.first['title'].should == merge_request_closed.title json_response.second['title'].should == merge_request_closed.title
json_response.second['title'].should == merge_request_merged.title json_response.first['title'].should == merge_request_merged.title
end end
it "should return an array of merged merge_requests" do it "should return an array of merged merge_requests" do
get api("/projects/#{project.id}/merge_requests?state=merged", user) get api("/projects/#{project.id}/merge_requests?state=merged", user)
response.status.should == 200 response.status.should == 200
...@@ -69,9 +73,10 @@ describe API::API, api: true do ...@@ -69,9 +73,10 @@ describe API::API, api: true do
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
json_response.length.should == 3 json_response.length.should == 3
json_response.first['id'].should == @mr_earlier.id json_response.last['id'].should == @mr_earlier.id
json_response.last['id'].should == @mr_later.id json_response.first['id'].should == @mr_later.id
end end
it "should return an array of merge_requests in descending order" do it "should return an array of merge_requests in descending order" do
get api("/projects/#{project.id}/merge_requests?sort=desc", user) get api("/projects/#{project.id}/merge_requests?sort=desc", user)
response.status.should == 200 response.status.should == 200
...@@ -80,21 +85,23 @@ describe API::API, api: true do ...@@ -80,21 +85,23 @@ describe API::API, api: true do
json_response.first['id'].should == @mr_later.id json_response.first['id'].should == @mr_later.id
json_response.last['id'].should == @mr_earlier.id json_response.last['id'].should == @mr_earlier.id
end end
it "should return an array of merge_requests ordered by updated_at" do it "should return an array of merge_requests ordered by updated_at" do
get api("/projects/#{project.id}/merge_requests?order_by=updated_at", user) get api("/projects/#{project.id}/merge_requests?order_by=updated_at", user)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
json_response.length.should == 3 json_response.length.should == 3
json_response.first['id'].should == @mr_earlier.id json_response.last['id'].should == @mr_earlier.id
json_response.last['id'].should == @mr_later.id json_response.first['id'].should == @mr_later.id
end end
it "should return an array of merge_requests ordered by created_at" do it "should return an array of merge_requests ordered by created_at" do
get api("/projects/#{project.id}/merge_requests?sort=created_at", user) get api("/projects/#{project.id}/merge_requests?sort=created_at", user)
response.status.should == 200 response.status.should == 200
json_response.should be_an Array json_response.should be_an Array
json_response.length.should == 3 json_response.length.should == 3
json_response.first['id'].should == @mr_earlier.id json_response.last['id'].should == @mr_earlier.id
json_response.last['id'].should == @mr_later.id json_response.first['id'].should == @mr_later.id
end end
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment