Commit c43b2896 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch '6-0-dev' of /home/git/repositories/gitlab/gitlabhq

parents f1fc1ae6 92ef845f
v 6.0.0
- Epic: Replace teams with group membership
- Add project filter on dashboard
- cache project graph
- Drop support of root namespaces
- Redesign project settings navigation
- Restlyed login screen
- Default theme is classic now
- Cache result of methods like authorize_projects, project.team.members etc
- Remove $.ready events
- Fix onclick events being double binded
- Add notification level to group membership
- Move all project controllers/views under Projects:: module
- Move all profile controllers/views under Profiles:: module
- Redesign ssh keys page
- Generate fingerprint for ssh keys
- You an use arrows to navigate at tree view
- Apply user project limit only for personal projects
v 5.4.0
- Ability to edit own comments
- Documentation improvements
......
load 'deploy'
load 'deploy/assets'
require 'bundler/capistrano'
load 'config/deploy'
......@@ -23,7 +23,7 @@ gem 'omniauth-github'
# Extracting information from a git repository
# Provide access to Gitlab::Git library
gem 'gitlab_git', '~> 1.3.0'
gem 'gitlab_git', '~> 1.4.1'
# Ruby/Rack Git Smart-HTTP Server Handler
gem 'gitlab-grack', '~> 1.0.1', require: 'grack'
......@@ -35,7 +35,7 @@ gem 'gitlab_omniauth-ldap', '1.0.3', require: "omniauth-ldap"
gem "gitlab-pygments.rb", '~> 0.3.2', require: 'pygments.rb'
# Git Wiki
gem "gitlab-gollum-lib", "~> 1.0.0", require: 'gollum-lib'
gem "gitlab-gollum-lib", "~> 1.0.1", require: 'gollum-lib'
# Language detection
gem "github-linguist", require: "linguist"
......@@ -173,7 +173,7 @@ group :development, :test do
gem 'factory_girl_rails'
# Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826)
gem 'minitest'
gem 'minitest', '~> 4.7.0'
# Generate Fake data
gem "ffaker"
......@@ -203,5 +203,5 @@ group :test do
end
group :production do
gem "gitlab_meta", '5.0'
gem "gitlab_meta", '6.0'
end
This diff is collapsed.
web: bundle exec puma -p $PORT
web: bundle exec unicorn_rails -p $PORT -E development
worker: bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,common,default,gitlab_shell
5.4.0.rc1
6.0.0.pre
app/assets/images/login-logo.png

1.4 KB | W: | H:

app/assets/images/login-logo.png

9.97 KB | W: | H:

app/assets/images/login-logo.png
app/assets/images/login-logo.png
app/assets/images/login-logo.png
app/assets/images/login-logo.png
  • 2-up
  • Swipe
  • Onion skin
class BlobView
constructor: ->
# See if there are lines selected
# "#L12" and "#L34-56" supported
highlightBlobLines = ->
if window.location.hash isnt ""
matches = window.location.hash.match(/\#L(\d+)(\-(\d+))?/)
first_line = parseInt(matches?[1])
last_line = parseInt(matches?[3])
unless isNaN first_line
last_line = first_line if isNaN(last_line)
$("#tree-content-holder .highlight .line").removeClass("hll")
$("#LC#{line}").addClass("hll") for line in [first_line..last_line]
$("#L#{first_line}").ScrollTo()
# Highlight the correct lines on load
highlightBlobLines()
# Highlight the correct lines when the hash part of the URL changes
$(window).on 'hashchange', highlightBlobLines
@BlobView = BlobView
......@@ -8,6 +8,22 @@ class Dashboard
@toggleFilter($(event.currentTarget))
@reloadActivities()
$(".dash-filter").keyup ->
terms = $(this).val()
uiBox = $(this).parents('.ui-box').first()
if terms == "" || terms == undefined
uiBox.find(".dash-list li").show()
else
uiBox.find(".dash-list li").each (index) ->
name = $(this).find(".well-title").text()
if name.toLowerCase().search(terms.toLowerCase()) == -1
$(this).hide()
else
$(this).show()
reloadActivities: ->
$(".content_list").html ''
Pager.init 20, true
......
......@@ -16,20 +16,26 @@ class Dispatcher
path = page.split(':')
switch page
when 'issues:index'
when 'projects:issues:index'
Issues.init()
when 'dashboard:show'
new Dashboard()
when 'commit:show'
when 'projects:commit:show'
new Commit()
when 'groups:show', 'teams:show', 'projects:show'
when 'groups:show', 'projects:show'
Pager.init(20, true)
when 'projects:new', 'projects:edit'
new Project()
when 'walls:show'
when 'projects:walls:show'
new Wall(project_id)
when 'teams:members:index'
when 'projects:teams:members:index'
new TeamMembers()
when 'groups:people'
new GroupMembers()
when 'projects:tree:show'
new TreeView()
when 'projects:blob:show'
new BlobView()
switch path.first()
when 'admin' then new Admin()
......
class GroupMembers
constructor: ->
$('li.users_group').bind 'ajax:success', ->
$(this).fadeOut()
@GroupMembers = GroupMembers
......@@ -50,11 +50,12 @@ window.startSpinner = ->
window.stopSpinner = ->
$('.turbolink-spinner').fadeOut()
window.stopEndlessScroll = ->
window.unbindEvents = ->
$(document).unbind('scroll')
$(document).off('scroll')
document.addEventListener("page:fetch", startSpinner)
document.addEventListener("page:fetch", stopEndlessScroll)
document.addEventListener("page:fetch", unbindEvents)
document.addEventListener("page:receive", stopSpinner)
$ ->
......@@ -66,7 +67,6 @@ $ ->
$('.appear-data').fadeIn()
e.preventDefault()
# Initialize chosen selects
$('select.chosen').chosen()
......@@ -110,6 +110,10 @@ $ ->
when 115
$("#search").focus()
e.preventDefault()
when 63
new Shortcuts()
e.preventDefault()
# Commit show suppressed diff
$(".supp_diff_link").bind "click", ->
......
var NoteList = {
id: null,
notes_path: null,
target_params: null,
target_id: 0,
......@@ -16,6 +16,22 @@ var NoteList = {
// get initial set of notes
NoteList.getContent();
// Unbind events to prevent firing twice
$(document).off("click", ".js-add-diff-note-button");
$(document).off("click", ".js-discussion-reply-button");
$(document).off("click", ".js-note-preview-button");
$(document).off("click", ".js-note-attachment-input");
$(document).off("click", ".js-close-discussion-note-form");
$(document).off("click", ".js-note-delete");
$(document).off("click", ".js-note-edit");
$(document).off("click", ".js-note-edit-cancel");
$(document).off("click", ".js-note-attachment-delete");
$(document).off("click", ".js-choose-note-attachment-button");
$(document).off("click", ".js-show-outdated-discussion");
$(document).off("ajax:complete", ".js-main-target-form");
// add a new diff note
$(document).on("click",
".js-add-diff-note-button",
......
class Shortcuts
constructor: ->
if $('#modal-shortcuts').length > 0
$('#modal-shortcuts').modal('show')
else
$.ajax(
url: '/help/shortcuts',
dataType: "script"
)
@Shortcuts = Shortcuts
......@@ -12,14 +12,35 @@ class window.ContributorsStatGraph
@master_graph.draw()
add_authors_graph: (author_data) ->
@authors = []
_.each(author_data, (d) =>
limited_author_data = author_data.slice(0, 100)
_.each(limited_author_data, (d) =>
author_header = @create_author_header(d)
$(".contributors-list").append(author_header)
@authors[d.author] = author_graph = new ContributorsAuthorGraph(d.dates)
author_graph.draw()
)
format_author_commit_info: (author) ->
author.commits + " commits " + author.additions + " ++ / " + author.deletions + " --"
commits = $('<span/>', {
class: 'graph-author-commits-count'
})
commits.text(author.commits + " commits")
additions = $('<span/>', {
class: 'graph-additions'
})
additions.text(author.additions + " ++")
deletions = $('<span/>', {
class: 'graph-deletions'
})
deletions.text(author.deletions + " --")
$('<span/>').append(commits)
.append(" / ")
.append(additions)
.append(" / ")
.append(deletions)
create_author_header: (author) ->
list_item = $('<li/>', {
class: 'person'
......@@ -30,7 +51,7 @@ class window.ContributorsStatGraph
class: 'commits'
})
author_commit_info = @format_author_commit_info(author)
author_commit_info_span.text(author_commit_info)
author_commit_info_span.html(author_commit_info)
list_item.append(author_name)
list_item.append(author_commit_info_span)
list_item
......@@ -52,10 +73,10 @@ class window.ContributorsStatGraph
@field = field
change_date_header: ->
x_domain = ContributorsGraph.prototype.x_domain
print_date_format = d3.time.format("%B %e %Y");
print = print_date_format(x_domain[0]) + " - " + print_date_format(x_domain[1]);
$("#date_header").text(print);
print_date_format = d3.time.format("%B %e %Y")
print = print_date_format(x_domain[0]) + " - " + print_date_format(x_domain[1])
$("#date_header").text(print)
redraw_author_commit_info: (author) ->
author_list_item = $(@authors[author.author].list_item)
author_commit_info = @format_author_commit_info(author)
author_list_item.find("span").text(author_commit_info)
\ No newline at end of file
author_list_item.find("span").html(author_commit_info)
......@@ -71,7 +71,7 @@ class window.ContributorsMasterGraph extends ContributorsGraph
super @width, @height
create_axes: ->
@x_axis = d3.svg.axis().scale(@x).orient("bottom")
@y_axis = d3.svg.axis().scale(@y).orient("left")
@y_axis = d3.svg.axis().scale(@y).orient("left").ticks(5)
create_svg: ->
@svg = d3.select("#contributors-master").append("svg")
.attr("width", @width + @MARGIN.left + @MARGIN.right)
......@@ -130,8 +130,8 @@ class window.ContributorsAuthorGraph extends ContributorsGraph
create_scale: ->
super @width, @height
create_axes: ->
@x_axis = d3.svg.axis().scale(@x).orient("bottom").tickFormat(d3.time.format("%m/%d"));
@y_axis = d3.svg.axis().scale(@y).orient("left")
@x_axis = d3.svg.axis().scale(@x).orient("bottom").ticks(8)
@y_axis = d3.svg.axis().scale(@y).orient("left").ticks(5)
create_area: (x, y) ->
@area = d3.svg.area().x((d) ->
parseDate = d3.time.format("%Y-%m-%d").parse
......@@ -148,7 +148,7 @@ class window.ContributorsAuthorGraph extends ContributorsGraph
.append("g")
.attr("transform", "translate(" + @MARGIN.left + "," + @MARGIN.top + ")")
draw_path: (data) ->
@svg.append("path").datum(data).attr("class", "area-contributor").attr("d", @area);
@svg.append("path").datum(data).attr("class", "area-contributor").attr("d", @area)
draw: ->
@create_scale()
@create_axes()
......
# Code browser tree slider
# Make the entire tree-item row clickable, but not if clicking another link (like a commit message)
$(".tree-content-holder .tree-item").live 'click', (e) ->
if (e.target.nodeName != "A")
path = $('.tree-item-file-name a', this).attr('href')
Turbolinks.visit(path)
class TreeView
constructor: ->
@initKeyNav()
$ ->
# Show the "Loading commit data" for only the first element
$('span.log_loading:first').removeClass('hide')
# Code browser tree slider
# Make the entire tree-item row clickable, but not if clicking another link (like a commit message)
$(".tree-content-holder .tree-item").on 'click', (e) ->
if (e.target.nodeName != "A")
path = $('.tree-item-file-name a', this).attr('href')
Turbolinks.visit(path)
# See if there are lines selected
# "#L12" and "#L34-56" supported
highlightBlobLines = ->
if window.location.hash isnt ""
matches = window.location.hash.match(/\#L(\d+)(\-(\d+))?/)
first_line = parseInt(matches?[1])
last_line = parseInt(matches?[3])
# Show the "Loading commit data" for only the first element
$('span.log_loading:first').removeClass('hide')
unless isNaN first_line
last_line = first_line if isNaN(last_line)
$("#tree-content-holder .highlight .line").removeClass("hll")
$("#LC#{line}").addClass("hll") for line in [first_line..last_line]
$("#L#{first_line}").ScrollTo()
initKeyNav: ->
li = $("tr.tree-item")
liSelected = null
$('body').keydown (e) ->
if e.which is 40
if liSelected
next = liSelected.next()
if next.length > 0
liSelected.removeClass "selected"
liSelected = next.addClass("selected")
else
liSelected = li.eq(0).addClass("selected")
# Highlight the correct lines on load
highlightBlobLines()
# Highlight the correct lines when the hash part of the URL changes
$(window).on 'hashchange', highlightBlobLines
$(liSelected).focus()
else if e.which is 38
if liSelected
next = liSelected.prev()
if next.length > 0
liSelected.removeClass "selected"
liSelected = next.addClass("selected")
else
liSelected = li.last().addClass("selected")
$(liSelected).focus()
else if e.which is 13
path = $('.tree-item.selected .tree-item-file-name a').attr('href')
Turbolinks.visit(path)
@TreeView = TreeView
......@@ -206,17 +206,6 @@ p.time {
}
}
.arrow{
background: #E3E5EA;
padding: 5px;
margin-top: 5px;
@include border-radius(5px);
text-shadow: none;
color: #999;
line-height: 16px;
font-weight: bold;
}
.thin_area{
height: 150px;
}
......@@ -311,14 +300,17 @@ li.note {
}
}
.error_message {
@extend .cred;
border-left: 4px solid #E99;
.error-message {
padding: 10px;
margin-bottom: 10px;
background: #FEE;
background: #C67;
padding-left: 20px;
margin: 0;
color: #FFF;
a {
color: #fff;
text-decoration: underline;
}
&.centered {
text-align: center;
}
......
......@@ -87,3 +87,10 @@ fieldset legend { font-size: 17px; }
color: #333;
text-shadow: 0 1px 1px #FFF;
}
pre.well-pre {
border: 1px solid #EEE;
background: #f9f9f9;
border-radius: 0;
color: #555;
}
......@@ -16,6 +16,12 @@
color: #888;
}
&.unstyled {
&:hover {
background: none;
}
}
&.smoke { background-color: #f5f5f5; }
&:hover {
......
......@@ -22,6 +22,13 @@
color: $style_color;
font-weight: bold;
}
&.nav-stacked-menu {
background: #FAFAFA;
li > a {
padding: 20px;
}
}
}
}
......
......@@ -7,28 +7,13 @@
@extend .pull-right;
.ui-box {
margin: 3px;
margin: 0px;
box-shadow: none;
> .title {
padding: 2px 15px;
}
.nav-projects-tabs li { padding: 0; }
.well-list {
li { padding: 15px; }
.arrow {
float: right;
padding: 10px;
margin: 0;
}
.last_activity {
padding-top: 5px;
display: block;
span, strong {
font-size: 12px;
color: #666;
}
}
}
@extend .ui-box;
}
}
}
......@@ -46,3 +31,72 @@
}
}
.dashboard {
.dash-filter {
margin: 0;
padding: 4px 6px;
width: 202px;
float: left;
margin-top: 3px;
margin-left: -2px;
}
}
@media (max-width: 1200px) {
.dashboard .dash-filter {
width: 132px;
}
}
.dash-sidebar-tabs {
margin-bottom: 2px;
border: none;
margin: 0;
li {
&.active {
a {
@include linear-gradient(#f5f5f5, #eee);
border-bottom: 1px solid #EEE !important;
&:hover {
background: #eee;
}
}
}
a {
border-color: #CCC !important;
}
}
}
.project-row, .group-row {
padding: 15px !important;
.namespace-name {
color: #666;
font-weight: bold;
}
.project-name, .group-name {
font-size: 16px;
}
.arrow {
float: right;
padding: 10px 5px;
margin: 0;
font-size: 20px;
color: #666;
}
.last-activity, .owner-info {
color: #AAA;
display: block;
margin-top: 5px;
.date, .owner {
color: #777;
}
}
}
......@@ -41,6 +41,8 @@
}
}
.event-body {
margin-left: 35px;
.commit p {
color: #666;
padding-top: 5px;
......@@ -51,7 +53,6 @@
.event-note {
color: #555;
margin-top: 5px;
margin-left: 40px;
pre {
border: none;
......@@ -77,10 +78,6 @@
margin-right: 5px;
}
}
.avatar {
position: relative;
top: -3px;
}
.event_icon {
position: relative;
float: right;
......@@ -95,11 +92,10 @@
}
}
ul {
margin-left: 50px;
margin-bottom: 5px;
.avatar {
width: 18px;
margin-top: 3px;
margin: 2px 4px;
}
}
......@@ -118,7 +114,12 @@
}
&.commits-stat {
display: block;
margin-top: 5px;
padding: 3px;
margin-top: 3px;
&:hover {
background: none;
}
}
}
}
......
.graph_holder {
.graph_holder {
border: 1px solid #aaa;
padding: 1px;
h4 {
h4 {
padding: 0 10px;
border-bottom: 1px solid #bbb;
@include bg-gray-gradient;
}
.graph {
.graph {
background: #f1f1f1;
height: 500px;
overflow-y: scroll;
......@@ -17,3 +17,16 @@
}
}
.graphs {
.graph-author-commits-count {
}
.graph-additions {
color: #4a2;
}
.graph-deletions {
color: #d12f19;
}
}
......@@ -120,7 +120,7 @@ header {
border-bottom: 1px solid #AAA;
.nav > li > a {
color: #DDD;
color: #AAA;
text-shadow: 0 1px 0 #444;
&:hover {
......@@ -130,6 +130,10 @@ header {
}
}
.turbolink-spinner {
color: #FFF;
}
.search {
.search-input {
background-color: #D2D5DA;
......@@ -156,7 +160,10 @@ header {
}
.project_name {
a {
color: #FFF;
color: #DDD;
&:hover {
color: #FFF;
}
}
color: #fff;
text-shadow: 0 1px 1px #444;
......
/* Login Page */
body.login-page{
background: #EEE;
background: #474D57;
.container .content { padding-top: 5%; }
}
......
.main-nav {
background: #f5f5f5;
margin: 30px 0;
margin-top: 10px;
margin-top: 0;
padding-top: 4px;
border-bottom: 1px solid #E1E1E1;
ul {
margin: auto;
height: 39px;
position: relative;
top: 3px;
height: 40px;
overflow: hidden;
.count {
font-weight: normal;
......@@ -33,10 +33,29 @@
display: table-cell;
width: 1%;
&.active {
border-bottom: 3px solid #777;
a {
color: $style_color;
font-weight: bolder;
&:after {
content: '';
display: block;
position: relative;
bottom: 8px;
left: 50%;
width: 0;
height: 0;
border-color: transparent transparent #777 transparent;
border-style: solid;
border-width: 6px;
margin-left: -6px;
}
}
}
&:hover {
a {
color: $style_color;
}
}
......@@ -54,11 +73,13 @@
display: block;
text-align: center;
font-weight: normal;
height: 36px;
height: 38px;
line-height: 34px;
color: #777;
text-shadow: 0 1px 1px white;
padding: 0 10px;
text-decoration: none;
padding-top: 2px;
}
}
}
......@@ -27,15 +27,15 @@
}
&.modern {
background: #567;
background: #345;
}
&.gray {
background: #708090;
background: #373737;
}
&.violet {
background: #657;
background: #547;
}
}
}
......
......@@ -23,6 +23,14 @@
}
cursor: pointer;
}
&.selected {
td {
background: $hover;
border-top: 1px solid #ADF;
border-bottom: 1px solid #ADF;
}
}
}
}
......
......@@ -8,4 +8,8 @@
background: #F9F9F9;
border-left: 1px solid #DDD;
}
.main-nav {
background: #FFF;
}
}
......@@ -16,15 +16,15 @@
@extend .header-dark;
&.navbar-gitlab {
.navbar-inner {
background: #657;
background: #547;
.app_logo {
&:hover {
background-color: #6A5A7A;
background-color: #435;
}
}
.separator {
background: #546;
border-left: 1px solid #706080;
background: #435;
border-left: 1px solid #658;
}
}
}
......
......@@ -16,15 +16,15 @@
@extend .header-dark;
&.navbar-gitlab {
.navbar-inner {
background: #708090;
background: #373737;
.app_logo {
&:hover {
background-color: #6A7A8A;
background-color: #272727;
}
}
.separator {
background: #607080;
border-left: 1px solid #8090A0;
background: #272727;
border-left: 1px solid #474747;
}
}
}
......
......@@ -16,15 +16,15 @@
@extend .header-dark;
&.navbar-gitlab {
.navbar-inner {
background: #567;
background: #345;
.app_logo {
&:hover {
background-color: #516171;
background-color: #234;
}
}
.separator {
background: #456;
border-left: 1px solid #678;
background: #234;
border-left: 1px solid #456;
}
}
}
......
......@@ -33,7 +33,7 @@ module Projects
# Find matching namespace and check if it allowed
# for current user if namespace_id passed.
if allowed_namespace?(current_user, namespace_id)
@project.namespace_id = namespace_id unless namespace_id == Namespace.global_id
@project.namespace_id = namespace_id
else
deny_namespace
return @project
......@@ -48,6 +48,7 @@ module Projects
# Import project from cloneable resource
if @project.valid? && @project.import_url.present?
shell = Gitlab::Shell.new
if shell.import_repository(@project.path_with_namespace, @project.import_url)
# We should create satellite for imported repo
@project.satellite.create unless @project.satellite.exists?
......@@ -59,7 +60,11 @@ module Projects
end
if @project.save
@project.users_projects.create(project_access: UsersProject::MASTER, user: current_user)
unless @project.group
@project.users_projects.create(project_access: UsersProject::MASTER, user: current_user)
end
@project.discover_default_branch
end
@project
......@@ -75,12 +80,8 @@ module Projects
end
def allowed_namespace?(user, namespace_id)
if namespace_id == Namespace.global_id
return user.admin
else
namespace = Namespace.find_by_id(namespace_id)
current_user.can?(:manage_namespace, namespace)
end
namespace = Namespace.find_by_id(namespace_id)
current_user.can?(:manage_namespace, namespace)
end
end
end
......@@ -5,12 +5,7 @@ module Projects
allowed_transfer = can?(current_user, :change_namespace, project) || role == :admin
if allowed_transfer && namespace_id.present?
if namespace_id == Namespace.global_id
if project.namespace.present?
# Transfer to global namespace from anyone
project.transfer(nil)
end
elsif namespace_id.to_i != project.namespace_id
if namespace_id.to_i != project.namespace_id
# Transfer to someone namespace
namespace = Namespace.find(namespace_id)
project.transfer(namespace)
......
......@@ -25,7 +25,7 @@ class Admin::GroupsController < Admin::ApplicationController
if @group.save
redirect_to [:admin, @group], notice: 'Group was successfully created.'
else
render action: "new"
render "new"
end
end
......@@ -34,42 +34,23 @@ class Admin::GroupsController < Admin::ApplicationController
owner_id =group_params.delete(:owner_id)
if owner_id
@group.owner = User.find(owner_id)
@group.change_owner(User.find(owner_id))
end
if @group.update_attributes(group_params)
redirect_to [:admin, @group], notice: 'Group was successfully updated.'
else
render action: "edit"
render "edit"
end
end
def project_update
project_ids = params[:project_ids]
Project.where(id: project_ids).each do |project|
project.transfer(@group)
end
redirect_to :back, notice: 'Group was successfully updated.'
end
def remove_project
@project = Project.find(params[:project_id])
@project.transfer(nil)
redirect_to :back, notice: 'Group was successfully updated.'
end
def project_teams_update
@group.add_users_to_project_teams(params[:user_ids].split(','), params[:project_access])
@group.add_users(params[:user_ids].split(','), params[:group_access])
redirect_to [:admin, @group], notice: 'Users were successfully added.'
end
def destroy
@group.truncate_teams
@group.destroy
redirect_to admin_groups_path, notice: 'Group was successfully deleted.'
......
class Admin::MembersController < Admin::ApplicationController
def destroy
user = User.find_by_username(params[:id])
project = Project.find_with_namespace(params[:project_id])
project.users_projects.where(user_id: user).first.destroy
redirect_to :back
end
end
# Provides a base class for Admin controllers to subclass
#
# Automatically sets the layout and ensures an administrator is logged in
class Admin::Projects::ApplicationController < Admin::ApplicationController
protected
def project
@project ||= Project.find_with_namespace(params[:project_id])
end
end
class Admin::Projects::MembersController < Admin::Projects::ApplicationController
def edit
@member = team_member
@project = project
@team_member_relation = team_member_relation
end
def update
if team_member_relation.update_attributes(params[:team_member])
redirect_to [:admin, project], notice: 'Project Access was successfully updated.'
else
render action: "edit"
end
end
def destroy
team_member_relation.destroy
redirect_to :back
end
private
def team_member
@member ||= project.users.find_by_username(params[:id])
end
def team_member_relation
team_member.users_projects.find_by_project_id(project)
end
end
......@@ -9,13 +9,13 @@ class Admin::ProjectsController < Admin::ApplicationController
@projects = @projects.where(public: true) if params[:public_only].present?
@projects = @projects.with_push if params[:with_push].present?
@projects = @projects.abandoned if params[:abandoned].present?
@projects = @projects.where(namespace_id: nil) if params[:namespace_id] == Namespace.global_id
@projects = @projects.search(params[:name]) if params[:name].present?
@projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20)
end
def show
@repository = @project.repository
@group = @project.group
end
protected
......
# Provides a base class for Admin controllers to subclass
#
# Automatically sets the layout and ensures an administrator is logged in
class Admin::Teams::ApplicationController < Admin::ApplicationController
private
def user_team
@team = UserTeam.find_by_path(params[:team_id])
end
end
class Admin::Teams::MembersController < Admin::Teams::ApplicationController
def new
@users = User.potential_team_members(user_team)
end
def create
unless params[:user_ids].blank?
user_ids = params[:user_ids]
access = params[:default_project_access]
is_admin = params[:group_admin]
user_team.add_members(user_ids, access, is_admin)
end
redirect_to admin_team_path(user_team), notice: 'Members were successfully added into Team of users.'
end
def edit
team_member
end
def update
options = {default_projects_access: params[:default_project_access], group_admin: params[:group_admin]}
if user_team.update_membership(team_member, options)
redirect_to admin_team_path(user_team), notice: "Membership for #{team_member.name} was successfully updated in Team of users."
else
render :edit
end
end
def destroy
user_team.remove_member(team_member)
redirect_to admin_team_path(user_team), notice: "Member #{team_member.name} was successfully removed from Team of users."
end
protected
def team_member
@member ||= user_team.members.find_by_username(params[:id])
end
end
class Admin::Teams::ProjectsController < Admin::Teams::ApplicationController
def new
@projects = Project.scoped
@projects = @projects.without_team(user_team) if user_team.projects.any?
#@projects.reject!(&:empty_repo?)
end
def create
unless params[:project_ids].blank?
project_ids = params[:project_ids]
access = params[:greatest_project_access]
user_team.assign_to_projects(project_ids, access)
end
redirect_to admin_team_path(user_team), notice: 'Team of users was successfully assigned to projects.'
end
def edit
team_project
end
def update
if user_team.update_project_access(team_project, params[:greatest_project_access])
redirect_to admin_team_path(user_team), notice: 'Access was successfully updated.'
else
render :edit
end
end
def destroy
user_team.resign_from_project(team_project)
redirect_to admin_team_path(user_team), notice: 'Team of users was successfully reassigned from project.'
end
protected
def team_project
@project ||= user_team.projects.find_with_namespace(params[:id])
end
end
class Admin::TeamsController < Admin::ApplicationController
def index
@teams = UserTeam.order('name ASC')
@teams = @teams.search(params[:name]) if params[:name].present?
@teams = @teams.page(params[:page]).per(20)
end
def show
user_team
end
def new
@team = UserTeam.new
end
def edit
user_team
end
def create
@team = UserTeam.new(params[:user_team])
@team.path = @team.name.dup.parameterize if @team.name
@team.owner = current_user
if @team.save
redirect_to admin_team_path(@team), notice: 'Team of users was successfully created.'
else
render action: "new"
end
end
def update
user_team_params = params[:user_team].dup
owner_id = user_team_params.delete(:owner_id)
if owner_id
user_team.owner = User.find(owner_id)
end
if user_team.update_attributes(user_team_params)
redirect_to admin_team_path(user_team), notice: 'Team of users was successfully updated.'
else
render action: "edit"
end
end
def destroy
user_team.destroy
redirect_to admin_teams_path, notice: 'Team of users was successfully deleted.'
end
protected
def user_team
@team ||= UserTeam.find_by_path(params[:id])
end
end
class Admin::UsersController < Admin::ApplicationController
before_filter :admin_user, only: [:show, :edit, :update, :destroy]
before_filter :user, only: [:show, :edit, :update, :destroy]
def index
@admin_users = User.scoped
@admin_users = @admin_users.filter(params[:filter])
@admin_users = @admin_users.search(params[:name]) if params[:name].present?
@admin_users = @admin_users.alphabetically.page(params[:page])
@users = User.scoped
@users = @users.filter(params[:filter])
@users = @users.search(params[:name]) if params[:name].present?
@users = @users.alphabetically.page(params[:page])
end
def show
# Projects user can be added to
@not_in_projects = Project.scoped
@not_in_projects = @not_in_projects.without_user(admin_user) if admin_user.authorized_projects.present?
# Projects he already own or joined
@projects = admin_user.authorized_projects
@projects = user.authorized_projects
end
def team_update
UsersProject.add_users_into_projects(
params[:project_ids],
[admin_user.id],
params[:project_access]
)
redirect_to [:admin, admin_user], notice: 'Teams were successfully updated.'
end
def new
@admin_user = User.new.with_defaults
@user = User.new.with_defaults
end
def edit
admin_user
user
end
def block
if admin_user.block
if user.block
redirect_to :back, alert: "Successfully blocked"
else
redirect_to :back, alert: "Error occured. User was not blocked"
......@@ -45,7 +29,7 @@ class Admin::UsersController < Admin::ApplicationController
end
def unblock
if admin_user.activate
if user.activate
redirect_to :back, alert: "Successfully unblocked"
else
redirect_to :back, alert: "Error occured. User was not unblocked"
......@@ -60,17 +44,17 @@ class Admin::UsersController < Admin::ApplicationController
password_expires_at: Time.now
}
@admin_user = User.new(params[:user].merge(opts), as: :admin)
@admin_user.admin = (admin && admin.to_i > 0)
@admin_user.created_by_id = current_user.id
@user = User.new(params[:user].merge(opts), as: :admin)
@user.admin = (admin && admin.to_i > 0)
@user.created_by_id = current_user.id
respond_to do |format|
if @admin_user.save
format.html { redirect_to [:admin, @admin_user], notice: 'User was successfully created.' }
format.json { render json: @admin_user, status: :created, location: @admin_user }
if @user.save
format.html { redirect_to [:admin, @user], notice: 'User was successfully created.' }
format.json { render json: @user, status: :created, location: @user }
else
format.html { render action: "new" }
format.json { render json: @admin_user.errors, status: :unprocessable_entity }
format.html { render "new" }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
......@@ -83,26 +67,26 @@ class Admin::UsersController < Admin::ApplicationController
params[:user].delete(:password_confirmation)
end
admin_user.admin = (admin && admin.to_i > 0)
user.admin = (admin && admin.to_i > 0)
respond_to do |format|
if admin_user.update_attributes(params[:user], as: :admin)
format.html { redirect_to [:admin, admin_user], notice: 'User was successfully updated.' }
if user.update_attributes(params[:user], as: :admin)
format.html { redirect_to [:admin, user], notice: 'User was successfully updated.' }
format.json { head :ok }
else
# restore username to keep form action url.
admin_user.username = params[:id]
format.html { render action: "edit" }
format.json { render json: admin_user.errors, status: :unprocessable_entity }
user.username = params[:id]
format.html { render "edit" }
format.json { render json: user.errors, status: :unprocessable_entity }
end
end
end
def destroy
if admin_user.personal_projects.count > 0
if user.personal_projects.count > 0
redirect_to admin_users_path, alert: "User is a project owner and can't be removed." and return
end
admin_user.destroy
user.destroy
respond_to do |format|
format.html { redirect_to admin_users_path }
......@@ -112,7 +96,7 @@ class Admin::UsersController < Admin::ApplicationController
protected
def admin_user
@admin_user ||= User.find_by_username!(params[:id])
def user
@user ||= User.find_by_username!(params[:id])
end
end
......@@ -95,14 +95,6 @@ class ApplicationController < ActionController::Base
return access_denied! unless can?(current_user, :create_team, nil)
end
def authorize_manage_user_team!
return access_denied! unless user_team.present? && can?(current_user, :manage_user_team, user_team)
end
def authorize_admin_user_team!
return access_denied! unless user_team.present? && can?(current_user, :admin_user_team, user_team)
end
def access_denied!
render "errors/access_denied", layout: "errors", status: 404
end
......
class DashboardController < ApplicationController
respond_to :html
before_filter :load_projects
before_filter :load_projects, except: [:projects]
before_filter :event_filter, only: :show
def show
@groups = current_user.authorized_groups.sort_by(&:human_name)
@has_authorized_projects = @projects.count > 0
@teams = current_user.authorized_teams
@projects_count = @projects.count
@projects = @projects.limit(20)
......@@ -27,18 +26,21 @@ class DashboardController < ApplicationController
def projects
@projects = case params[:scope]
when 'personal' then
@projects.personal(current_user)
current_user.namespace.projects
when 'joined' then
@projects.joined(current_user)
current_user.authorized_projects.joined(current_user)
when 'owned' then
current_user.owned_projects
else
@projects
end
current_user.authorized_projects
end.sorted_by_activity
@projects = @projects.tagged_with(params[:label]) if params[:label].present?
@projects = @projects.search(params[:search]) if params[:search].present?
@projects = @projects.page(params[:page]).per(30)
@labels = Project.where(id: @projects.map(&:id)).tags_on(:labels)
@labels = current_user.authorized_projects.tags_on(:labels)
@projects = @projects.tagged_with(params[:label]) if params[:label].present?
@projects = @projects.page(params[:page]).per(30)
end
# Get authored or assigned open merge requests
......
......@@ -63,19 +63,8 @@ class GroupsController < ApplicationController
def people
@project = group.projects.find(params[:project_id]) if params[:project_id]
@users = @project ? @project.users : group.users
@users.sort_by!(&:name)
if @project
@team_member = @project.users_projects.new
else
@team_member = UsersProject.new
end
end
def team_members
@group.add_users_to_project_teams(params[:user_ids].split(','), params[:project_access])
redirect_to people_group_path(@group), notice: 'Users were successfully added.'
@members = group.users_groups.order('group_access DESC')
@users_group = UsersGroup.new
end
def edit
......@@ -83,7 +72,7 @@ class GroupsController < ApplicationController
def update
group_params = params[:group].dup
owner_id =group_params.delete(:owner_id)
owner_id = group_params.delete(:owner_id)
if owner_id
@group.owner = User.find(owner_id)
......
......@@ -12,4 +12,7 @@ class HelpController < ApplicationController
not_found!
end
end
def shortcuts
end
end
class KeysController < ApplicationController
class Profiles::KeysController < ApplicationController
layout "profile"
respond_to :js, :html
def index
@keys = current_user.keys.all
@keys = current_user.keys.order('id DESC').all
end
def show
......@@ -12,15 +11,16 @@ class KeysController < ApplicationController
def new
@key = current_user.keys.new
respond_with(@key)
end
def create
@key = current_user.keys.new(params[:key])
@key.save
respond_with(@key)
if @key.save
redirect_to profile_key_path(@key)
else
render 'new'
end
end
def destroy
......@@ -28,7 +28,7 @@ class KeysController < ApplicationController
@key.destroy
respond_to do |format|
format.html { redirect_to keys_url }
format.html { redirect_to profile_keys_url }
format.js { render nothing: true }
end
end
......
class NotificationsController < ApplicationController
class Profiles::NotificationsController < ApplicationController
layout 'profile'
def show
@notification = current_user.notification
@users_projects = current_user.users_projects
@users_groups = current_user.users_groups
end
def update
......@@ -12,6 +13,10 @@ class NotificationsController < ApplicationController
@saved = if type == 'global'
current_user.notification_level = params[:notification_level]
current_user.save
elsif type == 'group'
users_group = current_user.users_groups.find(params[:notification_id])
users_group.notification_level = params[:notification_level]
users_group.save
else
users_project = current_user.users_projects.find(params[:notification_id])
users_project.notification_level = params[:notification_level]
......
class PasswordsController < ApplicationController
class Profiles::PasswordsController < ApplicationController
layout 'navless'
skip_before_filter :check_password_expiration
......
class ProjectResourceController < ApplicationController
before_filter :project
before_filter :repository
end
class Projects::ApplicationController < ApplicationController
before_filter :project
before_filter :repository
layout 'projects'
end
# Controller for viewing a file's blame
class BlameController < ProjectResourceController
class Projects::BlameController < Projects::ApplicationController
include ExtractsPath
# Authorize
......
# Controller for viewing a file's blame
class BlobController < ProjectResourceController
class Projects::BlobController < Projects::ApplicationController
include ExtractsPath
# Authorize
......
# Controller for a specific Commit
#
# Not to be confused with CommitsController, plural.
class CommitController < ProjectResourceController
class Projects::CommitController < Projects::ApplicationController
# Authorize
before_filter :authorize_read_project!
before_filter :authorize_code_access!
......
require "base64"
class CommitsController < ProjectResourceController
class Projects::CommitsController < Projects::ApplicationController
include ExtractsPath
# Authorize
......
class CompareController < ProjectResourceController
class Projects::CompareController < Projects::ApplicationController
# Authorize
before_filter :authorize_read_project!
before_filter :authorize_code_access!
......
class DeployKeysController < ProjectResourceController
class Projects::DeployKeysController < Projects::ApplicationController
respond_to :html
# Authorize
before_filter :authorize_admin_project!
layout "project_settings"
def index
@enabled_keys = @project.deploy_keys.all
@available_keys = available_keys - @enabled_keys
......
# Controller for edit a repository's file
class EditTreeController < ProjectResourceController
class Projects::EditTreeController < Projects::ApplicationController
include ExtractsPath
# Authorize
......
class GraphsController < ProjectResourceController
class Projects::GraphsController < Projects::ApplicationController
# Authorize
before_filter :authorize_read_project!
before_filter :authorize_code_access!
......@@ -8,10 +8,18 @@ class GraphsController < ProjectResourceController
respond_to do |format|
format.html
format.js do
@repo = @project.repository
@stats = Gitlab::Git::GitStats.new(@repo.raw, @repo.root_ref)
@log = @stats.parsed_log.to_json
fetch_graph
end
end
end
private
def fetch_graph
@log = @project.repository.graph_log.to_json
@success = true
rescue => ex
@log = []
@success = false
end
end
class HooksController < ProjectResourceController
class Projects::HooksController < Projects::ApplicationController
# Authorize
before_filter :authorize_read_project!
before_filter :authorize_admin_project!, only: [:new, :create, :destroy]
respond_to :html
layout "project_settings"
def index
@hooks = @project.hooks.all
@hook = ProjectHook.new
......
class IssuesController < ProjectResourceController
class Projects::IssuesController < Projects::ApplicationController
before_filter :module_enabled
before_filter :issue, only: [:edit, :update, :show]
......@@ -23,7 +23,7 @@ class IssuesController < ProjectResourceController
assignee_id, milestone_id = params[:assignee_id], params[:milestone_id]
@assignee = @project.users.find(assignee_id) if assignee_id.present? && !assignee_id.to_i.zero?
@assignee = @project.team.find(assignee_id) if assignee_id.present? && !assignee_id.to_i.zero?
@milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero?
respond_to do |format|
......
class LabelsController < ProjectResourceController
class Projects::LabelsController < Projects::ApplicationController
before_filter :module_enabled
# Allow read any issue
......
require 'gitlab/satellite/satellite'
class MergeRequestsController < ProjectResourceController
class Projects::MergeRequestsController < Projects::ApplicationController
before_filter :module_enabled
before_filter :merge_request, only: [:edit, :update, :show, :commits, :diffs, :automerge, :automerge_check, :ci_status]
before_filter :validates_merge_request, only: [:show, :diffs]
......@@ -30,7 +30,6 @@ class MergeRequestsController < ProjectResourceController
end
def diffs
@diffs = @merge_request.diffs
@commit = @merge_request.last_commit
@comments_allowed = @reply_allowed = true
......@@ -54,7 +53,7 @@ class MergeRequestsController < ProjectResourceController
@merge_request.reload_code
redirect_to [@project, @merge_request], notice: 'Merge request was successfully created.'
else
render action: "new"
render "new"
end
end
......@@ -64,7 +63,7 @@ class MergeRequestsController < ProjectResourceController
@merge_request.mark_as_unchecked
redirect_to [@project, @merge_request], notice: 'Merge request was successfully updated.'
else
render action: "edit"
render "edit"
end
end
......
class MilestonesController < ProjectResourceController
class Projects::MilestonesController < Projects::ApplicationController
before_filter :module_enabled
before_filter :milestone, only: [:edit, :update, :destroy, :show]
......
class NetworkController < ProjectResourceController
class Projects::NetworkController < Projects::ApplicationController
include ExtractsPath
include ApplicationHelper
......
class NotesController < ProjectResourceController
class Projects::NotesController < Projects::ApplicationController
# Authorize
before_filter :authorize_read_note!
before_filter :authorize_write_note!, only: [:create]
......
class ProtectedBranchesController < ProjectResourceController
class Projects::ProtectedBranchesController < Projects::ApplicationController
# Authorize
before_filter :authorize_read_project!
before_filter :require_non_empty_project
......
# Controller for viewing a file's raw
class RawController < ProjectResourceController
class Projects::RawController < Projects::ApplicationController
include ExtractsPath
# Authorize
......
class RefsController < ProjectResourceController
class Projects::RefsController < Projects::ApplicationController
include ExtractsPath
# Authorize
......
class RepositoriesController < ProjectResourceController
class Projects::RepositoriesController < Projects::ApplicationController
# Authorize
before_filter :authorize_read_project!
before_filter :authorize_code_access!
......
class ServicesController < ProjectResourceController
class Projects::ServicesController < Projects::ApplicationController
# Authorize
before_filter :authorize_admin_project!
before_filter :service, only: [:edit, :update, :test]
respond_to :html
layout "project_settings"
def index
@project.build_missing_services
@services = @project.services.reload
......
......@@ -14,7 +14,7 @@ class Projects::SnippetsController < Projects::ApplicationController
# Allow destroy snippet
before_filter :authorize_admin_project_snippet!, only: [:destroy]
layout 'project_resource'
layout 'projects'
respond_to :html
......
class TeamMembersController < ProjectResourceController
class Projects::TeamMembersController < Projects::ApplicationController
# Authorize
before_filter :authorize_read_project!
before_filter :authorize_admin_project!, except: [:index, :show]
def index
@team = @project.users_projects.scoped
@team = @team.send(params[:type]) if %w(masters developers reporters guests).include?(params[:type])
@team = @team.sort_by(&:project_access).reverse.group_by(&:project_access)
layout "project_settings"
@assigned_teams = @project.user_team_project_relationships
def index
@group = @project.group
@users_projects = @project.users_projects.order('project_access DESC')
end
def new
......
class Projects::TeamsController < Projects::ApplicationController
before_filter :authorize_admin_team_member!
def available
@teams = current_user.is_admin? ? UserTeam.scoped : current_user.user_teams
@teams = @teams.without_project(project)
unless @teams.any?
redirect_to project_team_index_path(project), notice: "No available teams for assigment."
end
end
def assign
unless params[:team_id].blank?
team = UserTeam.find(params[:team_id])
access = params[:greatest_project_access]
team.assign_to_project(project, access)
end
redirect_to project_team_index_path(project)
end
def resign
team = project.user_teams.find_by_path(params[:id])
team.resign_from_project(project)
redirect_to project_team_index_path(project)
end
protected
def user_team
@team ||= UserTeam.find_by_path(params[:id])
end
end
# Controller for viewing a repository's file structure
class TreeController < ProjectResourceController
class Projects::TreeController < Projects::ApplicationController
include ExtractsPath
# Authorize
......
class WallsController < ProjectResourceController
class Projects::WallsController < Projects::ApplicationController
before_filter :module_enabled
respond_to :js, :html
......
class WikisController < ProjectResourceController
class Projects::WikisController < Projects::ApplicationController
before_filter :authorize_read_wiki!
before_filter :authorize_write_wiki!, only: [:edit, :create, :history]
before_filter :authorize_admin_wiki!, only: :destroy
......
class ProjectsController < ProjectResourceController
class ProjectsController < Projects::ApplicationController
skip_before_filter :project, only: [:new, :create]
skip_before_filter :repository, only: [:new, :create]
......@@ -15,6 +15,7 @@ class ProjectsController < ProjectResourceController
end
def edit
render 'edit', layout: "project_settings"
end
def create
......@@ -26,7 +27,7 @@ class ProjectsController < ProjectResourceController
if @project.saved?
redirect_to @project
else
render action: "new"
render "new"
end
end
format.js
......@@ -42,7 +43,7 @@ class ProjectsController < ProjectResourceController
format.html { redirect_to edit_project_path(@project), notice: 'Project was successfully updated.' }
format.js
else
format.html { render action: "edit" }
format.html { render "edit", layout: "project_settings" }
format.js
end
end
......@@ -89,7 +90,7 @@ class ProjectsController < ProjectResourceController
redirect_to(@forked_project, notice: 'Project was successfully forked.')
else
@title = 'Fork project'
render action: "fork"
render "fork"
end
end
format.js
......@@ -100,7 +101,7 @@ class ProjectsController < ProjectResourceController
@suggestions = {
emojis: Emoji.names,
issues: @project.issues.select([:id, :title, :description]),
members: @project.users.select([:username, :name]).order(:username)
members: @project.team.members.sort_by(&:username).map { |user| { username: user.username, name: user.name } }
}
respond_to do |format|
......
class Teams::ApplicationController < ApplicationController
layout 'user_team'
before_filter :authorize_manage_user_team!
protected
def user_team
@team ||= UserTeam.find_by_path(params[:team_id])
end
end
class Teams::MembersController < Teams::ApplicationController
skip_before_filter :authorize_manage_user_team!, only: [:index]
def index
@members = user_team.members
end
def new
@users = User.potential_team_members(user_team)
end
def create
unless params[:user_ids].blank?
user_ids = params[:user_ids].split(',')
access = params[:default_project_access]
is_admin = params[:group_admin]
user_team.add_members(user_ids, access, is_admin)
end
redirect_to team_members_path(user_team), notice: 'Members were successfully added into Team of users.'
end
def edit
team_member
end
def update
member_params = params[:team_member]
options = {
default_projects_access: member_params[:permission],
group_admin: member_params[:group_admin]
}
if user_team.update_membership(team_member, options)
redirect_to team_members_path(user_team), notice: "Membership for #{team_member.name} was successfully updated in Team of users."
else
render :edit
end
end
def destroy
user_team.remove_member(team_member)
redirect_to team_path(user_team), notice: "Member #{team_member.name} was successfully removed from Team of users."
end
protected
def team_member
@member ||= user_team.members.find_by_username(params[:id])
end
end
class Teams::ProjectsController < Teams::ApplicationController
def create
redirect_to :back if params[:project_ids].blank?
project_ids = params[:project_ids]
access = params[:greatest_project_access]
# Reject non-allowed projects
allowed_project_ids = current_user.owned_projects.map(&:id)
project_ids.select! { |id| allowed_project_ids.include?(id.to_i) }
# Assign projects to team
user_team.assign_to_projects(project_ids, access)
redirect_to edit_team_path(user_team), notice: 'Team of users was successfully assigned to projects.'
end
def edit
team_project
end
def update
if user_team.update_project_access(team_project, params[:greatest_project_access])
redirect_to edit_team_path(user_team), notice: 'Access was successfully updated.'
else
render :edit
end
end
def destroy
user_team.resign_from_project(team_project)
redirect_to team_projects_path(user_team), notice: 'Team of users was successfully reassigned from project.'
end
private
def team_project
@project ||= user_team.projects.find_with_namespace(params[:id])
end
end
class TeamsController < ApplicationController
# Authorize
before_filter :authorize_create_team!, only: [:new, :create]
before_filter :authorize_manage_user_team!, only: [:edit, :update]
before_filter :authorize_admin_user_team!, only: [:destroy]
before_filter :user_team, except: [:new, :create]
layout :determine_layout
before_filter :set_title, only: [:new, :create]
def show
projects
@events = Event.in_projects(user_team.project_ids).limit(20).offset(params[:offset] || 0)
end
def edit
projects
@avaliable_projects = current_user.owned_projects.without_team(user_team)
end
def update
if user_team.update_attributes(params[:user_team])
redirect_to team_path(user_team)
else
render action: :edit
end
end
def destroy
user_team.destroy
redirect_to dashboard_path
end
def new
@team = UserTeam.new
end
def create
@team = UserTeam.new(params[:user_team])
@team.owner = current_user unless params[:owner]
@team.path = @team.name.dup.parameterize if @team.name
if @team.save
# Add current user as Master to the team
@team.add_members([current_user.id], UsersProject::MASTER, true)
redirect_to team_path(@team)
else
render action: :new
end
end
# Get authored or assigned open merge requests
def merge_requests
projects
@merge_requests = MergeRequest.of_user_team(user_team)
@merge_requests = FilterContext.new(@merge_requests, params).execute
@merge_requests = @merge_requests.recent.page(params[:page]).per(20)
end
# Get only assigned issues
def issues
projects
@issues = Issue.of_user_team(user_team)
@issues = FilterContext.new(@issues, params).execute
@issues = @issues.recent.page(params[:page]).per(20)
@issues = @issues.includes(:author, :project)
end
protected
def projects
@projects ||= user_team.projects.sorted_by_activity
end
def user_team
@team ||= current_user.authorized_teams.find_by_path(params[:id])
end
def set_title
@title = 'New Team'
end
def determine_layout
if [:new, :create].include?(action_name.to_sym)
'navless'
else
'user_team'
end
end
end
class UsersGroupsController < ApplicationController
before_filter :group
# Authorize
before_filter :authorize_admin_group!
layout 'group'
def create
@group.add_users(params[:user_ids].split(','), params[:group_access])
redirect_to people_group_path(@group), notice: 'Users were successfully added.'
end
def update
# TODO: implement
end
def destroy
@users_group = @group.users_groups.find(params[:id])
@users_group.destroy unless @users_group.user == @group.owner
respond_to do |format|
format.html { redirect_to people_group_path(@group), notice: 'User was successfully removed from group.' }
format.js { render nothing: true }
end
end
protected
def group
@group ||= Group.find_by_path(params[:group_id])
end
def authorize_admin_group!
unless can?(current_user, :manage_group, group)
return render_404
end
end
end
module Admin::Teams::MembersHelper
def member_since(team, member)
team.user_team_user_relationships.find_by_user_id(member).created_at
end
end
module Admin::Teams::ProjectsHelper
def assigned_since(team, project)
team.user_team_project_relationships.find_by_project_id(project).created_at
end
end
......@@ -92,11 +92,10 @@ module ApplicationHelper
def search_autocomplete_source
projects = current_user.authorized_projects.map { |p| { label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) } }
groups = current_user.authorized_groups.map { |group| { label: "group: #{simple_sanitize(group.name)}", url: group_path(group) } }
teams = current_user.authorized_teams.map { |team| { label: "team: #{simple_sanitize(team.name)}", url: team_path(team) } }
default_nav = [
{ label: "My Profile", url: profile_path },
{ label: "My SSH Keys", url: keys_path },
{ label: "My SSH Keys", url: profile_keys_path },
{ label: "My Dashboard", url: root_path },
{ label: "Admin Section", url: admin_root_path },
]
......@@ -116,19 +115,21 @@ module ApplicationHelper
project_nav = []
if @project && @project.repository.exists? && @project.repository.root_ref
project_nav = [
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Issues", url: project_issues_path(@project) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Files", url: project_tree_path(@project, @ref || @project.repository.root_ref) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Commits", url: project_commits_path(@project, @ref || @project.repository.root_ref) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Network", url: project_network_path(@project, @ref || @project.repository.root_ref) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Graph", url: project_graph_path(@project, @ref || @project.repository.root_ref) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Issues", url: project_issues_path(@project) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Merge Requests", url: project_merge_requests_path(@project) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Milestones", url: project_milestones_path(@project) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Snippets", url: project_snippets_path(@project) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Team", url: project_team_index_path(@project) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Tree", url: project_tree_path(@project, @ref || @project.repository.root_ref) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Wall", url: project_wall_path(@project) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Wiki", url: project_wikis_path(@project) },
]
end
[groups, teams, projects, default_nav, project_nav, help_nav].flatten.to_json
[groups, projects, default_nav, project_nav, help_nav].flatten.to_json
end
def emoji_autocomplete_source
......
......@@ -109,7 +109,7 @@ module CommitsHelper
end
def commit_to_html commit
escape_javascript(render 'commits/commit', commit: commit)
escape_javascript(render 'projects/commits/commit', commit: commit)
end
def diff_line_content(line)
......
......@@ -45,13 +45,15 @@ module EventsHelper
def event_feed_title(event)
if event.issue?
"#{event.author_name} #{event.action_name} issue ##{event.target_id}: #{event.issue_title} at #{event.project.name}"
"#{event.author_name} #{event.action_name} issue ##{event.target_id}: #{event.issue_title} at #{event.project_name}"
elsif event.merge_request?
"#{event.author_name} #{event.action_name} MR ##{event.target_id}: #{event.merge_request_title} at #{event.project.name}"
"#{event.author_name} #{event.action_name} MR ##{event.target_id}: #{event.merge_request_title} at #{event.project_name}"
elsif event.push?
"#{event.author_name} #{event.push_action_name} #{event.ref_type} #{event.ref_name} at #{event.project.name}"
"#{event.author_name} #{event.push_action_name} #{event.ref_type} #{event.ref_name} at #{event.project_name}"
elsif event.membership_changed?
"#{event.author_name} #{event.action_name} #{event.project.name}"
"#{event.author_name} #{event.action_name} #{event.project_name}"
elsif event.note?
"#{event.author_name} commented on #{event.note_target_type} ##{truncate event.note_target_id} at #{event.project_name}"
else
""
end
......
......@@ -14,4 +14,8 @@ module GroupsHelper
merge_requests_group_path(@group, options)
end
end
def remove_user_from_group_message(group, user)
"You are going to remove #{user.name} from #{group.name} Group. Are you sure?"
end
end
......@@ -3,12 +3,10 @@ module NamespacesHelper
groups = current_user.owned_groups.select {|n| n.type == 'Group'}
users = current_user.namespaces.reject {|n| n.type == 'Group'}
global_opts = ["Global", [['/', Namespace.global_id]] ]
group_opts = ["Groups", groups.sort_by(&:human_name).map {|g| [g.human_name, g.id]} ]
users_opts = [ "Users", users.sort_by(&:human_name).map {|u| [u.human_name, u.id]} ]
options = []
options << global_opts if current_user.admin
options << group_opts
options << users_opts
......
......@@ -10,13 +10,13 @@ module TreeHelper
tree = ""
# Render folders if we have any
tree += render partial: 'tree/tree_item', collection: folders, locals: {type: 'folder'} if folders.present?
tree += render partial: 'projects/tree/tree_item', collection: folders, locals: {type: 'folder'} if folders.present?
# Render files if we have any
tree += render partial: 'tree/blob_item', collection: files, locals: {type: 'file'} if files.present?
tree += render partial: 'projects/tree/blob_item', collection: files, locals: {type: 'file'} if files.present?
# Render submodules if we have any
tree += render partial: 'tree/submodule_item', collection: submodules if submodules.present?
tree += render partial: 'projects/tree/submodule_item', collection: submodules if submodules.present?
tree.html_safe
end
......
module UserTeamsHelper
def team_filter_path(entity, options={})
exist_opts = {
status: params[:status],
project_id: params[:project_id],
}
options = exist_opts.merge(options)
case entity
when 'issue' then
issues_team_path(@team, options)
when 'merge_request'
merge_requests_team_path(@team, options)
end
end
def grouped_user_team_members(team)
team.user_team_user_relationships.sort_by(&:permission).reverse.group_by(&:permission)
end
def remove_from_user_team_message(team, member)
"You are going to remove #{member.name} from #{team.name}. Are you sure?"
end
end
......@@ -8,7 +8,7 @@ module Emails
def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id)
@issue = Issue.find(issue_id)
@previous_assignee ||= User.find(previous_assignee_id)
@previous_assignee = User.find_by_id(previous_assignee_id) if previous_assignee_id
@project = @issue.project
mail(to: recipient(recipient_id), subject: subject("changed issue ##{@issue.id}", @issue.title))
end
......
......@@ -8,7 +8,7 @@ module Emails
def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id)
@merge_request = MergeRequest.find(merge_request_id)
@previous_assignee ||= User.find(previous_assignee_id)
@previous_assignee = User.find_by_id(previous_assignee_id) if previous_assignee_id
@project = @merge_request.project
mail(to: recipient(recipient_id), subject: subject("changed merge request !#{@merge_request.id}", @merge_request.title))
end
......
......@@ -8,10 +8,10 @@ module Emails
end
def project_was_moved_email(user_project_id)
@users_project = UsersProject.find user_project_id
@project = @users_project.project
mail(to: @users_project.user.email,
def project_was_moved_email(project_id, user_id)
@user = User.find user_id
@project = Project.find project_id
mail(to: @user.email,
subject: subject("project was moved"))
end
end
......
......@@ -10,8 +10,8 @@ class Ability
when "ProjectSnippet" then project_snippet_abilities(user, subject)
when "PersonalSnippet" then personal_snippet_abilities(user, subject)
when "MergeRequest" then merge_request_abilities(user, subject)
when "Group", "Namespace" then group_abilities(user, subject)
when "UserTeam" then user_team_abilities(user, subject)
when "Group" then group_abilities(user, subject)
when "Namespace" then namespace_abilities(user, subject)
else []
end.concat(global_abilities(user))
end
......@@ -19,7 +19,6 @@ class Ability
def global_abilities(user)
rules = []
rules << :create_group if user.can_create_group
rules << :create_team if user.can_create_team
rules
end
......@@ -50,6 +49,10 @@ class Ability
rules << project_admin_rules
end
if project.group && project.group.owners.include?(user)
rules << project_admin_rules
end
rules.flatten
end
......@@ -132,7 +135,7 @@ class Ability
rules = []
# Only group owner and administrators can manage group
if group.owner == user || user.admin?
if group.owners.include?(user) || user.admin?
rules << [
:manage_group,
:manage_namespace
......@@ -142,16 +145,14 @@ class Ability
rules.flatten
end
def user_team_abilities user, team
def namespace_abilities user, namespace
rules = []
# Only group owner and administrators can manage team
if user.admin? || team.owner == user || team.admin?(user)
rules << [ :manage_user_team ]
end
if team.owner == user || user.admin?
rules << [ :admin_user_team ]
# Only namespace owner and administrators can manage it
if namespace.owner == user || user.admin?
rules << [
:manage_namespace
]
end
rules.flatten
......
......@@ -11,6 +11,8 @@
# updated_at :datetime not null
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
#
class CampfireService < Service
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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