diff --git a/CHANGELOG b/CHANGELOG index 8e07452b721..57f7fbab240 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,13 @@ v 2.4.0 + - Ability to block user + - Simplified dashboard area + - Improved admin area - Accept merge request + - Bootstrap 2.0 + - Responsive layout + - Big commits handling + - Perfomance improved + - Milestones v 2.3.1 - Issues pagination diff --git a/app/assets/stylesheets/gitlab_bootstrap.scss b/app/assets/stylesheets/gitlab_bootstrap.scss index 85672ab9ade..641064a3091 100644 --- a/app/assets/stylesheets/gitlab_bootstrap.scss +++ b/app/assets/stylesheets/gitlab_bootstrap.scss @@ -450,3 +450,17 @@ form { } } + +table.admin-table { + @extend .table-bordered; + @extend .zebra-striped; + th { + border-color: #CCC; + border-bottom: 1px solid #bbb; + background:#eee; + background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); + background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf); + background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); + background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); + } +} diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 5b194d89b9b..bbb1990c8a7 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -4,7 +4,9 @@ class Admin::UsersController < ApplicationController before_filter :authenticate_admin! def index - @admin_users = User.page(params[:page]) + @admin_users = User.scoped + @admin_users = @admin_users.filter(params[:filter]) + @admin_users = @admin_users.order("updated_at DESC").page(params[:page]) end def show @@ -38,13 +40,31 @@ class Admin::UsersController < ApplicationController @admin_user = User.find(params[:id]) end + def block + @admin_user = User.find(params[:id]) + + if @admin_user.block + redirect_to :back, alert: "Successfully blocked" + else + redirect_to :back, alert: "Error occured. User was not blocked" + end + end + + def unblock + @admin_user = User.find(params[:id]) + + if @admin_user.update_attribute(:blocked, false) + redirect_to :back, alert: "Successfully unblocked" + else + redirect_to :back, alert: "Error occured. User was not unblocked" + end + end + def create admin = params[:user].delete("admin") - blocked = params[:user].delete("blocked") @admin_user = User.new(params[:user]) @admin_user.admin = (admin && admin.to_i > 0) - @admin_user.blocked = blocked respond_to do |format| if @admin_user.save @@ -59,7 +79,6 @@ class Admin::UsersController < ApplicationController def update admin = params[:user].delete("admin") - blocked = params[:user].delete("blocked") if params[:user][:password].blank? params[:user].delete(:password) @@ -68,7 +87,6 @@ class Admin::UsersController < ApplicationController @admin_user = User.find(params[:id]) @admin_user.admin = (admin && admin.to_i > 0) - @admin_user.blocked = blocked respond_to do |format| if @admin_user.update_attributes(params[:user]) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 5ae19a7bdf8..17bcef4bb23 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,5 +1,6 @@ class ApplicationController < ActionController::Base before_filter :authenticate_user! + before_filter :reject_blocked! before_filter :set_current_user_for_mailer protect_from_forgery helper_method :abilities, :can? @@ -16,6 +17,14 @@ class ApplicationController < ActionController::Base protected + def reject_blocked! + if current_user && current_user.blocked + sign_out current_user + flash[:alert] = "Your account was blocked" + redirect_to new_user_session_path + end + end + def after_sign_in_path_for resource if resource.is_a?(User) && resource.respond_to?(:blocked) && resource.blocked sign_out resource diff --git a/app/models/user.rb b/app/models/user.rb index 3149de432c5..b98ae33818f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -48,7 +48,25 @@ class User < ActiveRecord::Base before_create :ensure_authentication_token alias_attribute :private_token, :authentication_token + scope :not_in_project, lambda { |project| where("id not in (:ids)", :ids => project.users.map(&:id) ) } + scope :admins, where(:admin => true) + scope :blocked, where(:blocked => true) + scope :active, where(:blocked => false) + + def self.filter filter_name + case filter_name + when "admins"; self.admins + when "blocked"; self.blocked + when "wop"; self.without_projects + else + self.active + end + end + + def self.without_projects + where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)') + end def identifier email.gsub /[@.]/, "_" @@ -58,6 +76,7 @@ class User < ActiveRecord::Base admin end + def require_ssh_key? keys.count == 0 end @@ -101,6 +120,17 @@ class User < ActiveRecord::Base def project_ids projects.map(&:id) end + + # Remove user from all projects and + # set blocked attribute to true + def block + users_projects.all.each do |membership| + return false unless membership.destroy + end + + self.blocked = true + save + end end # == Schema Information # diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index 046cffdcc04..bf576e49a4f 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -2,7 +2,7 @@ Projects = link_to 'New Project', new_admin_project_path, :class => "btn small right" %br -%table.zebra-striped.table-bordered +%table.admin-table %thead %th Name %th Path diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index a387fc72c15..5303a0e6f54 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -2,9 +2,8 @@ = @admin_project.name = link_to 'Edit', edit_admin_project_path(@admin_project), :class => "btn right small" -%hr - -%table.zebra-striped +%br +%table.zebra-striped.table-bordered %tr %td %b @@ -29,47 +28,47 @@ Description: %td = @admin_project.description +%br +%h3 + Team + %small + (#{@admin_project.users_projects.count}) +%br +%table.zebra-striped.table-bordered + %thead + %tr + %th Name + %th Project Access + %th Repository Access + %th + - @admin_project.users_projects.each do |tm| + %tr + %td + = link_to tm.user_name, admin_user_path(tm.user) + %td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), :class => "medium project-access-select", :disabled => :disabled + %td= link_to 'Edit Access', edit_admin_team_member_path(tm), :class => "btn small" + %td= link_to 'Remove from team', admin_team_member_path(tm), :confirm => 'Are you sure?', :method => :delete, :class => "btn danger small" -.span12 - - %h3 - Team - %small - (#{@admin_project.users_projects.count}) - - %hr - - %table.zebra-striped +%br +%h3 Add new team member +%br += form_tag team_update_admin_project_path(@admin_project), :class => "bulk_import", :method => :put do + %table.zebra-striped.table-bordered %thead %tr - %th Name - %th Project Access - %th Repository Access - %th + %th Users + %th Project Access: - - @admin_project.users_projects.each do |tm| - %tr - %td - = link_to tm.user_name, admin_user_path(tm.user) - %td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), :class => "medium project-access-select", :disabled => :disabled - %td= link_to 'Edit Access', edit_admin_team_member_path(tm), :class => "btn small" - %td= link_to 'Remove from team', admin_team_member_path(tm), :confirm => 'Are you sure?', :method => :delete, :class => "btn danger small" + %tr + %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name), :multiple => true + %td= select_tag :project_access, options_for_select(Project.access_options), :class => "project-access-select" - = form_tag team_update_admin_project_path(@admin_project), :class => "bulk_import", :method => :put do - %table - %thead - %tr - %th Users - %th Project Access: - %th Repo Access: - - %tr - %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name), :multiple => true - %td= select_tag :project_access, options_for_select(Project.access_options), :class => "project-access-select" - - .actions - = submit_tag 'Add', :class => "btn primary" + %tr + %td= submit_tag 'Add', :class => "btn primary" + %td + Read more about project permissions + %strong= link_to "here", help_permissions_path, :class => "vlink" :css form select { diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml index 2fd4f7107e2..d493ebf7852 100644 --- a/app/views/admin/users/_form.html.haml +++ b/app/views/admin/users/_form.html.haml @@ -6,41 +6,55 @@ - @admin_user.errors.full_messages.each do |msg| %li= msg - .clearfix - = f.label :name - .input= f.text_field :name - .clearfix - = f.label :email - .input= f.text_field :email - .clearfix - = f.label :password - .input= f.password_field :password - .clearfix - = f.label :password_confirmation - .input= f.password_field :password_confirmation + .row + .span6 + .clearfix + = f.label :name + .input + = f.text_field :name + %span.help-inline * requried + .clearfix + = f.label :email + .input + = f.text_field :email + %span.help-inline * requried + .clearfix + = f.label :password + .input= f.password_field :password + .clearfix + = f.label :password_confirmation + .input= f.password_field :password_confirmation + %hr + .clearfix + = f.label :skype + .input= f.text_field :skype + .clearfix + = f.label :linkedin + .input= f.text_field :linkedin + .clearfix + = f.label :twitter + .input= f.text_field :twitter + .span6 + .clearfix + = f.label :projects_limit + .input= f.text_field :projects_limit, :class => "small_input" - .clearfix - = f.label :projects_limit - .input= f.text_field :projects_limit, :class => "small_input" - - .clearfix - = f.label :skype - .input= f.text_field :skype - .clearfix - = f.label :linkedin - .input= f.text_field :linkedin - .clearfix - = f.label :twitter - .input= f.text_field :twitter - %hr - .clearfix - = f.label :admin do - = f.check_box :admin - %span Administrator - .clearfix - = f.label :blocked do - = f.check_box :blocked - %span Blocked + .alert + .clearfix + %p Give user ability to manage application. + = f.label :admin, :class => "checkbox" do + = f.check_box :admin + %span Administrator + - unless @admin_user.new_record? + .alert.alert-error + - if @admin_user.blocked + %span + = link_to 'Unblock', unblock_admin_user_path(@admin_user), :method => :put, :class => "btn small" + This user is blocked and is not able to login GitLab + - else + %span + = link_to 'Block', block_admin_user_path(@admin_user), :confirm => 'USER WILL BE BLOCKED! Are you sure?', :method => :put, :class => "btn small danger" + Blocked user will removed from all projects & will not be able to login to GitLab. .actions = f.submit 'Save', :class => "btn primary" - if @admin_user.new_record? diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index a7003f81124..13325986907 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -2,15 +2,29 @@ Users = link_to 'New User', new_admin_user_path, :class => "btn small right" %br -%table.zebra-striped.table-bordered + +%ul.nav.nav-pills + %li{:class => "#{'active' unless params[:filter]}"} + = link_to "Active", admin_users_path + %li{:class => "#{'active' if params[:filter] == "admins"}"} + = link_to admin_users_path(:filter => "admins") do + Admins + %li{:class => "#{'active' if params[:filter] == "blocked"}"} + = link_to admin_users_path(:filter => "blocked") do + Blocked + %li{:class => "#{'active' if params[:filter] == "wop"}"} + = link_to admin_users_path(:filter => "wop") do + Without projects + +%table.admin-table %thead %th Admin %th Name %th Email %th Projects + %th Edit %th Blocked %th - %th - @admin_users.each do |user| %tr @@ -18,8 +32,12 @@ %td= link_to user.name, [:admin, user] %td= user.email %td= user.users_projects.count - %td= check_box_tag "blocked", 1, user.blocked, :disabled => :disabled %td= link_to 'Edit', edit_admin_user_path(user), :id => "edit_#{dom_id(user)}", :class => "btn small" - %td= link_to 'Destroy', [:admin, user], :confirm => 'Are you sure?', :method => :delete, :class => "btn small danger" + %td + - if user.blocked + = link_to 'Unblock', unblock_admin_user_path(user), :method => :put, :class => "btn small success" + - else + = link_to 'Block', block_admin_user_path(user), :confirm => 'USER WILL BE BLOCKED! Are you sure?', :method => :put, :class => "btn small danger" + %td= link_to 'Destroy', [:admin, user], :confirm => 'USER WILL BE REMOVED! Are you sure?', :method => :delete, :class => "btn small danger" = paginate @admin_users, :theme => "admin" diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index fd7f4dcd937..060dd0c76ce 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -1,10 +1,14 @@ %h3 = @admin_user.name + - if @admin_user.blocked + %small Blocked + - if @admin_user.admin + %small Administrator = link_to 'Edit', edit_admin_user_path(@admin_user), :class => "btn small right" -%hr +%br -%table.zebra-striped +%table.zebra-striped.table-bordered %tr %td %b @@ -49,41 +53,47 @@ %td = @admin_user.twitter -%h3 Projects -%hr - -%table.zebra-striped - %tr - %thead - %th Name - %th Project Access - %th Repository Access - %th - %th - - - @admin_user.users_projects.each do |tm| - - project = tm.project - %tr - %td= link_to project.name, admin_project_path(project) - %td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), :class => "medium project-access-select", :disabled => :disabled - %td= link_to 'Edit Access', edit_admin_team_member_path(tm), :class => "btn small" - %td= link_to 'Remove from team', admin_team_member_path(tm), :confirm => 'Are you sure?', :method => :delete, :class => "btn small danger" +%br +%h3 Add User to Projects +%br = form_tag team_update_admin_user_path(@admin_user), :class => "bulk_import", :method => :put do - %table + %table.table-bordered %thead %tr %th Projects %th Project Access: - %th Repo Access: %tr %td= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name), :multiple => true %td= select_tag :project_access, options_for_select(Project.access_options), :class => "project-access-select" - .actions - = submit_tag 'Add', :class => "btn primary" + %tr + %td= submit_tag 'Add', :class => "btn primary" + %td + Read more about project permissions + %strong= link_to "here", help_permissions_path, :class => "vlink" +%br +- if @admin_user.projects.present? + %h3 Projects + %br + + %table.zebra-striped.table-bordered + %tr + %thead + %th Name + %th Project Access + %th + %th + + - @admin_user.users_projects.each do |tm| + - project = tm.project + %tr + %td= link_to project.name, admin_project_path(project) + %td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), :class => "medium project-access-select", :disabled => :disabled + %td= link_to 'Edit Access', edit_admin_team_member_path(tm), :class => "btn small" + %td= link_to 'Remove from team', admin_team_member_path(tm), :confirm => 'Are you sure?', :method => :delete, :class => "btn small danger" :css form select { diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml index d246addb317..6e180acd7dd 100644 --- a/app/views/help/index.html.haml +++ b/app/views/help/index.html.haml @@ -1,6 +1,6 @@ %h3 Gitlabhq - %span.right v2.3 + %span.right v2.4 %hr %h4 Self Hosted Git Management %h4 Fast, secure and stable solution based on Ruby on Rails & Gitolite. diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml index 78d3cb8aa77..a71dd57de02 100644 --- a/app/views/layouts/admin.html.haml +++ b/app/views/layouts/admin.html.haml @@ -7,8 +7,8 @@ .container %nav.main_menu = render "layouts/const_menu_links" - = link_to "Users", admin_users_path, :class => controller.controller_name == "users" ? "current" : nil = link_to "Projects", admin_projects_path, :class => controller.controller_name == "projects" ? "current" : nil + = link_to "Users", admin_users_path, :class => controller.controller_name == "users" ? "current" : nil = link_to "Emails", admin_emails_path, :class => controller.controller_name == "mailer" ? "current" : nil = link_to "Resque", "/info/resque" diff --git a/config/routes.rb b/config/routes.rb index c13ffd03dcc..6e29ec7e3dd 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -14,6 +14,8 @@ Gitlab::Application.routes.draw do resources :users do member do put :team_update + put :block + put :unblock end end resources :projects, :constraints => { :id => /[^\/]+/ } do